Skip to content
16 changes: 8 additions & 8 deletions CONTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ type inputModel struct {
}

// "bar" command constructor
func NewCmd() *cobra.Command {
func NewCmd(p *print.Printer) *cobra.Command {
cmd := &cobra.Command{
Use: "bar",
Short: "Short description of the command (is shown in the help of parent command)",
Expand All @@ -88,13 +88,13 @@ func NewCmd() *cobra.Command {
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(cmd, args)
model, err := parseInput(p, cmd, args)
if err != nil {
return err
}

// Configure API client
apiClient, err := client.ConfigureClient(cmd)
apiClient, err := client.ConfigureClient(p, cmd)
if err != nil {
return err
}
Expand All @@ -106,7 +106,7 @@ func NewCmd() *cobra.Command {
return fmt.Errorf("(...): %w", err)
}

projectLabel, err := projectname.GetProjectName(ctx, cmd)
projectLabel, err := projectname.GetProjectName(ctx, p, cmd)
if err != nil {
projectLabel = model.ProjectId
}
Expand All @@ -116,7 +116,7 @@ func NewCmd() *cobra.Command {
p.Info("(...)", projectLabel)
return nil
}
return outputResult(cmd, model.OutputFormat, instances)
return outputResult(p, cmd, model.OutputFormat, instances)
},
}

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

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

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

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).

Expand Down
28 changes: 22 additions & 6 deletions internal/cmd/argus/instance/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package create

import (
"context"
"encoding/json"
"errors"
"fmt"

Expand Down Expand Up @@ -102,12 +103,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
s.Stop()
}

operationState := "Created"
if model.Async {
operationState = "Triggered creation of"
}
p.Outputf("%s instance for project %q. Instance ID: %s\n", operationState, projectLabel, instanceId)
return nil
return outputResult(p, model, projectLabel, resp)
},
}
configureFlags(cmd)
Expand Down Expand Up @@ -190,3 +186,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient argusClient)
})
return req, nil
}

func outputResult(p *print.Printer, model *inputModel, projectLabel string, resp *argus.CreateInstanceResponse) error {
switch model.OutputFormat {
case print.JSONOutputFormat:
details, err := json.MarshalIndent(resp, "", " ")
if err != nil {
return fmt.Errorf("marshal Argus instance: %w", err)
}
p.Outputln(string(details))

return nil
default:
operationState := "Created"
if model.Async {
operationState = "Triggered creation of"
}
p.Outputf("%s instance for project %q. Instance ID: %s\n", operationState, projectLabel, *resp.InstanceId)
return nil
}
}
109 changes: 71 additions & 38 deletions internal/cmd/config/list/list.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package list

import (
"encoding/json"
"fmt"

"slices"
"sort"
"strconv"
Expand All @@ -10,13 +12,18 @@ import (
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
"github.com/stackitcloud/stackit-cli/internal/pkg/tables"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type inputModel struct {
*globalflags.GlobalFlagModel
}

func NewCmd(p *print.Printer) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Expand All @@ -35,56 +42,82 @@ func NewCmd(p *print.Printer) *cobra.Command {
examples.NewExample(
`List your active configuration`,
"$ stackit config list"),
examples.NewExample(
`List your active configuration in a json format`,
"$ stackit config list --output-format json"),
),
RunE: func(cmd *cobra.Command, args []string) error {
configData := viper.AllSettings()

// Sort the config options by key
configKeys := make([]string, 0, len(configData))
for k := range configData {
configKeys = append(configKeys, k)
}
sort.Strings(configKeys)
model := parseInput(p, cmd)
return outputResult(p, model.OutputFormat, configData)
},
}
return cmd
}

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

// Convert value to string
// (Assuming value is either string or bool)
valueString, ok := value.(string)
if !ok {
valueBool, ok := value.(bool)
if !ok {
continue
}
valueString = strconv.FormatBool(valueBool)
}
return &inputModel{
GlobalFlagModel: globalFlags,
}
}

