Skip to content

Commit a7bb83e

Browse files
Add json output format (#238)
* fix typo in error message * remove unused flag * add json output format for the responses * fix linting * adapt some parameters in Contribution file * change globalflags to print to use json format * Update internal/cmd/opensearch/credentials/create/create.go Co-authored-by: Vicente Pinto <[email protected]> * remove redundant error from return values of config list * shift switch case in the outputResult function --------- Co-authored-by: Vicente Pinto <[email protected]>
1 parent 9fcbc2d commit a7bb83e

File tree

37 files changed

+842
-286
lines changed

37 files changed

+842
-286
lines changed

CONTRIBUTION.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ type inputModel struct {
7474
}
7575

7676
// "bar" command constructor
77-
func NewCmd() *cobra.Command {
77+
func NewCmd(p *print.Printer) *cobra.Command {
7878
cmd := &cobra.Command{
7979
Use: "bar",
8080
Short: "Short description of the command (is shown in the help of parent command)",
@@ -88,13 +88,13 @@ func NewCmd() *cobra.Command {
8888
),
8989
RunE: func(cmd *cobra.Command, args []string) error {
9090
ctx := context.Background()
91-
model, err := parseInput(cmd, args)
91+
model, err := parseInput(p, cmd, args)
9292
if err != nil {
9393
return err
9494
}
9595

9696
// Configure API client
97-
apiClient, err := client.ConfigureClient(cmd)
97+
apiClient, err := client.ConfigureClient(p, cmd)
9898
if err != nil {
9999
return err
100100
}
@@ -106,7 +106,7 @@ func NewCmd() *cobra.Command {
106106
return fmt.Errorf("(...): %w", err)
107107
}
108108

109-
projectLabel, err := projectname.GetProjectName(ctx, cmd)
109+
projectLabel, err := projectname.GetProjectName(ctx, p, cmd)
110110
if err != nil {
111111
projectLabel = model.ProjectId
112112
}
@@ -116,7 +116,7 @@ func NewCmd() *cobra.Command {
116116
p.Info("(...)", projectLabel)
117117
return nil
118118
}
119-
return outputResult(cmd, model.OutputFormat, instances)
119+
return outputResult(p, cmd, model.OutputFormat, instances)
120120
},
121121
}
122122

@@ -152,9 +152,9 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *foo.APIClie
152152
}
153153

154154
// Output result based on the configured output format
155-
func outputResult(cmd *cobra.Command, outputFormat string, resources []foo.Resource) error {
155+
func outputResult(p *print.Printer, cmd *cobra.Command, outputFormat string, resources []foo.Resource) error {
156156
switch outputFormat {
157-
case globalflags.JSONOutputFormat:
157+
case print.JSONOutputFormat:
158158
details, err := json.MarshalIndent(resources, "", " ")
159159
if err != nil {
160160
return fmt.Errorf("marshal resource list: %w", err)
@@ -177,7 +177,7 @@ func outputResult(cmd *cobra.Command, outputFormat string, resources []foo.Resou
177177
}
178178
```
179179

180-
Please remeber to always add unit tests for `parseInput`, `buildRequest` (in `bar_test.go`), and any other util functions used.
180+
Please remember to always add unit tests for `parseInput`, `buildRequest` (in `bar_test.go`), and any other util functions used.
181181

182182
If the new command `bar` is the first command in the CLI using a STACKIT service `foo`, please refer to [Onboarding a new STACKIT service](./CONTRIBUTION.md/#onboarding-a-new-stackit-service).
183183

internal/cmd/argus/instance/create/create.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package create
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
67
"fmt"
78

@@ -102,12 +103,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
102103
s.Stop()
103104
}
104105

105-
operationState := "Created"
106-
if model.Async {
107-
operationState = "Triggered creation of"
108-
}
109-
p.Outputf("%s instance for project %q. Instance ID: %s\n", operationState, projectLabel, instanceId)
110-
return nil
106+
return outputResult(p, model, projectLabel, resp)
111107
},
112108
}
113109
configureFlags(cmd)
@@ -190,3 +186,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient argusClient)
190186
})
191187
return req, nil
192188
}
189+
190+
func outputResult(p *print.Printer, model *inputModel, projectLabel string, resp *argus.CreateInstanceResponse) error {
191+
switch model.OutputFormat {
192+
case print.JSONOutputFormat:
193+
details, err := json.MarshalIndent(resp, "", " ")
194+
if err != nil {
195+
return fmt.Errorf("marshal Argus instance: %w", err)
196+
}
197+
p.Outputln(string(details))
198+
199+
return nil
200+
default:
201+
operationState := "Created"
202+
if model.Async {
203+
operationState = "Triggered creation of"
204+
}
205+
p.Outputf("%s instance for project %q. Instance ID: %s\n", operationState, projectLabel, *resp.InstanceId)
206+
return nil
207+
}
208+
}

internal/cmd/config/list/list.go

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package list
22

33
import (
4+
"encoding/json"
45
"fmt"
6+
57
"slices"
68
"sort"
79
"strconv"
@@ -10,13 +12,18 @@ import (
1012
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
1113
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
1214
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
15+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
1316
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
1417
"github.com/stackitcloud/stackit-cli/internal/pkg/tables"
1518

1619
"github.com/spf13/cobra"
1720
"github.com/spf13/viper"
1821
)
1922

23+
type inputModel struct {
24+
*globalflags.GlobalFlagModel
25+
}
26+
2027
func NewCmd(p *print.Printer) *cobra.Command {
2128
cmd := &cobra.Command{
2229
Use: "list",
@@ -35,56 +42,82 @@ func NewCmd(p *print.Printer) *cobra.Command {
3542
examples.NewExample(
3643
`List your active configuration`,
3744
"$ stackit config list"),
45+
examples.NewExample(
46+
`List your active configuration in a json format`,
47+
"$ stackit config list --output-format json"),
3848
),
3949
RunE: func(cmd *cobra.Command, args []string) error {
4050
configData := viper.AllSettings()
4151

42-
// Sort the config options by key
43-
configKeys := make([]string, 0, len(configData))
44-
for k := range configData {
45-
configKeys = append(configKeys, k)
46-
}
47-
sort.Strings(configKeys)
52+
model := parseInput(p, cmd)
53+
return outputResult(p, model.OutputFormat, configData)
54+
},
55+
}
56+
return cmd
57+
}
4858

49-
table := tables.NewTable()
50-
table.SetHeader("NAME", "VALUE")
51-
for _, key := range configKeys {
52-
value := configData[key]
59+
func parseInput(p *print.Printer, cmd *cobra.Command) *inputModel {
60+
globalFlags := globalflags.Parse(p, cmd)
5361

54-
// Convert value to string
55-
// (Assuming value is either string or bool)
56-
valueString, ok := value.(string)
57-
if !ok {
58-
valueBool, ok := value.(bool)
59-
if !ok {
60-
continue
61-
}
62-
valueString = strconv.FormatBool(valueBool)
63-
}
62+
return &inputModel{
63+
GlobalFlagModel: globalFlags,
64+
}
65+
}
6466

65-
// Don't show unset values
66-
if valueString == "" {
67-
continue
68-
}
67+
func outputResult(p *print.Printer, outputFormat string, configData map[string]any) error {
68+
switch outputFormat {
69+
case print.JSONOutputFormat:
70+
details, err := json.MarshalIndent(configData, "", " ")
71+
if err != nil {
72+
return fmt.Errorf("marshal config list: %w", err)
73+
}
74+
p.Outputln(string(details))
75+
return nil
76+
default:
77+
// Sort the config options by key
78+
configKeys := make([]string, 0, len(configData))
79+
for k := range configData {
80+
configKeys = append(configKeys, k)
81+
}
82+
sort.Strings(configKeys)
6983

70-
// Don't show unsupported (deprecated or user-inputted) configuration options
71-
// that might be present in the config file
72-
if !slices.Contains(config.ConfigKeys, key) {
84+
table := tables.NewTable()
85+
table.SetHeader("NAME", "VALUE")
86+
for _, key := range configKeys {
87+
value := configData[key]
88+
89+
// Convert value to string
90+
// (Assuming value is either string or bool)
91+
valueString, ok := value.(string)
92+
if !ok {
93+
valueBool, ok := value.(bool)
94+
if !ok {
7395
continue
7496
}
97+
valueString = strconv.FormatBool(valueBool)
98+
}
7599

76-
// Replace "_" with "-" to match the flags
77-
key = strings.ReplaceAll(key, "_", "-")
78-
79-
table.AddRow(key, valueString)
80-
table.AddSeparator()
100+
// Don't show unset values
101+
if valueString == "" {
102+
continue
81103
}
82-
err := table.Display(p)
83-
if err != nil {
84-
return fmt.Errorf("render table: %w", err)
104+
105+
// Don't show unsupported (deprecated or user-inputted) configuration options
106+
// that might be present in the config file
107+
if !slices.Contains(config.ConfigKeys, key) {
108+
continue
85109
}
86-
return nil
87-
},
110+
111+
// Replace "_" with "-" to match the flags
112+
key = strings.ReplaceAll(key, "_", "-")
113+
114+
table.AddRow(key, valueString)
115+
table.AddSeparator()
116+
}
117+
err := table.Display(p)
118+
if err != nil {
119+
return fmt.Errorf("render table: %w", err)
120+
}
121+
return nil
88122
}
89-
return cmd
90123
}

internal/cmd/curl/curl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func outputResponse(p *print.Printer, model *inputModel, resp *http.Response) er
212212
}
213213
respBody, err := io.ReadAll(resp.Body)
214214
if err != nil {
215-
return fmt.Errorf("read respose body: %w", err)
215+
return fmt.Errorf("read response body: %w", err)
216216
}
217217
output = append(output, respBody...)
218218

internal/cmd/dns/record-set/create/create.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package create
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67

78
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
@@ -98,12 +99,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
9899
s.Stop()
99100
}
100101

101-
operationState := "Created"
102-
if model.Async {
103-
operationState = "Triggered creation of"
104-
}
105-
p.Outputf("%s record set for zone %s. Record set ID: %s\n", operationState, zoneLabel, recordSetId)
106-
return nil
102+
return outputResult(p, model, zoneLabel, resp)
107103
},
108104
}
109105
configureFlags(cmd)
@@ -157,3 +153,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *dns.APIClie
157153
})
158154
return req
159155
}
156+
157+
func outputResult(p *print.Printer, model *inputModel, zoneLabel string, resp *dns.RecordSetResponse) error {
158+
switch model.OutputFormat {
159+
case print.JSONOutputFormat:
160+
details, err := json.MarshalIndent(resp, "", " ")
161+
if err != nil {
162+
return fmt.Errorf("marshal DNS record-set: %w", err)
163+
}
164+
p.Outputln(string(details))
165+
166+
return nil
167+
default:
168+
operationState := "Created"
169+
if model.Async {
170+
operationState = "Triggered creation of"
171+
}
172+
p.Outputf("%s record set for zone %s. Record set ID: %s\n", operationState, zoneLabel, *resp.Rrset.Id)
173+
return nil
174+
}
175+
}

internal/cmd/dns/zone/create/create.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package create
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67

78
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
@@ -112,12 +113,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
112113
s.Stop()
113114
}
114115

115-
operationState := "Created"
116-
if model.Async {
117-
operationState = "Triggered creation of"
118-
}
119-
p.Outputf("%s zone for project %q. Zone ID: %s\n", operationState, projectLabel, zoneId)
120-
return nil
116+
return outputResult(p, model, projectLabel, resp)
121117
},
122118
}
123119
configureFlags(cmd)
@@ -186,3 +182,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *dns.APIClie
186182
})
187183
return req
188184
}
185+
186+
func outputResult(p *print.Printer, model *inputModel, projectLabel string, resp *dns.ZoneResponse) error {
187+
switch model.OutputFormat {
188+
case print.JSONOutputFormat:
189+
details, err := json.MarshalIndent(resp, "", " ")
190+
if err != nil {
191+
return fmt.Errorf("marshal DNS zone: %w", err)
192+
}
193+
p.Outputln(string(details))
194+
195+
return nil
196+
default:
197+
operationState := "Created"
198+
if model.Async {
199+
operationState = "Triggered creation of"
200+
}
201+
p.Outputf("%s zone for project %q. Zone ID: %s\n", operationState, projectLabel, *resp.Zone.Id)
202+
return nil
203+
}
204+
}

0 commit comments

Comments
 (0)