Skip to content

Commit 676fbf4

Browse files
committed
feature: apply review findings
1 parent dc9cf2f commit 676fbf4

File tree

9 files changed

+209
-295
lines changed

9 files changed

+209
-295
lines changed

internal/cmd/beta/security-group/create/create.go

Lines changed: 58 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ import (
1818
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
1919
)
2020

21+
const (
22+
nameFlag = "name"
23+
descriptionFlag = "description"
24+
statefulFlag = "stateful"
25+
labelsFlag = "labels"
26+
)
27+
2128
type inputModel struct {
2229
*globalflags.GlobalFlagModel
23-
Labels map[string]any
30+
Labels *map[string]any
2431
Description string
2532
Name string
2633
Stateful bool
@@ -29,114 +36,95 @@ type inputModel struct {
2936
func NewCmd(p *print.Printer) *cobra.Command {
3037
cmd := &cobra.Command{
3138
Use: "create",
32-
Short: "create security groups",
33-
Long: "create security groups",
39+
Short: "Create security groups",
40+
Long: "Create security groups.",
3441
Args: args.NoArgs,
3542
Example: examples.Build(
3643
examples.NewExample(`create a named group`, `$ stackit beta security-group create --name my-new-group`),
3744
examples.NewExample(`create a named group with labels`, `$ stackit beta security-group create --name my-new-group --labels label1=value1,label2=value2`),
3845
),
3946
RunE: func(cmd *cobra.Command, args []string) error {
40-
return executeCreate(cmd, p, args)
41-
},
42-
}
47+
ctx := context.Background()
48+
model, err := parseInput(p, cmd)
49+
if err != nil {
50+
return err
51+
}
4352

44-
configureFlags(cmd)
45-
return cmd
46-
}
53+
// Configure API client
54+
apiClient, err := client.ConfigureClient(p)
55+
if err != nil {
56+
return err
57+
}
4758

48-
func configureFlags(cmd *cobra.Command) {
49-
cmd.Flags().String("name", "", "the name of the security group. Must be <= 63 chars")
50-
cmd.Flags().String("description", "", "an optional description of the security group. Must be <= 127 chars")
51-
cmd.Flags().Bool("stateful", false, "create a stateful or a stateless security group")
52-
cmd.Flags().StringSlice("labels", nil, "a list of labels in the form <key>=<value>")
59+
if !model.AssumeYes {
60+
prompt := fmt.Sprintf("Are you sure you want to create the security group %q?", model.Name)
61+
err = p.PromptForConfirmation(prompt)
62+
if err != nil {
63+
return err
64+
}
65+
}
5366

54-
if err := flags.MarkFlagsRequired(cmd, "name"); err != nil {
55-
cobra.CheckErr(err)
56-
}
57-
}
67+
// Call API
68+
request := buildRequest(ctx, model, apiClient)
5869

59-
func executeCreate(cmd *cobra.Command, p *print.Printer, _ []string) error {
60-
p.Info("executing create command")
61-
ctx := context.Background()
62-
model, err := parseInput(p, cmd)
63-
if err != nil {
64-
return err
65-
}
70+
operationState := "Created"
71+
p.Info("%s security group %q for %q\n", operationState, model.Name, model.ProjectId)
6672

67-
// Configure API client
68-
apiClient, err := client.ConfigureClient(p)
69-
if err != nil {
70-
return err
71-
}
73+
group, err := request.Execute()
74+
if err != nil {
75+
return fmt.Errorf("create security group: %w", err)
76+
}
77+
if err := outputResult(p, model, group); err != nil {
78+
return err
79+
}
7280

73-
if !model.AssumeYes {
74-
prompt := fmt.Sprintf("Are you sure you want to create the security group %q?", model.Name)
75-
err = p.PromptForConfirmation(prompt)
76-
if err != nil {
77-
return err
78-
}
81+
return nil
82+
},
7983
}
8084

81-
// Call API
82-
request := buildRequest(ctx, model, apiClient)
85+
configureFlags(cmd)
86+
return cmd
87+
}
8388

84-
operationState := "Enabled"
85-
if model.Async {
86-
operationState = "Triggered security group creation"
87-
}
88-
p.Info("%s security group %q for %q\n", operationState, model.Name, model.ProjectId)
89+
func configureFlags(cmd *cobra.Command) {
90+
cmd.Flags().String(nameFlag, "", "the name of the security group. Must be <= 63 chars")
91+
cmd.Flags().String(descriptionFlag, "", "an optional description of the security group. Must be <= 127 chars")
92+
cmd.Flags().Bool(statefulFlag, false, "create a stateful or a stateless security group")
93+
cmd.Flags().StringSlice(labelsFlag, nil, "Labels are key-value string pairs which can be attached to a network-interface. E.g. '--labels key1=value1,key2=value2,...'")
8994

90-
group, err := request.Execute()
91-
if err != nil {
92-
return fmt.Errorf("create security group: %w", err)
93-
}
94-
if err:=outputResult(p, model, group);err != nil {
95-
return err
95+
if err := flags.MarkFlagsRequired(cmd, nameFlag); err != nil {
96+
cobra.CheckErr(err)
9697
}
97-
98-
return nil
9998
}
10099

101100
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
102101
globalFlags := globalflags.Parse(p, cmd)
103102
if globalFlags.ProjectId == "" {
104103
return nil, &errors.ProjectIdError{}
105104
}
106-
name := flags.FlagToStringValue(p, cmd, "name")
107-
if len(name) >= 64 {
108-
return nil, &errors.ArgValidationError{
109-
Arg: "invalid name",
110-
Details: "name exceeds 63 characters in length",
111-
}
112-
}
105+
name := flags.FlagToStringValue(p, cmd, nameFlag)
113106

114107
labels := make(map[string]any)
115-
for _, label := range flags.FlagToStringSliceValue(p, cmd, "labels") {
108+
for _, label := range flags.FlagToStringSliceValue(p, cmd, labelsFlag) {
116109
parts := strings.Split(label, "=")
117110
if len(parts) != 2 {
118111
return nil, &errors.ArgValidationError{
119-
Arg: "labels",
112+
Arg: labelsFlag,
120113
Details: "invalid label declaration. Must be in the form <key>=<value>",
121114
}
122115
}
123116
labels[parts[0]] = parts[1]
124117

125118
}
126-
description := flags.FlagToStringValue(p, cmd, "description")
127-
if len(description) >= 128 {
128-
return nil, &errors.ArgValidationError{
129-
Arg: "invalid description",
130-
Details: "description exceeds 127 characters in length",
131-
}
132-
}
119+
description := flags.FlagToStringValue(p, cmd, descriptionFlag)
120+
133121
model := inputModel{
134122
GlobalFlagModel: globalFlags,
135123
Name: name,
136124

137-
Labels: labels,
125+
Labels: &labels,
138126
Description: description,
139-
Stateful: flags.FlagToBoolValue(p, cmd, "stateful"),
127+
Stateful: flags.FlagToBoolValue(p, cmd, statefulFlag),
140128
}
141129

142130
if p.IsVerbosityDebug() {
@@ -158,7 +146,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli
158146
if model.Labels != nil {
159147
// this check assure that we don't end up with a pointer to nil
160148
// which is a thing in go!
161-
payload.Labels = &model.Labels
149+
payload.Labels = model.Labels
162150
}
163151
payload.Name = &model.Name
164152
payload.Stateful = &model.Stateful
@@ -188,9 +176,6 @@ func outputResult(p *print.Printer, model *inputModel, resp *iaas.SecurityGroup)
188176
return nil
189177
default:
190178
operationState := "Created"
191-
if model.Async {
192-
operationState = "Triggered creation of"
193-
}
194179
p.Outputf("%s security group %q\n", operationState, model.Name)
195180
return nil
196181
}

internal/cmd/beta/security-group/create/create_test.go

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

33
import (
44
"context"
5-
"strings"
65
"testing"
76

87
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
@@ -35,11 +34,11 @@ var (
3534

3635
func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
3736
flagValues := map[string]string{
38-
projectIdFlag: testProjectId,
39-
"description": testDescription,
40-
"labels": "fooKey=fooValue,barKey=barValue,bazKey=bazValue",
41-
"stateful": "true",
42-
"name": testName,
37+
projectIdFlag: testProjectId,
38+
descriptionFlag: testDescription,
39+
labelsFlag: "fooKey=fooValue,barKey=barValue,bazKey=bazValue",
40+
"stateful": "true",
41+
nameFlag: testName,
4342
}
4443
for _, mod := range mods {
4544
mod(flagValues)
@@ -50,7 +49,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st
5049
func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
5150
model := &inputModel{
5251
GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault},
53-
Labels: testLabels,
52+
Labels: &testLabels,
5453
Description: testDescription,
5554
Name: testName,
5655
Stateful: testStateful,
@@ -118,57 +117,43 @@ func TestParseInput(t *testing.T) {
118117
{
119118
description: "name missing",
120119
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
121-
delete(flagValues, "name")
122-
}),
123-
isValid: false,
124-
},
125-
{
126-
description: "name too long",
127-
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
128-
flagValues["name"] = strings.Repeat("toolong", 1000)
129-
}),
130-
isValid: false,
131-
},
132-
{
133-
description: "description too long",
134-
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
135-
flagValues["description"] = strings.Repeat("toolong", 1000)
120+
delete(flagValues, nameFlag)
136121
}),
137122
isValid: false,
138123
},
139124
{
140125
description: "no labels",
141126
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
142-
delete(flagValues, "labels")
127+
delete(flagValues, labelsFlag)
143128
}),
144129
isValid: true,
145130
expectedModel: fixtureInputModel(func(model *inputModel) {
146-
model.Labels = map[string]any{}
131+
model.Labels = &map[string]any{}
147132
}),
148133
},
149134
{
150135
description: "single label",
151136
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
152-
flagValues["labels"] = "foo=bar"
137+
flagValues[labelsFlag] = "foo=bar"
153138
}),
154139
isValid: true,
155140
expectedModel: fixtureInputModel(func(model *inputModel) {
156-
model.Labels = map[string]any{
141+
model.Labels = &map[string]any{
157142
"foo": "bar",
158143
}
159144
}),
160145
},
161146
{
162147
description: "malformed labels 1",
163148
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
164-
flagValues["labels"] = "foo=bar=baz"
149+
flagValues[labelsFlag] = "foo=bar=baz"
165150
}),
166151
isValid: false,
167152
},
168153
{
169154
description: "malformed labels 2",
170155
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
171-
flagValues["labels"] = "foobarbaz"
156+
flagValues[labelsFlag] = "foobarbaz"
172157
}),
173158
isValid: false,
174159
},

