add release tag for install and history

add release tag for update

adding tests

added more tests

Signed-off-by: Nicholas Colbert <ncolbert@goodrx.com>
pull/11165/head
Nicholas Colbert 3 years ago
parent 211bd2b60a
commit 886f1e551d

@ -90,6 +90,7 @@ type releaseInfo struct {
Chart string `json:"chart"` Chart string `json:"chart"`
AppVersion string `json:"app_version"` AppVersion string `json:"app_version"`
Description string `json:"description"` Description string `json:"description"`
ReleaseTag string `json:"release_tag"`
} }
type releaseHistory []releaseInfo type releaseHistory []releaseInfo
@ -104,9 +105,13 @@ func (r releaseHistory) WriteYAML(out io.Writer) error {
func (r releaseHistory) WriteTable(out io.Writer) error { func (r releaseHistory) WriteTable(out io.Writer) error {
tbl := uitable.New() tbl := uitable.New()
tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION") tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION", "RELEASE TAG")
for _, item := range r { for _, item := range r {
tbl.AddRow(item.Revision, item.Updated.Format(time.ANSIC), item.Status, item.Chart, item.AppVersion, item.Description) if item.ReleaseTag != "" {
tbl.AddRow(item.Revision, item.Updated.Format(time.ANSIC), item.Status, item.Chart, item.AppVersion, item.Description, item.ReleaseTag)
} else {
tbl.AddRow(item.Revision, item.Updated.Format(time.ANSIC), item.Status, item.Chart, item.AppVersion, item.Description)
}
} }
return output.EncodeTable(out, tbl) return output.EncodeTable(out, tbl)
} }
@ -141,6 +146,7 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
v := r.Version v := r.Version
d := r.Info.Description d := r.Info.Description
a := formatAppVersion(r.Chart) a := formatAppVersion(r.Chart)
t := r.Info.ReleaseTag
rInfo := releaseInfo{ rInfo := releaseInfo{
Revision: v, Revision: v,
@ -148,6 +154,7 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
Chart: c, Chart: c,
AppVersion: a, AppVersion: a,
Description: d, Description: d,
ReleaseTag: t,
} }
if !r.Info.LastDeployed.IsZero() { if !r.Info.LastDeployed.IsZero() {
rInfo.Updated = r.Info.LastDeployed rInfo.Updated = r.Info.LastDeployed

@ -23,12 +23,17 @@ import (
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/release"
) )
const (
noTag string = ""
)
func TestHistoryCmd(t *testing.T) { func TestHistoryCmd(t *testing.T) {
mk := func(name string, vers int, status release.Status) *release.Release { mk := func(name, releaseTag string, vers int, status release.Status) *release.Release {
return release.Mock(&release.MockReleaseOptions{ return release.Mock(&release.MockReleaseOptions{
Name: name, Name: name,
Version: vers, Version: vers,
Status: status, Status: status,
ReleaseTag: releaseTag,
}) })
} }
@ -36,36 +41,62 @@ func TestHistoryCmd(t *testing.T) {
name: "get history for release", name: "get history for release",
cmd: "history angry-bird", cmd: "history angry-bird",
rels: []*release.Release{ rels: []*release.Release{
mk("angry-bird", 4, release.StatusDeployed), mk("angry-bird", noTag, 4, release.StatusDeployed),
mk("angry-bird", 3, release.StatusSuperseded), mk("angry-bird", noTag, 3, release.StatusSuperseded),
mk("angry-bird", 2, release.StatusSuperseded), mk("angry-bird", noTag, 2, release.StatusSuperseded),
mk("angry-bird", 1, release.StatusSuperseded), mk("angry-bird", noTag, 1, release.StatusSuperseded),
}, },
golden: "output/history.txt", golden: "output/history.txt",
}, { }, {
name: "get history with max limit set", name: "get history with max limit set",
cmd: "history angry-bird --max 2", cmd: "history angry-bird --max 2",
rels: []*release.Release{ rels: []*release.Release{
mk("angry-bird", 4, release.StatusDeployed), mk("angry-bird", noTag, 4, release.StatusDeployed),
mk("angry-bird", 3, release.StatusSuperseded), mk("angry-bird", noTag, 3, release.StatusSuperseded),
}, },
golden: "output/history-limit.txt", golden: "output/history-limit.txt",
}, { }, {
name: "get history with yaml output format", name: "get history with yaml output format",
cmd: "history angry-bird --output yaml", cmd: "history angry-bird --output yaml",
rels: []*release.Release{ rels: []*release.Release{
mk("angry-bird", 4, release.StatusDeployed), mk("angry-bird", noTag, 4, release.StatusDeployed),
mk("angry-bird", 3, release.StatusSuperseded), mk("angry-bird", noTag, 3, release.StatusSuperseded),
}, },
golden: "output/history.yaml", golden: "output/history.yaml",
}, { }, {
name: "get history with json output format", name: "get history with json output format",
cmd: "history angry-bird --output json", cmd: "history angry-bird --output json",
rels: []*release.Release{ rels: []*release.Release{
mk("angry-bird", 4, release.StatusDeployed), mk("angry-bird", noTag, 4, release.StatusDeployed),
mk("angry-bird", 3, release.StatusSuperseded), mk("angry-bird", noTag, 3, release.StatusSuperseded),
}, },
golden: "output/history.json", golden: "output/history.json",
}, {
name: "get history for release with release tag",
cmd: "history angry-bird",
rels: []*release.Release{
mk("angry-bird", "tag-4", 4, release.StatusDeployed),
mk("angry-bird", "tag-3", 3, release.StatusSuperseded),
mk("angry-bird", "tag-2", 2, release.StatusSuperseded),
mk("angry-bird", "tag-1", 1, release.StatusSuperseded),
},
golden: "output/history-release-tag.txt",
}, {
name: "get history with yaml output format",
cmd: "history angry-bird --output yaml",
rels: []*release.Release{
mk("angry-bird", "tag-4", 4, release.StatusDeployed),
mk("angry-bird", "tag-3", 3, release.StatusSuperseded),
},
golden: "output/history-release-tag.yaml",
}, {
name: "get history with yaml output format",
cmd: "history angry-bird --output json",
rels: []*release.Release{
mk("angry-bird", "tag-4", 4, release.StatusDeployed),
mk("angry-bird", "tag-3", 3, release.StatusSuperseded),
},
golden: "output/history-release-tag.json",
}} }}
runTestCmd(t, tests) runTestCmd(t, tests)
} }

