From 62eb653164e4935384af41f3f3b4790421763ad3 Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Fri, 29 May 2026 02:12:22 +0100 Subject: [PATCH 1/8] fix(template): trim extra trailing newline in writeToFile output-dir path Signed-off-by: Cloud-Architect-Emma --- pkg/action/install.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 580b8a0cb..5cf9980af 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -732,7 +732,7 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er defer f.Close() - _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, data) + _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, strings.TrimRight(data, "\n")) if err != nil { return err From ff18e5b0ef9891a8cf39eeb7eb7e82afee5dc6cc Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Sat, 30 May 2026 12:39:41 +0100 Subject: [PATCH 2/8] test(action): add test for writeToFile trailing newline fix Verify that output files written via --output-dir end with exactly one newline and not two, covering the regression fixed in #32163. Co-authored-by: Cloud-Architect-Emma Signed-off-by: Cloud-Architect-Emma --- pkg/action/install_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 38d692a0b..76a87d0fa 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1297,3 +1297,35 @@ func TestInstallRelease_WaitOptionsPassedDownstream(t *testing.T) { // Verify that WaitOptions were passed to GetWaiter is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") } + + +func TestWriteToFileNoTrailingNewline(t *testing.T) { + is := assert.New(t) + instAction := installAction(t) + vals := map[string]any{} + + dir := t.TempDir() + instAction.OutputDir = dir + + _, err := instAction.Run(buildChart(withSampleTemplates()), vals) + if err != nil { + t.Fatalf("Failed install: %s", err) + } + + // Each output file should end with exactly one newline, not two. + for _, name := range []string{ + "hello/templates/hello", + "hello/templates/goodbye", + } { + path := filepath.Join(dir, name) + data, err := os.ReadFile(path) + if err != nil { + t.Fatalf("Failed to read %s: %s", path, err) + } + is.True(len(data) > 0, "file should not be empty: %s", name) + is.Equal(byte('\n'), data[len(data)-1], "file should end with exactly one newline: %s", name) + if len(data) >= 2 { + is.NotEqual(byte('\n'), data[len(data)-2], "file should not end with two newlines: %s", name) + } + } +} \ No newline at end of file From d35c8eeb99c67588aba1ac08bfc14eb513065e7b Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Sat, 30 May 2026 13:16:55 +0100 Subject: [PATCH 3/8] test(action): fix formatting in TestWriteToFileNoTrailingNewline Co-authored-by: Cloud-Architect-Emma Signed-off-by: Cloud-Architect-Emma --- pkg/action/install_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 76a87d0fa..da68f4521 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1298,7 +1298,6 @@ func TestInstallRelease_WaitOptionsPassedDownstream(t *testing.T) { is.NotEmpty(failer.RecordedWaitOptions, "WaitOptions should be passed to GetWaiter") } - func TestWriteToFileNoTrailingNewline(t *testing.T) { is := assert.New(t) instAction := installAction(t) @@ -1328,4 +1327,4 @@ func TestWriteToFileNoTrailingNewline(t *testing.T) { is.NotEqual(byte('\n'), data[len(data)-2], "file should not end with two newlines: %s", name) } } -} \ No newline at end of file +} From f21f0c1358df4737314f389bad225ce8225fe9ed Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Sat, 30 May 2026 17:57:34 +0100 Subject: [PATCH 4/8] test(action): simplify trailing newline assertion Co-authored-by: Cloud-Architect-Emma Signed-off-by: Cloud-Architect-Emma --- pkg/action/install_test.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index da68f4521..d8c523262 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1299,7 +1299,6 @@ func TestInstallRelease_WaitOptionsPassedDownstream(t *testing.T) { } func TestWriteToFileNoTrailingNewline(t *testing.T) { - is := assert.New(t) instAction := installAction(t) vals := map[string]any{} @@ -1311,7 +1310,7 @@ func TestWriteToFileNoTrailingNewline(t *testing.T) { t.Fatalf("Failed install: %s", err) } - // Each output file should end with exactly one newline, not two. + // Each output file should end with exactly one newline (no double newline). for _, name := range []string{ "hello/templates/hello", "hello/templates/goodbye", @@ -1321,10 +1320,12 @@ func TestWriteToFileNoTrailingNewline(t *testing.T) { if err != nil { t.Fatalf("Failed to read %s: %s", path, err) } - is.True(len(data) > 0, "file should not be empty: %s", name) - is.Equal(byte('\n'), data[len(data)-1], "file should end with exactly one newline: %s", name) - if len(data) >= 2 { - is.NotEqual(byte('\n'), data[len(data)-2], "file should not end with two newlines: %s", name) + content := string(data) + if strings.HasSuffix(content, "\n\n") { + t.Errorf("file %s ends with double newline, expected single newline", name) + } + if !strings.HasSuffix(content, "\n") { + t.Errorf("file %s does not end with a newline", name) } } -} +} \ No newline at end of file From 84fe10720e5b0b5c4a92489f93448c36f1f7b60a Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Sat, 30 May 2026 23:29:45 +0100 Subject: [PATCH 5/8] test(action): fix gofmt formatting Co-authored-by: Cloud-Architect-Emma Signed-off-by: Cloud-Architect-Emma --- pkg/action/install_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index d8c523262..efcf0b0da 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1328,4 +1328,4 @@ func TestWriteToFileNoTrailingNewline(t *testing.T) { t.Errorf("file %s does not end with a newline", name) } } -} \ No newline at end of file +} From efb2e0984f9ac2ca0595302fb3779d3e651c69ff Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Sun, 31 May 2026 09:36:45 +0100 Subject: [PATCH 6/8] test(action): fix template file names in trailing newline test Co-authored-by: Cloud-Architect-Emma Signed-off-by: Cloud-Architect-Emma --- pkg/action/install_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index efcf0b0da..312e58964 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1312,8 +1312,8 @@ func TestWriteToFileNoTrailingNewline(t *testing.T) { // Each output file should end with exactly one newline (no double newline). for _, name := range []string{ - "hello/templates/hello", "hello/templates/goodbye", + "hello/templates/with-partials", } { path := filepath.Join(dir, name) data, err := os.ReadFile(path) From b9b535c21821868139d5271ff719ec8b27795d71 Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Sun, 31 May 2026 20:18:23 +0100 Subject: [PATCH 7/8] fix(template): use TrimSuffix instead of TrimRight to avoid over-stripping TrimRight strips all trailing newlines which could affect templates that intentionally end without a trailing newline (see #31948). TrimSuffix removes at most one trailing newline, which is sufficient to fix the double-newline regression from #32163. Co-authored-by: Cloud-Architect-Emma Signed-off-by: Cloud-Architect-Emma --- pkg/action/install.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index 5cf9980af..79d4c674a 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -732,7 +732,7 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er defer f.Close() - _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, strings.TrimRight(data, "\n")) + _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, strings.TrimSuffix(data, "\n")) if err != nil { return err From e95221e4b1273b39964fcb8215333bc4e8f36db3 Mon Sep 17 00:00:00 2001 From: Cloud-Architect-Emma Date: Fri, 3 Jul 2026 07:38:00 +0100 Subject: [PATCH 8/8] fix: apply TrimSuffix to pkg/cmd/template.go and fix test to actually verify the regression Signed-off-by: Cloud-Architect-Emma --- pkg/action/install_test.go | 39 ++++++++++++++++++-------------------- pkg/cmd/template.go | 2 +- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 312e58964..09c75e134 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -1299,33 +1299,30 @@ func TestInstallRelease_WaitOptionsPassedDownstream(t *testing.T) { } func TestWriteToFileNoTrailingNewline(t *testing.T) { + // Use a template whose output already ends with \n to expose the regression. + // Without the fix, writeToFile appends another \n producing double newline at EOF. + templates := []*common.File{ + {Name: "templates/test.yaml", Data: []byte("key: value\n")}, + } + chart := buildChartWithTemplates(templates) instAction := installAction(t) vals := map[string]any{} - dir := t.TempDir() instAction.OutputDir = dir - - _, err := instAction.Run(buildChart(withSampleTemplates()), vals) + _, err := instAction.Run(chart, vals) if err != nil { t.Fatalf("Failed install: %s", err) } - - // Each output file should end with exactly one newline (no double newline). - for _, name := range []string{ - "hello/templates/goodbye", - "hello/templates/with-partials", - } { - path := filepath.Join(dir, name) - data, err := os.ReadFile(path) - if err != nil { - t.Fatalf("Failed to read %s: %s", path, err) - } - content := string(data) - if strings.HasSuffix(content, "\n\n") { - t.Errorf("file %s ends with double newline, expected single newline", name) - } - if !strings.HasSuffix(content, "\n") { - t.Errorf("file %s does not end with a newline", name) - } + path := filepath.Join(dir, "hello/templates/test.yaml") + data, err := os.ReadFile(path) + if err != nil { + t.Fatalf("Failed to read output file: %s", err) + } + c := string(data) + if strings.HasSuffix(c, "\n\n") { + t.Errorf("output file ends with double newline (regression): got %q", c) + } + if !strings.HasSuffix(c, "\n") { + t.Errorf("output file does not end with newline: got %q", c) } } diff --git a/pkg/cmd/template.go b/pkg/cmd/template.go index 047fd60df..c29703b3d 100644 --- a/pkg/cmd/template.go +++ b/pkg/cmd/template.go @@ -249,7 +249,7 @@ func writeToFile(outputDir string, name string, data string, appendData bool) er defer f.Close() - _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, data) + _, err = fmt.Fprintf(f, "---\n# Source: %s\n%s\n", name, strings.TrimSuffix(data, "\n")) if err != nil { return err