diff --git a/cmd/helm/push.go b/cmd/helm/push.go index 7daa66563..0283ee87f 100644 --- a/cmd/helm/push.go +++ b/cmd/helm/push.go @@ -38,7 +38,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := experimental.NewPushWithOpts(experimental.WithPushConfig(cfg)) cmd := &cobra.Command{ - Use: "push [chart] [remote]", + Use: "push [chart] [remote] [tag]", Short: "push a chart to remote", Long: pushDesc, Hidden: !FeatureGateOCI.IsEnabled(), @@ -48,7 +48,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { chartRef := args[0] remote := args[1] client.Settings = settings - output, err := client.Run(chartRef, remote) + output, err := client.Run(chartRef, remote, client.Tag) if err != nil { return err } @@ -57,5 +57,8 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } + f := cmd.Flags() + f.StringVar(&client.Tag, "tag", "", "Special deployment tags such as latest/qa. Default: Chart.Version") + return cmd } diff --git a/internal/experimental/action/push.go b/internal/experimental/action/push.go index b125ae1f4..5d1258ba9 100644 --- a/internal/experimental/action/push.go +++ b/internal/experimental/action/push.go @@ -32,6 +32,7 @@ import ( type Push struct { Settings *cli.EnvSettings cfg *action.Configuration + Tag string } // PushOpt is a type of function that sets options for a push action. @@ -54,7 +55,8 @@ func NewPushWithOpts(opts ...PushOpt) *Push { } // Run executes 'helm push' against the given chart archive. -func (p *Push) Run(chartRef string, remote string) (string, error) { +func (p *Push) Run(chartRef string, remote string, tag string) (string, error) { + var out strings.Builder c := uploader.ChartUploader{ @@ -67,5 +69,5 @@ func (p *Push) Run(chartRef string, remote string) (string, error) { c.Options = append(c.Options, pusher.WithRegistryClient(p.cfg.RegistryClient)) } - return out.String(), c.UploadTo(chartRef, remote) + return out.String(), c.UploadTo(chartRef, remote, tag) } diff --git a/internal/experimental/pusher/ocipusher.go b/internal/experimental/pusher/ocipusher.go index a1df0da85..fe3523991 100644 --- a/internal/experimental/pusher/ocipusher.go +++ b/internal/experimental/pusher/ocipusher.go @@ -34,14 +34,14 @@ type OCIPusher struct { } // Push performs a Push from repo.Pusher. -func (pusher *OCIPusher) Push(chartRef, href string, options ...Option) error { +func (pusher *OCIPusher) Push(chartRef, href string, tag string, options ...Option) error { for _, opt := range options { opt(&pusher.opts) } - return pusher.push(chartRef, href) + return pusher.push(chartRef, href, tag) } -func (pusher *OCIPusher) push(chartRef, href string) error { +func (pusher *OCIPusher) push(chartRef, href string, tag string) error { stat, err := os.Stat(chartRef) if err != nil { if os.IsNotExist(err) { @@ -75,12 +75,18 @@ func (pusher *OCIPusher) push(chartRef, href string) error { pushOpts = append(pushOpts, registry.PushOptProvData(provBytes)) } + pushVersion := meta.Metadata.Version + if tag != "" { + pushVersion = tag + } + ref := fmt.Sprintf("%s:%s", path.Join(strings.TrimPrefix(href, fmt.Sprintf("%s://", registry.OCIScheme)), meta.Metadata.Name), - meta.Metadata.Version) + pushVersion) _, err = client.Push(chartBytes, ref, pushOpts...) return err + } // NewOCIPusher constructs a valid OCI client as a Pusher diff --git a/internal/experimental/pusher/pusher.go b/internal/experimental/pusher/pusher.go index 32c1351e9..2d0b69faa 100644 --- a/internal/experimental/pusher/pusher.go +++ b/internal/experimental/pusher/pusher.go @@ -44,7 +44,7 @@ func WithRegistryClient(client *registry.Client) Option { // Pusher is an interface to support upload to the specified URL. type Pusher interface { // Push file content by url string - Push(chartRef, url string, options ...Option) error + Push(chartRef, url string, tag string, options ...Option) error } // Constructor is the function for every pusher which creates a specific instance diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index cc9e1fe79..6cf3c19f7 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -400,7 +400,7 @@ type ( // Push uploads a chart to a registry. func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) { operation := &pushOperation{ - strictMode: true, // By default, enable strict mode + strictMode: false, // disabled untill we can figure out how to override this for tags } for _, option := range options { option(operation) diff --git a/internal/experimental/uploader/chart_uploader.go b/internal/experimental/uploader/chart_uploader.go index 87a9d5772..488d2d558 100644 --- a/internal/experimental/uploader/chart_uploader.go +++ b/internal/experimental/uploader/chart_uploader.go @@ -39,7 +39,7 @@ type ChartUploader struct { } // UploadTo uploads a chart. Depending on the settings, it may also upload a provenance file. -func (c *ChartUploader) UploadTo(ref, remote string) error { +func (c *ChartUploader) UploadTo(ref, remote string, tag string) error { u, err := url.Parse(remote) if err != nil { return errors.Errorf("invalid chart URL format: %s", remote) @@ -54,5 +54,5 @@ func (c *ChartUploader) UploadTo(ref, remote string) error { return err } - return p.Push(ref, u.String(), c.Options...) + return p.Push(ref, u.String(), tag, c.Options...) }