@ -155,6 +155,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
f.BoolVar(&client.Atomic, "atomic", false, "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used") f.BoolVar(&client.Atomic, "atomic", false, "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used")
f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present") f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present")
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
f.StringVar(&client.ReleaseTag, "release-tag", "", "if set, a tag can be added to the name of the release")
addValueOptionsFlags(f, valueOpts) addValueOptionsFlags(f, valueOpts)
addChartPathOptionsFlags(f, &client.ChartPathOptions) addChartPathOptionsFlags(f, &client.ChartPathOptions)

@ -1,3 +1,3 @@
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION RELEASE TAG
3 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock 3 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock
4 Fri Sep 2 22:04:05 1977 deployed foo-0.1.0-beta.1 1.0 Release mock 4 Fri Sep 2 22:04:05 1977 deployed foo-0.1.0-beta.1 1.0 Release mock

@ -0,0 +1 @@
[{"revision":3,"updated":"1977-09-02T22:04:05Z","status":"superseded","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock","release_tag":"tag-3"},{"revision":4,"updated":"1977-09-02T22:04:05Z","status":"deployed","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock","release_tag":"tag-4"}]

@ -0,0 +1,5 @@
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION RELEASE TAG
1 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock tag-1
2 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock tag-2
3 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock tag-3
4 Fri Sep 2 22:04:05 1977 deployed foo-0.1.0-beta.1 1.0 Release mock tag-4

@ -0,0 +1,14 @@
- app_version: "1.0"
chart: foo-0.1.0-beta.1
description: Release mock
release_tag: tag-3
revision: 3
status: superseded
updated: "1977-09-02T22:04:05Z"
- app_version: "1.0"
chart: foo-0.1.0-beta.1
description: Release mock
release_tag: tag-4
revision: 4
status: deployed
updated: "1977-09-02T22:04:05Z"

@ -1 +1 @@
[{"revision":3,"updated":"1977-09-02T22:04:05Z","status":"superseded","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock"},{"revision":4,"updated":"1977-09-02T22:04:05Z","status":"deployed","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock"}] [{"revision":3,"updated":"1977-09-02T22:04:05Z","status":"superseded","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock","release_tag":""},{"revision":4,"updated":"1977-09-02T22:04:05Z","status":"deployed","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock","release_tag":""}]

@ -1,4 +1,4 @@
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION RELEASE TAG
1 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock 1 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock
2 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock 2 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock
3 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock 3 Fri Sep 2 22:04:05 1977 superseded foo-0.1.0-beta.1 1.0 Release mock

@ -1,12 +1,14 @@
- app_version: "1.0" - app_version: "1.0"
chart: foo-0.1.0-beta.1 chart: foo-0.1.0-beta.1
description: Release mock description: Release mock
release_tag: ""
revision: 3 revision: 3
status: superseded status: superseded
updated: "1977-09-02T22:04:05Z" updated: "1977-09-02T22:04:05Z"
- app_version: "1.0" - app_version: "1.0"
chart: foo-0.1.0-beta.1 chart: foo-0.1.0-beta.1
description: Release mock description: Release mock
release_tag: ""
revision: 4 revision: 4
status: deployed status: deployed
updated: "1977-09-02T22:04:05Z" updated: "1977-09-02T22:04:05Z"

