diff --git a/api/filters/replacement/replacement_test.go b/api/filters/replacement/replacement_test.go index 76294ef24..35919734b 100644 --- a/api/filters/replacement/replacement_test.go +++ b/api/filters/replacement/replacement_test.go @@ -1338,6 +1338,34 @@ spec: `, expectedErr: "delimiter option can only be used with scalar nodes", }, + "mapping value contains '.' character": { + input: `apiVersion: v1 +kind: Custom +metadata: + name: custom + annotations: + a.b.c/d-e: source + f.g.h/i-j: target +`, + replacements: `replacements: +- source: + name: custom + fieldPath: metadata.annotations.[a.b.c/d-e] + targets: + - select: + name: custom + fieldPaths: + - metadata.annotations.[f.g.h/i-j] +`, + expected: `apiVersion: v1 +kind: Custom +metadata: + name: custom + annotations: + a.b.c/d-e: source + f.g.h/i-j: source +`, + }, "list index contains '.' character": { input: `apiVersion: v1 kind: ConfigMap diff --git a/api/internal/utils/pathsplitter.go b/api/internal/utils/pathsplitter.go index 002f43bb4..aa560299f 100644 --- a/api/internal/utils/pathsplitter.go +++ b/api/internal/utils/pathsplitter.go @@ -23,12 +23,17 @@ func PathSplitter(path string, delimiter string) []string { return res } -// SmarterPathSplitter splits a path, retaining bracketed list entry identifiers. -// E.g. [name=com.foo.someapp] survives as one thing after splitting +// SmarterPathSplitter splits a path, retaining bracketed elements. +// If the element is a list entry identifier (defined by the '='), +// it will retain the brackets. +// E.g. "[name=com.foo.someapp]" survives as one thing after splitting // "spec.template.spec.containers.[name=com.foo.someapp].image" // See kyaml/yaml/match.go for use of list entry identifiers. -// This function uses `PathSplitter`, so it respects list entry identifiers -// and escaped delimiters. +// If the element is a mapping entry identifier, it will remove the +// brackets. +// E.g. "a.b.c" survives as one thing after splitting +// "metadata.annotations.[a.b.c] +// This function uses `PathSplitter`, so it also respects escaped delimiters. func SmarterPathSplitter(path string, delimiter string) []string { var result []string split := PathSplitter(path, delimiter) @@ -45,7 +50,12 @@ func SmarterPathSplitter(path string, delimiter string) []string { break } } - result = append(result, strings.Join(bracketed, delimiter)) + bracketedStr := strings.Join(bracketed, delimiter) + if strings.Contains(bracketedStr, "=") { + result = append(result, bracketedStr) + } else { + result = append(result, strings.Trim(bracketedStr, "[]")) + } } else { result = append(result, elem) } diff --git a/api/internal/utils/pathsplitter_test.go b/api/internal/utils/pathsplitter_test.go index 5e133f572..21dcc8391 100644 --- a/api/internal/utils/pathsplitter_test.go +++ b/api/internal/utils/pathsplitter_test.go @@ -81,6 +81,10 @@ func TestSmarterPathSplitter(t *testing.T) { input: "spec.data.[name=f.i.[r.s.t..key", expected: []string{"spec", "data", "[name=f.i.[r.s.t..key"}, }, + "mapping value with .": { + input: "metadata.annotations.[a.b.c/d.e.f-g.]", + expected: []string{"metadata", "annotations", "a.b.c/d.e.f-g."}, + }, } for tn, tc := range testCases { t.Run(tn, func(t *testing.T) {