Skip to content

Commit 29ef9c4

Browse files
feat(converge): support multiple values within --add-annotation/--add-label flag
Now the flag accepts multiple values separated by a delimiter, allowing more flexible input handling. This improves usability when passing multiple parameters in a single flag instance. Signed-off-by: Aleksei Igrychev <aleksei.igrychev@palark.com>
1 parent cc413d5 commit 29ef9c4

24 files changed

+274
-47
lines changed

cmd/werf/bundle/apply/apply.go

+2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ func NewCmd(ctx context.Context) *cobra.Command {
8484
common.SetupLogProjectDir(&commonCmdData, cmd)
8585

8686
common.SetupAddAnnotations(&commonCmdData, cmd)
87+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
8788
common.SetupAddLabels(&commonCmdData, cmd)
89+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
8890

8991
common.SetupSetDockerConfigJsonValue(&commonCmdData, cmd)
9092
common.SetupSet(&commonCmdData, cmd)

cmd/werf/bundle/publish/publish.go

+2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ func NewCmd(ctx context.Context) *cobra.Command {
113113
common.SetupKubeContext(&commonCmdData, cmd)
114114

115115
common.SetupAddAnnotations(&commonCmdData, cmd)
116+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
116117
common.SetupAddLabels(&commonCmdData, cmd)
118+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
117119

118120
common.SetupSet(&commonCmdData, cmd)
119121
common.SetupSetString(&commonCmdData, cmd)

cmd/werf/bundle/render/render.go

+2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ func NewCmd(ctx context.Context) *cobra.Command {
8787
common.SetupLogProjectDir(&commonCmdData, cmd)
8888

8989
common.SetupAddAnnotations(&commonCmdData, cmd)
90+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
9091
common.SetupAddLabels(&commonCmdData, cmd)
92+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
9193

9294
common.SetupSetDockerConfigJsonValue(&commonCmdData, cmd)
9395
common.SetupSet(&commonCmdData, cmd)

cmd/werf/common/cmd_data.go

+2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ type CmdData struct {
2727
Release *string
2828
Namespace *string
2929
AddAnnotations *[]string
30+
AddAnnotationSeparator *string
3031
AddLabels *[]string
32+
AddLabelSeparator *string
3133
KubeContext *string
3234
KubeConfig *string
3335
KubeConfigBase64 *string

cmd/werf/common/common.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -424,17 +424,41 @@ func SetupNamespace(cmdData *CmdData, cmd *cobra.Command, projectConfigParsed bo
424424
func SetupAddAnnotations(cmdData *CmdData, cmd *cobra.Command) {
425425
cmdData.AddAnnotations = new([]string)
426426
cmd.Flags().StringArrayVarP(cmdData.AddAnnotations, "add-annotation", "", []string{}, `Add annotation to deploying resources (can specify multiple).
427-
Format: annoName=annoValue.
427+
Format: annoName=annoValue[<separator>annoName=annoValue ...]. The default separator is a newline ("\n"), but it can be customized using the --add-annotation-separator flag.
428428
Also, can be specified with $WERF_ADD_ANNOTATION_* (e.g. $WERF_ADD_ANNOTATION_1=annoName1=annoValue1, $WERF_ADD_ANNOTATION_2=annoName2=annoValue2)`)
429429
}
430430

431+
const DefaultAnnoAndLabelPairSeparator = "\n"
432+
433+
func SetupAddAnnotationSeparator(cmdData *CmdData, cmd *cobra.Command) {
434+
cmdData.AddAnnotationSeparator = new(string)
435+
436+
defaultValue := DefaultAnnoAndLabelPairSeparator
437+
if os.Getenv("WERF_ADD_ANNOTATION_SEPARATOR") != "" {
438+
defaultValue = os.Getenv("WERF_ADD_ANNOTATION_SEPARATOR")
439+
}
440+
441+
cmd.Flags().StringVarP(cmdData.AddAnnotationSeparator, "add-annotation-separator", "", defaultValue, `Separator for --add-annotation values (default $WERF_ADD_ANNOTATION_SEPARATOR or "\n")`)
442+
}
443+
431444
func SetupAddLabels(cmdData *CmdData, cmd *cobra.Command) {
432445
cmdData.AddLabels = new([]string)
433446
cmd.Flags().StringArrayVarP(cmdData.AddLabels, "add-label", "", []string{}, `Add label to deploying resources (can specify multiple).
434-
Format: labelName=labelValue.
447+
Format: labelName=labelValue[<separator>labelName=labelValue ...]. The default separator is a newline ("\n"), but it can be customized using the --add-label-separator flag.
435448
Also, can be specified with $WERF_ADD_LABEL_* (e.g. $WERF_ADD_LABEL_1=labelName1=labelValue1, $WERF_ADD_LABEL_2=labelName2=labelValue2)`)
436449
}
437450

451+
func SetupAddLabelSeparator(cmdData *CmdData, cmd *cobra.Command) {
452+
cmdData.AddLabelSeparator = new(string)
453+
454+
defaultValue := DefaultAnnoAndLabelPairSeparator
455+
if os.Getenv("WERF_ADD_LABEL_SEPARATOR") != "" {
456+
defaultValue = os.Getenv("WERF_ADD_LABEL_SEPARATOR")
457+
}
458+
459+
cmd.Flags().StringVarP(cmdData.AddLabelSeparator, "add-label-separator", "", defaultValue, `Separator for --add-label values (default $WERF_ADD_LABEL_SEPARATOR or "\n")`)
460+
}
461+
438462
func SetupKubeContext(cmdData *CmdData, cmd *cobra.Command) {
439463
cmdData.KubeContext = new(string)
440464
cmd.PersistentFlags().StringVarP(cmdData.KubeContext, "kube-context", "", os.Getenv("WERF_KUBE_CONTEXT"), "Kubernetes config context (default $WERF_KUBE_CONTEXT)")

cmd/werf/common/deploy_params.go

+35-22
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,59 @@ package common
33
import (
44
"fmt"
55
"strings"
6-
)
7-
8-
func GetUserExtraAnnotations(cmdData *CmdData) (map[string]string, error) {
9-
extraAnnotationMap := map[string]string{}
10-
var addAnnotations []string
116

12-
addAnnotations = append(addAnnotations, GetAddAnnotations(cmdData)...)
7+
"github.com/werf/common-go/pkg/util"
8+
)
139

14-
for _, addAnnotation := range addAnnotations {
15-
parts := strings.Split(addAnnotation, "=")
16-
if len(parts) != 2 {
17-
return nil, fmt.Errorf("bad --add-annotation value %s", addAnnotation)
18-
}
10+
const (
11+
DefaultKeyValueSeparator = "="
12+
DefaultPairSeparator = ","
13+
)
1914

20-
extraAnnotationMap[parts[0]] = parts[1]
15+
func GetUserExtraAnnotations(cmdData *CmdData) (map[string]string, error) {
16+
result, err := InputArrayToKeyValueMap(GetAddAnnotations(cmdData), ",", DefaultKeyValueSeparator)
17+
if err != nil {
18+
return nil, fmt.Errorf("unsupported --add-annotation value: %w", err)
2119
}
2220

23-
return extraAnnotationMap, nil
21+
return result, nil
2422
}
2523

2624
func GetUserExtraLabels(cmdData *CmdData) (map[string]string, error) {
27-
addLabelArray := append([]string{}, GetAddLabels(cmdData)...)
28-
addLabelMap, err := KeyValueArrayToMap(addLabelArray, "=")
25+
result, err := InputArrayToKeyValueMap(GetAddLabels(cmdData), ",", DefaultKeyValueSeparator)
2926
if err != nil {
3027
return nil, fmt.Errorf("unsupported --add-label value: %w", err)
3128
}
3229

33-
return addLabelMap, nil
30+
return result, nil
31+
}
32+
33+
// InputArrayToKeyValueMap converts an array of strings in the form of key1=value1[,key2=value2] to a map.
34+
func InputArrayToKeyValueMap(input []string, pairSep, keyValueSep string) (map[string]string, error) {
35+
result := map[string]string{}
36+
for _, value := range input {
37+
pairs := strings.Split(value, pairSep)
38+
valueResult, err := keyValueArrayToMap(pairs, keyValueSep)
39+
if err != nil {
40+
return nil, fmt.Errorf("invalid value %q (%q): %w", value, pairSep, err)
41+
}
42+
43+
result = util.MergeMaps(result, valueResult)
44+
}
45+
46+
return result, nil
3447
}
3548

36-
func KeyValueArrayToMap(pairs []string, sep string) (map[string]string, error) {
37-
keyValueMap := map[string]string{}
49+
func keyValueArrayToMap(pairs []string, sep string) (map[string]string, error) {
50+
result := map[string]string{}
3851
for _, pair := range pairs {
3952
parts := strings.SplitN(pair, sep, 2)
40-
if len(parts) != 2 {
41-
return nil, fmt.Errorf("invalid key=value pair %q", pair)
53+
if len(parts) != 2 || parts[0] == "" {
54+
return nil, fmt.Errorf("invalid key=value pair %q (%q)", pair, sep)
4255
}
4356

44-
keyValueMap[parts[0]] = parts[1]
57+
result[parts[0]] = parts[1]
4558
}
4659

47-
return keyValueMap, nil
60+
return result, nil
4861
}

cmd/werf/common/deploy_params_test.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
func TestKeyValueArrayToMap_Positive(t *testing.T) {
9+
tests := []struct {
10+
input []string
11+
expected map[string]string
12+
}{
13+
{
14+
input: []string{"key1=value1"},
15+
expected: map[string]string{
16+
"key1": "value1",
17+
},
18+
},
19+
{
20+
input: []string{"key1=value1", "key2=value2"},
21+
expected: map[string]string{
22+
"key1": "value1",
23+
"key2": "value2",
24+
},
25+
},
26+
{
27+
input: []string{"key1=value1,key2=value2"},
28+
expected: map[string]string{
29+
"key1": "value1",
30+
"key2": "value2",
31+
},
32+
},
33+
{
34+
input: []string{"key1=value1,key2="},
35+
expected: map[string]string{
36+
"key1": "value1",
37+
"key2": "",
38+
},
39+
},
40+
{
41+
input: []string{"key=value with pair separator="},
42+
expected: map[string]string{
43+
"key": "value with pair separator=",
44+
},
45+
},
46+
}
47+
48+
for _, test := range tests {
49+
t.Run(fmt.Sprintf("input=%v", test.input), func(t *testing.T) {
50+
result, err := InputArrayToKeyValueMap(test.input, DefaultPairSeparator, DefaultKeyValueSeparator)
51+
if err != nil {
52+
t.Errorf("unexpected error: %v", err)
53+
}
54+
55+
if !mapsEqual(result, test.expected) {
56+
t.Errorf("expected %v, but got %v", test.expected, result)
57+
}
58+
})
59+
}
60+
}
61+
62+
func TestKeyValueArrayToMap_Negative(t *testing.T) {
63+
inputs := [][]string{
64+
{""},
65+
{"=value"},
66+
{","},
67+
{"key=value,with value separator"},
68+
}
69+
70+
for _, input := range inputs {
71+
t.Run(fmt.Sprintf("input=%v", input), func(t *testing.T) {
72+
_, err := InputArrayToKeyValueMap(input, DefaultPairSeparator, DefaultKeyValueSeparator)
73+
if err == nil {
74+
t.Errorf("expected error but got nil")
75+
}
76+
})
77+
}
78+
}
79+
80+
// mapsEqual compares two maps and checks for exact equality.
81+
func mapsEqual(a, b map[string]string) bool {
82+
if len(a) != len(b) {
83+
return false
84+
}
85+
for key, value := range a {
86+
if b[key] != value {
87+
return false
88+
}
89+
}
90+
return true
91+
}

cmd/werf/converge/converge.go

+3
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ werf converge --repo registry.mydomain.com/web --env production`,
136136

137137
common.SetupRelease(&commonCmdData, cmd, true)
138138
common.SetupNamespace(&commonCmdData, cmd, true)
139+
139140
common.SetupAddAnnotations(&commonCmdData, cmd)
141+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
140142
common.SetupAddLabels(&commonCmdData, cmd)
143+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
141144

142145
common.SetupSetDockerConfigJsonValue(&commonCmdData, cmd)
143146
common.SetupSet(&commonCmdData, cmd)

cmd/werf/export/export.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func NewExportCmd(ctx context.Context) *cobra.Command {
7070
var err error
7171
{
7272
addLabelArray := append(util.PredefinedValuesByEnvNamePrefix("WERF_EXPORT_ADD_LABEL_"), addLabelArray...)
73-
addLabelMap, err = common.KeyValueArrayToMap(addLabelArray, "=")
73+
addLabelMap, err = common.InputArrayToKeyValueMap(addLabelArray, "=", ",")
7474
if err != nil {
7575
common.PrintHelp(cmd)
7676
return fmt.Errorf("unsupported --add-label value: %w", err)

cmd/werf/helm/werf_chart.go

+2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import (
1212

1313
func SetupRenderRelatedWerfChartParams(cmd *cobra.Command, commonCmdData *common.CmdData) {
1414
common.SetupAddAnnotations(commonCmdData, cmd)
15+
common.SetupAddAnnotationSeparator(commonCmdData, cmd)
1516
common.SetupAddLabels(commonCmdData, cmd)
17+
common.SetupAddLabelSeparator(commonCmdData, cmd)
1618

1719
common.SetupSecretValues(commonCmdData, cmd, true)
1820
common.SetupIgnoreSecretKey(commonCmdData, cmd)

cmd/werf/kube_run/kube_run.go

+3
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,11 @@ func NewCmd(ctx context.Context) *cobra.Command {
150150
common.SetupGiterminismConfigPath(&commonCmdData, cmd)
151151
common.SetupEnvironment(&commonCmdData, cmd)
152152
common.SetupNamespace(&commonCmdData, cmd, true)
153+
153154
common.SetupAddAnnotations(&commonCmdData, cmd)
155+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
154156
common.SetupAddLabels(&commonCmdData, cmd)
157+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
155158

156159
common.SetupGiterminismOptions(&commonCmdData, cmd)
157160

cmd/werf/plan/plan.go

+3
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ werf plan --repo registry.mydomain.com/web --env production`,
136136

137137
common.SetupRelease(&commonCmdData, cmd, true)
138138
common.SetupNamespace(&commonCmdData, cmd, true)
139+
139140
common.SetupAddAnnotations(&commonCmdData, cmd)
141+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
140142
common.SetupAddLabels(&commonCmdData, cmd)
143+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
141144

142145
common.SetupSetDockerConfigJsonValue(&commonCmdData, cmd)
143146
common.SetupSet(&commonCmdData, cmd)

cmd/werf/render/render.go

+3
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,11 @@ func NewCmd(ctx context.Context) *cobra.Command {
124124

125125
common.SetupRelease(&commonCmdData, cmd, true)
126126
common.SetupNamespace(&commonCmdData, cmd, true)
127+
127128
common.SetupAddAnnotations(&commonCmdData, cmd)
129+
common.SetupAddAnnotationSeparator(&commonCmdData, cmd)
128130
common.SetupAddLabels(&commonCmdData, cmd)
131+
common.SetupAddLabelSeparator(&commonCmdData, cmd)
129132

130133
common.SetupSetDockerConfigJsonValue(&commonCmdData, cmd)
131134
common.SetupSet(&commonCmdData, cmd)

docs/_includes/reference/cli/werf_bundle_apply.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,22 @@ werf bundle apply [options]
1717
```shell
1818
--add-annotation="[]"
1919
Add annotation to deploying resources (can specify multiple).
20-
Format: annoName=annoValue.
20+
Format: annoName=annoValue[<separator>annoName=annoValue ...]. The default separator is
21+
a newline ("\n"), but it can be customized using the --add-annotation-separator flag.
2122
Also, can be specified with $WERF_ADD_ANNOTATION_* (e.g.
2223
$WERF_ADD_ANNOTATION_1=annoName1=annoValue1,
2324
$WERF_ADD_ANNOTATION_2=annoName2=annoValue2)
25+
--add-annotation-separator="\n"
26+
Separator for --add-annotation values (default $WERF_ADD_ANNOTATION_SEPARATOR or "\n")
2427
--add-label="[]"
2528
Add label to deploying resources (can specify multiple).
26-
Format: labelName=labelValue.
29+
Format: labelName=labelValue[<separator>labelName=labelValue ...]. The default
30+
separator is a newline ("\n"), but it can be customized using the --add-label-separator
31+
flag.
2732
Also, can be specified with $WERF_ADD_LABEL_* (e.g.
2833
$WERF_ADD_LABEL_1=labelName1=labelValue1, $WERF_ADD_LABEL_2=labelName2=labelValue2)
34+
--add-label-separator="\n"
35+
Separator for --add-label values (default $WERF_ADD_LABEL_SEPARATOR or "\n")
2936
--atomic="false"
3037
Enable auto rollback of the failed release to the previous deployed release version
3138
when current deploy process have failed ($WERF_ATOMIC by default)

docs/_includes/reference/cli/werf_bundle_publish.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ werf bundle publish [IMAGE_NAME...] [options]
1818
```shell
1919
--add-annotation="[]"
2020
Add annotation to deploying resources (can specify multiple).
21-
Format: annoName=annoValue.
21+
Format: annoName=annoValue[<separator>annoName=annoValue ...]. The default separator is
22+
a newline ("\n"), but it can be customized using the --add-annotation-separator flag.
2223
Also, can be specified with $WERF_ADD_ANNOTATION_* (e.g.
2324
$WERF_ADD_ANNOTATION_1=annoName1=annoValue1,
2425
$WERF_ADD_ANNOTATION_2=annoName2=annoValue2)
26+
--add-annotation-separator="\n"
27+
Separator for --add-annotation values (default $WERF_ADD_ANNOTATION_SEPARATOR or "\n")
2528
--add-custom-tag="[]"
2629
Set tag alias for the content-based tag.
2730
The alias may contain the following shortcuts:
@@ -33,9 +36,13 @@ werf bundle publish [IMAGE_NAME...] [options]
3336
$WERF_ADD_CUSTOM_TAG_1="%image%-tag1", $WERF_ADD_CUSTOM_TAG_2="%image%-tag2")
3437
--add-label="[]"
3538
Add label to deploying resources (can specify multiple).
36-
Format: labelName=labelValue.
39+
Format: labelName=labelValue[<separator>labelName=labelValue ...]. The default
40+
separator is a newline ("\n"), but it can be customized using the --add-label-separator
41+
flag.
3742
Also, can be specified with $WERF_ADD_LABEL_* (e.g.
3843
$WERF_ADD_LABEL_1=labelName1=labelValue1, $WERF_ADD_LABEL_2=labelName2=labelValue2)
44+
--add-label-separator="\n"
45+
Separator for --add-label values (default $WERF_ADD_LABEL_SEPARATOR or "\n")
3946
--allowed-backend-storage-volume-usage="70"
4047
Set allowed percentage of backend (Docker or Buildah) storage volume usage which will
4148
cause cleanup of least recently used local backend images (default 70% or

0 commit comments

Comments
 (0)