feat(helm): add --format flag to 'helm list'

When 'helm list --format (text|json|yaml) is run, this will print the list
of releases in the specified format.

WIP #1534
pull/2950/head
Sam Leavens 8 years ago
parent d815310928
commit a0db07ea23

@ -17,6 +17,7 @@ limitations under the License.
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -24,10 +25,13 @@ import (
"github.com/gosuri/uitable" "github.com/gosuri/uitable"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"bytes"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/timeconv"
"time"
) )
var listHelp = ` var listHelp = `
@ -73,9 +77,19 @@ type listCmd struct {
namespace string namespace string
superseded bool superseded bool
pending bool pending bool
format string
client helm.Interface client helm.Interface
} }
type listRelease struct {
Name string
Revision int32
Updated string
Status string
Namespace string
Chart string
}
func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
list := &listCmd{ list := &listCmd{
out: out, out: out,
@ -112,6 +126,7 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
f.BoolVar(&list.failed, "failed", false, "show failed releases") f.BoolVar(&list.failed, "failed", false, "show failed releases")
f.BoolVar(&list.pending, "pending", false, "show pending releases") f.BoolVar(&list.pending, "pending", false, "show pending releases")
f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace") f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace")
f.StringVar(&list.format, "format", "text", "format output as text, json, or yaml")
// TODO: Do we want this as a feature of 'helm list'? // TODO: Do we want this as a feature of 'helm list'?
//f.BoolVar(&list.superseded, "history", true, "show historical releases") //f.BoolVar(&list.superseded, "history", true, "show historical releases")
@ -150,19 +165,20 @@ func (l *listCmd) run() error {
return nil return nil
} }
if res.Next != "" && !l.short { if res.Next != "" && !l.short && l.format == "text" {
fmt.Fprintf(l.out, "\tnext: %s\n", res.Next) fmt.Fprintf(l.out, "\tnext: %s\n", res.Next)
} }
rels := res.Releases format := l.format
if l.short { if l.short {
for _, r := range rels { format = "short"
fmt.Fprintln(l.out, r.Name)
} }
return nil
formatted, err := formatList(res.Releases, format)
if err != nil {
return err
} }
fmt.Fprintln(l.out, formatList(rels)) fmt.Fprint(l.out, formatted)
return nil return nil
} }
@ -207,7 +223,26 @@ func (l *listCmd) statusCodes() []release.Status_Code {
return status return status
} }
func formatList(rels []*release.Release) string { func formatList(rels []*release.Release, format string) (string, error) {
var res string
var err error
switch format {
case "text":
res = formatText(rels)
case "short":
res = formatShort(rels)
case "json":
res = fmt.Sprintf("%s\n", formatJSON(rels))
case "yaml":
res = fmt.Sprintf("%s", formatYAML(rels))
default:
err = fmt.Errorf("invalid format \"%s\"", format)
}
return res, err
}
func formatText(rels []*release.Release) string {
table := uitable.New() table := uitable.New()
table.MaxColWidth = 60 table.MaxColWidth = 60
table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE") table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE")
@ -219,5 +254,44 @@ func formatList(rels []*release.Release) string {
n := r.Namespace n := r.Namespace
table.AddRow(r.Name, v, t, s, c, n) table.AddRow(r.Name, v, t, s, c, n)
} }
return table.String() return fmt.Sprintf("%s\n", table.String())
}
func formatShort(rels []*release.Release) string {
var buffer bytes.Buffer
for _, r := range rels {
_, err := buffer.WriteString(fmt.Sprintf("%s\n", r.Name))
if err != nil {
panic(err)
}
}
return buffer.String()
}
func formatJSON(rels []*release.Release) []byte {
listReleases := []listRelease{}
for _, r := range rels {
lr := listRelease{
Name: r.Name,
Revision: r.Version,
Updated: timeconv.Format(r.Info.LastDeployed, time.RFC3339),
Status: r.Info.Status.Code.String(),
Chart: fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version),
Namespace: r.Namespace,
}
listReleases = append(listReleases, lr)
}
res, err := json.MarshalIndent(listReleases, "", " ")
if err != nil {
panic(err)
}
return res
}
func formatYAML(rels []*release.Release) []byte {
res, err := yaml.JSONToYAML(formatJSON(rels))
if err != nil {
panic(err)
}
return res
} }

@ -48,6 +48,22 @@ func TestListCmd(t *testing.T) {
}, },
expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\tdefault \n", expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\tdefault \n",
}, },
{
name: "list format JSON",
args: []string{"--format", "json"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "atlas"}),
},
expected: "\"Name\": \"atlas\",\n",
},
{
name: "list format YAML",
args: []string{"--format", "yaml"},
resp: []*release.Release{
releaseMock(&releaseOptions{name: "atlas"}),
},
expected: "- Chart: foo-0.1.0-beta.1\n Name: atlas\n Namespace: default\n Revision: 1\n Status: DEPLOYED\n",
},
{ {
name: "list, one deployed, one failed", name: "list, one deployed, one failed",
args: []string{"-q"}, args: []string{"-q"},

Loading…
Cancel
Save