diff --git a/.vscode/settings.json b/.vscode/settings.json index f8b04f126..f103538b7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,5 +17,8 @@ "python.envFile": "${workspaceRoot}/.env", "python.analysis.stubPath": ".vscode", "jupyter.interactiveWindow.cellMarker.codeRegex": "^# COMMAND ----------|^# Databricks notebook source|^(#\\s*%%|#\\s*\\|#\\s*In\\[\\d*?\\]|#\\s*In\\[ \\])", - "jupyter.interactiveWindow.cellMarker.default": "# COMMAND ----------" + "jupyter.interactiveWindow.cellMarker.default": "# COMMAND ----------", + "files.associations": { + "script": "shellscript" + } } diff --git a/acceptance/bundle/exec/basic/output.txt b/acceptance/bundle/exec/basic/output.txt index d45ebfb83..c1be99c9e 100644 --- a/acceptance/bundle/exec/basic/output.txt +++ b/acceptance/bundle/exec/basic/output.txt @@ -1,6 +1,6 @@ ->>> errcode [CLI] bundle exec -- echo hello -hello -Error: Error waiting for command: exec: Wait was already called +>>> [CLI] bundle exec -- echo hello, world +hello, world -Exit code: 1 +>>> [CLI] bundle exec -- pwd +[TMPDIR] diff --git a/acceptance/bundle/exec/basic/script b/acceptance/bundle/exec/basic/script index c65cd19ea..48d20c1bd 100644 --- a/acceptance/bundle/exec/basic/script +++ b/acceptance/bundle/exec/basic/script @@ -1 +1,3 @@ -trace errcode $CLI bundle exec -- echo hello +trace $CLI bundle exec -- echo "hello, world" + +trace $CLI bundle exec -- pwd diff --git a/acceptance/bundle/exec/cwd/a/b/c/.gitkeep b/acceptance/bundle/exec/cwd/a/b/c/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/acceptance/bundle/exec/cwd/databricks.yml b/acceptance/bundle/exec/cwd/databricks.yml new file mode 100644 index 000000000..432311dab --- /dev/null +++ b/acceptance/bundle/exec/cwd/databricks.yml @@ -0,0 +1,2 @@ +bundle: + name: foobar diff --git a/acceptance/bundle/exec/cwd/output.txt b/acceptance/bundle/exec/cwd/output.txt new file mode 100644 index 000000000..e6496afab --- /dev/null +++ b/acceptance/bundle/exec/cwd/output.txt @@ -0,0 +1,8 @@ + +>>> cd a/b/c + +>>> pwd +[TMPDIR]/a/b/c + +>>> [CLI] bundle exec -- pwd +[TMPDIR] diff --git a/acceptance/bundle/exec/cwd/script b/acceptance/bundle/exec/cwd/script new file mode 100644 index 000000000..73a0966d3 --- /dev/null +++ b/acceptance/bundle/exec/cwd/script @@ -0,0 +1,6 @@ +trace cd a/b/c + +trace pwd + +# Scripts that bundle exec executes should run from the bundle root. +trace $CLI bundle exec -- pwd diff --git a/acceptance/bundle/exec/no-auth/databricks.yml b/acceptance/bundle/exec/no-auth/databricks.yml new file mode 100644 index 000000000..432311dab --- /dev/null +++ b/acceptance/bundle/exec/no-auth/databricks.yml @@ -0,0 +1,2 @@ +bundle: + name: foobar diff --git a/acceptance/bundle/exec/no-auth/output.txt b/acceptance/bundle/exec/no-auth/output.txt new file mode 100644 index 000000000..fce8e3f61 --- /dev/null +++ b/acceptance/bundle/exec/no-auth/output.txt @@ -0,0 +1,6 @@ + +>>> [CLI] bundle exec -- echo hello +hello + +>>> [CLI] bundle exec -- pwd +[TMPDIR] diff --git a/acceptance/bundle/exec/no-auth/script b/acceptance/bundle/exec/no-auth/script new file mode 100644 index 000000000..93715d448 --- /dev/null +++ b/acceptance/bundle/exec/no-auth/script @@ -0,0 +1,8 @@ +export DATABRICKS_HOST="" +export DATABRICKS_TOKEN="" + +# Confirm that bundle exec works for commands that do not require authentication, +# even if authentication is not provided. +trace $CLI bundle exec -- echo hello + +trace $CLI bundle exec -- pwd diff --git a/acceptance/bundle/exec/no-bundle/output.txt b/acceptance/bundle/exec/no-bundle/output.txt new file mode 100644 index 000000000..7030c5405 --- /dev/null +++ b/acceptance/bundle/exec/no-bundle/output.txt @@ -0,0 +1,5 @@ + +>>> [CLI] bundle exec -- echo hello +Error: unable to locate bundle root: databricks.yml not found + +Exit code: 1 diff --git a/acceptance/bundle/exec/no-bundle/script b/acceptance/bundle/exec/no-bundle/script new file mode 100644 index 000000000..b872f65db --- /dev/null +++ b/acceptance/bundle/exec/no-bundle/script @@ -0,0 +1 @@ +trace $CLI bundle exec -- echo hello diff --git a/cmd/bundle/exec.go b/cmd/bundle/exec.go index daeb0c4a2..64bc70da5 100644 --- a/cmd/bundle/exec.go +++ b/cmd/bundle/exec.go @@ -24,7 +24,13 @@ func newExecCommand() *cobra.Command { Use: "exec", Short: "Execute a command using the same authentication context as the bundle", Args: cobra.MinimumNArgs(1), - Long: `Examples: + // TODO: format once we have all the documentation here. + // TODO: implement and pass the cwd environment variable. Maybe we can defer + // it until we have a scripts section. + Long: ` +Note: This command executes scripts + +Examples: 1. databricks bundle exec -- echo hello 2. databricks bundle exec -- /bin/bash -c "echo hello"" 3. databricks bundle exec -- uv run pytest"`, @@ -36,7 +42,7 @@ func newExecCommand() *cobra.Command { // Load the bundle configuration to get the authentication credentials // set in the context. // TODO: What happens when no bundle is configured? - _, diags := root.MustConfigureBundle(cmd) + b, diags := root.MustConfigureBundle(cmd) if diags.HasError() { return diags.Error() } @@ -44,7 +50,11 @@ func newExecCommand() *cobra.Command { childCmd := exec.Command(args[0], args[1:]...) childCmd.Env = auth.ProcessEnv(root.ConfigUsed(cmd.Context())) - // Create pipes for stdout and stderr + // Execute all scripts from the bundle root directory. + childCmd.Dir = b.BundleRootPath + + // Create pipes for stdout and stderr. + // TODO: Test streaming of this? Is there a way? stdout, err := childCmd.StdoutPipe() if err != nil { return fmt.Errorf("Error creating stdout pipe: %w", err) @@ -87,8 +97,7 @@ func newExecCommand() *cobra.Command { if exitErr, ok := err.(*exec.ExitError); ok { return fmt.Errorf("Command exited with code: %d", exitErr.ExitCode()) } - - if err := childCmd.Wait(); err != nil { + if err != nil { return fmt.Errorf("Error waiting for command: %w", err) }