New output flag for list command (#1215)

* New output flag for list command

Support output as json
Add new formatters file to handle extrac formatting to its own concern
New config interface to support list command specification

* Fix usage message

* Add error handling for formatters
This commit is contained in:
Rene Hernandez 2020-04-18 08:11:12 -04:00 committed by GitHub
parent 71bb7354e7
commit e0a793b7c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 140 additions and 8 deletions

14
main.go
View File

@ -471,7 +471,13 @@ func main() {
{
Name: "list",
Usage: "list releases defined in state file",
Flags: []cli.Flag{},
Flags: []cli.Flag{
cli.StringFlag{
Name: "output",
Value: "",
Usage: "output releases list as a json string",
},
},
Action: action(func(run *app.App, c configImpl) error {
return run.ListReleases(c)
}),
@ -597,6 +603,12 @@ func (c configImpl) Timeout() int {
return c.c.Int("timeout")
}
// ListConfig
func (c configImpl) Output() string {
return c.c.String("output")
}
// GlobalConfig
func (c configImpl) HelmBinary() string {

View File

@ -14,7 +14,6 @@ import (
"syscall"
"text/tabwriter"
"github.com/gosuri/uitable"
"github.com/roboll/helmfile/pkg/argparser"
"github.com/roboll/helmfile/pkg/helmexec"
"github.com/roboll/helmfile/pkg/remote"
@ -60,6 +59,13 @@ type App struct {
helmsMutex sync.Mutex
}
type HelmRelease struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Enabled bool `json:"enabled"`
Labels string `json:"labels"`
}
func New(conf ConfigProvider) *App {
return Init(&App{
OverrideKubeContext: conf.KubeContext(),
@ -259,9 +265,8 @@ func (a *App) PrintState(c StateConfigProvider) error {
})
}
func (a *App) ListReleases(c StateConfigProvider) error {
table := uitable.New()
table.AddRow("NAME", "NAMESPACE", "ENABLED", "LABELS")
func (a *App) ListReleases(c ListConfigProvider) error {
var releases []*HelmRelease
err := a.VisitDesiredStatesWithReleasesFiltered(a.FileOrDir, func(st *state.HelmState) []error {
//var releases m
@ -270,12 +275,28 @@ func (a *App) ListReleases(c StateConfigProvider) error {
for k, v := range r.Labels {
labels = fmt.Sprintf("%s,%s:%s", labels, k, v)
}
labels = strings.Trim(labels, ",")
installed := r.Installed == nil || *r.Installed
table.AddRow(r.Name, r.Namespace, fmt.Sprintf("%t", installed), strings.Trim(labels, ","))
releases = append(releases, &HelmRelease{
Name: r.Name,
Namespace: r.Namespace,
Enabled: installed,
Labels: labels,
})
}
return []error{}
})
fmt.Println(table.String())
if err != nil {
return err
}
if c.Output() == "json" {
err = FormatAsJson(releases)
} else {
err = FormatAsTable(releases)
}
return err
}

View File

@ -1962,7 +1962,8 @@ services:
}
type configImpl struct {
set []string
set []string
output string
}
func (c configImpl) Set() []string {
@ -1993,6 +1994,10 @@ func (c configImpl) Concurrency() int {
return 1
}
func (c configImpl) Output() string {
return c.output
}
type applyConfig struct {
args string
values []string
@ -3849,6 +3854,63 @@ myrelease4 true id:myrelease1
assert.Equal(t, expected, out)
}
func TestListWithJsonOutput(t *testing.T) {
files := map[string]string{
"/path/to/helmfile.d/first.yaml": `
releases:
- name: myrelease1
chart: mychart1
installed: no
labels:
id: myrelease1
- name: myrelease2
chart: mychart1
`,
"/path/to/helmfile.d/second.yaml": `
releases:
- name: myrelease3
chart: mychart1
installed: yes
- name: myrelease4
chart: mychart1
labels:
id: myrelease1
`,
}
stdout := os.Stdout
defer func() { os.Stdout = stdout }()
var buffer bytes.Buffer
logger := helmexec.NewLogger(&buffer, "debug")
app := appWithFs(&App{
OverrideHelmBinary: DefaultHelmBinary,
glob: filepath.Glob,
abs: filepath.Abs,
OverrideKubeContext: "default",
Env: "default",
Logger: logger,
Namespace: "testNamespace",
}, files)
expectNoCallsToHelm(app)
out := captureStdout(func() {
err := app.ListReleases(configImpl{
output: "json",
})
assert.NilError(t, err)
})
expected := "[" +
"{\"name\":\"myrelease1\",\"namespace\":\"\",\"enabled\":false,\"labels\":\"id:myrelease1\"}," +
"{\"name\":\"myrelease2\",\"namespace\":\"\",\"enabled\":true,\"labels\":\"\"}," +
"{\"name\":\"myrelease3\",\"namespace\":\"\",\"enabled\":true,\"labels\":\"\"}," +
"{\"name\":\"myrelease4\",\"namespace\":\"\",\"enabled\":true,\"labels\":\"id:myrelease1\"}" +
"]\n"
assert.Equal(t, expected, out)
}
func TestSetValuesTemplate(t *testing.T) {
files := map[string]string{
"/path/to/helmfile.yaml": `

View File

@ -156,3 +156,7 @@ type loggingConfig interface {
type interactive interface {
Interactive() bool
}
type ListConfigProvider interface {
Output() string
}

33
pkg/app/formatters.go Normal file
View File

@ -0,0 +1,33 @@
package app
import (
"encoding/json"
"fmt"
"github.com/gosuri/uitable"
)
func FormatAsTable(releases []*HelmRelease) error {
table := uitable.New()
table.AddRow("NAME", "NAMESPACE", "ENABLED", "LABELS")
for _, r := range releases {
table.AddRow(r.Name, r.Namespace, fmt.Sprintf("%t", r.Enabled), r.Labels)
}
fmt.Println(table.String())
return nil
}
func FormatAsJson(releases []*HelmRelease) error {
output, err := json.Marshal(releases)
if err != nil {
return fmt.Errorf("error generating json: %v", err)
}
fmt.Println(string(output))
return nil
}