Skip to content

Commit 50360e9

Browse files
authored
Preserve field order when updating kustomization.yaml file (argoproj-labs#666)
Signed-off-by: Jaye Doepke <[email protected]>
1 parent 2bf4b0a commit 50360e9

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed

pkg/argocd/git.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"sigs.k8s.io/kustomize/api/konfig"
1414
"sigs.k8s.io/kustomize/api/types"
15+
"sigs.k8s.io/kustomize/kyaml/order"
1516
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
1617

1718
"github.com/argoproj-labs/argocd-image-updater/pkg/image"
@@ -327,14 +328,43 @@ func writeKustomization(app *v1alpha1.Application, wbc *WriteBackConfig, gitC gi
327328
if err != nil {
328329
return err, false
329330
}
330-
err = kyaml.UpdateFile(filterFunc, kustFile)
331-
if err != nil {
331+
332+
if err = updateKustomizeFile(filterFunc, kustFile); err != nil {
332333
return err, false
333334
}
334335

335336
return nil, false
336337
}
337338

339+
// updateKustomizeFile reads the kustomization file at path, applies the filter to it, and writes the result back
340+
// to the file. This is the same behavior as kyaml.UpdateFile, but it preserves the original order
341+
// of YAML fields to minimize git diffs.
342+
func updateKustomizeFile(filter kyaml.Filter, path string) error {
343+
// Read the yaml
344+
y, err := kyaml.ReadFile(path)
345+
if err != nil {
346+
return err
347+
}
348+
349+
// Update the yaml
350+
yCpy := y.Copy()
351+
if err := yCpy.PipeE(filter); err != nil {
352+
return err
353+
}
354+
355+
// Preserve the original order of fields
356+
if err := order.SyncOrder(y, yCpy); err != nil {
357+
return err
358+
}
359+
360+
// Write the yaml
361+
if err := kyaml.WriteFile(yCpy, path); err != nil {
362+
return err
363+
}
364+
365+
return nil
366+
}
367+
338368
func imagesFilter(images v1alpha1.KustomizeImages) (kyaml.Filter, error) {
339369
var overrides []kyaml.Filter
340370
for _, img := range images {

pkg/argocd/git_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package argocd
22

33
import (
4+
"os"
45
"testing"
56
"text/template"
67
"time"
@@ -215,3 +216,74 @@ images:
215216
})
216217
}
217218
}
219+
220+
func Test_updateKustomizeFile(t *testing.T) {
221+
makeTmpKustomization := func(t *testing.T, content []byte) string {
222+
f, err := os.CreateTemp("", "kustomization-*.yaml")
223+
if err != nil {
224+
t.Fatal(err)
225+
}
226+
_, err = f.Write(content)
227+
if err != nil {
228+
t.Fatal(err)
229+
}
230+
f.Close()
231+
t.Cleanup(func() {
232+
os.Remove(f.Name())
233+
})
234+
return f.Name()
235+
}
236+
237+
filter, err := imagesFilter(v1alpha1.KustomizeImages{"foo@sha23456"})
238+
if err != nil {
239+
t.Fatal(err)
240+
}
241+
242+
tests := []struct {
243+
name string
244+
content string
245+
wantContent string
246+
filter kyaml.Filter
247+
wantErr bool
248+
}{
249+
{
250+
name: "sorted",
251+
content: `images:
252+
- digest: sha12345
253+
name: foo
254+
`,
255+
wantContent: `images:
256+
- digest: sha23456
257+
name: foo
258+
`,
259+
filter: filter,
260+
},
261+
{
262+
name: "not-sorted",
263+
content: `images:
264+
- name: foo
265+
digest: sha12345
266+
`,
267+
wantContent: `images:
268+
- name: foo
269+
digest: sha23456
270+
`,
271+
filter: filter,
272+
},
273+
}
274+
for _, tt := range tests {
275+
t.Run(tt.name, func(t *testing.T) {
276+
path := makeTmpKustomization(t, []byte(tt.content))
277+
err := updateKustomizeFile(tt.filter, path)
278+
if tt.wantErr {
279+
assert.Error(t, err)
280+
} else {
281+
got, err := os.ReadFile(path)
282+
if err != nil {
283+
t.Fatal(err)
284+
}
285+
assert.Equal(t, tt.wantContent, string(got))
286+
}
287+
})
288+
}
289+
}

0 commit comments

Comments
 (0)