diff --git a/kustomize/commands/internal/kustfile/kustomizationfile.go b/kustomize/commands/internal/kustfile/kustomizationfile.go index 1f9e5f22bb..480eac473a 100644 --- a/kustomize/commands/internal/kustfile/kustomizationfile.go +++ b/kustomize/commands/internal/kustfile/kustomizationfile.go @@ -40,6 +40,7 @@ func determineFieldOrder() []string { ordered := []string{ "MetaData", + "SortOptions", "Resources", "Bases", "NamePrefix", @@ -65,6 +66,7 @@ func determineFieldOrder() []string { "Configurations", "Generators", "Transformers", + "Validators", "Components", "OpenAPI", "BuildMetadata", diff --git a/kustomize/commands/internal/kustfile/kustomizationfile_test.go b/kustomize/commands/internal/kustfile/kustomizationfile_test.go index 87d2f0fc67..846ca81748 100644 --- a/kustomize/commands/internal/kustfile/kustomizationfile_test.go +++ b/kustomize/commands/internal/kustfile/kustomizationfile_test.go @@ -5,6 +5,7 @@ package kustfile import ( "reflect" + "slices" "strings" "testing" @@ -21,6 +22,7 @@ func TestFieldOrder(t *testing.T) { "APIVersion", "Kind", "MetaData", + "SortOptions", "Resources", "Bases", "NamePrefix", @@ -46,6 +48,7 @@ func TestFieldOrder(t *testing.T) { "Configurations", "Generators", "Transformers", + "Validators", "Components", "OpenAPI", "BuildMetadata", @@ -87,6 +90,154 @@ func TestWriteAndRead(t *testing.T) { } } +func TestReadAndWrite(t *testing.T) { + kWrite := []byte(completeKustfileInOrder) + + fSys := filesys.MakeFsInMemory() + testutils_test.WriteTestKustomizationWith(fSys, kWrite) + mf, err := NewKustomizationFile(fSys) + if err != nil { + t.Fatalf("Unexpected Error: %v", err) + } + + kustomization, err := mf.Read() + if err != nil { + t.Fatalf("Unexpected Error: %v", err) + } + + if err := mf.Write(kustomization); err != nil { + t.Fatalf("Couldn't write kustomization file: %v\n", err) + } + + kRead, err := testutils_test.ReadTestKustomization(fSys) + if err != nil { + t.Fatalf("Unexpected Error: %v", err) + } + + if !reflect.DeepEqual(kWrite, kRead) { + t.Fatal("Written kustomization is different from read kustomization") + } +} + +func TestReadAndWriteDummy(t *testing.T) { + kWrite := &types.Kustomization{ + TypeMeta: types.TypeMeta{ + APIVersion: "kustomize.config.k8s.io/v1beta1", + Kind: "Kustomization", + }, + MetaData: &types.ObjectMeta{ + Name: "name", + Namespace: "namespace", + Labels: map[string]string{"label": "label"}, + Annotations: map[string]string{"annotation": "annotation"}, + }, + OpenAPI: map[string]string{"path": "schema.json"}, + NamePrefix: "prefix", + NameSuffix: "suffix", + Namespace: "namespace", + CommonLabels: map[string]string{"commonLabel": "commonLabel"}, + Labels: []types.Label{{ + Pairs: map[string]string{"label": "label"}, + IncludeSelectors: true, + IncludeTemplates: true, + FieldSpecs: []types.FieldSpec{{ + Path: "metadata.labels.label", + }}, + }}, + CommonAnnotations: map[string]string{"commonAnnotation": "commonAnnotation"}, + Patches: []types.Patch{{ + Path: "path", + }}, + Images: []types.Image{{ + Name: "name", + NewName: "newName", + TagSuffix: "tagSuffix", + NewTag: "newTag", + Digest: "digest", + }}, + Replacements: []types.ReplacementField{{ + Path: "path", + }}, + Replicas: []types.Replica{{ + Name: "name", + Count: 1, + }}, + SortOptions: &types.SortOptions{ + Order: types.LegacySortOrder, + LegacySortOptions: &types.LegacySortOptions{ + OrderFirst: []string{"orderFirst"}, + OrderLast: []string{"orderLast"}, + }, + }, + Resources: []string{"resource"}, + Components: []string{"component"}, + Crds: []string{"crd"}, + ConfigMapGenerator: []types.ConfigMapArgs{{ + GeneratorArgs: types.GeneratorArgs{ + Namespace: "namespace", + Name: "name", + }, + }}, + SecretGenerator: []types.SecretArgs{{ + GeneratorArgs: types.GeneratorArgs{ + Namespace: "namespace", + Name: "name", + }, + }}, + HelmGlobals: &types.HelmGlobals{ + ChartHome: "chartHome", + ConfigHome: "configHome", + }, + HelmCharts: []types.HelmChart{{ + Name: "name", + }}, + GeneratorOptions: &types.GeneratorOptions{ + Labels: map[string]string{"label": "label"}, + }, + Configurations: []string{"configuration"}, + Generators: []string{"generator"}, + Transformers: []string{"transformer"}, + Validators: []string{"validator"}, + BuildMetadata: []string{"buildMetadata"}, + } + + // this check is for forward compatibility: if this fails, add a dummy value to the Kustomization above + assertAllNonZeroExcept(t, kWrite, []string{"PatchesStrategicMerge", "PatchesJson6902", "ImageTags", "Vars", "Bases", "HelmChartInflationGenerator"}) + + fSys := filesys.MakeFsInMemory() + testutils_test.WriteTestKustomization(fSys) + mf, err := NewKustomizationFile(fSys) + if err != nil { + t.Fatalf("Unexpected Error: %v", err) + } + + if err := mf.Write(kWrite); err != nil { + t.Fatalf("Couldn't write kustomization file: %v\n", err) + } + + kRead, err := mf.Read() + if err != nil { + t.Fatalf("Unexpected Error: %v", err) + } + + if !reflect.DeepEqual(kWrite, kRead) { + t.Fatal("Written kustomization is different from read kustomization.") + } +} + +func assertAllNonZeroExcept(t *testing.T, val *types.Kustomization, except []string) { + fFor := reflect.ValueOf(val).Elem() + n := fFor.NumField() + for i := 0; i < n; i++ { + key := fFor.Type().Field(i).Name + val := fFor.Field(i) + if val.IsZero() && !slices.Contains(except, key) { + t.Helper() + t.Fatalf("Key %s should not be empty", key) + } + } +} + func TestGetPath(t *testing.T) { fSys := filesys.MakeEmptyDirInMemory() testutils_test.WriteTestKustomization(fSys) @@ -386,3 +537,80 @@ foo: t.Fatalf("Expect an unknown field error but got: %v", err) } } + +const completeKustfileInOrder = ` +kind: Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +metadata: + annotations: + annotation: annotation + labels: + label: label + name: name + namespace: namespace +openapi: + path: schema.json +namePrefix: prefix +nameSuffix: suffix +namespace: namespace +commonLabels: + commonLabel: commonLabel +labels: +- fields: + - path: metadata.labels.label + includeSelectors: true + includeTemplates: true + pairs: + label: label +commonAnnotations: + commonAnnotation: commonAnnotation +patches: +- path: path +images: +- digest: digest + name: name + newName: newName + newTag: newTag + tagSuffix: tagSuffix +replacements: +- path: path +replicas: +- count: 1 + name: name +sortOptions: + legacySortOptions: + orderFirst: + - orderFirst + orderLast: + - orderLast + order: legacy +resources: +- resource +components: +- component +crds: +- crd +configMapGenerator: +- name: name + namespace: namespace +secretGenerator: +- name: name + namespace: namespace +helmGlobals: + chartHome: chartHome + configHome: configHome +helmCharts: +- name: name +- name: chartName +generatorOptions: + labels: + label: label +configurations: +- configuration +generators: +- generator +transformers: +- transformer +buildMetadata: +- buildMetadata +`