From ae8e02c3235408b40f601e7a07818d7ab8fb192f Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 15 Apr 2026 16:34:27 +0000 Subject: [PATCH 1/4] Fix script output dropping last line without trailing newline bufio.Reader.ReadString returns both data and io.EOF when the stream ends without a delimiter. The old loop condition `for err == nil` caused the last line of output to be silently dropped when it lacked a trailing newline. This affected any bundle script (experimental.scripts hooks) whose output didn't end with `\n`. Restructure the loop to always process data before checking for errors, which is the idiomatic Go pattern for ReadString. Task: 001.md Co-authored-by: Isaac --- bundle/scripts/scripts.go | 12 +++++--- bundle/scripts/scripts_test.go | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 bundle/scripts/scripts_test.go diff --git a/bundle/scripts/scripts.go b/bundle/scripts/scripts.go index cca380129a..29cef46041 100644 --- a/bundle/scripts/scripts.go +++ b/bundle/scripts/scripts.go @@ -51,10 +51,14 @@ func (m *script) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics { cmdio.LogString(ctx, fmt.Sprintf("Executing '%s' script", m.scriptHook)) reader := bufio.NewReader(out) - line, err := reader.ReadString('\n') - for err == nil { - cmdio.LogString(ctx, strings.TrimSpace(line)) - line, err = reader.ReadString('\n') + for { + line, err := reader.ReadString('\n') + if line != "" { + cmdio.LogString(ctx, strings.TrimSpace(line)) + } + if err != nil { + break + } } err = cmd.Wait() diff --git a/bundle/scripts/scripts_test.go b/bundle/scripts/scripts_test.go new file mode 100644 index 0000000000..38941fc798 --- /dev/null +++ b/bundle/scripts/scripts_test.go @@ -0,0 +1,50 @@ +package scripts_test + +import ( + "runtime" + "testing" + + "github.com/databricks/cli/bundle" + "github.com/databricks/cli/bundle/config" + "github.com/databricks/cli/bundle/scripts" + "github.com/databricks/cli/libs/cmdio" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExecuteOutputWithoutTrailingNewline(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping on windows") + } + + dir := t.TempDir() + b := &bundle.Bundle{ + BundleRootPath: dir, + Config: config.Root{ + Experimental: &config.Experimental{ + Scripts: map[config.ScriptHook]config.Command{ + config.ScriptPreInit: "printf 'line1\nline2\nlast line without newline'", + }, + }, + }, + } + + ctx, stderr := cmdio.NewTestContextWithStderr(t.Context()) + diags := bundle.Apply(ctx, b, scripts.Execute(config.ScriptPreInit)) + require.NoError(t, diags.Error()) + + output := stderr.String() + assert.Contains(t, output, "line1") + assert.Contains(t, output, "line2") + assert.Contains(t, output, "last line without newline") +} + +func TestExecuteNoScript(t *testing.T) { + b := &bundle.Bundle{ + Config: config.Root{}, + } + + ctx, _ := cmdio.NewTestContextWithStderr(t.Context()) + diags := bundle.Apply(ctx, b, scripts.Execute(config.ScriptPreInit)) + require.NoError(t, diags.Error()) +} From 6483881f8ee8009f4132356cf5fef4c7a0abc770 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 15 Apr 2026 16:42:36 +0000 Subject: [PATCH 2/4] Update NEXT_CHANGELOG.md Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 0db4b902e1..f205d55449 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -7,6 +7,7 @@ ### CLI ### Bundles +* Fix script output dropping last line without trailing newline (denik/random-bugfixes-4) ### Dependency updates From 1b8e5da07821fb70cfaa574473c630309efe3415 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 16 Apr 2026 13:58:14 +0000 Subject: [PATCH 3/4] Add acceptance test for script output without trailing newline This test demonstrates the bug where the last line of script output was dropped when it didn't end with a trailing newline. Running this test with -useversion 0.296.0 shows the bug: "line without newline" is missing from the output. Task: 002.md Co-authored-by: Isaac --- .../scripts/no-trailing-newline/databricks.yml | 6 ++++++ .../bundle/scripts/no-trailing-newline/myscript.py | 5 +++++ .../scripts/no-trailing-newline/out.test.toml | 5 +++++ .../bundle/scripts/no-trailing-newline/output.txt | 13 +++++++++++++ .../bundle/scripts/no-trailing-newline/script | 1 + 5 files changed, 30 insertions(+) create mode 100644 acceptance/bundle/scripts/no-trailing-newline/databricks.yml create mode 100644 acceptance/bundle/scripts/no-trailing-newline/myscript.py create mode 100644 acceptance/bundle/scripts/no-trailing-newline/out.test.toml create mode 100644 acceptance/bundle/scripts/no-trailing-newline/output.txt create mode 100644 acceptance/bundle/scripts/no-trailing-newline/script diff --git a/acceptance/bundle/scripts/no-trailing-newline/databricks.yml b/acceptance/bundle/scripts/no-trailing-newline/databricks.yml new file mode 100644 index 0000000000..3f4116151d --- /dev/null +++ b/acceptance/bundle/scripts/no-trailing-newline/databricks.yml @@ -0,0 +1,6 @@ +bundle: + name: scripts_no_trailing_newline + +experimental: + scripts: + preinit: "python3 ./myscript.py" diff --git a/acceptance/bundle/scripts/no-trailing-newline/myscript.py b/acceptance/bundle/scripts/no-trailing-newline/myscript.py new file mode 100644 index 0000000000..c8937dbf85 --- /dev/null +++ b/acceptance/bundle/scripts/no-trailing-newline/myscript.py @@ -0,0 +1,5 @@ +import sys + +sys.stdout.write("line 1\n") +sys.stdout.write("line 2\n") +sys.stdout.write("line without newline") diff --git a/acceptance/bundle/scripts/no-trailing-newline/out.test.toml b/acceptance/bundle/scripts/no-trailing-newline/out.test.toml new file mode 100644 index 0000000000..d560f1de04 --- /dev/null +++ b/acceptance/bundle/scripts/no-trailing-newline/out.test.toml @@ -0,0 +1,5 @@ +Local = true +Cloud = false + +[EnvMatrix] + DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/bundle/scripts/no-trailing-newline/output.txt b/acceptance/bundle/scripts/no-trailing-newline/output.txt new file mode 100644 index 0000000000..49ccb79237 --- /dev/null +++ b/acceptance/bundle/scripts/no-trailing-newline/output.txt @@ -0,0 +1,13 @@ + +>>> [CLI] bundle validate +Executing 'preinit' script +line 1 +line 2 +line without newline +Name: scripts_no_trailing_newline +Target: default +Workspace: + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/scripts_no_trailing_newline/default + +Validation OK! diff --git a/acceptance/bundle/scripts/no-trailing-newline/script b/acceptance/bundle/scripts/no-trailing-newline/script new file mode 100644 index 0000000000..5350876150 --- /dev/null +++ b/acceptance/bundle/scripts/no-trailing-newline/script @@ -0,0 +1 @@ +trace $CLI bundle validate From a86395cce4dcc738e89adbfcda05cab6b35502c7 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 16 Apr 2026 14:14:37 +0000 Subject: [PATCH 4/4] Update NEXT_CHANGELOG.md with PR #4995 --- NEXT_CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index f205d55449..7c419b8c69 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -7,7 +7,7 @@ ### CLI ### Bundles -* Fix script output dropping last line without trailing newline (denik/random-bugfixes-4) +* Fix script output dropping last line without trailing newline ([#4995](https://github.com/databricks/cli/pull/4995)) ### Dependency updates