From a05311e6fd75c081e6aeb092c768d526399b787b Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Fri, 14 Dec 2018 15:59:46 -0500 Subject: [PATCH 1/2] feat(helm): add AppVersion column to the output of helm history command Signed-off-by: Arash Deshmeh --- cmd/helm/history.go | 25 +++++++++----- cmd/helm/history_test.go | 71 ++++++++++++++++++++------------------- docs/helm/helm_history.md | 12 +++---- 3 files changed, 60 insertions(+), 48 deletions(-) diff --git a/cmd/helm/history.go b/cmd/helm/history.go index 365346e89..71210f677 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -36,6 +36,7 @@ type releaseInfo struct { Updated string `json:"updated"` Status string `json:"status"` Chart string `json:"chart"` + AppVersion string `json:"appVersion"` Description string `json:"description"` } @@ -50,11 +51,11 @@ configures the maximum length of the revision list returned. The historical release set is printed as a formatted table, e.g: $ helm history angry-bird --max=4 - REVISION UPDATED STATUS CHART DESCRIPTION - 1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Initial install - 2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Upgraded successfully - 3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Rolled back to 2 - 4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 Upgraded successfully + REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION + 1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 1.1 Initial install + 2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 1.2 Upgraded successfully + 3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 1.1 Rolled back to 2 + 4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 1.3 Upgraded successfully ` type historyCmd struct { @@ -136,16 +137,17 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) { for i := len(rls) - 1; i >= 0; i-- { r := rls[i] c := formatChartname(r.Chart) + a := appVersionFromChart(r.Chart) t := timeconv.String(r.Info.LastDeployed) s := r.Info.Status.Code.String() v := r.Version d := r.Info.Description - rInfo := releaseInfo{ Revision: v, Updated: t, Status: s, Chart: c, + AppVersion: a, Description: d, } history = append(history, rInfo) @@ -158,10 +160,10 @@ func formatAsTable(releases releaseHistory, colWidth uint) []byte { tbl := uitable.New() tbl.MaxColWidth = colWidth - tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "DESCRIPTION") + tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION") for i := 0; i <= len(releases)-1; i++ { r := releases[i] - tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.Description) + tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion, r.Description) } return tbl.Bytes() } @@ -174,3 +176,10 @@ func formatChartname(c *chart.Chart) string { } return fmt.Sprintf("%s-%s", c.Metadata.Name, c.Metadata.Version) } + +func appVersionFromChart(c *chart.Chart) string { + if c == nil || c.Metadata == nil { + return "MISSING" + } + return c.Metadata.AppVersion +} diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index 5d5146228..71cb6b2fb 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -23,59 +23,62 @@ import ( "github.com/spf13/cobra" "k8s.io/helm/pkg/helm" + "k8s.io/helm/pkg/proto/hapi/chart" rpb "k8s.io/helm/pkg/proto/hapi/release" ) func TestHistoryCmd(t *testing.T) { - mk := func(name string, vers int32, code rpb.Status_Code) *rpb.Release { + mk := func(name string, vers int32, code rpb.Status_Code, appVersion string) *rpb.Release { + ch := &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "foo", + Version: "0.1.0-beta.1", + AppVersion: appVersion, + }, + } + return helm.ReleaseMock(&helm.MockReleaseOptions{ Name: name, + Chart: ch, Version: vers, StatusCode: code, }) } + releases := []*rpb.Release{ + mk("angry-bird", 4, rpb.Status_DEPLOYED, "1.4"), + mk("angry-bird", 3, rpb.Status_SUPERSEDED, "1.3"), + mk("angry-bird", 2, rpb.Status_SUPERSEDED, "1.2"), + mk("angry-bird", 1, rpb.Status_SUPERSEDED, "1.1"), + } + tests := []releaseCase{ { - name: "get history for release", - args: []string{"angry-bird"}, - rels: []*rpb.Release{ - mk("angry-bird", 4, rpb.Status_DEPLOYED), - mk("angry-bird", 3, rpb.Status_SUPERSEDED), - mk("angry-bird", 2, rpb.Status_SUPERSEDED), - mk("angry-bird", 1, rpb.Status_SUPERSEDED), - }, - expected: "REVISION\tUPDATED \tSTATUS \tCHART \tDESCRIPTION \n1 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n2 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\tRelease mock\n", + name: "get history for release", + args: []string{"angry-bird"}, + rels: releases, + expected: "REVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\tDESCRIPTION \n1 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\t1.1 \tRelease mock\n2 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\t1.2 \tRelease mock\n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\t1.3 \tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\t1.4 \tRelease mock\n", }, { - name: "get history with max limit set", - args: []string{"angry-bird"}, - flags: []string{"--max", "2"}, - rels: []*rpb.Release{ - mk("angry-bird", 4, rpb.Status_DEPLOYED), - mk("angry-bird", 3, rpb.Status_SUPERSEDED), - }, - expected: "REVISION\tUPDATED \tSTATUS \tCHART \tDESCRIPTION \n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\tRelease mock\n", + name: "get history with max limit set", + args: []string{"angry-bird"}, + flags: []string{"--max", "2"}, + rels: releases[:2], + expected: "REVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\tDESCRIPTION \n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\t1.3 \tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\t1.4 \tRelease mock\n", }, { - name: "get history with yaml output format", - args: []string{"angry-bird"}, - flags: []string{"--output", "yaml"}, - rels: []*rpb.Release{ - mk("angry-bird", 4, rpb.Status_DEPLOYED), - mk("angry-bird", 3, rpb.Status_SUPERSEDED), - }, - expected: "- chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 3\n status: SUPERSEDED\n updated: (.*)\n- chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 4\n status: DEPLOYED\n updated: (.*)\n\n", + name: "get history with yaml output format", + args: []string{"angry-bird"}, + flags: []string{"--output", "yaml"}, + rels: releases[:2], + expected: "- appVersion: \"1.3\"\n chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 3\n status: SUPERSEDED\n updated: (.*)\n- appVersion: \"1.4\"\n chart: foo-0.1.0-beta.1\n description: Release mock\n revision: 4\n status: DEPLOYED\n updated: (.*)\n\n", }, { - name: "get history with json output format", - args: []string{"angry-bird"}, - flags: []string{"--output", "json"}, - rels: []*rpb.Release{ - mk("angry-bird", 4, rpb.Status_DEPLOYED), - mk("angry-bird", 3, rpb.Status_SUPERSEDED), - }, - expected: `[{"revision":3,"updated":".*","status":"SUPERSEDED","chart":"foo\-0.1.0-beta.1","description":"Release mock"},{"revision":4,"updated":".*","status":"DEPLOYED","chart":"foo\-0.1.0-beta.1","description":"Release mock"}]\n`, + name: "get history with json output format", + args: []string{"angry-bird"}, + flags: []string{"--output", "json"}, + rels: releases[:2], + expected: `[{"revision":3,"updated":".*","status":"SUPERSEDED","chart":"foo\-0.1.0-beta.1","appVersion":"1.3","description":"Release mock"},{"revision":4,"updated":".*","status":"DEPLOYED","chart":"foo\-0.1.0-beta.1","appVersion":"1.4","description":"Release mock"}]\n`, }, } diff --git a/docs/helm/helm_history.md b/docs/helm/helm_history.md index 7f0a68928..1d7287fd9 100755 --- a/docs/helm/helm_history.md +++ b/docs/helm/helm_history.md @@ -13,11 +13,11 @@ configures the maximum length of the revision list returned. The historical release set is printed as a formatted table, e.g: $ helm history angry-bird --max=4 - REVISION UPDATED STATUS CHART DESCRIPTION - 1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Initial install - 2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Upgraded successfully - 3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Rolled back to 2 - 4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 Upgraded successfully + REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION + 1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 1.1 Initial install + 2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 1.2 Upgraded successfully + 3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 1.1 Rolled back to 2 + 4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 1.3 Upgraded successfully ``` @@ -55,4 +55,4 @@ helm history [flags] RELEASE_NAME * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 10-Aug-2018 +###### Auto generated by spf13/cobra on 17-Dec-2018 From ff3dc9dd33f3a31b6bbc3681d2853c03cd57ebdf Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Mon, 17 Dec 2018 14:21:45 -0500 Subject: [PATCH 2/2] fix(helm): fix unit tests of the history command to ensure the max option is covered. Add the required support to the fake client Signed-off-by: Arash Deshmeh --- cmd/helm/history_test.go | 2 +- pkg/helm/fake.go | 17 +++++++++- pkg/helm/fake_test.go | 72 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index 71cb6b2fb..eab94a9d5 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -63,7 +63,7 @@ func TestHistoryCmd(t *testing.T) { name: "get history with max limit set", args: []string{"angry-bird"}, flags: []string{"--max", "2"}, - rels: releases[:2], + rels: releases, expected: "REVISION\tUPDATED \tSTATUS \tCHART \tAPP VERSION\tDESCRIPTION \n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\t1.3 \tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\t1.4 \tRelease mock\n", }, { diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 46be7d398..6da0ac70d 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -229,7 +229,22 @@ func (c *FakeClient) ReleaseContent(rlsName string, opts ...ContentOption) (resp // ReleaseHistory returns a release's revision history. func (c *FakeClient) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) { - return &rls.GetHistoryResponse{Releases: c.Rels}, nil + reqOpts := c.Opts + for _, opt := range opts { + opt(&reqOpts) + } + maxLen := int(reqOpts.histReq.Max) + + var resp rls.GetHistoryResponse + for _, rel := range c.Rels { + if maxLen > 0 && len(resp.Releases) >= maxLen { + return &resp, nil + } + if rel.Name == rlsName { + resp.Releases = append(resp.Releases, rel) + } + } + return &resp, nil } // RunReleaseTest executes a pre-defined tests on a release diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index ecb0a2855..cff10051f 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -446,3 +446,75 @@ func TestFakeClient_UpdateReleaseFromChart(t *testing.T) { }) } } + +func TestFakeClient_ReleaseHistory(t *testing.T) { + relName := "angry-dolphin" + rels := []*release.Release{ + ReleaseMock(&MockReleaseOptions{Name: relName, Version: 1}), + ReleaseMock(&MockReleaseOptions{Name: relName, Version: 2}), + ReleaseMock(&MockReleaseOptions{Name: relName, Version: 3}), + ReleaseMock(&MockReleaseOptions{Name: relName, Version: 4}), + } + + type fields struct { + Rels []*release.Release + } + type args struct { + rlsName string + opts []HistoryOption + } + tests := []struct { + name string + fields fields + args args + want *rls.GetHistoryResponse + wantErr bool + }{ + { + name: "Get all revisions of a release", + fields: fields{ + Rels: rels, + }, + args: args{ + rlsName: relName, + opts: nil, + }, + want: &rls.GetHistoryResponse{ + Releases: rels, + }, + wantErr: false, + }, + { + name: "Get only 2 revisions of a release", + fields: fields{ + Rels: rels, + }, + args: args{ + rlsName: relName, + opts: []HistoryOption{ + WithMaxHistory(2), + }, + }, + want: &rls.GetHistoryResponse{ + Releases: rels[:2], + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &FakeClient{ + Rels: tt.fields.Rels, + } + got, err := c.ReleaseHistory(tt.args.rlsName, tt.args.opts...) + if (err != nil) != tt.wantErr { + t.Errorf("FakeClient.ReleaseHistory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("FakeClient.ReleaseHistory() = %v, want %v", got, tt.want) + } + }) + } +}