Skip to content

Commit e46faee

Browse files
committedMay 5, 2024··
feat: groupByLabelWithDefault template function
1 parent ec3fa07 commit e46faee

File tree

4 files changed

+109
-72
lines changed

4 files changed

+109
-72
lines changed
 

‎README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,8 @@ For example, this is a JSON version of an emitted RuntimeContainer struct:
385385
- _`groupByWithDefault $containers $fieldPath $defaultValue`_: Returns the same as `groupBy`, but containers that do not have a value for the field path are instead included in the map under the `$defaultValue` key.
386386
- _`groupByKeys $containers $fieldPath`_: Returns the same as `groupBy` but only returns the keys of the map.
387387
- _`groupByMulti $containers $fieldPath $sep`_: Like `groupBy`, but the string value specified by `$fieldPath` is first split by `$sep` into a list of strings. A container whose `$fieldPath` value contains a list of strings will show up in the map output under each of those strings.
388-
- _`groupByLabel $containers $label`_: Returns the same as `groupBy` but grouping by the given label's value.
388+
- _`groupByLabel $containers $label`_: Returns the same as `groupBy` but grouping by the given label's value. Containers that do not have the `$label` set are omitted.
389+
- _`groupByLabelWithDefault $containers $label $defaultValue`_: Returns the same as `groupBy` but grouping by the given label's value. Containers that do not have the `$label` set are included in the map under the `$defaultValue` key.
389390
- _`include $file`_: Returns content of `$file`, and empty string if file reading error.
390391
- _`intersect $slice1 $slice2`_: Returns the strings that exist in both string slices.
391392
- _`json $value`_: Returns the JSON representation of `$value` as a `string`.

‎internal/template/groupby.go

+16
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,19 @@ func groupByLabel(entries interface{}, label string) (map[string][]interface{},
9898
groups[value.(string)] = append(groups[value.(string)], v)
9999
})
100100
}
101+
102+
// groupByLabelWithDefault is the same as groupByLabel but allows a default value to be set
103+
func groupByLabelWithDefault(entries interface{}, label string, defaultValue string) (map[string][]interface{}, error) {
104+
getLabel := func(v interface{}) (interface{}, error) {
105+
if container, ok := v.(*context.RuntimeContainer); ok {
106+
if value, ok := container.Labels[label]; ok {
107+
return value, nil
108+
}
109+
return defaultValue, nil
110+
}
111+
return nil, fmt.Errorf("must pass an array or slice of *RuntimeContainer to 'groupByLabel'; received %v", v)
112+
}
113+
return generalizedGroupBy("groupByLabelWithDefault", entries, getLabel, func(groups map[string][]interface{}, value interface{}, v interface{}) {
114+
groups[value.(string)] = append(groups[value.(string)], v)
115+
})
116+
}

‎internal/template/groupby_test.go

+46-27
Original file line numberDiff line numberDiff line change
@@ -83,38 +83,38 @@ func TestGeneralizedGroupByError(t *testing.T) {
8383
assert.Nil(t, groups)
8484
}
8585

