feature: Add --output option to `helm dep list`

Signed-off-by: Yonatan Kahana <yonatankahana.il@gmail.com>
pull/8073/head
Yonatan Kahana 5 years ago
parent e29ed7a108
commit 35d4c93c0b

@ -23,6 +23,7 @@ import (
"helm.sh/helm/v3/cmd/helm/require" "helm.sh/helm/v3/cmd/helm/require"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli/output"
) )
const dependencyDesc = ` const dependencyDesc = `
@ -99,8 +100,7 @@ func newDependencyCmd(out io.Writer) *cobra.Command {
} }
func newDependencyListCmd(out io.Writer) *cobra.Command { func newDependencyListCmd(out io.Writer) *cobra.Command {
client := action.NewDependency() var outfmt output.Format
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list CHART", Use: "list CHART",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
@ -112,8 +112,11 @@ func newDependencyListCmd(out io.Writer) *cobra.Command {
if len(args) > 0 { if len(args) > 0 {
chartpath = filepath.Clean(args[0]) chartpath = filepath.Clean(args[0])
} }
return client.List(chartpath, out) return outfmt.Write(out, &action.DependencyListWriter{Chartpath: chartpath})
}, },
} }
bindOutputFlag(cmd, &outfmt)
return cmd return cmd
} }

