diff --git a/internal/action/config.go b/internal/action/config.go index 61a42e201..f19a3972d 100644 --- a/internal/action/config.go +++ b/internal/action/config.go @@ -19,6 +19,7 @@ package action import ( "context" "fmt" + "io" "log/slog" helmaction "helm.sh/helm/v4/pkg/action" @@ -183,6 +184,10 @@ func (c *ConfigFactory) Build(log slog.Handler, observers ...storage.ObserveFunc conf.RESTClientGetter = c.Getter conf.Releases = c.NewStorage(observers...) conf.KubeClient = client + // Helm's own CLI initialization defaults HookOutputFunc to io.Discard, but + // helmaction.NewConfiguration does not. Without it, hooks annotated with + // helm.sh/hook-output-log-policy make Helm panic on a nil HookOutputFunc. + conf.HookOutputFunc = func(_, _, _ string) io.Writer { return io.Discard } return conf } diff --git a/internal/action/config_test.go b/internal/action/config_test.go index 1c82b6cbf..cbb322997 100644 --- a/internal/action/config_test.go +++ b/internal/action/config_test.go @@ -18,6 +18,7 @@ package action import ( "errors" + "io" "log/slog" "testing" @@ -257,6 +258,15 @@ func TestConfigFactory_Build(t *testing.T) { g.Expect(cfg.Releases).ToNot(BeNil()) g.Expect(cfg.Releases.Driver).To(BeAssignableToTypeOf(&storage.Observer{})) }) + + t.Run("sets a non-nil HookOutputFunc", func(t *testing.T) { + g := NewWithT(t) + + cfg := (&ConfigFactory{}).Build(nil) + + g.Expect(cfg.HookOutputFunc).ToNot(BeNil()) + g.Expect(cfg.HookOutputFunc("ns", "pod", "container")).To(Equal(io.Discard)) + }) } func TestConfigFactory_Valid(t *testing.T) {