diff --git a/cmd/helm/history.go b/cmd/helm/history.go index b92fb81c6677542aee7b7325e01f9aff48622c44..f992e5aeac3854600aae36dadcf978ea4b9f362f 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 5d51462288b497d79190593b6cc0def38d9fa0b5..eab94a9d5d9e01cb14cf91165a41742c45febe91 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, + 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 2c93adebc6940d6b1969b35277d7250133b2135f..17262a258a413cc8ee75509bef0d33e42f006e4b 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 ``` diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index c8ce91f4418961049513ea5f44d359e9bdf89f31..b904bc565b072bd39b466406c0d7a4ebc1182d8c 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 4376742d7b010b52b8ef0960b353fa74a2188ca3..261065b595c07572db53a7e8478cf8bfa534141e 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -448,3 +448,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) + } + }) + } +}