-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathupdate.go
154 lines (132 loc) · 4.57 KB
/
update.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package update
import (
"context"
"fmt"
"regexp"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/confirm"
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/projectname"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/client"
"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-sdk-go/services/resourcemanager"
)
const (
parentIdFlag = "parent-id"
nameFlag = "name"
labelFlag = "label"
ownerRole = "project.owner"
labelKeyRegex = `[A-ZÄÜÖa-zäüöß0-9_-]{1,64}`
labelValueRegex = `^$|[A-ZÄÜÖa-zäüöß0-9_-]{1,64}`
)
type inputModel struct {
*globalflags.GlobalFlagModel
ParentId *string
Name *string
Labels *map[string]string
}
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update",
Short: "Updates a STACKIT project",
Long: "Updates a STACKIT project.",
Args: args.NoArgs,
Example: examples.Build(
examples.NewExample(
`Update the name of the configured STACKIT project`,
"$ stackit project update --name my-updated-project"),
examples.NewExample(
`Add labels to the configured STACKIT project`,
"$ stackit project update --label key=value,foo=bar"),
examples.NewExample(
`Update the name of a STACKIT project by explicitly providing the project ID`,
"$ stackit project update --name my-updated-project --project-id xxx"),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(cmd)
if err != nil {
return err
}
// Configure API client
apiClient, err := client.ConfigureClient(cmd)
if err != nil {
return err
}
projectLabel, err := projectname.GetProjectName(ctx, cmd)
if err != nil {
projectLabel = model.ProjectId
}
if !model.AssumeYes {
prompt := fmt.Sprintf("Are you sure you want to update project %q?", projectLabel)
err = confirm.PromptForConfirmation(cmd, prompt)
if err != nil {
return err
}
}
// Call API
req := buildRequest(ctx, model, apiClient)
_, err = req.Execute()
if err != nil {
return fmt.Errorf("update project: %w", err)
}
cmd.Printf("Updated project %q\n", projectLabel)
return nil
},
}
configureFlags(cmd)
return cmd
}
func configureFlags(cmd *cobra.Command) {
cmd.Flags().String(parentIdFlag, "", "Parent resource identifier. Both container ID (user-friendly) and UUID are supported")
cmd.Flags().String(nameFlag, "", "Project name")
cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a project. A label can be provided with the format key=value and the flag can be used multiple times to provide a list of labels")
}
func parseInput(cmd *cobra.Command) (*inputModel, error) {
globalFlags := globalflags.Parse(cmd)
if globalFlags.ProjectId == "" {
return nil, &errors.ProjectIdError{}
}
labels := flags.FlagToStringToStringPointer(cmd, labelFlag)
parentId := flags.FlagToStringPointer(cmd, parentIdFlag)
name := flags.FlagToStringPointer(cmd, nameFlag)
if labels == nil && parentId == nil && name == nil {
return nil, &errors.EmptyUpdateError{}
}
if labels != nil {
labelKeyRegex := regexp.MustCompile(labelKeyRegex)
labelValueRegex := regexp.MustCompile(labelValueRegex)
for key, value := range *labels {
if !labelKeyRegex.MatchString(key) {
return nil, &errors.FlagValidationError{
Flag: labelFlag,
Details: fmt.Sprintf("label key %s didn't match the required regex expression %s", key, labelKeyRegex),
}
}
if !labelValueRegex.MatchString(value) {
return nil, &errors.FlagValidationError{
Flag: labelFlag,
Details: fmt.Sprintf("label value %s for key %s didn't match the required regex expression %s", value, key, labelValueRegex),
}
}
}
}
return &inputModel{
GlobalFlagModel: globalFlags,
ParentId: parentId,
Name: name,
Labels: labels,
}, nil
}
func buildRequest(ctx context.Context, model *inputModel, apiClient *resourcemanager.APIClient) resourcemanager.ApiPartialUpdateProjectRequest {
req := apiClient.PartialUpdateProject(ctx, model.ProjectId)
req = req.PartialUpdateProjectPayload(resourcemanager.PartialUpdateProjectPayload{
ContainerParentId: model.ParentId,
Name: model.Name,
Labels: model.Labels,
})
return req
}