Skip to content

Commit ab551b1

Browse files
committed
feat(labeler): support comma-separated JSONPath queries in DefaultQuery
1 parent a4aa447 commit ab551b1

2 files changed

Lines changed: 48 additions & 14 deletions

File tree

internal/metastructure/resource_update/resource_labeler.go

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,30 +69,42 @@ func (l *ResourceLabeler) LabelForUnmanagedResource(
6969
// extractLabelFromQuery evaluates a JSONPath query against properties and returns
7070
// concatenated string results. When the query returns multiple values (e.g., from
7171
// a filter with OR conditions), all values are joined with the label separator.
72+
// Supports comma-separated queries (e.g., "$.metadata.namespace,$.metadata.name")
73+
// where each query is evaluated independently and results are joined.
7274
func (l *ResourceLabeler) extractLabelFromQuery(properties json.RawMessage, query string) string {
7375
if len(properties) == 0 {
7476
return ""
7577
}
7678

77-
path, err := labelJSONPathParser.Parse(query)
78-
if err != nil {
79-
return ""
80-
}
81-
8279
var data any
8380
if err := json.Unmarshal(properties, &data); err != nil {
8481
return ""
8582
}
8683

87-
results := path.Select(data)
88-
if len(results) == 0 {
89-
return ""
84+
var parts []string
85+
for _, q := range strings.Split(query, ",") {
86+
q = strings.TrimSpace(q)
87+
if q == "" {
88+
continue
89+
}
90+
for _, s := range l.evaluateQuery(data, q) {
91+
parts = append(parts, s)
92+
}
9093
}
9194

92-
// Collect all string values from results
95+
return strings.Join(parts, labelSeparator)
96+
}
97+
98+
// evaluateQuery runs a single JSONPath query and returns string results.
99+
func (l *ResourceLabeler) evaluateQuery(data any, query string) []string {
100+
path, err := labelJSONPathParser.Parse(query)
101+
if err != nil {
102+
return nil
103+
}
104+
105+
results := path.Select(data)
93106
var parts []string
94107
for _, result := range results {
95-
// Handle array result (e.g., from tag filter query)
96108
if arr, ok := result.([]any); ok {
97109
for _, item := range arr {
98110
if str, ok := item.(string); ok && str != "" {
@@ -101,14 +113,11 @@ func (l *ResourceLabeler) extractLabelFromQuery(properties json.RawMessage, quer
101113
}
102114
continue
103115
}
104-
105-
// Handle direct string result
106116
if str, ok := result.(string); ok && str != "" {
107117
parts = append(parts, str)
108118
}
109119
}
110-
111-
return strings.Join(parts, labelSeparator)
120+
return parts
112121
}
113122

114123
// extractLabelFromLegacyTagKeys extracts a label using the legacy tag-based approach.

internal/metastructure/resource_update/resource_labeler_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,31 @@ func TestLabelForUnmanagedResource_JSONPathQueryTakesPrecedenceOverLegacyTagKeys
206206
assert.Equal(t, "FromJSONPath", label)
207207
}
208208

209+
func TestLabelForUnmanagedResource_CommaSeparatedQueryJoinsResults(t *testing.T) {
210+
nativeId := "canary-defaults/canary-svc"
211+
properties := json.RawMessage(`{"metadata":{"namespace":"canary-defaults","name":"canary-svc"}}`)
212+
labelConfig := pkgmodel.LabelConfig{
213+
DefaultQuery: "$.metadata.namespace,$.metadata.name",
214+
}
215+
216+
l := newResourceLabelerForTest(t)
217+
label := l.LabelForUnmanagedResource(nativeId, "K8S::Core::Service", properties, labelConfig, nil)
218+
assert.Equal(t, "canary-defaults-canary-svc", label)
219+
}
220+
221+
func TestLabelForUnmanagedResource_CommaSeparatedQuerySingleResult(t *testing.T) {
222+
nativeId := "canary-clusterrole"
223+
properties := json.RawMessage(`{"metadata":{"name":"canary-clusterrole"}}`)
224+
labelConfig := pkgmodel.LabelConfig{
225+
DefaultQuery: "$.metadata.namespace,$.metadata.name",
226+
}
227+
228+
l := newResourceLabelerForTest(t)
229+
label := l.LabelForUnmanagedResource(nativeId, "K8S::Rbac::ClusterRole", properties, labelConfig, nil)
230+
// Cluster-scoped: no namespace, only name
231+
assert.Equal(t, "canary-clusterrole", label)
232+
}
233+
209234
func newResourceLabelerForTest(t *testing.T, setup ...func(datastore.Datastore)) *resource_update.ResourceLabeler {
210235
t.Helper()
211236

0 commit comments

Comments
 (0)