// Don't show unset values
if valueString == "" {
continue
}
func outputResult(p *print.Printer, outputFormat string, configData map[string]any) error {
switch outputFormat {
case print.JSONOutputFormat:
details, err := json.MarshalIndent(configData, "", " ")
if err != nil {
return fmt.Errorf("marshal config list: %w", err)
}
p.Outputln(string(details))
return nil
default:
// Sort the config options by key
configKeys := make([]string, 0, len(configData))
for k := range configData {
configKeys = append(configKeys, k)
}
sort.Strings(configKeys)

// Don't show unsupported (deprecated or user-inputted) configuration options
// that might be present in the config file
if !slices.Contains(config.ConfigKeys, key) {
table := tables.NewTable()
table.SetHeader("NAME", "VALUE")
for _, key := range configKeys {
value := configData[key]

// Convert value to string
// (Assuming value is either string or bool)
valueString, ok := value.(string)
if !ok {
valueBool, ok := value.(bool)
if !ok {
continue
}
valueString = strconv.FormatBool(valueBool)
}

// Replace "_" with "-" to match the flags
key = strings.ReplaceAll(key, "_", "-")

table.AddRow(key, valueString)
table.AddSeparator()
// Don't show unset values
if valueString == "" {
continue
}
err := table.Display(p)
if err != nil {
return fmt.Errorf("render table: %w", err)

// Don't show unsupported (deprecated or user-inputted) configuration options
// that might be present in the config file
if !slices.Contains(config.ConfigKeys, key) {
continue
}
return nil
},

// Replace "_" with "-" to match the flags
key = strings.ReplaceAll(key, "_", "-")

table.AddRow(key, valueString)
table.AddSeparator()
}
err := table.Display(p)
if err != nil {
return fmt.Errorf("render table: %w", err)
}
return nil
}
return cmd
}
2 changes: 1 addition & 1 deletion internal/cmd/curl/curl.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func outputResponse(p *print.Printer, model *inputModel, resp *http.Response) er
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read respose body: %w", err)
return fmt.Errorf("read response body: %w", err)
}
output = append(output, respBody...)

Expand Down
28 changes: 22 additions & 6 deletions internal/cmd/dns/record-set/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package create

import (
"context"
"encoding/json"
"fmt"

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

operationState := "Created"
if model.Async {
operationState = "Triggered creation of"
}
p.Outputf("%s record set for zone %s. Record set ID: %s\n", operationState, zoneLabel, recordSetId)
return nil
return outputResult(p, model, zoneLabel, resp)
},
}
configureFlags(cmd)
Expand Down Expand Up @@ -157,3 +153,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *dns.APIClie
})
return req
}

func outputResult(p *print.Printer, model *inputModel, zoneLabel string, resp *dns.RecordSetResponse) error {
switch model.OutputFormat {
case print.JSONOutputFormat:
details, err := json.MarshalIndent(resp, "", " ")
if err != nil {
return fmt.Errorf("marshal DNS record-set: %w", err)
}
p.Outputln(string(details))

return nil
default:
operationState := "Created"
if model.Async {
operationState = "Triggered creation of"
}
p.Outputf("%s record set for zone %s. Record set ID: %s\n", operationState, zoneLabel, *resp.Rrset.Id)
return nil
}
}
28 changes: 22 additions & 6 deletions internal/cmd/dns/zone/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package create

import (
"context"
"encoding/json"
"fmt"

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

operationState := "Created"
if model.Async {
operationState = "Triggered creation of"
}
p.Outputf("%s zone for project %q. Zone ID: %s\n", operationState, projectLabel, zoneId)
return nil
return outputResult(p, model, projectLabel, resp)
},
}
configureFlags(cmd)
Expand Down Expand Up @@ -186,3 +182,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *dns.APIClie
})
return req
}

func outputResult(p *print.Printer, model *inputModel, projectLabel string, resp *dns.ZoneResponse) error {
switch model.OutputFormat {
case print.JSONOutputFormat:
details, err := json.MarshalIndent(resp, "", " ")
if err != nil {
return fmt.Errorf("marshal DNS zone: %w", err)
}
p.Outputln(string(details))

return nil
default:
operationState := "Created"
if model.Async {
operationState = "Triggered creation of"
}
p.Outputf("%s zone for project %q. Zone ID: %s\n", operationState, projectLabel, *resp.Zone.Id)
return nil
}
}
Loading