diff --git a/pkg/action/get.go b/pkg/action/get.go index dbe5f4cb3..b5e7c194b 100644 --- a/pkg/action/get.go +++ b/pkg/action/get.go @@ -17,7 +17,7 @@ limitations under the License. package action import ( - release "helm.sh/helm/v4/pkg/release/v1" + release "helm.sh/helm/v4/pkg/release" ) // Get is the action for checking a given release's information. @@ -38,7 +38,7 @@ func NewGet(cfg *Configuration) *Get { } // Run executes 'helm get' against the given release. -func (g *Get) Run(name string) (*release.Release, error) { +func (g *Get) Run(name string) (release.Releaser, error) { if err := g.cfg.KubeClient.IsReachable(); err != nil { return nil, err } diff --git a/pkg/cmd/get_hooks.go b/pkg/cmd/get_hooks.go index 7ffefd93c..d344307cb 100644 --- a/pkg/cmd/get_hooks.go +++ b/pkg/cmd/get_hooks.go @@ -25,6 +25,7 @@ import ( "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/cmd/require" + "helm.sh/helm/v4/pkg/release" ) const getHooksHelp = ` @@ -52,8 +53,16 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if err != nil { return err } - for _, hook := range res.Hooks { - fmt.Fprintf(out, "---\n# Source: %s\n%s\n", hook.Path, hook.Manifest) + rac, err := release.NewAccessor(res) + if err != nil { + return err + } + for _, hook := range rac.Hooks() { + hac, err := release.NewHookAccessor(hook) + if err != nil { + return err + } + fmt.Fprintf(out, "---\n# Source: %s\n%s\n", hac.Path(), hac.Manifest()) } return nil }, diff --git a/pkg/cmd/get_manifest.go b/pkg/cmd/get_manifest.go index 021495d8d..253b011c1 100644 --- a/pkg/cmd/get_manifest.go +++ b/pkg/cmd/get_manifest.go @@ -25,6 +25,7 @@ import ( "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/cmd/require" + "helm.sh/helm/v4/pkg/release" ) var getManifestHelp = ` @@ -54,7 +55,11 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command if err != nil { return err } - fmt.Fprintln(out, res.Manifest) + rac, err := release.NewAccessor(res) + if err != nil { + return err + } + fmt.Fprintln(out, rac.Manifest()) return nil }, } diff --git a/pkg/cmd/get_notes.go b/pkg/cmd/get_notes.go index ae79d8bcc..46fbeeaf5 100644 --- a/pkg/cmd/get_notes.go +++ b/pkg/cmd/get_notes.go @@ -25,6 +25,7 @@ import ( "helm.sh/helm/v4/pkg/action" "helm.sh/helm/v4/pkg/cmd/require" + "helm.sh/helm/v4/pkg/release" ) var getNotesHelp = ` @@ -50,8 +51,12 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if err != nil { return err } - if len(res.Info.Notes) > 0 { - fmt.Fprintf(out, "NOTES:\n%s\n", res.Info.Notes) + rac, err := release.NewAccessor(res) + if err != nil { + return err + } + if len(rac.Notes()) > 0 { + fmt.Fprintf(out, "NOTES:\n%s\n", rac.Notes()) } return nil }, diff --git a/pkg/cmd/status.go b/pkg/cmd/status.go index 3d1309c3e..1988dc5c7 100644 --- a/pkg/cmd/status.go +++ b/pkg/cmd/status.go @@ -33,7 +33,8 @@ import ( "helm.sh/helm/v4/pkg/chart/common/util" "helm.sh/helm/v4/pkg/cli/output" "helm.sh/helm/v4/pkg/cmd/require" - release "helm.sh/helm/v4/pkg/release/v1" + "helm.sh/helm/v4/pkg/release" + releasev1 "helm.sh/helm/v4/pkg/release/v1" ) // NOTE: Keep the list of statuses up-to-date with pkg/release/status.go. @@ -110,54 +111,66 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } type statusPrinter struct { - release *release.Release + release release.Releaser debug bool showMetadata bool hideNotes bool noColor bool } +func (s statusPrinter) getV1Release() *releasev1.Release { + switch rel := s.release.(type) { + case releasev1.Release: + return &rel + case *releasev1.Release: + return rel + } + return &releasev1.Release{} +} + func (s statusPrinter) WriteJSON(out io.Writer) error { - return output.EncodeJSON(out, s.release) + return output.EncodeJSON(out, s.getV1Release()) } func (s statusPrinter) WriteYAML(out io.Writer) error { - return output.EncodeYAML(out, s.release) + return output.EncodeYAML(out, s.getV1Release()) } func (s statusPrinter) WriteTable(out io.Writer) error { if s.release == nil { return nil } - _, _ = fmt.Fprintf(out, "NAME: %s\n", s.release.Name) - if !s.release.Info.LastDeployed.IsZero() { - _, _ = fmt.Fprintf(out, "LAST DEPLOYED: %s\n", s.release.Info.LastDeployed.Format(time.ANSIC)) + rel := s.getV1Release() + fmt.Printf("%+v", rel) + _, _ = fmt.Fprintf(out, "NAME: %s\n", rel.Name) + if !rel.Info.LastDeployed.IsZero() { + _, _ = fmt.Fprintf(out, "LAST DEPLOYED: %s\n", rel.Info.LastDeployed.Format(time.ANSIC)) } - _, _ = fmt.Fprintf(out, "NAMESPACE: %s\n", coloroutput.ColorizeNamespace(s.release.Namespace, s.noColor)) - _, _ = fmt.Fprintf(out, "STATUS: %s\n", coloroutput.ColorizeStatus(s.release.Info.Status, s.noColor)) - _, _ = fmt.Fprintf(out, "REVISION: %d\n", s.release.Version) + _, _ = fmt.Fprintf(out, "NAMESPACE: %s\n", coloroutput.ColorizeNamespace(rel.Namespace, s.noColor)) + _, _ = fmt.Fprintf(out, "STATUS: %s\n", coloroutput.ColorizeStatus(rel.Info.Status, s.noColor)) + _, _ = fmt.Fprintf(out, "REVISION: %d\n", rel.Version) if s.showMetadata { - _, _ = fmt.Fprintf(out, "CHART: %s\n", s.release.Chart.Metadata.Name) - _, _ = fmt.Fprintf(out, "VERSION: %s\n", s.release.Chart.Metadata.Version) - _, _ = fmt.Fprintf(out, "APP_VERSION: %s\n", s.release.Chart.Metadata.AppVersion) + _, _ = fmt.Fprintf(out, "CHART: %s\n", rel.Chart.Metadata.Name) + _, _ = fmt.Fprintf(out, "VERSION: %s\n", rel.Chart.Metadata.Version) + _, _ = fmt.Fprintf(out, "APP_VERSION: %s\n", rel.Chart.Metadata.AppVersion) } - _, _ = fmt.Fprintf(out, "DESCRIPTION: %s\n", s.release.Info.Description) + _, _ = fmt.Fprintf(out, "DESCRIPTION: %s\n", rel.Info.Description) - if len(s.release.Info.Resources) > 0 { + if len(rel.Info.Resources) > 0 { buf := new(bytes.Buffer) printFlags := get.NewHumanPrintFlags() typePrinter, _ := printFlags.ToPrinter("") printer := &get.TablePrinter{Delegate: typePrinter} var keys []string - for key := range s.release.Info.Resources { + for key := range rel.Info.Resources { keys = append(keys, key) } for _, t := range keys { _, _ = fmt.Fprintf(buf, "==> %s\n", t) - vk := s.release.Info.Resources[t] + vk := rel.Info.Resources[t] for _, resource := range vk { if err := printer.PrintObj(resource, buf); err != nil { _, _ = fmt.Fprintf(buf, "failed to print object type %s: %v\n", t, err) @@ -170,8 +183,8 @@ func (s statusPrinter) WriteTable(out io.Writer) error { _, _ = fmt.Fprintf(out, "RESOURCES:\n%s\n", buf.String()) } - executions := executionsByHookEvent(s.release) - if tests, ok := executions[release.HookTest]; !ok || len(tests) == 0 { + executions := executionsByHookEvent(rel) + if tests, ok := executions[releasev1.HookTest]; !ok || len(tests) == 0 { _, _ = fmt.Fprintln(out, "TEST SUITE: None") } else { for _, h := range tests { @@ -190,14 +203,14 @@ func (s statusPrinter) WriteTable(out io.Writer) error { if s.debug { _, _ = fmt.Fprintln(out, "USER-SUPPLIED VALUES:") - err := output.EncodeYAML(out, s.release.Config) + err := output.EncodeYAML(out, rel.Config) if err != nil { return err } // Print an extra newline _, _ = fmt.Fprintln(out) - cfg, err := util.CoalesceValues(s.release.Chart, s.release.Config) + cfg, err := util.CoalesceValues(rel.Chart, rel.Config) if err != nil { return err } @@ -211,28 +224,28 @@ func (s statusPrinter) WriteTable(out io.Writer) error { _, _ = fmt.Fprintln(out) } - if strings.EqualFold(s.release.Info.Description, "Dry run complete") || s.debug { + if strings.EqualFold(rel.Info.Description, "Dry run complete") || s.debug { _, _ = fmt.Fprintln(out, "HOOKS:") - for _, h := range s.release.Hooks { + for _, h := range rel.Hooks { _, _ = fmt.Fprintf(out, "---\n# Source: %s\n%s\n", h.Path, h.Manifest) } - _, _ = fmt.Fprintf(out, "MANIFEST:\n%s\n", s.release.Manifest) + _, _ = fmt.Fprintf(out, "MANIFEST:\n%s\n", rel.Manifest) } // Hide notes from output - option in install and upgrades - if !s.hideNotes && len(s.release.Info.Notes) > 0 { - _, _ = fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(s.release.Info.Notes)) + if !s.hideNotes && len(rel.Info.Notes) > 0 { + _, _ = fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(rel.Info.Notes)) } return nil } -func executionsByHookEvent(rel *release.Release) map[release.HookEvent][]*release.Hook { - result := make(map[release.HookEvent][]*release.Hook) +func executionsByHookEvent(rel *releasev1.Release) map[releasev1.HookEvent][]*releasev1.Hook { + result := make(map[releasev1.HookEvent][]*releasev1.Hook) for _, h := range rel.Hooks { for _, e := range h.Events { executions, ok := result[e] if !ok { - executions = []*release.Hook{} + executions = []*releasev1.Hook{} } result[e] = append(executions, h) } diff --git a/pkg/release/common.go b/pkg/release/common.go new file mode 100644 index 000000000..5cdcf9b88 --- /dev/null +++ b/pkg/release/common.go @@ -0,0 +1,81 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "errors" + + v1release "helm.sh/helm/v4/pkg/release/v1" +) + +var NewAccessor func(rel Releaser) (Accessor, error) = NewDefaultAccessor //nolint:revive + +var NewHookAccessor func(rel Hook) (HookAccessor, error) = NewDefaultHookAccessor //nolint:revive + +func NewDefaultAccessor(rel Releaser) (Accessor, error) { + switch v := rel.(type) { + case v1release.Release: + return &v1Accessor{&v}, nil + case *v1release.Release: + return &v1Accessor{v}, nil + default: + return nil, errors.New("unsupported release type") + } +} + +func NewDefaultHookAccessor(hook Hook) (HookAccessor, error) { + switch h := hook.(type) { + case v1release.Hook: + return &v1HookAccessor{&h}, nil + case *v1release.Hook: + return &v1HookAccessor{h}, nil + default: + return nil, errors.New("unsupported release hook type") + } +} + +type v1Accessor struct { + rel *v1release.Release +} + +func (a *v1Accessor) Hooks() []Hook { + var hooks = make([]Hook, len(a.rel.Hooks)) + for i, h := range a.rel.Hooks { + hooks[i] = h + } + return hooks +} + +func (a *v1Accessor) Manifest() string { + return a.rel.Manifest +} + +func (a *v1Accessor) Notes() string { + return a.rel.Info.Notes +} + +type v1HookAccessor struct { + hook *v1release.Hook +} + +func (a *v1HookAccessor) Path() string { + return a.hook.Path +} + +func (a *v1HookAccessor) Manifest() string { + return a.hook.Manifest +} diff --git a/pkg/release/interfaces.go b/pkg/release/interfaces.go new file mode 100644 index 000000000..9d6987625 --- /dev/null +++ b/pkg/release/interfaces.go @@ -0,0 +1,32 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +type Releaser interface{} + +type Hook interface{} + +type Accessor interface { + Hooks() []Hook + Manifest() string + Notes() string +} + +type HookAccessor interface { + Path() string + Manifest() string +}