@ -27,6 +27,7 @@ import (
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli/output"
) )
// Dependency is the action for building a given chart's dependency tree. // Dependency is the action for building a given chart's dependency tree.
@ -43,25 +44,66 @@ func NewDependency() *Dependency {
return &Dependency{} return &Dependency{}
} }
// List executes 'helm dependency list'. type dependencyListElement struct {
func (d *Dependency) List(chartpath string, out io.Writer) error { Name string `json:"name"`
c, err := loader.Load(chartpath) Version string `json:"version"`
Repository string `json:"repository"`
Status string `json:"status"`
}
type DependencyListWriter struct {
Chartpath string
}
func (w *DependencyListWriter) WriteTable(out io.Writer) error {
c, err := loader.Load(w.Chartpath)
if err != nil { if err != nil {
return err return err
} }
if c.Metadata.Dependencies == nil { if c.Metadata.Dependencies == nil {
fmt.Fprintf(out, "WARNING: no dependencies at %s\n", filepath.Join(chartpath, "charts")) fmt.Fprintf(out, "WARNING: no dependencies at %s\n", filepath.Join(w.Chartpath, "charts"))
return nil return nil
} }
d.printDependencies(chartpath, out, c) w.printDependenciesTable(w.Chartpath, out, c)
fmt.Fprintln(out) fmt.Fprintln(out)
d.printMissing(chartpath, out, c.Metadata.Dependencies) w.printMissing(w.Chartpath, out, c.Metadata.Dependencies)
return nil
}
func (w *DependencyListWriter) WriteJSON(out io.Writer) error {
return w.encodeByFormat(out, output.JSON)
}
func (w *DependencyListWriter) WriteYAML(out io.Writer) error {
return w.encodeByFormat(out, output.YAML)
}
func (w *DependencyListWriter) encodeByFormat(out io.Writer, format output.Format) error {
c, err := loader.Load(w.Chartpath)
if err != nil {
return err
}
// Initialize the array so no results returns an empty array instead of null
elements := make([]dependencyListElement, 0, len(c.Metadata.Dependencies))
for _, d := range c.Metadata.Dependencies {
elements = append(elements, dependencyListElement{Name: d.Name, Repository: d.Repository, Status: w.dependencyStatus(w.Chartpath, d, c), Version: d.Version})
}
switch format {
case output.JSON:
return output.EncodeJSON(out, elements)
case output.YAML:
return output.EncodeYAML(out, elements)
}
return nil return nil
} }
func (d *Dependency) dependencyStatus(chartpath string, dep *chart.Dependency, parent *chart.Chart) string { func (w *DependencyListWriter) dependencyStatus(chartpath string, dep *chart.Dependency, parent *chart.Chart) string {
filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*") filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*")
// If a chart is unpacked, this will check the unpacked chart's `charts/` directory for tarballs. // If a chart is unpacked, this will check the unpacked chart's `charts/` directory for tarballs.
@ -137,20 +179,20 @@ func (d *Dependency) dependencyStatus(chartpath string, dep *chart.Dependency, p
return "unpacked" return "unpacked"
} }
// printDependencies prints all of the dependencies in the yaml file. // printDependenciesTable prints all of the dependencies in the yaml file.
func (d *Dependency) printDependencies(chartpath string, out io.Writer, c *chart.Chart) { func (w *DependencyListWriter) printDependenciesTable(chartpath string, out io.Writer, c *chart.Chart) {
table := uitable.New() table := uitable.New()
table.MaxColWidth = 80 table.MaxColWidth = 80
table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS") table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS")
for _, row := range c.Metadata.Dependencies { for _, row := range c.Metadata.Dependencies {
table.AddRow(row.Name, row.Version, row.Repository, d.dependencyStatus(chartpath, row, c)) table.AddRow(row.Name, row.Version, row.Repository, w.dependencyStatus(chartpath, row, c))
} }
fmt.Fprintln(out, table) fmt.Fprintln(out, table)
} }
// printMissing prints warnings about charts that are present on disk, but are // printMissing prints warnings about charts that are present on disk, but are
// not in Charts.yaml. // not in Charts.yaml.
func (d *Dependency) printMissing(chartpath string, out io.Writer, reqs []*chart.Dependency) { func (w *DependencyListWriter) printMissing(chartpath string, out io.Writer, reqs []*chart.Dependency) {
folder := filepath.Join(chartpath, "charts/*") folder := filepath.Join(chartpath, "charts/*")
files, err := filepath.Glob(folder) files, err := filepath.Glob(folder)
if err != nil { if err != nil {
@ -161,7 +203,7 @@ func (d *Dependency) printMissing(chartpath string, out io.Writer, reqs []*chart
for _, f := range files { for _, f := range files {
fi, err := os.Stat(f) fi, err := os.Stat(f)
if err != nil { if err != nil {
fmt.Fprintf(out, "Warning: %s\n", err) fmt.Fprintf(out, "WARNING: %s\n", err)
} }
// Skip anything that is not a directory and not a tgz file. // Skip anything that is not a directory and not a tgz file.
if !fi.IsDir() && filepath.Ext(f) != ".tgz" { if !fi.IsDir() && filepath.Ext(f) != ".tgz" {

@ -21,36 +21,93 @@ import (
"testing" "testing"
"helm.sh/helm/v3/internal/test" "helm.sh/helm/v3/internal/test"
"helm.sh/helm/v3/pkg/cli/output"
) )
func TestList(t *testing.T) { func TestList(t *testing.T) {
for _, tcase := range []struct { for _, tcase := range []struct {
chart string chart string
golden string golden string
outfmt output.Format
}{ }{
{ {
chart: "testdata/charts/chart-with-compressed-dependencies", chart: "testdata/charts/chart-with-compressed-dependencies",
golden: "output/compressed-deps.txt", golden: "output/compressed-deps.txt",
outfmt: output.Table,
}, },
{ {
chart: "testdata/charts/chart-with-compressed-dependencies-2.1.8.tgz", chart: "testdata/charts/chart-with-compressed-dependencies-2.1.8.tgz",
golden: "output/compressed-deps-tgz.txt", golden: "output/compressed-deps-tgz.txt",
outfmt: output.Table,
}, },
{ {
chart: "testdata/charts/chart-with-uncompressed-dependencies", chart: "testdata/charts/chart-with-uncompressed-dependencies",
golden: "output/uncompressed-deps.txt", golden: "output/uncompressed-deps.txt",
outfmt: output.Table,
}, },
{ {
chart: "testdata/charts/chart-with-uncompressed-dependencies-2.1.8.tgz", chart: "testdata/charts/chart-with-uncompressed-dependencies-2.1.8.tgz",
golden: "output/uncompressed-deps-tgz.txt", golden: "output/uncompressed-deps-tgz.txt",
outfmt: output.Table,
}, },
{ {
chart: "testdata/charts/chart-missing-deps", chart: "testdata/charts/chart-missing-deps",
golden: "output/missing-deps.txt", golden: "output/missing-deps.txt",
outfmt: output.Table,
},
{
chart: "testdata/charts/chart-with-compressed-dependencies",
golden: "output/compressed-deps.json",
outfmt: output.JSON,
},
{
chart: "testdata/charts/chart-with-compressed-dependencies-2.1.8.tgz",
golden: "output/compressed-deps-tgz.json",
outfmt: output.JSON,
},
{
chart: "testdata/charts/chart-with-uncompressed-dependencies",
golden: "output/uncompressed-deps.json",
outfmt: output.JSON,
},
{
chart: "testdata/charts/chart-with-uncompressed-dependencies-2.1.8.tgz",
golden: "output/uncompressed-deps-tgz.json",
outfmt: output.JSON,
},
{
chart: "testdata/charts/chart-missing-deps",
golden: "output/missing-deps.json",
outfmt: output.JSON,
},
{
chart: "testdata/charts/chart-with-compressed-dependencies",
golden: "output/compressed-deps.yaml",
outfmt: output.YAML,
},
{
chart: "testdata/charts/chart-with-compressed-dependencies-2.1.8.tgz",
golden: "output/compressed-deps-tgz.yaml",
outfmt: output.YAML,
},
{
chart: "testdata/charts/chart-with-uncompressed-dependencies",
golden: "output/uncompressed-deps.yaml",
outfmt: output.YAML,
},
{
chart: "testdata/charts/chart-with-uncompressed-dependencies-2.1.8.tgz",
golden: "output/uncompressed-deps-tgz.yaml",
outfmt: output.YAML,
},
{
chart: "testdata/charts/chart-missing-deps",
golden: "output/missing-deps.yaml",
outfmt: output.YAML,
}, },
} { } {
buf := bytes.Buffer{} buf := bytes.Buffer{}
if err := NewDependency().List(tcase.chart, &buf); err != nil { if err := tcase.outfmt.Write(&buf, &DependencyListWriter{Chartpath: tcase.chart}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
test.AssertGoldenBytes(t, buf.Bytes(), tcase.golden) test.AssertGoldenBytes(t, buf.Bytes(), tcase.golden)

@ -0,0 +1 @@
[{"name":"mariadb","version":"4.x.x","repository":"https://kubernetes-charts.storage.googleapis.com/","status":"unpacked"}]

@ -0,0 +1,4 @@
- name: mariadb
repository: https://kubernetes-charts.storage.googleapis.com/
status: unpacked
version: 4.x.x

@ -0,0 +1 @@
[{"name":"mariadb","version":"4.x.x","repository":"https://kubernetes-charts.storage.googleapis.com/","status":"ok"}]

@ -0,0 +1,4 @@
- name: mariadb
repository: https://kubernetes-charts.storage.googleapis.com/
status: ok
version: 4.x.x

@ -0,0 +1 @@
[{"name":"mariadb","version":"4.x.x","repository":"https://kubernetes-charts.storage.googleapis.com/","status":"missing"}]

@ -0,0 +1,4 @@
- name: mariadb
repository: https://kubernetes-charts.storage.googleapis.com/
status: missing
version: 4.x.x

@ -0,0 +1 @@
[{"name":"mariadb","version":"4.x.x","repository":"https://kubernetes-charts.storage.googleapis.com/","status":"unpacked"}]

@ -0,0 +1,4 @@
- name: mariadb
repository: https://kubernetes-charts.storage.googleapis.com/
status: unpacked
version: 4.x.x

@ -0,0 +1 @@
[{"name":"mariadb","version":"4.x.x","repository":"https://kubernetes-charts.storage.googleapis.com/","status":"unpacked"}]

@ -0,0 +1,4 @@
- name: mariadb
repository: https://kubernetes-charts.storage.googleapis.com/
status: unpacked
version: 4.x.x
Loading…
Cancel
Save