Unverified Commit bb48cd43 authored by bryanl's avatar bryanl
Browse files

Add JSON output to `env list`


Signed-off-by: default avatarbryanl <bryanliles@gmail.com>
parent 3595adb1
......@@ -94,6 +94,13 @@ const (
OptionVersion = "version"
)
const (
// OutputWide is wide output
OutputWide = "wide"
// EnvListOutputJSON is JSON output
EnvListOutputJSON = "json"
)
var (
// ErrNotInApp is an error stating the user is not in a ksonnet application directory
// hierarchy.
......
......@@ -16,12 +16,14 @@
package actions
import (
"encoding/json"
"io"
"os"
"sort"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/pkg/util/table"
"github.com/pkg/errors"
)
// RunEnvList runs `env list`
......@@ -36,16 +38,18 @@ func RunEnvList(m map[string]interface{}) error {
// EnvList lists available namespaces
type EnvList struct {
app app.App
out io.Writer
app app.App
outputType string
out io.Writer
}
// NewEnvList creates an instance of EnvList
func NewEnvList(m map[string]interface{}) (*EnvList, error) {
ol := newOptionLoader(m)
nl := &EnvList{
app: ol.loadApp(),
el := &EnvList{
app: ol.loadApp(),
outputType: ol.loadOptionalString(OptionOutput),
out: os.Stdout,
}
......@@ -54,17 +58,41 @@ func NewEnvList(m map[string]interface{}) (*EnvList, error) {
return nil, ol.err
}
return nl, nil
if el.outputType == "" {
el.outputType = OutputWide
}
return el, nil
}
// Run runs the env list action.
func (nl *EnvList) Run() error {
environments, err := nl.app.Environments()
func (el *EnvList) Run() error {
switch el.outputType {
default:
return errors.Errorf("unknown output format %q", el.outputType)
case OutputWide:
return el.outputWide()
case EnvListOutputJSON:
return el.outputJSON()
}
}
func (el *EnvList) outputJSON() error {
environments, err := el.app.Environments()
if err != nil {
return err
}
return json.NewEncoder(el.out).Encode(environments)
}
func (el *EnvList) outputWide() error {
environments, err := el.app.Environments()
if err != nil {
return err
}
table := table.New(nl.out)
table := table.New(el.out)
table.SetHeader([]string{"name", "override", "kubernetes-version", "namespace", "server"})
var rows [][]string
......
......@@ -17,10 +17,12 @@ package actions
import (
"bytes"
"path/filepath"
"testing"
"github.com/ksonnet/ksonnet/metadata/app"
amocks "github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/ksonnet/ksonnet/pkg/util/test"
"github.com/stretchr/testify/require"
)
......@@ -39,19 +41,57 @@ func TestEnvList(t *testing.T) {
}
appMock.On("Environments").Return(envs, nil)
in := map[string]interface{}{
OptionApp: appMock,
cases := []struct {
name string
outputType string
expectedFile string
isErr bool
}{
{
name: "no format specified",
expectedFile: filepath.Join("env", "list", "output.txt"),
},
{
name: "wide output",
outputType: OutputWide,
expectedFile: filepath.Join("env", "list", "output.txt"),
},
{
name: "json output",
outputType: EnvListOutputJSON,
expectedFile: filepath.Join("env", "list", "output.json"),
},
{
name: "invalid output format",
outputType: "invalid",
isErr: true,
},
}
a, err := NewEnvList(in)
require.NoError(t, err)
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
in := map[string]interface{}{
OptionApp: appMock,
OptionOutput: tc.outputType,
}
a, err := NewEnvList(in)
require.NoError(t, err)
var buf bytes.Buffer
a.out = &buf
var buf bytes.Buffer
a.out = &buf
err = a.Run()
require.NoError(t, err)
err = a.Run()
if tc.isErr {
require.Error(t, err)
return
}
require.NoError(t, err)
test.AssertOutput(t, tc.expectedFile, buf.String())
})
}
assertOutput(t, "env/list/output.txt", buf.String())
})
}
{"default":{"k8sVersion":"v1.7.0","path":"","destination":{"server":"http://example.com","namespace":"default"}}}
......@@ -50,7 +50,6 @@ func init() {
envCmd.AddCommand(envAddCmd)
envCmd.AddCommand(envRmCmd)
envCmd.AddCommand(envListCmd)
// TODO: We need to make this default to checking the `kubeconfig` file.
envAddCmd.PersistentFlags().String(flagAPISpec, "version:v1.7.0",
......
......@@ -20,6 +20,11 @@ import (
"github.com/ksonnet/ksonnet/actions"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
vEnvListOutput = "env-list-output"
)
var envListCmd = &cobra.Command{
......@@ -31,7 +36,8 @@ var envListCmd = &cobra.Command{
}
m := map[string]interface{}{
actions.OptionApp: ka,
actions.OptionApp: ka,
actions.OptionOutput: viper.GetString(vEnvListOutput),
}
return runAction(actionEnvList, m)
......@@ -49,3 +55,10 @@ current ksonnet app. Specifically, this will display the (1) *name*,
### Syntax
`,
}
func init() {
envCmd.AddCommand(envListCmd)
envListCmd.Flags().StringP(flagOutput, shortOutput, "", "Output format. One of: json|wide")
viper.BindPFlag(vEnvListOutput, envListCmd.Flags().Lookup(flagOutput))
}
......@@ -28,7 +28,17 @@ func Test_envListCmd(t *testing.T) {
args: []string{"env", "list"},
action: actionEnvList,
expected: map[string]interface{}{
actions.OptionApp: ka,
actions.OptionApp: ka,
actions.OptionOutput: "",
},
},
{
name: "with output flag",
args: []string{"env", "list", "-o", "json"},
action: actionEnvList,
expected: map[string]interface{}{
actions.OptionApp: ka,
actions.OptionOutput: "json",
},
},
}
......
......@@ -25,7 +25,8 @@ ks env list [flags]
### Options
```
-h, --help help for list
-h, --help help for list
-o, --output string Output format. One of: json|wide
```
### Options inherited from parent commands
......
......@@ -110,3 +110,12 @@ func WithAppFs(t *testing.T, root string, fs afero.Fs, fn func(*mocks.App, afero
fn(a, fs)
}
// AssertOutput asserts the output matches the actual contents
func AssertOutput(t *testing.T, filename, actual string) {
path := filepath.Join("testdata", filename)
b, err := ioutil.ReadFile(path)
require.NoError(t, err)
require.Equal(t, string(b), actual)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment