From 7ff393d4d754bb6c9fb650aa92c66af4f3efb2f7 Mon Sep 17 00:00:00 2001 From: Ilan Zerath Date: Wed, 20 May 2020 21:38:28 +0200 Subject: [PATCH] feat(list-dependencies): Implement -with-dependencies args to list command (#8081) Signed-off-by: Ilan Zerath --- cmd/helm/list.go | 145 +++++++++++++----- cmd/helm/list_test.go | 37 +++++ cmd/helm/testdata/output/list-all.txt | 1 + cmd/helm/testdata/output/list-pending.txt | 5 +- cmd/helm/testdata/output/list-short-table.txt | 4 + .../output/list-with-dependencies.txt | 14 ++ 6 files changed, 167 insertions(+), 39 deletions(-) create mode 100644 cmd/helm/testdata/output/list-short-table.txt create mode 100644 cmd/helm/testdata/output/list-with-dependencies.txt diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 08d6beb79..f2ed8eec3 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -28,6 +28,7 @@ import ( "helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/release" ) @@ -61,6 +62,7 @@ flag with the '--offset' flag allows you to page through results. func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewList(cfg) + var outfmt output.Format cmd := &cobra.Command{ @@ -75,40 +77,45 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return err } } + client.SetStateMask() results, err := client.Run() + if err != nil { return err } - if client.Short { + if client.WithDependencies { + return outfmt.Write(out, newReleaseListWriter(results, true)) + } - names := make([]string, 0) - for _, res := range results { - names = append(names, res.Name) - } + if !client.Short { + return outfmt.Write(out, newReleaseListWriter(results, false)) + } - outputFlag := cmd.Flag("output") - - switch outputFlag.Value.String() { - case "json": - output.EncodeJSON(out, names) - return nil - case "yaml": - output.EncodeYAML(out, names) - return nil - case "table": - for _, res := range results { - fmt.Fprintln(out, res.Name) - } - return nil - default: - return outfmt.Write(out, newReleaseListWriter(results)) - } + names := make([]string, 0) + for _, res := range results { + names = append(names, res.Name) } - return outfmt.Write(out, newReleaseListWriter(results)) + outputFlag := cmd.Flag("output") + + switch outputFlag.Value.String() { + case "json": + output.EncodeJSON(out, names) + return nil + case "yaml": + output.EncodeYAML(out, names) + return nil + case "table": + for _, res := range results { + fmt.Fprintln(out, res.Name) + } + return nil + default: + return outfmt.Write(out, newReleaseListWriter(results, false)) + } }, } @@ -117,6 +124,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVarP(&client.ByDate, "date", "d", false, "sort by release date") f.BoolVarP(&client.SortReverse, "reverse", "r", false, "reverse the sort order") f.BoolVarP(&client.All, "all", "a", false, "show all releases without any filter applied") + f.BoolVarP(&client.WithDependencies, "with-dependencies", "p", false, "show all releases without any filter applied and dependencies") f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases (if 'helm uninstall --keep-history' was used)") f.BoolVar(&client.Superseded, "superseded", false, "show superseded releases") f.BoolVar(&client.Uninstalling, "uninstalling", false, "show releases that are currently being uninstalled") @@ -132,47 +140,78 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return cmd } +type releaseElementChart struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` + Repository string `json:"repository"` + Enabled bool `json:"enabled,omitempty"` +} + type releaseElement struct { - Name string `json:"name"` - Namespace string `json:"namespace"` - Revision string `json:"revision"` - Updated string `json:"updated"` - Status string `json:"status"` - Chart string `json:"chart"` - AppVersion string `json:"app_version"` + Name string `json:"name"` + Namespace string `json:"namespace"` + Revision string `json:"revision"` + Updated string `json:"updated"` + Status string `json:"status"` + Chart string `json:"chart"` + AppVersion string `json:"app_version"` + Dependencies []releaseElementChart `json:"dependencies"` } type releaseListWriter struct { releases []releaseElement } -func newReleaseListWriter(releases []*release.Release) *releaseListWriter { +func newReleaseListWriter(releases []*release.Release, withDependencies bool) *releaseListWriter { // Initialize the array so no results returns an empty array instead of null elements := make([]releaseElement, 0, len(releases)) + for _, r := range releases { + dependencies := []releaseElementChart{} + + if withDependencies { + dependencies = handleChartDependencies(r.Chart.Metadata.Dependencies) + } + element := releaseElement{ - Name: r.Name, - Namespace: r.Namespace, - Revision: strconv.Itoa(r.Version), - Status: r.Info.Status.String(), - Chart: fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version), - AppVersion: r.Chart.Metadata.AppVersion, + Name: r.Name, + Namespace: r.Namespace, + Revision: strconv.Itoa(r.Version), + Status: r.Info.Status.String(), + Chart: fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version), + AppVersion: r.Chart.Metadata.AppVersion, + Dependencies: dependencies, } + t := "-" if tspb := r.Info.LastDeployed; !tspb.IsZero() { t = tspb.String() } + element.Updated = t elements = append(elements, element) } + return &releaseListWriter{elements} } func (r *releaseListWriter) WriteTable(out io.Writer) error { table := uitable.New() + tableDependencies := uitable.New() + table.AddRow("NAME", "NAMESPACE", "REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION") + for _, r := range r.releases { table.AddRow(r.Name, r.Namespace, r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion) + + if len(r.Dependencies) < 1 { + continue + } + + table.Wrap = true + buildDependenciesTable(tableDependencies, r.Dependencies) + + table.AddRow(tableDependencies) } return output.EncodeTable(out, table) } @@ -207,3 +246,35 @@ func compListReleases(toComplete string, cfg *action.Configuration) ([]string, c return choices, completion.BashCompDirectiveNoFileComp } + +func buildDependenciesTable(table *uitable.Table, dependencies []releaseElementChart) { + table.AddRow("======== DEPENDENCIES ========") + table.AddRow("NAME", "Version", "Repository", "Enabled") + + for _, d := range dependencies { + table.AddRow(d.Name, d.Version, d.Repository, d.Enabled) + } + + table.AddRow("================") +} + +func handleChartDependencies(chartDependencies []*chart.Dependency) []releaseElementChart { + if len(chartDependencies) < 1 { + return []releaseElementChart{} + } + + dependencies := []releaseElementChart{} + + for _, d := range chartDependencies { + chart := releaseElementChart{ + Name: d.Name, + Version: d.Version, + Repository: d.Repository, + Enabled: d.Enabled, + } + + dependencies = append(dependencies, chart) + } + + return dependencies +} diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index dadb57b94..c15237df6 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -40,6 +40,23 @@ func TestListCmd(t *testing.T) { }, } + chartWithDependencies := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "prims47", + Version: "4.7.7", + AppVersion: "0.0.1", + Home: "https://charts.com/prims47", + Dependencies: []*chart.Dependency{ + { + Name: "benArfa", + Version: "4.7.7", + Repository: "https://helm.com/prims47", + Enabled: true, + }, + }, + }, + } + releaseFixture := []*release.Release{ { Name: "starlord", @@ -61,6 +78,16 @@ func TestListCmd(t *testing.T) { }, Chart: chartInfo, }, + { + Name: "fuegoPepito", + Version: 1, + Namespace: defaultNamespace, + Info: &release.Info{ + LastDeployed: timestamp1, + Status: release.StatusPendingInstall, + }, + Chart: chartWithDependencies, + }, { Name: "groot", Version: 1, @@ -153,6 +180,11 @@ func TestListCmd(t *testing.T) { cmd: "list --all", golden: "output/list-all.txt", rels: releaseFixture, + }, { + name: "list all releases with dependencies", + cmd: "list --with-dependencies", + golden: "output/list-with-dependencies.txt", + rels: releaseFixture, }, { name: "list releases sorted by release date", cmd: "list --date", @@ -208,6 +240,11 @@ func TestListCmd(t *testing.T) { cmd: "list --short --output json", golden: "output/list-short-json.txt", rels: releaseFixture, + }, { + name: "list releases in short output format", + cmd: "list --short --output table", + golden: "output/list-short-table.txt", + rels: releaseFixture, }, { name: "list superseded releases", cmd: "list --superseded", diff --git a/cmd/helm/testdata/output/list-all.txt b/cmd/helm/testdata/output/list-all.txt index ef6d44cd5..bd8cd95aa 100644 --- a/cmd/helm/testdata/output/list-all.txt +++ b/cmd/helm/testdata/output/list-all.txt @@ -1,5 +1,6 @@ NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION drax default 1 2016-01-16 00:00:01 +0000 UTC uninstalling chickadee-1.0.0 0.0.1 +fuegoPepito default 1 2016-01-16 00:00:01 +0000 UTC pending-install prims47-4.7.7 0.0.1 gamora default 1 2016-01-16 00:00:01 +0000 UTC superseded chickadee-1.0.0 0.0.1 groot default 1 2016-01-16 00:00:01 +0000 UTC uninstalled chickadee-1.0.0 0.0.1 hummingbird default 1 2016-01-16 00:00:03 +0000 UTC deployed chickadee-1.0.0 0.0.1 diff --git a/cmd/helm/testdata/output/list-pending.txt b/cmd/helm/testdata/output/list-pending.txt index f3d7aa03b..bb5f36d43 100644 --- a/cmd/helm/testdata/output/list-pending.txt +++ b/cmd/helm/testdata/output/list-pending.txt @@ -1,2 +1,3 @@ -NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -thanos default 1 2016-01-16 00:00:01 +0000 UTC pending-install chickadee-1.0.0 0.0.1 +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +fuegoPepito default 1 2016-01-16 00:00:01 +0000 UTC pending-install prims47-4.7.7 0.0.1 +thanos default 1 2016-01-16 00:00:01 +0000 UTC pending-install chickadee-1.0.0 0.0.1 diff --git a/cmd/helm/testdata/output/list-short-table.txt b/cmd/helm/testdata/output/list-short-table.txt new file mode 100644 index 000000000..0a63be990 --- /dev/null +++ b/cmd/helm/testdata/output/list-short-table.txt @@ -0,0 +1,4 @@ +hummingbird +iguana +rocket +starlord diff --git a/cmd/helm/testdata/output/list-with-dependencies.txt b/cmd/helm/testdata/output/list-with-dependencies.txt new file mode 100644 index 000000000..50f665d06 --- /dev/null +++ b/cmd/helm/testdata/output/list-with-dependencies.txt @@ -0,0 +1,14 @@ +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +drax default 1 2016-01-16 00:00:01 +0000 UTC uninstalling chickadee-1.0.0 0.0.1 +fuegoPepito default 1 2016-01-16 00:00:01 +0000 UTC pending-install prims47-4.7.7 0.0.1 +======== DEPENDENCIES ======== +NAME Version Repository Enabled +benArfa 4.7.7 https://helm.com/prims47 true +================ +gamora default 1 2016-01-16 00:00:01 +0000 UTC superseded chickadee-1.0.0 0.0.1 +groot default 1 2016-01-16 00:00:01 +0000 UTC uninstalled chickadee-1.0.0 0.0.1 +hummingbird default 1 2016-01-16 00:00:03 +0000 UTC deployed chickadee-1.0.0 0.0.1 +iguana default 2 2016-01-16 00:00:04 +0000 UTC deployed chickadee-1.0.0 0.0.1 +rocket default 1 2016-01-16 00:00:02 +0000 UTC failed chickadee-1.0.0 0.0.1 +starlord default 2 2016-01-16 00:00:01 +0000 UTC deployed chickadee-1.0.0 0.0.1 +thanos default 1 2016-01-16 00:00:01 +0000 UTC pending-install chickadee-1.0.0 0.0.1