Merge pull request #6550 from thomastaylor312/fix/missing_debug

fix(cmd): Fix all the outputs
pull/6596/head
Taylor Thomas 6 years ago committed by GitHub
commit 0210d43a66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,6 +23,7 @@ import (
"github.com/spf13/pflag"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/cli/values"
)
@ -48,10 +49,34 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
}
// bindOutputFlag will add the output flag to the given command and bind the
// value to the given string pointer
func bindOutputFlag(cmd *cobra.Command, varRef *string) {
// NOTE(taylor): A possible refactor here is that we can implement all the
// validation for the OutputFormat type here so we don't have to do the
// parsing and checking in the command
cmd.Flags().StringVarP(varRef, outputFlag, "o", string(action.Table), fmt.Sprintf("prints the output in the specified format. Allowed values: %s, %s, %s", action.Table, action.JSON, action.YAML))
// value to the given format pointer
func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) {
cmd.Flags().VarP(newOutputValue(output.Table, varRef), outputFlag, "o", fmt.Sprintf("prints the output in the specified format. Allowed values: %s, %s, %s", output.Table, output.JSON, output.YAML))
}
type outputValue output.Format
func newOutputValue(defaultValue output.Format, p *output.Format) *outputValue {
*p = defaultValue
return (*outputValue)(p)
}
func (o *outputValue) String() string {
// It is much cleaner looking (and technically less allocations) to just
// convert to a string rather than type asserting to the underlying
// output.Format
return string(*o)
}
func (o *outputValue) Type() string {
return "format"
}
func (o *outputValue) Set(s string) error {
outfmt, err := output.ParseFormat(s)
if err != nil {
return err
}
*o = outputValue(outfmt)
return nil
}