@ -117,6 +117,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
instClient.SubNotes = client.SubNotes instClient.SubNotes = client.SubNotes
instClient.Description = client.Description instClient.Description = client.Description
instClient.DependencyUpdate = client.DependencyUpdate instClient.DependencyUpdate = client.DependencyUpdate
instClient.ReleaseTag = client.ReleaseTag
rel, err := runInstall(args, instClient, valueOpts, out) rel, err := runInstall(args, instClient, valueOpts, out)
if err != nil { if err != nil {
@ -230,6 +231,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
f.StringVar(&client.Description, "description", "", "add a custom description") f.StringVar(&client.Description, "description", "", "add a custom description")
f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "update dependencies if they are missing before installing the chart") f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "update dependencies if they are missing before installing the chart")
f.StringVar(&client.ReleaseTag, "release-tag", "", "if set, a tag can be added to the name of the release")
addChartPathOptionsFlags(f, &client.ChartPathOptions) addChartPathOptionsFlags(f, &client.ChartPathOptions)
addValueOptionsFlags(f, valueOpts) addValueOptionsFlags(f, valueOpts)
bindOutputFlag(cmd, &outfmt) bindOutputFlag(cmd, &outfmt)

@ -102,6 +102,8 @@ type Install struct {
PostRenderer postrender.PostRenderer PostRenderer postrender.PostRenderer
// Lock to control raceconditions when the process receives a SIGTERM // Lock to control raceconditions when the process receives a SIGTERM
Lock sync.Mutex Lock sync.Mutex
// Used to tag a release // --release-tag
ReleaseTag string
} }
// ChartPathOptions captures common options used for controlling chart paths // ChartPathOptions captures common options used for controlling chart paths
@ -405,6 +407,7 @@ func (i *Install) performInstall(c chan<- resultMessage, rel *release.Release, t
rel.SetStatus(release.StatusDeployed, "Install complete") rel.SetStatus(release.StatusDeployed, "Install complete")
} }
rel.SetReleaseTag(i.ReleaseTag)
// This is a tricky case. The release has been created, but the result // This is a tricky case. The release has been created, but the result
// cannot be recorded. The truest thing to tell the user is that the // cannot be recorded. The truest thing to tell the user is that the
// release was created. However, the user will not be able to do anything // release was created. However, the user will not be able to do anything

@ -131,6 +131,7 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele
// Because we lose the reference to previous version elsewhere, we set the // Because we lose the reference to previous version elsewhere, we set the
// message here, and only override it later if we experience failure. // message here, and only override it later if we experience failure.
Description: fmt.Sprintf("Rollback to %d", previousVersion), Description: fmt.Sprintf("Rollback to %d", previousVersion),
ReleaseTag: previousRelease.Info.ReleaseTag,
}, },
Version: currentRelease.Version + 1, Version: currentRelease.Version + 1,
Manifest: previousRelease.Manifest, Manifest: previousRelease.Manifest,

@ -103,6 +103,8 @@ type Upgrade struct {
DependencyUpdate bool DependencyUpdate bool
// Lock to control raceconditions when the process receives a SIGTERM // Lock to control raceconditions when the process receives a SIGTERM
Lock sync.Mutex Lock sync.Mutex
// Used to tag a release // --release-tag
ReleaseTag string
} }
type resultMessage struct { type resultMessage struct {
@ -247,6 +249,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
LastDeployed: Timestamper(), LastDeployed: Timestamper(),
Status: release.StatusPendingUpgrade, Status: release.StatusPendingUpgrade,
Description: "Preparing upgrade", // This should be overwritten later. Description: "Preparing upgrade", // This should be overwritten later.
ReleaseTag: u.ReleaseTag, // update release tag
}, },
Version: revision, Version: revision,
Manifest: manifestDoc.String(), Manifest: manifestDoc.String(),

@ -33,4 +33,6 @@ type Info struct {
Status Status `json:"status,omitempty"` Status Status `json:"status,omitempty"`
// Contains the rendered templates/NOTES.txt if available // Contains the rendered templates/NOTES.txt if available
Notes string `json:"notes,omitempty"` Notes string `json:"notes,omitempty"`
// ReleaseTag is a optional tag that can be added to the release
ReleaseTag string `json:"release_tag,omitempty"`
} }

@ -41,11 +41,12 @@ metadata:
// MockReleaseOptions allows for user-configurable options on mock release objects. // MockReleaseOptions allows for user-configurable options on mock release objects.
type MockReleaseOptions struct { type MockReleaseOptions struct {
Name string Name string
Version int Version int
Chart *chart.Chart Chart *chart.Chart
Status Status Status Status
Namespace string Namespace string
ReleaseTag string
} }
// Mock creates a mock release object based on options set by MockReleaseOptions. This function should typically not be used outside of testing. // Mock creates a mock release object based on options set by MockReleaseOptions. This function should typically not be used outside of testing.
@ -92,6 +93,7 @@ func Mock(opts *MockReleaseOptions) *Release {
Status: scode, Status: scode,
Description: "Release mock", Description: "Release mock",
Notes: "Some mock release notes!", Notes: "Some mock release notes!",
ReleaseTag: opts.ReleaseTag,
} }
return &Release{ return &Release{

@ -47,3 +47,8 @@ func (r *Release) SetStatus(status Status, msg string) {
r.Info.Status = status r.Info.Status = status
r.Info.Description = msg r.Info.Description = msg
} }
// SetReleaseTag is a helper for setting the tag on a release.
func (r *Release) SetReleaseTag(rt string) {
r.Info.ReleaseTag = rt
}

Loading…
Cancel
Save