diff --git a/api/internal/builtins/PrefixTransformer.go b/api/internal/builtins/PrefixTransformer.go index ef60d3e7903..03040ce0f9f 100644 --- a/api/internal/builtins/PrefixTransformer.go +++ b/api/internal/builtins/PrefixTransformer.go @@ -19,6 +19,7 @@ type PrefixTransformerPlugin struct { FieldSpecs types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` } +// TODO: Make this gvk skip list part of the config. var prefixFieldSpecsToSkip = types.FsSlice{ {Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}}, {Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}}, diff --git a/api/internal/builtins/SuffixTransformer.go b/api/internal/builtins/SuffixTransformer.go index 09a2d697700..2b389d8e55e 100644 --- a/api/internal/builtins/SuffixTransformer.go +++ b/api/internal/builtins/SuffixTransformer.go @@ -19,6 +19,7 @@ type SuffixTransformerPlugin struct { FieldSpecs types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` } +// TODO: Make this gvk skip list part of the config. var suffixFieldSpecsToSkip = types.FsSlice{ {Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}}, {Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}}, diff --git a/api/krusty/legacy_order_test.go b/api/krusty/legacy_order_test.go new file mode 100644 index 00000000000..f8b37b11fd3 --- /dev/null +++ b/api/krusty/legacy_order_test.go @@ -0,0 +1,62 @@ +package krusty_test + +import ( + "testing" + + kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest" +) + +func TestIssue4388(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteK(".", ` +resources: +- resources.yaml +`) + th.WriteF("resources.yaml", ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: testing +data: + key: value +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: testing-one +data: + key: value +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: testing-two +data: + key: value +`) + opts := th.MakeDefaultOptions() + opts.DoLegacyResourceSort = true + m := th.Run(".", opts) + th.AssertActualEqualsExpected(m, ` +apiVersion: v1 +data: + key: value +kind: ConfigMap +metadata: + name: testing +--- +apiVersion: v1 +data: + key: value +kind: ConfigMap +metadata: + name: testing-one +--- +apiVersion: v1 +data: + key: value +kind: ConfigMap +metadata: + name: testing-two +`) +} diff --git a/api/resmap/idslice.go b/api/resmap/idslice.go index a13d9d3c943..8c25cbb2a37 100644 --- a/api/resmap/idslice.go +++ b/api/resmap/idslice.go @@ -33,5 +33,5 @@ func (a IdSlice) Less(i, j int) bool { if !a[i].Gvk.Equals(a[j].Gvk) { return a[i].Gvk.IsLessThan(a[j].Gvk) } - return a[i].String() < a[j].String() + return a[i].LegacySortString() < a[j].LegacySortString() } diff --git a/kyaml/resid/gvk.go b/kyaml/resid/gvk.go index 6279b739ccd..2c8cbb1f5d7 100644 --- a/kyaml/resid/gvk.go +++ b/kyaml/resid/gvk.go @@ -97,6 +97,29 @@ func (x Gvk) String() string { return strings.Join([]string{k, v, g}, fieldSep) } +// legacySortString returns an older version of String() that LegacyOrderTransformer depends on +// to keep its ordering stable across Kustomize versions +func (x Gvk) legacySortString() string { + legacyNoGroup := "~G" + legacyNoVersion := "~V" + legacyNoKind := "~K" + legacyFieldSeparator := "_" + + g := x.Group + if g == "" { + g = legacyNoGroup + } + v := x.Version + if v == "" { + v = legacyNoVersion + } + k := x.Kind + if k == "" { + k = legacyNoKind + } + return strings.Join([]string{g, v, k}, legacyFieldSeparator) +} + // ApiVersion returns the combination of Group and Version func (x Gvk) ApiVersion() string { var sb strings.Builder @@ -180,7 +203,7 @@ func (x Gvk) IsLessThan(o Gvk) bool { if indexI != indexJ { return indexI < indexJ } - return x.String() < o.String() + return x.legacySortString() < o.legacySortString() } // IsSelected returns true if `selector` selects `x`; otherwise, false. diff --git a/kyaml/resid/resid.go b/kyaml/resid/resid.go index cddbcdde60f..f786f136607 100644 --- a/kyaml/resid/resid.go +++ b/kyaml/resid/resid.go @@ -60,6 +60,25 @@ func (id ResId) String() string { []string{id.Gvk.String(), strings.Join([]string{nm, ns}, fieldSep)}, separator) } +// LegacySortString returns an older version of String() that LegacyOrderTransformer depends on +// to keep its ordering stable across Kustomize versions +func (id ResId) LegacySortString() string { + legacyNoNamespace := "~X" + legacyNoName := "~N" + legacySeparator := "|" + + ns := id.Namespace + if ns == "" { + ns = legacyNoNamespace + } + nm := id.Name + if nm == "" { + nm = legacyNoName + } + return strings.Join( + []string{id.Gvk.String(), ns, nm}, legacySeparator) +} + func FromString(s string) ResId { values := strings.Split(s, separator) gvk := GvkFromString(values[0])