@ -23,6 +23,7 @@ import (
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
)
var getHelp = `
@ -58,7 +59,8 @@ func newGetCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
}
return tpl(template, data, out)
}
return printRelease(out, res)
return output.Table.Write(out, &statusPrinter{res, true})
},
}

@ -19,6 +19,7 @@ package main
import (
"fmt"
"io"
"time"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
@ -26,6 +27,7 @@ import (
"helm.sh/helm/v3/cmd/helm/require"
"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"
"helm.sh/helm/v3/pkg/releaseutil"
)
@ -48,6 +50,7 @@ The historical release set is printed as a formatted table, e.g:
func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewHistory(cfg)
var outfmt output.Format
cmd := &cobra.Command{
Use: "history RELEASE_NAME",
@ -56,55 +59,48 @@ func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Aliases: []string{"hist"},
Args: require.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
output, err := action.ParseOutputFormat(client.OutputFormat)
if err != nil {
return err
}
history, err := getHistory(client, args[0])
if err != nil {
return err
}
return output.Write(out, history)
return outfmt.Write(out, history)
},
}
f := cmd.Flags()
f.IntVar(&client.Max, "max", 256, "maximum number of revision to include in history")
bindOutputFlag(cmd, &client.OutputFormat)
bindOutputFlag(cmd, &outfmt)
return cmd
}
type releaseInfo struct {
Revision int `json:"revision"`
Updated string `json:"updated"`
Status string `json:"status"`
Chart string `json:"chart"`
AppVersion string `json:"app_version"`
Description string `json:"description"`
Revision int `json:"revision"`
Updated time.Time `json:"updated"`
Status string `json:"status"`
Chart string `json:"chart"`
AppVersion string `json:"app_version"`
Description string `json:"description"`
}
type releaseHistory []releaseInfo
func (r releaseHistory) WriteJSON(out io.Writer) error {
return action.EncodeJSON(out, r)
return output.EncodeJSON(out, r)
}
func (r releaseHistory) WriteYAML(out io.Writer) error {
return action.EncodeYAML(out, r)
return output.EncodeYAML(out, r)
}
func (r releaseHistory) WriteTable(out io.Writer) error {
tbl := uitable.New()
tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION")
for _, item := range r {
tbl.AddRow(item.Revision, item.Updated, item.Status, item.Chart, item.AppVersion, item.Description)
tbl.AddRow(item.Revision, item.Updated.Format(time.ANSIC), item.Status, item.Chart, item.AppVersion, item.Description)
}
return action.EncodeTable(out, tbl)
return output.EncodeTable(out, tbl)
}
func getHistory(client *action.History, name string) (releaseHistory, error) {
@ -146,7 +142,7 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
Description: d,
}
if !r.Info.LastDeployed.IsZero() {
rInfo.Updated = r.Info.LastDeployed.String()
rInfo.Updated = r.Info.LastDeployed
}
history = append(history, rInfo)

@ -28,6 +28,7 @@ import (
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/cli/values"
"helm.sh/helm/v3/pkg/downloader"
"helm.sh/helm/v3/pkg/getter"
@ -104,6 +105,7 @@ charts in a repository, use 'helm search'.
func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewInstall(cfg)
valueOpts := &values.Options{}
var outfmt output.Format
cmd := &cobra.Command{
Use: "install [NAME] [CHART]",
@ -111,24 +113,17 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Long: installDesc,
Args: require.MinimumNArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
output, err := action.ParseOutputFormat(client.OutputFormat)
if err != nil {
return err
}
rel, err := runInstall(args, client, valueOpts, out)
if err != nil {
return err
}
return output.Write(out, &statusPrinter{rel})
return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
},
}
addInstallFlags(cmd.Flags(), client, valueOpts)
bindOutputFlag(cmd, &client.OutputFormat)
bindOutputFlag(cmd, &outfmt)
return cmd
}

@ -26,6 +26,7 @@ import (
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/release"
)
@ -58,6 +59,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{
Use: "list",
@ -66,13 +68,6 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Aliases: []string{"ls"},
Args: require.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
output, err := action.ParseOutputFormat(client.OutputFormat)
if err != nil {
return err
}
if client.AllNamespaces {
initActionConfig(cfg, true)
}
@ -87,7 +82,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return err
}
return output.Write(out, newReleaseListWriter(results))
return outfmt.Write(out, newReleaseListWriter(results))
},
}
@ -106,7 +101,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.IntVarP(&client.Limit, "max", "m", 256, "maximum number of releases to fetch")
f.IntVar(&client.Offset, "offset", 0, "next release name in the list, used to offset from start value")
f.StringVarP(&client.Filter, "filter", "f", "", "a regular expression (Perl compatible). Any releases that match the expression will be included in the results")
bindOutputFlag(cmd, &client.OutputFormat)
bindOutputFlag(cmd, &outfmt)
return cmd
}
@ -153,13 +148,13 @@ func (r *releaseListWriter) WriteTable(out io.Writer) error {
for _, r := range r.releases {
table.AddRow(r.Name, r.Namespace, r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion)
}
return action.EncodeTable(out, table)
return output.EncodeTable(out, table)
}
func (r *releaseListWriter) WriteJSON(out io.Writer) error {
return action.EncodeJSON(out, r.releases)
return output.EncodeJSON(out, r.releases)
}
func (r *releaseListWriter) WriteYAML(out io.Writer) error {
return action.EncodeYAML(out, r.releases)
return output.EncodeYAML(out, r.releases)
}

@ -19,59 +19,8 @@ package main
import (
"io"
"text/template"
"time"
"sigs.k8s.io/yaml"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/release"
)
var printReleaseTemplate = `REVISION: {{.Release.Version}}
RELEASED: {{.ReleaseDate}}
CHART: {{.Release.Chart.Metadata.Name}}-{{.Release.Chart.Metadata.Version}}
USER-SUPPLIED VALUES:
{{.Config}}
COMPUTED VALUES:
{{.ComputedValues}}
HOOKS:
{{- range .Release.Hooks }}
---
# {{.Name}}
{{.Manifest}}
{{- end }}
MANIFEST:
{{.Release.Manifest}}
`
func printRelease(out io.Writer, rel *release.Release) error {
if rel == nil {
return nil
}
cfg, err := chartutil.CoalesceValues(rel.Chart, rel.Config)
if err != nil {
return err
}
computed, err := cfg.YAML()
if err != nil {
return err
}
config, err := yaml.Marshal(rel.Config)
if err != nil {
return err
}
data := map[string]interface{}{
"Release": rel,
"Config": string(config),
"ComputedValues": computed,
"ReleaseDate": rel.Info.LastDeployed.Format(time.ANSIC),
}
return tpl(printReleaseTemplate, data, out)
}
func tpl(t string, vals map[string]interface{}, out io.Writer) error {
tt, err := template.New("_").Parse(t)
if err != nil {

@ -24,24 +24,18 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/repo"
)
func newRepoListCmd(out io.Writer) *cobra.Command {
var output string
var outfmt output.Format
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "list chart repositories",
Args: require.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
outfmt, err := action.ParseOutputFormat(output)
if err != nil {
return err
}
f, err := repo.LoadFile(settings.RepositoryConfig)
if isNotExist(err) || len(f.Repositories) == 0 {
return errors.New("no repositories to show")
@ -51,7 +45,7 @@ func newRepoListCmd(out io.Writer) *cobra.Command {
},
}
bindOutputFlag(cmd, &output)
bindOutputFlag(cmd, &outfmt)
return cmd
}
@ -71,18 +65,18 @@ func (r *repoListWriter) WriteTable(out io.Writer) error {
for _, re := range r.repos {
table.AddRow(re.Name, re.URL)
}
return action.EncodeTable(out, table)
return output.EncodeTable(out, table)
}
func (r *repoListWriter) WriteJSON(out io.Writer) error {
return r.encodeByFormat(out, action.JSON)
return r.encodeByFormat(out, output.JSON)
}
func (r *repoListWriter) WriteYAML(out io.Writer) error {
return r.encodeByFormat(out, action.YAML)
return r.encodeByFormat(out, output.YAML)
}
func (r *repoListWriter) encodeByFormat(out io.Writer, format action.OutputFormat) error {
func (r *repoListWriter) encodeByFormat(out io.Writer, format output.Format) error {
// Initialize the array so no results returns an empty array instead of null
repolist := make([]repositoryElement, 0, len(r.repos))
@ -91,10 +85,10 @@ func (r *repoListWriter) encodeByFormat(out io.Writer, format action.OutputForma
}
switch format {
case action.JSON:
return action.EncodeJSON(out, repolist)
case action.YAML:
return action.EncodeYAML(out, repolist)
case output.JSON:
return output.EncodeJSON(out, repolist)
case output.YAML:
return output.EncodeYAML(out, repolist)
}
// Because this is a non-exported function and only called internally by

@ -26,7 +26,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/internal/monocular"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
)
const searchHubDesc = `
@ -44,7 +44,7 @@ Helm Hub. You can find it at https://github.com/helm/monocular
type searchHubOptions struct {
searchEndpoint string
maxColWidth uint
outputFormat string
outputFormat output.Format
}
func newSearchHubCmd(out io.Writer) *cobra.Command {
@ -68,13 +68,6 @@ func newSearchHubCmd(out io.Writer) *cobra.Command {
}
func (o *searchHubOptions) run(out io.Writer, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
outfmt, err := action.ParseOutputFormat(o.outputFormat)
if err != nil {
return err
}
c, err := monocular.New(o.searchEndpoint)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to create connection to %q", o.searchEndpoint))
@ -87,7 +80,7 @@ func (o *searchHubOptions) run(out io.Writer, args []string) error {
return fmt.Errorf("unable to perform search against %q", o.searchEndpoint)
}
return outfmt.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth))
return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth))
}
type hubChartElement struct {
@ -125,18 +118,18 @@ func (h *hubSearchWriter) WriteTable(out io.Writer) error {
for _, r := range h.elements {
table.AddRow(r.URL, r.Version, r.AppVersion, r.Description)
}
return action.EncodeTable(out, table)
return output.EncodeTable(out, table)
}
func (h *hubSearchWriter) WriteJSON(out io.Writer) error {
return h.encodeByFormat(out, action.JSON)
return h.encodeByFormat(out, output.JSON)
}
func (h *hubSearchWriter) WriteYAML(out io.Writer) error {
return h.encodeByFormat(out, action.YAML)
return h.encodeByFormat(out, output.YAML)
}
func (h *hubSearchWriter) encodeByFormat(out io.Writer, format action.OutputFormat) error {
func (h *hubSearchWriter) encodeByFormat(out io.Writer, format output.Format) error {
// Initialize the array so no results returns an empty array instead of null
chartList := make([]hubChartElement, 0, len(h.elements))
@ -145,10 +138,10 @@ func (h *hubSearchWriter) encodeByFormat(out io.Writer, format action.OutputForm
}
switch format {
case action.JSON:
return action.EncodeJSON(out, chartList)
case action.YAML:
return action.EncodeYAML(out, chartList)
case output.JSON:
return output.EncodeJSON(out, chartList)
case output.YAML:
return output.EncodeYAML(out, chartList)
}
// Because this is a non-exported function and only called internally by

@ -28,7 +28,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/search"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/helmpath"
"helm.sh/helm/v3/pkg/repo"
)
@ -51,7 +51,7 @@ type searchRepoOptions struct {
maxColWidth uint
repoFile string
repoCacheDir string
outputFormat string
outputFormat output.Format
}
func newSearchRepoCmd(out io.Writer) *cobra.Command {
@ -79,13 +79,6 @@ func newSearchRepoCmd(out io.Writer) *cobra.Command {
}
func (o *searchRepoOptions) run(out io.Writer, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
outfmt, err := action.ParseOutputFormat(o.outputFormat)
if err != nil {
return err
}
index, err := o.buildIndex(out)
if err != nil {
return err
@ -108,7 +101,7 @@ func (o *searchRepoOptions) run(out io.Writer, args []string) error {
return err
}
return outfmt.Write(out, &repoSearchWriter{data, o.maxColWidth})
return o.outputFormat.Write(out, &repoSearchWriter{data, o.maxColWidth})
}
func (o *searchRepoOptions) applyConstraint(res []*search.Result) ([]*search.Result, error) {
@ -188,18 +181,18 @@ func (r *repoSearchWriter) WriteTable(out io.Writer) error {
for _, r := range r.results {
table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description)
}
return action.EncodeTable(out, table)
return output.EncodeTable(out, table)
}
func (r *repoSearchWriter) WriteJSON(out io.Writer) error {
return r.encodeByFormat(out, action.JSON)
return r.encodeByFormat(out, output.JSON)
}
func (r *repoSearchWriter) WriteYAML(out io.Writer) error {
return r.encodeByFormat(out, action.YAML)
return r.encodeByFormat(out, output.YAML)
}
func (r *repoSearchWriter) encodeByFormat(out io.Writer, format action.OutputFormat) error {
func (r *repoSearchWriter) encodeByFormat(out io.Writer, format output.Format) error {
// Initialize the array so no results returns an empty array instead of null
chartList := make([]repoChartElement, 0, len(r.results))
@ -208,10 +201,10 @@ func (r *repoSearchWriter) encodeByFormat(out io.Writer, format action.OutputFor
}
switch format {
case action.JSON:
return action.EncodeJSON(out, chartList)
case action.YAML:
return action.EncodeYAML(out, chartList)
case output.JSON:
return output.EncodeJSON(out, chartList)
case output.YAML:
return output.EncodeYAML(out, chartList)
}
// Because this is a non-exported function and only called internally by

@ -17,12 +17,17 @@ limitations under the License.
package main
import (
"fmt"
"io"
"strings"
"time"
"github.com/spf13/cobra"
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/release"
)
@ -39,6 +44,7 @@ The status consists of:
func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewStatus(cfg)
var outfmt output.Format
cmd := &cobra.Command{
Use: "status RELEASE_NAME",
@ -46,13 +52,6 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Long: statusHelp,
Args: require.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
outfmt, err := action.ParseOutputFormat(client.OutputFormat)
if err != nil {
return err
}
rel, err := client.Run(args[0])
if err != nil {
return err
@ -61,30 +60,105 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
// strip chart metadata from the output
rel.Chart = nil
return outfmt.Write(out, &statusPrinter{rel})
return outfmt.Write(out, &statusPrinter{rel, false})
},
}
f := cmd.PersistentFlags()
f.IntVar(&client.Version, "revision", 0, "if set, display the status of the named release with revision")
bindOutputFlag(cmd, &client.OutputFormat)
bindOutputFlag(cmd, &outfmt)
return cmd
}
type statusPrinter struct {
release *release.Release
debug bool
}
func (s statusPrinter) WriteJSON(out io.Writer) error {
return action.EncodeJSON(out, s.release)
return output.EncodeJSON(out, s.release)
}
func (s statusPrinter) WriteYAML(out io.Writer) error {
return action.EncodeYAML(out, s.release)
return output.EncodeYAML(out, s.release)
}
func (s statusPrinter) WriteTable(out io.Writer) error {
action.PrintRelease(out, s.release)
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))
}
fmt.Fprintf(out, "NAMESPACE: %s\n", s.release.Namespace)
fmt.Fprintf(out, "STATUS: %s\n", s.release.Info.Status.String())
fmt.Fprintf(out, "REVISION: %d\n", s.release.Version)
executions := executionsByHookEvent(s.release)
if tests, ok := executions[release.HookTest]; ok {
for _, h := range tests {
// Don't print anything if hook has not been initiated
if h.LastRun.StartedAt.IsZero() {
continue
}
fmt.Fprintf(out, "TEST SUITE: %s\n%s\n%s\n%s\n\n",
h.Name,
fmt.Sprintf("Last Started: %s", h.LastRun.StartedAt.Format(time.ANSIC)),
fmt.Sprintf("Last Completed: %s", h.LastRun.CompletedAt.Format(time.ANSIC)),
fmt.Sprintf("Phase: %s", h.LastRun.Phase),
)
}
}
if s.debug {
fmt.Fprintln(out, "USER-SUPPLIED VALUES:")
err := output.EncodeYAML(out, s.release.Config)
if err != nil {
return err
}
// Print an extra newline
fmt.Fprintln(out)
cfg, err := chartutil.CoalesceValues(s.release.Chart, s.release.Config)
if err != nil {
return err
}
fmt.Fprintln(out, "COMPUTED VALUES:")
err = output.EncodeYAML(out, cfg.AsMap())
if err != nil {
return err
}
// Print an extra newline
fmt.Fprintln(out)
}
if strings.EqualFold(s.release.Info.Description, "Dry run complete") || s.debug {
fmt.Fprintln(out, "HOOKS:")
for _, h := range s.release.Hooks {
fmt.Fprintf(out, "---\n# Source: %s\n%s\n", h.Path, h.Manifest)
}
fmt.Fprintf(out, "MANIFEST:\n%s\n", s.release.Manifest)
}
if len(s.release.Info.Notes) > 0 {
fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(s.release.Info.Notes))
}
return nil
}
func executionsByHookEvent(rel *release.Release) map[release.HookEvent][]*release.Hook {
result := make(map[release.HookEvent][]*release.Hook)
for _, h := range rel.Hooks {
for _, e := range h.Events {
executions, ok := result[e]
if !ok {
executions = []*release.Hook{}
}
result[e] = append(executions, h)
}
}
return result
}

@ -1,6 +1,8 @@
NAME: thomas-guide
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1
RELEASED: Fri Sep 2 22:04:05 1977
CHART: foo-0.1.0-beta.1
USER-SUPPLIED VALUES:
name: value
@ -9,7 +11,7 @@ name: value
HOOKS:
---
# pre-install-hook
# Source: pre-install-hook.yaml
apiVersion: v1
kind: Job
metadata:

@ -1,3 +1,3 @@
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
3 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
4 1977-09-02 22:04:05 +0000 UTC deployed foo-0.1.0-beta.1 1.0 Release mock
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
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

@ -1 +1 @@
[{"revision":3,"updated":"1977-09-02 22:04:05 +0000 UTC","status":"superseded","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock"},{"revision":4,"updated":"1977-09-02 22:04:05 +0000 UTC","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"},{"revision":4,"updated":"1977-09-02T22:04:05Z","status":"deployed","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock"}]

@ -1,5 +1,5 @@
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
2 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
3 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
4 1977-09-02 22:04:05 +0000 UTC deployed foo-0.1.0-beta.1 1.0 Release mock
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
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
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

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

@ -1,4 +1,5 @@
NAME: aeneas
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: FOOBAR
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: aeneas
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: virgil
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: virgil
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: foobar
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: virgil
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: virgil
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: apollo
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: aeneas
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,4 +1,5 @@
NAME: schema
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,6 +1,7 @@
NAME: flummoxed-chickadee
LAST DEPLOYED: 2016-01-16 00:00:00 +0000 UTC
LAST DEPLOYED: Sat Jan 16 00:00:00 2016
NAMESPACE: default
STATUS: deployed
REVISION: 0
NOTES:
release notes

@ -1,14 +1,15 @@
NAME: flummoxed-chickadee
LAST DEPLOYED: 2016-01-16 00:00:00 +0000 UTC
LAST DEPLOYED: Sat Jan 16 00:00:00 2016
NAMESPACE: default
STATUS: deployed
REVISION: 0
TEST SUITE: passing-test
Last Started: 2006-01-02 15:04:05 +0000 UTC
Last Completed: 2006-01-02 15:04:07 +0000 UTC
Last Started: Mon Jan 2 15:04:05 2006
Last Completed: Mon Jan 2 15:04:07 2006
Phase: Succeeded
TEST SUITE: failing-test
Last Started: 2006-01-02 15:10:05 +0000 UTC
Last Completed: 2006-01-02 15:10:07 +0000 UTC
Last Started: Mon Jan 2 15:10:05 2006
Last Completed: Mon Jan 2 15:10:07 2006
Phase: Failed

@ -1,4 +1,5 @@
NAME: flummoxed-chickadee
LAST DEPLOYED: 2016-01-16 00:00:00 +0000 UTC
LAST DEPLOYED: Sat Jan 16 00:00:00 2016
NAMESPACE: default
STATUS: deployed
REVISION: 0

@ -1,4 +1,5 @@
NAME: schema
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 1

@ -1,5 +1,6 @@
Release "crazy-bunny" has been upgraded. Happy Helming!
NAME: crazy-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2

@ -1,5 +1,6 @@
Release "zany-bunny" has been upgraded. Happy Helming!
NAME: zany-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 2

@ -1,5 +1,6 @@
Release "funny-bunny" has been upgraded. Happy Helming!
NAME: funny-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 5

@ -1,5 +1,6 @@
Release "funny-bunny" has been upgraded. Happy Helming!
NAME: funny-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 6

@ -1,5 +1,6 @@
Release "funny-bunny" has been upgraded. Happy Helming!
NAME: funny-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 4

@ -1,5 +1,6 @@
Release "crazy-bunny" has been upgraded. Happy Helming!
NAME: crazy-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 3

@ -1,5 +1,6 @@
Release "funny-bunny" has been upgraded. Happy Helming!
NAME: funny-bunny
LAST DEPLOYED: 1977-09-02 22:04:05 +0000 UTC
LAST DEPLOYED: Fri Sep 2 22:04:05 1977
NAMESPACE: default
STATUS: deployed
REVISION: 3

@ -27,6 +27,7 @@ import (
"helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli/output"
"helm.sh/helm/v3/pkg/cli/values"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/storage/driver"
@ -62,6 +63,7 @@ set for a key called 'foo', the 'newbar' value would take precedence:
func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewUpgrade(cfg)
valueOpts := &values.Options{}
var outfmt output.Format
cmd := &cobra.Command{
Use: "upgrade [RELEASE] [CHART]",
@ -69,13 +71,6 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Long: upgradeDesc,
Args: require.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
// validate the output format first so we don't waste time running a
// request that we'll throw away
output, err := action.ParseOutputFormat(client.OutputFormat)
if err != nil {
return err
}
client.Namespace = getNamespace()
if client.Version == "" && client.Devel {
@ -99,7 +94,10 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
histClient := action.NewHistory(cfg)
histClient.Max = 1
if _, err := histClient.Run(args[0]); err == driver.ErrReleaseNotFound {
fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0])
// Only print this to stdout for table output
if outfmt == output.Table {
fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0])
}
instClient := action.NewInstall(cfg)
instClient.ChartPathOptions = client.ChartPathOptions
instClient.DryRun = client.DryRun
@ -114,7 +112,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
if err != nil {
return err
}
return output.Write(out, &statusPrinter{rel})
return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
}
}
@ -129,27 +127,16 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
}
}
resp, err := client.Run(args[0], ch, vals)
rel, err := client.Run(args[0], ch, vals)
if err != nil {
return errors.Wrap(err, "UPGRADE FAILED")
}
if settings.Debug {
action.PrintRelease(out, resp)
}
if output == action.Table {
if outfmt == output.Table {
fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", args[0])
}
// Print the status like status command does
statusClient := action.NewStatus(cfg)
rel, err := statusClient.Run(args[0])
if err != nil {
return err
}
return output.Write(out, &statusPrinter{rel})
return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
},
}
@ -171,7 +158,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")
addChartPathOptionsFlags(f, &client.ChartPathOptions)
addValueOptionsFlags(f, valueOpts)
bindOutputFlag(cmd, &client.OutputFormat)
bindOutputFlag(cmd, &outfmt)
return cmd
}

