Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep yaml sequence indentation when writing back to Git to a kustomize file #1002

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 53 additions & 12 deletions pkg/argocd/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"os"
"path"
Expand All @@ -12,6 +13,7 @@ import (

"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/order"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"

Expand Down Expand Up @@ -345,43 +347,82 @@ func writeKustomization(app *v1alpha1.Application, wbc *WriteBackConfig, gitC gi
}

// updateKustomizeFile reads the kustomization file at path, applies the filter to it, and writes the result back
// to the file. This is the same behavior as kyaml.UpdateFile, but it preserves the original order
// of YAML fields to minimize git diffs.
// to the file. This is the same behavior as kyaml.UpdateFile, but it preserves the original order of YAML fields
// and indentation of YAML sequences to minimize git diffs.
func updateKustomizeFile(filter kyaml.Filter, path string) (error, bool) {
// Read the yaml
y, err := kyaml.ReadFile(path)
// Open the input file for read
yRaw, err := os.ReadFile(path)
if err != nil {
return err, false
}

originalData, err := y.String()
// Read the yaml document from bytes
originalYSlice, err := kio.FromBytes(yRaw)
if err != nil {
return err, false
}

// Check that we are dealing with a single document
if len(originalYSlice) != 1 {
return errors.New("target parameter file should contain a single YAML document"), false
}
originalY := originalYSlice[0]

// Get the (parsed) original document
originalData, err := originalY.String()
if err != nil {
return err, false
}

// Create a reader, preserving indentation of sequences
var out bytes.Buffer
rw := &kio.ByteReadWriter{
Reader: bytes.NewBuffer(yRaw),
Writer: &out,
PreserveSeqIndent: true,
}

// Read input file
newYSlice, err := rw.Read()
if err != nil {
return err, false
}
// We can safely assume we have a single document from the previous check
newY := newYSlice[0]

// Update the yaml
yCpy := y.Copy()
if err := yCpy.PipeE(filter); err != nil {
if err := newY.PipeE(filter); err != nil {
return err, false
}

// Preserve the original order of fields
if err := order.SyncOrder(y, yCpy); err != nil {
if err := order.SyncOrder(originalY, newY); err != nil {
return err, false
}

override, err := yCpy.String()
// Write the yaml document to the output buffer
if err = rw.Write([]*kyaml.RNode{newY}); err != nil {
return err, false
}

// yCpy contains metadata used by kio to preserve sequence indentation,
// hence we need to parse the output buffer instead
newParsedY, err := kyaml.Parse(out.String())
if err != nil {
return err, false
}
newData, err := newParsedY.String()
if err != nil {
return err, false
}

if originalData == override {
// Diff the updated document with the original
if originalData == newData {
log.Debugf("target parameter file and marshaled data are the same, skipping commit.")
return nil, true
}

// Write the yaml
if err := os.WriteFile(path, []byte(override), 0600); err != nil {
if err := os.WriteFile(path, out.Bytes(), 0600); err != nil {
return err, false
}

Expand Down
12 changes: 12 additions & 0 deletions pkg/argocd/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,18 @@ func Test_updateKustomizeFile(t *testing.T) {
wantContent: `images:
- name: foo
digest: sha23456
`,
filter: filter,
},
{
name: "indented",
content: `images:
- name: foo
digest: sha12345
`,
wantContent: `images:
- name: foo
digest: sha23456
`,
chengfang marked this conversation as resolved.
Show resolved Hide resolved
filter: filter,
},
Expand Down
Loading