Skip to content

Commit 4d88162

Browse files
committed
add support to set labels without selector
1 parent cc9dd34 commit 4d88162

File tree

3 files changed

+123
-4
lines changed

3 files changed

+123
-4
lines changed

kustomize/commands/edit/add/addmetadata.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func newCmdAddLabel(fSys filesys.FileSystem, v func(map[string]string) error) *c
7070
o.mapValidator = v
7171
cmd := &cobra.Command{
7272
Use: "label",
73-
Short: "Adds one or more commonLabels to " +
73+
Short: "Adds one or more commonLabels or labels to " +
7474
konfig.DefaultKustomizationFileName(),
7575
Example: `
7676
add label {labelKey1:labelValue1} {labelKey2:labelValue2}`,

kustomize/commands/edit/set/setlabel.go

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ import (
1515
)
1616

1717
type setLabelOptions struct {
18-
metadata map[string]string
19-
mapValidator func(map[string]string) error
18+
metadata map[string]string
19+
mapValidator func(map[string]string) error
20+
labelsWithoutSelector bool
21+
includeTemplates bool
2022
}
2123

2224
// newCmdSetLabel sets one or more commonLabels to the kustomization file.
@@ -25,14 +27,20 @@ func newCmdSetLabel(fSys filesys.FileSystem, v func(map[string]string) error) *c
2527
o.mapValidator = v
2628
cmd := &cobra.Command{
2729
Use: "label",
28-
Short: "Sets one or more commonLabels in " +
30+
Short: "Sets one or more commonLabels or labels in " +
2931
konfig.DefaultKustomizationFileName(),
3032
Example: `
3133
set label {labelKey1:labelValue1} {labelKey2:labelValue2}`,
3234
RunE: func(cmd *cobra.Command, args []string) error {
3335
return o.runE(args, fSys, o.setLabels)
3436
},
3537
}
38+
cmd.Flags().BoolVar(&o.labelsWithoutSelector, "without-selector", false,
39+
"using set labels without selector option",
40+
)
41+
cmd.Flags().BoolVar(&o.includeTemplates, "include-templates", false,
42+
"include labels in templates (requires --without-selector)",
43+
)
3644
return cmd
3745
}
3846

@@ -62,6 +70,9 @@ func (o *setLabelOptions) validateAndParse(args []string) error {
6270
if len(args) < 1 {
6371
return fmt.Errorf("must specify label")
6472
}
73+
if !o.labelsWithoutSelector && o.includeTemplates {
74+
return fmt.Errorf("--without-selector flag must be specified for --include-templates to work")
75+
}
6576
m, err := util.ConvertSliceToMap(args, "label")
6677
if err != nil {
6778
return err
@@ -74,9 +85,36 @@ func (o *setLabelOptions) validateAndParse(args []string) error {
7485
}
7586

7687
func (o *setLabelOptions) setLabels(m *types.Kustomization) error {
88+
if o.labelsWithoutSelector {
89+
o.removeDuplicateLabels(m)
90+
91+
var labelPairs *types.Label
92+
for _, label := range m.Labels {
93+
if !label.IncludeSelectors && label.IncludeTemplates == o.includeTemplates {
94+
labelPairs = &label
95+
break
96+
}
97+
}
98+
99+
if labelPairs != nil {
100+
if labelPairs.Pairs == nil {
101+
labelPairs.Pairs = make(map[string]string)
102+
}
103+
return o.writeToMap(labelPairs.Pairs)
104+
}
105+
106+
m.Labels = append(m.Labels, types.Label{
107+
Pairs: make(map[string]string),
108+
IncludeSelectors: false,
109+
IncludeTemplates: o.includeTemplates,
110+
})
111+
return o.writeToMap(m.Labels[len(m.Labels)-1].Pairs)
112+
}
113+
77114
if m.CommonLabels == nil {
78115
m.CommonLabels = make(map[string]string)
79116
}
117+
80118
return o.writeToMap(m.CommonLabels)
81119
}
82120

@@ -86,3 +124,25 @@ func (o *setLabelOptions) writeToMap(m map[string]string) error {
86124
}
87125
return nil
88126
}
127+
128+
func (o *setLabelOptions) removeDuplicateLabels(m *types.Kustomization) {
129+
for k := range o.metadata {
130+
delete(m.CommonLabels, k)
131+
for idx, label := range m.Labels {
132+
if label.IncludeTemplates != o.includeTemplates {
133+
m.Labels = deleteLabel(k, label, m.Labels, idx)
134+
}
135+
if label.IncludeSelectors {
136+
m.Labels = deleteLabel(k, label, m.Labels, idx)
137+
}
138+
}
139+
}
140+
}
141+
142+
func deleteLabel(key string, label types.Label, labels []types.Label, idx int) []types.Label {
143+
delete(label.Pairs, key)
144+
if len(label.Pairs) == 0 {
145+
labels = append(labels[:idx], labels[idx+1:]...)
146+
}
147+
return labels
148+
}

kustomize/commands/edit/set/setlabel_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package set
66
import (
77
"testing"
88

9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
911
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
1012
"sigs.k8s.io/kustomize/api/types"
1113
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
@@ -152,3 +154,60 @@ func TestSetLabelExisting(t *testing.T) {
152154
t.Errorf("unexpected error: %v", err.Error())
153155
}
154156
}
157+
158+
func TestSetLabelWithoutSelector(t *testing.T) {
159+
var o setLabelOptions
160+
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
161+
o.labelsWithoutSelector = true
162+
163+
m := makeKustomization(t)
164+
require.NoError(t, o.setLabels(m))
165+
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar"}})
166+
}
167+
168+
func TestSetLabelWithoutSelectorWithExistingLabels(t *testing.T) {
169+
var o setLabelOptions
170+
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
171+
o.labelsWithoutSelector = true
172+
173+
m := makeKustomization(t)
174+
require.NoError(t, o.setLabels(m))
175+
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar"}})
176+
177+
o.metadata = map[string]string{"key3": "foobar"}
178+
require.NoError(t, o.setLabels(m))
179+
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar", "key3": "foobar"}})
180+
}
181+
182+
func TestSetLabelWithoutSelectorWithDuplicateLabel(t *testing.T) {
183+
var o setLabelOptions
184+
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
185+
o.labelsWithoutSelector = true
186+
o.includeTemplates = true
187+
188+
m := makeKustomization(t)
189+
require.NoError(t, o.setLabels(m))
190+
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar"}, IncludeTemplates: true})
191+
192+
o.metadata = map[string]string{"key2": "bar"}
193+
o.includeTemplates = false
194+
require.NoError(t, o.setLabels(m))
195+
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo"}, IncludeTemplates: true})
196+
assert.Equal(t, m.Labels[1], types.Label{Pairs: map[string]string{"key2": "bar"}})
197+
}
198+
199+
func TestSetLabelWithoutSelectorWithCommonLabel(t *testing.T) {
200+
var o setLabelOptions
201+
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
202+
203+
m := makeKustomization(t)
204+
require.NoError(t, o.setLabels(m))
205+
assert.Empty(t, m.Labels)
206+
assert.Equal(t, m.CommonLabels, map[string]string{"app": "helloworld", "key1": "foo", "key2": "bar"})
207+
208+
o.metadata = map[string]string{"key2": "bar"}
209+
o.labelsWithoutSelector = true
210+
require.NoError(t, o.setLabels(m))
211+
assert.Equal(t, m.CommonLabels, map[string]string{"app": "helloworld", "key1": "foo"})
212+
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key2": "bar"}})
213+
}

0 commit comments

Comments
 (0)