Skip to content

Commit

Permalink
Make seq indent configurable and add retain seq indent functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
phanimarupaka committed Jul 7, 2021
1 parent e1804cb commit ed38b5f
Show file tree
Hide file tree
Showing 7 changed files with 509 additions and 6 deletions.
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

0 comments on commit ed38b5f

Please sign in to comment.