diff --git a/pkg/action/push.go b/pkg/action/push.go index 5eb6110b8..4c61856eb 100644 --- a/pkg/action/push.go +++ b/pkg/action/push.go @@ -17,6 +17,7 @@ limitations under the License. package action import ( + "fmt" "io" "helm.sh/helm/v4/pkg/cli" @@ -98,6 +99,9 @@ func (p *Push) Run(chartRef string, remote string) (*registry.PushResult, error) } if registry.IsOCI(remote) { + if p.cfg == nil { + return nil, fmt.Errorf("missing action configuration: use WithPushConfig when constructing Push") + } // Don't use the default registry client if tls options are set. c.Options = append(c.Options, pusher.WithRegistryClient(p.cfg.RegistryClient)) } diff --git a/pkg/cmd/push.go b/pkg/cmd/push.go index 71e79a7c7..defe416c6 100644 --- a/pkg/cmd/push.go +++ b/pkg/cmd/push.go @@ -19,6 +19,7 @@ package cmd import ( "fmt" "io" + "strings" "github.com/spf13/cobra" @@ -57,6 +58,21 @@ type pushWriter struct { result pushResult } +// suppressSummaryWriter forwards all writes to the underlying writer, silently +// dropping lines that match the registry client's built-in "Pushed:"/"Digest:" +// summary output. Warnings, errors, and other output are forwarded intact. +type suppressSummaryWriter struct { + w io.Writer +} + +func (s *suppressSummaryWriter) Write(p []byte) (int, error) { + line := string(p) + if strings.HasPrefix(line, "Pushed: ") || strings.HasPrefix(line, "Digest: ") { + return len(p), nil + } + return s.w.Write(p) +} + // WriteTable writes the push result in human-readable form, using the same // "Pushed:"/"Digest:" labels as the registry client's built-in output so that // the default (--output table) experience is consistent and familiar. @@ -101,13 +117,14 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } return noMoreArgsComp() }, - RunE: func(_ *cobra.Command, args []string) error { - // Suppress the registry client's built-in "Pushed:"/"Digest:" lines; - // the --output writer (WriteTable/WriteJSON/WriteYAML) is the single + RunE: func(cmd *cobra.Command, args []string) error { + // Suppress the registry client's built-in "Pushed:"/"Digest:" summary + // lines while forwarding all other output (warnings, etc.) to stderr. + // The --output writer (WriteTable/WriteJSON/WriteYAML) is the single // source of structured push output for this command. registryClient, err := newRegistryClient( o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSVerify, o.plainHTTP, o.username, o.password, - io.Discard, + &suppressSummaryWriter{w: cmd.ErrOrStderr()}, ) if err != nil { diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 02d004420..bbc2739f3 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -410,7 +410,7 @@ func newRegistryClient( w ...io.Writer, ) (*registry.Client, error) { out := io.Writer(os.Stderr) - if len(w) > 0 { + if len(w) > 0 && w[0] != nil { out = w[0] } if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSVerify {