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

Make seq indent configurable and add retain seq indent functionality #4043

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
68 changes: 66 additions & 2 deletions kyaml/kio/byteio_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sort"
"strings"

"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/kustomize/kyaml/yaml"
Expand Down Expand Up @@ -47,12 +48,16 @@ type ByteReadWriter struct {
NoWrap bool
WrappingAPIVersion string
WrappingKind string

// RetainSeqIndent if true retains the sequence indentation of
RetainSeqIndent bool
}

func (rw *ByteReadWriter) Read() ([]*yaml.RNode, error) {
b := &ByteReader{
Reader: rw.Reader,
OmitReaderAnnotations: rw.OmitReaderAnnotations,
Reader: rw.Reader,
OmitReaderAnnotations: rw.OmitReaderAnnotations,
AddSeqIndentAnnotation: rw.RetainSeqIndent,
}
val, err := b.Read()
if rw.FunctionConfig == nil {
Expand Down Expand Up @@ -130,6 +135,9 @@ type ByteReader struct {
// WrappingKind is set by Read(), and is the kind of the object that
// the read objects were originally wrapped in.
WrappingKind string

// AddSeqIndentAnnotation if true adds kioutil.SeqIndentAnnotation to each resource
AddSeqIndentAnnotation bool
}

var _ Reader = &ByteReader{}
Expand Down Expand Up @@ -195,6 +203,13 @@ func (r *ByteReader) Read() ([]*yaml.RNode, error) {
if err == io.EOF {
continue
}

if r.AddSeqIndentAnnotation {
if err := addSeqIndentAnno(values[i], node); err != nil {
return nil, errors.Wrap(err)
}
}

if err != nil {
return nil, errors.Wrap(err)
}
Expand Down Expand Up @@ -245,6 +260,55 @@ func (r *ByteReader) Read() ([]*yaml.RNode, error) {
return output, nil
}

// addSeqIndentAnno adds the sequence indentation annotation to the resource
// value is the input yaml string and node is the decoded equivalent of value
// the annotation value is decided by deriving the existing sequence indentation of resource
func addSeqIndentAnno(value string, node *yaml.RNode) error {
anno := node.GetAnnotations()
if anno[kioutil.SeqIndentAnnotation] != "" {
// the annotation already exists, so don't change it
return nil
}

currentDefaultIndent := yaml.SequenceIndentationStyle()
defer yaml.SetSequenceIndentationStyle(currentDefaultIndent)

// encode the node to string with default 2 space sequence indentation and calculate the diff
yaml.SetSequenceIndentationStyle(yaml.WideSequenceStyle)
n, err := yaml.Parse(value)
if err != nil {
return err
}
out, err := n.String()
if err != nil {
return err
}
twoSpaceIndentDiff := copyutil.PrettyFileDiff(out, value)

// encode the node to string with compact 0 space sequence indentation and calculate the diff
yaml.SetSequenceIndentationStyle(yaml.CompactSequenceStyle)
n, err = yaml.Parse(value)
if err != nil {
return err
}
out, err = n.String()
if err != nil {
return err
}
noIndentDiff := copyutil.PrettyFileDiff(out, value)

var style string
if len(noIndentDiff) <= len(twoSpaceIndentDiff) {
style = yaml.CompactSequenceStyle
} else {
style = yaml.WideSequenceStyle
}

return node.PipeE(
yaml.LookupCreate(yaml.MappingNode, yaml.MetadataField, yaml.AnnotationsField),
yaml.SetField(kioutil.SeqIndentAnnotation, yaml.NewScalarRNode(style)))
}

func (r *ByteReader) decode(index int, decoder *yaml.Decoder) (*yaml.RNode, error) {
node := &yaml.Node{}
err := decoder.Decode(node)
Expand Down
119 changes: 119 additions & 0 deletions kyaml/kio/byteio_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,3 +805,122 @@ items:
})
}
}

func TestByteReader_RetainSeqIndent(t *testing.T) {
type testCase struct {
name string
err string
input string
expectedOutput string
}

testCases := []testCase{
{
name: "read with wide indentation",
input: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
`,
expectedOutput: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
metadata:
annotations:
internal.config.kubernetes.io/seqindent: wide
`,
},
{
name: "read with compact indentation",
input: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
`,
expectedOutput: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
metadata:
annotations:
internal.config.kubernetes.io/seqindent: compact
`,
},
{
name: "read with mixed indentation, wide wins",
input: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
env:
- foo
- bar
`,
expectedOutput: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
env:
- foo
- bar
metadata:
annotations:
internal.config.kubernetes.io/seqindent: wide
`,
},
{
name: "read with mixed indentation, compact wins",
input: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
env:
- foo
- bar
`,
expectedOutput: `apiVersion: apps/v1
kind: Deployment
spec:
- foo
- bar
- baz
env:
- foo
- bar
metadata:
annotations:
internal.config.kubernetes.io/seqindent: compact
`,
},
}

for i := range testCases {
tc := testCases[i]
t.Run(tc.name, func(t *testing.T) {
rNodes, err := (&ByteReader{
OmitReaderAnnotations: true,
AddSeqIndentAnnotation: true,
Reader: bytes.NewBuffer([]byte(tc.input)),
}).Read()
assert.NoError(t, err)
actual, err := rNodes[0].String()
assert.NoError(t, err)
assert.Equal(t, tc.expectedOutput, actual)
})
}
}
Loading