@ -28,8 +28,8 @@ import (
type History struct {
cfg *Configuration
Max int
OutputFormat string
Max int
Version int
}
// NewHistory creates a new History object with the given configuration.

@ -82,7 +82,6 @@ type Install struct {
OutputDir string
Atomic bool
SkipCRDs bool
OutputFormat string
SubNotes bool
}

@ -125,7 +125,6 @@ type List struct {
Deployed bool
Failed bool
Pending bool
OutputFormat string
}
// NewList constructs a new *List

@ -1,76 +0,0 @@
/*
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 action
import (
"fmt"
"io"
"strings"
"helm.sh/helm/v3/pkg/release"
)
// PrintRelease prints info about a release
func PrintRelease(out io.Writer, rel *release.Release) {
if rel == nil {
return
}
fmt.Fprintf(out, "NAME: %s\n", rel.Name)
if !rel.Info.LastDeployed.IsZero() {
fmt.Fprintf(out, "LAST DEPLOYED: %s\n", rel.Info.LastDeployed)
}
fmt.Fprintf(out, "NAMESPACE: %s\n", rel.Namespace)
fmt.Fprintf(out, "STATUS: %s\n", rel.Info.Status.String())
executions := executionsByHookEvent(rel)
if tests, ok := executions[release.HookTest]; ok {
for _, h := range tests {
// Don't print anything if hook has not been initiated
if h.LastRun.StartedAt.IsZero() {
continue
}
fmt.Fprintf(out, "TEST SUITE: %s\n%s\n%s\n%s\n\n",
h.Name,
fmt.Sprintf("Last Started: %s", h.LastRun.StartedAt),
fmt.Sprintf("Last Completed: %s", h.LastRun.CompletedAt),
fmt.Sprintf("Phase: %s", h.LastRun.Phase),
)
}
}
if strings.EqualFold(rel.Info.Description, "Dry run complete") {
fmt.Fprintf(out, "MANIFEST:\n%s\n", rel.Manifest)
}
if len(rel.Info.Notes) > 0 {
fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(rel.Info.Notes))
}
}
func executionsByHookEvent(rel *release.Release) map[release.HookEvent][]*release.Hook {
result := make(map[release.HookEvent][]*release.Hook)
for _, h := range rel.Hooks {
for _, e := range h.Events {
executions, ok := result[e]
if !ok {
executions = []*release.Hook{}
}
result[e] = append(executions, h)
}
}
return result
}

@ -26,8 +26,7 @@ import (
type Status struct {
cfg *Configuration
Version int
OutputFormat string
Version int
}
// NewStatus creates a new Status object with the given configuration.

@ -57,7 +57,6 @@ type Upgrade struct {
MaxHistory int
Atomic bool
CleanupOnFail bool
OutputFormat string
SubNotes bool
}

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package action
package output
import (
"encoding/json"
@ -26,26 +26,26 @@ import (
"sigs.k8s.io/yaml"
)
// OutputFormat is a type for capturing supported output formats
type OutputFormat string
// Format is a type for capturing supported output formats
type Format string
const (
Table OutputFormat = "table"
JSON OutputFormat = "json"
YAML OutputFormat = "yaml"
Table Format = "table"
JSON Format = "json"
YAML Format = "yaml"
)
// ErrInvalidFormatType is returned when an unsupported format type is used
var ErrInvalidFormatType = fmt.Errorf("invalid format type")
// String returns the string reprsentation of the OutputFormat
func (o OutputFormat) String() string {
// String returns the string reprsentation of the Format
func (o Format) String() string {
return string(o)
}
// Write the output in the given format to the io.Writer. Unsupported formats
// will return an error
func (o OutputFormat) Write(out io.Writer, w Writer) error {
func (o Format) Write(out io.Writer, w Writer) error {
switch o {
case Table:
return w.WriteTable(out)
@ -57,9 +57,9 @@ func (o OutputFormat) Write(out io.Writer, w Writer) error {
return ErrInvalidFormatType
}
// ParseOutputFormat takes a raw string and returns the matching OutputFormat.
// ParseFormat takes a raw string and returns the matching Format.
// If the format does not exists, ErrInvalidFormatType is returned
func ParseOutputFormat(s string) (out OutputFormat, err error) {
func ParseFormat(s string) (out Format, err error) {
switch s {
case Table.String():
out, err = Table, nil
Loading…
Cancel
Save