diff --git a/docs/reference/manual/hcloud_context_list.md b/docs/reference/manual/hcloud_context_list.md index 431eb2ae4..801143b19 100644 --- a/docs/reference/manual/hcloud_context_list.md +++ b/docs/reference/manual/hcloud_context_list.md @@ -22,7 +22,7 @@ hcloud context list [options] ``` -h, --help help for list - -o, --output stringArray output options: noheader|columns=... + -o, --output stringArray output options: noheader|columns=...|json|yaml ``` ### Options inherited from parent commands diff --git a/internal/cmd/context/list.go b/internal/cmd/context/list.go index b11bed312..118fef846 100644 --- a/internal/cmd/context/list.go +++ b/internal/cmd/context/list.go @@ -8,6 +8,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" ) type presentation struct { @@ -16,6 +17,13 @@ type presentation struct { Active string } +type schemaPresentation struct { + Name string `json:"name"` + Token string `json:"token"` + Active bool `json:"active"` + Preferences map[string]any `json:"preferences,omitempty"` +} + func NewListCommand(s state.State) *cobra.Command { cols := newListOutputTable(io.Discard).Columns() cmd := &cobra.Command{ @@ -30,11 +38,12 @@ func NewListCommand(s state.State) *cobra.Command { DisableFlagsInUseLine: true, RunE: state.Wrap(s, runList), } - output.AddFlag(cmd, output.OptionNoHeader(), output.OptionColumns(cols)) + output.AddFlag(cmd, output.OptionNoHeader(), output.OptionColumns(cols), output.OptionJSON(), output.OptionYAML()) return cmd } func runList(s state.State, cmd *cobra.Command, _ []string) error { + cfg := s.Config() outOpts := output.FlagsForCommand(cmd) cols := []string{"active", "name"} @@ -42,7 +51,36 @@ func runList(s state.State, cmd *cobra.Command, _ []string) error { cols = outOpts["columns"] } - tw := newListOutputTable(cmd.OutOrStdout()) + quiet, err := config.OptionQuiet.Get(s.Config()) + if err != nil { + return err + } + + out := cmd.OutOrStdout() + if quiet { + // If we are in quiet mode, we saved the original output in cmd.errWriter. We can now restore it. + out = cmd.ErrOrStderr() + } + + isSchema := outOpts.IsSet("json") || outOpts.IsSet("yaml") + if isSchema { + contexts, activeCtx := cfg.Contexts(), cfg.ActiveContext() + schema := make([]schemaPresentation, 0, len(contexts)) + for _, ctx := range contexts { + schema = append(schema, schemaPresentation{ + Name: ctx.Name(), + Token: ctx.Token(), + Active: ctx == activeCtx, + Preferences: ctx.Preferences(), + }) + } + if outOpts.IsSet("json") { + return util.DescribeJSON(out, schema) + } + return util.DescribeYAML(out, schema) + } + + tw := newListOutputTable(out) warnings, err := tw.ValidateColumns(cols) if err != nil { return err @@ -54,7 +92,6 @@ func runList(s state.State, cmd *cobra.Command, _ []string) error { if !outOpts.IsSet("noheader") { tw.WriteHeader(cols) } - cfg := s.Config() for _, context := range cfg.Contexts() { presentation := presentation{ Name: context.Name(), diff --git a/internal/cmd/context/list_test.go b/internal/cmd/context/list_test.go index 02477ae7d..63e2fd573 100644 --- a/internal/cmd/context/list_test.go +++ b/internal/cmd/context/list_test.go @@ -87,6 +87,29 @@ my-third-context my-context * my-other-context my-third-context +`, + }, + { + name: "json", + args: []string{"-o=json"}, + config: testConfig, + expOut: `[ + { + "name": "my-context", + "token": "super secret token", + "active": true + }, + { + "name": "my-other-context", + "token": "another super secret token", + "active": false + }, + { + "name": "my-third-context", + "token": "yet another super secret token", + "active": false + } +] `, }, }