internal/cmd/beta/security-group/delete/delete.go

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,61 +22,53 @@ type inputModel struct {
2222
Id string
2323
}
2424

25-
const argNameGroupId = "groupId"
25+
const argNameGroupId = "GROUP_ID"
2626

2727
func NewCmd(p *print.Printer) *cobra.Command {
2828
cmd := &cobra.Command{
2929
Use: "delete",
30-
Short: "delete a security group",
31-
Long: "delete a security group by its internal id",
30+
Short: "Delete a security group",
31+
Long: "Delete a security group by its internal id.",
3232
Args: args.SingleArg(argNameGroupId, utils.ValidateUUID),
3333
Example: examples.Build(
3434
examples.NewExample(`delete a named group`, `$ stackit beta security-group delete 43ad419a-c68b-4911-87cd-e05752ac1e31`),
3535
),
3636
RunE: func(cmd *cobra.Command, args []string) error {
37-
return executeDelete(cmd, p, args)
38-
},
39-
}
40-
41-
return cmd
42-
}
37+
ctx := context.Background()
38+
model, err := parseInput(p, cmd, args)
39+
if err != nil {
40+
return err
41+
}
4342

44-
func executeDelete(cmd *cobra.Command, p *print.Printer, args []string) error {
45-
p.Info("executing delete command")
46-
ctx := context.Background()
47-
model, err := parseInput(p, cmd, args)
48-
if err != nil {
49-
return err
50-
}
43+
// Configure API client
44+
apiClient, err := client.ConfigureClient(p)
45+
if err != nil {
46+
return err
47+
}
5148

52-
// Configure API client
53-
apiClient, err := client.ConfigureClient(p)
54-
if err != nil {
55-
return err
56-
}
49+
if !model.AssumeYes {
50+
prompt := fmt.Sprintf("Are you sure you want to delete the security group %q?", model.Id)
51+
err = p.PromptForConfirmation(prompt)
52+
if err != nil {
53+
return err
54+
}
55+
}
5756

58-
if !model.AssumeYes {
59-
prompt := fmt.Sprintf("Are you sure you want to delete the security group %q?", model.Id)
60-
err = p.PromptForConfirmation(prompt)
61-
if err != nil {
62-
return err
63-
}
64-
}
57+
// Call API
58+
request := buildRequest(ctx, model, apiClient)
6559

66-
// Call API
67-
request := buildRequest(ctx, model, apiClient)
60+
operationState := "Deleted"
61+
p.Info("%s security group %q for %q\n", operationState, model.Id, model.ProjectId)
6862

69-
operationState := "Enabled"
70-
if model.Async {
71-
operationState = "Triggered security group deletion"
72-
}
73-
p.Info("%s security group %q for %q\n", operationState, model.Id, model.ProjectId)
63+
if err := request.Execute(); err != nil {
64+
return fmt.Errorf("delete security group: %w", err)
65+
}
7466

75-
if err := request.Execute(); err != nil {
76-
return fmt.Errorf("delete security group: %w", err)
67+
return nil
68+
},
7769
}
7870

79-
return nil
71+
return cmd
8072
}
8173

8274
func parseInput(p *print.Printer, cmd *cobra.Command, args []string) (*inputModel, error) {

0 commit comments

Comments
 (0)