86-
func TestGroupByLabel(t *testing.T) {
87-
containers := []*context.RuntimeContainer{
88-
{
89-
Labels: map[string]string{
90-
"com.docker.compose.project": "one",
91-
},
92-
ID: "1",
93-
},
94-
{
95-
Labels: map[string]string{
96-
"com.docker.compose.project": "two",
97-
},
98-
ID: "2",
86+
var groupByLabelContainers = []*context.RuntimeContainer{
87+
{
88+
Labels: map[string]string{
89+
"com.docker.compose.project": "one",
9990
},
100-
{
101-
Labels: map[string]string{
102-
"com.docker.compose.project": "one",
103-
},
104-
ID: "3",
91+
ID: "1",
92+
},
93+
{
94+
Labels: map[string]string{
95+
"com.docker.compose.project": "two",
10596
},
106-
{
107-
ID: "4",
97+
ID: "2",
98+
},
99+
{
100+
Labels: map[string]string{
101+
"com.docker.compose.project": "one",
108102
},
109-
{
110-
Labels: map[string]string{
111-
"com.docker.compose.project": "",
112-
},
113-
ID: "5",
103+
ID: "3",
104+
},
105+
{
106+
ID: "4",
107+
},
108+
{
109+
Labels: map[string]string{
110+
"com.docker.compose.project": "",
114111
},
115-
}
112+
ID: "5",
113+
},
114+
}
116115

117-
groups, err := groupByLabel(containers, "com.docker.compose.project")
116+
func TestGroupByLabel(t *testing.T) {
117+
groups, err := groupByLabel(groupByLabelContainers, "com.docker.compose.project")
118118

119119
assert.NoError(t, err)
120120
assert.Len(t, groups, 3)
@@ -131,6 +131,25 @@ func TestGroupByLabelError(t *testing.T) {
131131
assert.Nil(t, groups)
132132
}
133133

134+
func TestGroupByLabelWithDefault(t *testing.T) {
135+
groups, err := groupByLabelWithDefault(groupByLabelContainers, "com.docker.compose.project", "default")
136+
137+
assert.NoError(t, err)
138+
assert.Len(t, groups, 4)
139+
assert.Len(t, groups["one"], 2)
140+
assert.Len(t, groups["two"], 1)
141+
assert.Len(t, groups[""], 1)
142+
assert.Len(t, groups["default"], 1)
143+
assert.Equal(t, "4", groups["default"][0].(*context.RuntimeContainer).ID)
144+
}
145+
146+
func TestGroupByLabelWithDefaultError(t *testing.T) {
147+
strings := []string{"foo", "bar", "baz"}
148+
groups, err := groupByLabelWithDefault(strings, "", "")
149+
assert.Error(t, err)
150+
assert.Nil(t, groups)
151+
}
152+
134153
func TestGroupByMulti(t *testing.T) {
135154
containers := []*context.RuntimeContainer{
136155
{

‎internal/template/template.go

+45-44
Original file line numberDiff line numberDiff line change
@@ -58,50 +58,51 @@ func newTemplate(name string) *template.Template {
5858
return buf.String(), nil
5959
}
6060
tmpl.Funcs(sprig.TxtFuncMap()).Funcs(template.FuncMap{
61-
"closest": arrayClosest,
62-
"coalesce": coalesce,
63-
"contains": contains,
64-
"dir": dirList,
65-
"eval": eval,
66-
"exists": utils.PathExists,
67-
"groupBy": groupBy,
68-
"groupByWithDefault": groupByWithDefault,
69-
"groupByKeys": groupByKeys,
70-
"groupByMulti": groupByMulti,
71-
"groupByLabel": groupByLabel,
72-
"json": marshalJson,
73-
"include": include,
74-
"intersect": intersect,
75-
"keys": keys,
76-
"replace": strings.Replace,
77-
"parseBool": strconv.ParseBool,
78-
"parseJson": unmarshalJson,
79-
"fromYaml": fromYaml,
80-
"toYaml": toYaml,
81-
"mustFromYaml": mustFromYaml,
82-
"mustToYaml": mustToYaml,
83-
"queryEscape": url.QueryEscape,
84-
"sha1": hashSha1,
85-
"split": strings.Split,
86-
"splitN": strings.SplitN,
87-
"sortStringsAsc": sortStringsAsc,
88-
"sortStringsDesc": sortStringsDesc,
89-
"sortObjectsByKeysAsc": sortObjectsByKeysAsc,
90-
"sortObjectsByKeysDesc": sortObjectsByKeysDesc,
91-
"trimPrefix": trimPrefix,
92-
"trimSuffix": trimSuffix,
93-
"toLower": toLower,
94-
"toUpper": toUpper,
95-
"when": when,
96-
"where": where,
97-
"whereNot": whereNot,
98-
"whereExist": whereExist,
99-
"whereNotExist": whereNotExist,
100-
"whereAny": whereAny,
101-
"whereAll": whereAll,
102-
"whereLabelExists": whereLabelExists,
103-
"whereLabelDoesNotExist": whereLabelDoesNotExist,
104-
"whereLabelValueMatches": whereLabelValueMatches,
61+
"closest": arrayClosest,
62+
"coalesce": coalesce,
63+
"contains": contains,
64+
"dir": dirList,
65+
"eval": eval,
66+
"exists": utils.PathExists,
67+
"groupBy": groupBy,
68+
"groupByWithDefault": groupByWithDefault,
69+
"groupByKeys": groupByKeys,
70+
"groupByMulti": groupByMulti,
71+
"groupByLabel": groupByLabel,
72+
"groupByLabelWithDefault": groupByLabelWithDefault,
73+
"json": marshalJson,
74+
"include": include,
75+
"intersect": intersect,
76+
"keys": keys,
77+
"replace": strings.Replace,
78+
"parseBool": strconv.ParseBool,
79+
"parseJson": unmarshalJson,
80+
"fromYaml": fromYaml,
81+
"toYaml": toYaml,
82+
"mustFromYaml": mustFromYaml,
83+
"mustToYaml": mustToYaml,
84+
"queryEscape": url.QueryEscape,
85+
"sha1": hashSha1,
86+
"split": strings.Split,
87+
"splitN": strings.SplitN,
88+
"sortStringsAsc": sortStringsAsc,
89+
"sortStringsDesc": sortStringsDesc,
90+
"sortObjectsByKeysAsc": sortObjectsByKeysAsc,
91+
"sortObjectsByKeysDesc": sortObjectsByKeysDesc,
92+
"trimPrefix": trimPrefix,
93+
"trimSuffix": trimSuffix,
94+
"toLower": toLower,
95+
"toUpper": toUpper,
96+
"when": when,
97+
"where": where,
98+
"whereNot": whereNot,
99+
"whereExist": whereExist,
100+
"whereNotExist": whereNotExist,
101+
"whereAny": whereAny,
102+
"whereAll": whereAll,
103+
"whereLabelExists": whereLabelExists,
104+
"whereLabelDoesNotExist": whereLabelDoesNotExist,
105+
"whereLabelValueMatches": whereLabelValueMatches,
105106
})
106107
return tmpl
107108
}

0 commit comments

Comments
 (0)
Please sign in to comment.