diff --git a/internal/core/printer.go b/internal/core/printer.go index 59c851749c..6c4097e64c 100644 --- a/internal/core/printer.go +++ b/internal/core/printer.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/scaleway/scaleway-cli/internal/human" + "gopkg.in/yaml.v2" ) // Type defines an formatter format. @@ -21,6 +22,9 @@ const ( // PrinterTypeJSON defines a JSON formatter. PrinterTypeJSON = PrinterType("json") + // PrinterTypeYAML defines a YAML formatter. + PrinterTypeYAML = PrinterType("yaml") + // PrinterTypeHuman defines a human readable formatted formatter. PrinterTypeHuman = PrinterType("human") @@ -58,7 +62,8 @@ func NewPrinter(config *PrinterConfig) (*Printer, error) { if err != nil { return nil, err } - + case PrinterTypeYAML.String(): + printer.printerType = PrinterTypeYAML default: return nil, fmt.Errorf("invalid output format: %s", printerName) } @@ -110,6 +115,8 @@ func (p *Printer) Print(data interface{}, opt *human.MarshalOpt) error { err = p.printHuman(data, opt) case PrinterTypeJSON: err = p.printJSON(data) + case PrinterTypeYAML: + err = p.printYAML(data) default: err = fmt.Errorf("unknown format: %s", p.printerType) } @@ -199,3 +206,22 @@ func (p *Printer) printJSON(data interface{}) error { return encoder.Encode(data) } + +func (p *Printer) printYAML(data interface{}) error { + _, implementMarshaler := data.(yaml.Marshaler) + err, isError := data.(error) + + if isError && !implementMarshaler { + data = map[string]string{ + "error": err.Error(), + } + } + + writer := p.stdout + if isError { + writer = p.stderr + } + encoder := yaml.NewEncoder(writer) + + return encoder.Encode(data) +} diff --git a/internal/core/printer_test.go b/internal/core/printer_test.go index 495195a547..cc22cb8783 100644 --- a/internal/core/printer_test.go +++ b/internal/core/printer_test.go @@ -65,3 +65,76 @@ func Test_CorePrinter(t *testing.T) { Check: TestCheckGolden(), })) } + +func Test_YamlPrinter(t *testing.T) { + type Human struct { + ID string `json:"id"` + Name string `json:"name"` + } + + commands := NewCommands( + &Command{ + Namespace: "get", + ArgsType: reflect.TypeOf(struct{}{}), + Run: func(ctx context.Context, argsI interface{}) (interface{}, error) { + return Human{ + ID: "111111111-111111111", + Name: "David Copperfield", + }, nil + }, + }, + &Command{ + Namespace: "list", + ArgsType: reflect.TypeOf(struct{}{}), + Run: func(ctx context.Context, argsI interface{}) (interface{}, error) { + return []*Human{ + {ID: "111111111-111111111", Name: "David Copperfield"}, + {ID: "222222222-222222222", Name: "Xavier Niel"}, + }, nil + }, + }, + &Command{ + Namespace: "NilSlice", + ArgsType: reflect.TypeOf(struct{}{}), + Run: func(ctx context.Context, argsI interface{}) (interface{}, error) { + return []Human{}, nil + }, + }, + ) + + t.Run("human-simple-without-option", Test(&TestConfig{ + Commands: commands, + Cmd: "scw get -o yaml", + Check: TestCheckGolden(), + })) + + t.Run("human-simple-with-options", Test(&TestConfig{ + Commands: commands, + Cmd: "scw get -o yaml=ID,Name", + Check: TestCheckGolden(), + })) + + t.Run("human-list-without-option", Test(&TestConfig{ + Commands: commands, + Cmd: "scw list -o yaml", + Check: TestCheckGolden(), + })) + + t.Run("human-list-with-options", Test(&TestConfig{ + Commands: commands, + Cmd: "scw list -o yaml=Name,ID", + Check: TestCheckGolden(), + })) + + t.Run("human-list-with-options-unknown-column", Test(&TestConfig{ + Commands: commands, + Cmd: "scw -D list -o yaml=Name,ID,Unknown", + Check: TestCheckGolden(), + })) + + t.Run("nil-slice", Test(&TestConfig{ + Commands: commands, + Cmd: "scw NilSlice -o yaml", + Check: TestCheckGolden(), + })) +} diff --git a/internal/core/testdata/test-yaml-printer-human-list-with-options-unknown-column.golden b/internal/core/testdata/test-yaml-printer-human-list-with-options-unknown-column.golden new file mode 100644 index 0000000000..30a099ebef --- /dev/null +++ b/internal/core/testdata/test-yaml-printer-human-list-with-options-unknown-column.golden @@ -0,0 +1,17 @@ +🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲 +🟩🟩🟩 STDOUT️ 🟩🟩🟩️ +- id: 111111111-111111111 + name: David Copperfield +- id: 222222222-222222222 + name: Xavier Niel +🟩🟩🟩 JSON STDOUT 🟩🟩🟩 +[ + { + "id": "111111111-111111111", + "name": "David Copperfield" + }, + { + "id": "222222222-222222222", + "name": "Xavier Niel" + } +] diff --git a/internal/core/testdata/test-yaml-printer-human-list-with-options.golden b/internal/core/testdata/test-yaml-printer-human-list-with-options.golden new file mode 100644 index 0000000000..30a099ebef --- /dev/null +++ b/internal/core/testdata/test-yaml-printer-human-list-with-options.golden @@ -0,0 +1,17 @@ +🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲 +🟩🟩🟩 STDOUT️ 🟩🟩🟩️ +- id: 111111111-111111111 + name: David Copperfield +- id: 222222222-222222222 + name: Xavier Niel +🟩🟩🟩 JSON STDOUT 🟩🟩🟩 +[ + { + "id": "111111111-111111111", + "name": "David Copperfield" + }, + { + "id": "222222222-222222222", + "name": "Xavier Niel" + } +] diff --git a/internal/core/testdata/test-yaml-printer-human-list-without-option.golden b/internal/core/testdata/test-yaml-printer-human-list-without-option.golden new file mode 100644 index 0000000000..30a099ebef --- /dev/null +++ b/internal/core/testdata/test-yaml-printer-human-list-without-option.golden @@ -0,0 +1,17 @@ +🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲 +🟩🟩🟩 STDOUT️ 🟩🟩🟩️ +- id: 111111111-111111111 + name: David Copperfield +- id: 222222222-222222222 + name: Xavier Niel +🟩🟩🟩 JSON STDOUT 🟩🟩🟩 +[ + { + "id": "111111111-111111111", + "name": "David Copperfield" + }, + { + "id": "222222222-222222222", + "name": "Xavier Niel" + } +] diff --git a/internal/core/testdata/test-yaml-printer-human-simple-with-options.golden b/internal/core/testdata/test-yaml-printer-human-simple-with-options.golden new file mode 100644 index 0000000000..9906883602 --- /dev/null +++ b/internal/core/testdata/test-yaml-printer-human-simple-with-options.golden @@ -0,0 +1,9 @@ +🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲 +🟩🟩🟩 STDOUT️ 🟩🟩🟩️ +id: 111111111-111111111 +name: David Copperfield +🟩🟩🟩 JSON STDOUT 🟩🟩🟩 +{ + "id": "111111111-111111111", + "name": "David Copperfield" +} diff --git a/internal/core/testdata/test-yaml-printer-human-simple-without-option.golden b/internal/core/testdata/test-yaml-printer-human-simple-without-option.golden new file mode 100644 index 0000000000..9906883602 --- /dev/null +++ b/internal/core/testdata/test-yaml-printer-human-simple-without-option.golden @@ -0,0 +1,9 @@ +🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲 +🟩🟩🟩 STDOUT️ 🟩🟩🟩️ +id: 111111111-111111111 +name: David Copperfield +🟩🟩🟩 JSON STDOUT 🟩🟩🟩 +{ + "id": "111111111-111111111", + "name": "David Copperfield" +} diff --git a/internal/core/testdata/test-yaml-printer-nil-slice.golden b/internal/core/testdata/test-yaml-printer-nil-slice.golden new file mode 100644 index 0000000000..9518371a99 --- /dev/null +++ b/internal/core/testdata/test-yaml-printer-nil-slice.golden @@ -0,0 +1,5 @@ +🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲 +🟩🟩🟩 STDOUT️ 🟩🟩🟩️ +[] +🟩🟩🟩 JSON STDOUT 🟩🟩🟩 +[]