ref(*): Refactors output into its own package

Signed-off-by: Taylor Thomas <taylor.thomas@microsoft.com>
pull/6550/head
Taylor Thomas 6 years ago
parent 3799d0024c
commit 768d27b387

@ -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"
)
@ -53,5 +54,5 @@ 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))
cmd.Flags().StringVarP(varRef, outputFlag, "o", output.Table.String(), fmt.Sprintf("prints the output in the specified format. Allowed values: %s, %s, %s", output.Table, output.JSON, output.YAML))
}

@ -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 action.PrintRelease(out, res, true)
return output.Table.Write(out, &statusPrinter{res, true})
},
}

@ -27,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"
)
@ -59,7 +60,7 @@ func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
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)
output, err := output.ParseFormat(client.OutputFormat)
if err != nil {
return err
}
@ -92,11 +93,11 @@ type releaseInfo struct {
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 {
@ -105,7 +106,7 @@ func (r releaseHistory) WriteTable(out io.Writer) error {
for _, item := range r {
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) {

@ -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"
@ -113,7 +114,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
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)
output, err := output.ParseFormat(client.OutputFormat)
if err != nil {
return err
}

@ -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"
)
@ -68,7 +69,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
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)
output, err := output.ParseFormat(client.OutputFormat)
if err != nil {
return err
}
@ -153,13 +154,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)
}

@ -24,12 +24,12 @@ 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 outputFormat string
cmd := &cobra.Command{
Use: "list",
Short: "list chart repositories",
@ -37,7 +37,7 @@ func newRepoListCmd(out io.Writer) *cobra.Command {
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)
outfmt, err := output.ParseFormat(outputFormat)
if err != nil {
return err
}
@ -50,7 +50,7 @@ func newRepoListCmd(out io.Writer) *cobra.Command {
},
}
bindOutputFlag(cmd, &output)
bindOutputFlag(cmd, &outputFormat)
return cmd
}
@ -70,18 +70,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))
@ -90,10 +90,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 = `
@ -70,7 +70,7 @@ 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)
outfmt, err := output.ParseFormat(o.outputFormat)
if err != nil {
return err
}
@ -125,18 +125,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 +145,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"
)
@ -81,7 +81,7 @@ 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)
outfmt, err := output.ParseFormat(o.outputFormat)
if err != nil {
return err
}
@ -188,18 +188,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 +208,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"
)
@ -48,7 +53,7 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
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)
outfmt, err := output.ParseFormat(client.OutputFormat)
if err != nil {
return err
}
@ -78,13 +83,88 @@ type statusPrinter struct {
}
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 {
return action.PrintRelease(out, s.release, s.debug)
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
}

@ -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"
@ -71,7 +72,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
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)
outfmt, err := output.ParseFormat(client.OutputFormat)
if err != nil {
return err
}
@ -100,7 +101,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
histClient.Max = 1
if _, err := histClient.Run(args[0]); err == driver.ErrReleaseNotFound {
// Only print this to stdout for table output
if output == action.Table {
if outfmt == output.Table {
fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0])
}
instClient := action.NewInstall(cfg)
@ -117,7 +118,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
if err != nil {
return err
}
return output.Write(out, &statusPrinter{rel, settings.Debug})
return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
}
}
@ -137,11 +138,11 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return errors.Wrap(err, "UPGRADE FAILED")
}
if output == action.Table {
if outfmt == output.Table {
fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", args[0])
}
return output.Write(out, &statusPrinter{rel, settings.Debug})
return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
},
}

@ -1,108 +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"
"time"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/release"
)
// PrintRelease prints info about a release. If fullInfo is true, it will print
// the user supplied values and the computed values used to render the chart
func PrintRelease(out io.Writer, rel *release.Release, fullInfo bool) error {
if rel == nil {
return nil
}
fmt.Fprintf(out, "NAME: %s\n", rel.Name)
if !rel.Info.LastDeployed.IsZero() {
fmt.Fprintf(out, "LAST DEPLOYED: %s\n", rel.Info.LastDeployed.Format(time.ANSIC))
}
fmt.Fprintf(out, "NAMESPACE: %s\n", rel.Namespace)
fmt.Fprintf(out, "STATUS: %s\n", rel.Info.Status.String())
fmt.Fprintf(out, "REVISION: %d\n", rel.Version)
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.Format(time.ANSIC)),
fmt.Sprintf("Last Completed: %s", h.LastRun.CompletedAt.Format(time.ANSIC)),
fmt.Sprintf("Phase: %s", h.LastRun.Phase),
)
}
}
if fullInfo {
fmt.Fprintln(out, "USER-SUPPLIED VALUES:")
err := EncodeYAML(out, rel.Config)
if err != nil {
return err
}
// Print an extra newline
fmt.Fprintln(out)
cfg, err := chartutil.CoalesceValues(rel.Chart, rel.Config)
if err != nil {
return err
}
fmt.Fprintln(out, "COMPUTED VALUES:")
err = EncodeYAML(out, cfg.AsMap())
if err != nil {
return err
}
// Print an extra newline
fmt.Fprintln(out)
}
if strings.EqualFold(rel.Info.Description, "Dry run complete") || fullInfo {
fmt.Fprintln(out, "HOOKS:")
for _, h := range rel.Hooks {
fmt.Fprintf(out, "---\n# Source: %s\n%s\n", h.Path, h.Manifest)
}
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))
}
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
}

@ -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