Skip to content

Commit 4cba009

Browse files
committed
pkg.parser: add the ability to parse manifests with comments
Signed-off-by: Muvaffak Onus <[email protected]>
1 parent b689131 commit 4cba009

File tree

2 files changed

+55
-16
lines changed

2 files changed

+55
-16
lines changed

pkg/parser/parser.go

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"context"
2323
"io"
2424
"strings"
25-
"unicode"
2625

2726
"github.com/spf13/afero"
2827
corev1 "k8s.io/api/core/v1"
@@ -91,7 +90,7 @@ func New(meta, obj ObjectCreaterTyper) *PackageParser {
9190
// decode objects recognized by the meta scheme, then attempts to decode objects
9291
// recognized by the object scheme. Objects not recognized by either scheme
9392
// return an error rather than being skipped.
94-
func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package, error) { //nolint:gocyclo // Only at 11.
93+
func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package, error) {
9594
pkg := NewPackage()
9695
if reader == nil {
9796
return pkg, nil
@@ -101,27 +100,25 @@ func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package
101100
dm := json.NewSerializerWithOptions(json.DefaultMetaFactory, p.metaScheme, p.metaScheme, json.SerializerOptions{Yaml: true})
102101
do := json.NewSerializerWithOptions(json.DefaultMetaFactory, p.objScheme, p.objScheme, json.SerializerOptions{Yaml: true})
103102
for {
104-
bytes, err := yr.Read()
103+
content, err := yr.Read()
105104
if err != nil && !errors.Is(err, io.EOF) {
106105
return pkg, err
107106
}
108107
if errors.Is(err, io.EOF) {
109108
break
110109
}
111-
if len(bytes) == 0 {
110+
content = cleanYAML(content)
111+
if len(content) == 0 {
112112
continue
113113
}
114-
if isWhiteSpace(bytes) {
115-
continue
116-
}
117-
m, _, err := dm.Decode(bytes, nil, nil)
114+
m, _, err := dm.Decode(content, nil, nil)
118115
if err != nil {
119116
// NOTE(hasheddan): we only try to decode with object scheme if the
120117
// error is due the object not being registered in the meta scheme.
121118
if !runtime.IsNotRegisteredError(err) {
122119
return pkg, annotateErr(err, reader)
123120
}
124-
o, _, err := do.Decode(bytes, nil, nil)
121+
o, _, err := do.Decode(content, nil, nil)
125122
if err != nil {
126123
return pkg, annotateErr(err, reader)
127124
}
@@ -133,17 +130,27 @@ func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package
133130
return pkg, nil
134131
}
135132

136-
// isWhiteSpace determines whether the passed in bytes are all unicode white
137-
// space.
138-
func isWhiteSpace(bytes []byte) bool {
133+
// cleanYAML cleans up YAML by removing empty and commented out lines which
134+
// cause issues with decoding.
135+
func cleanYAML(y []byte) []byte {
136+
lines := []string{}
139137
empty := true
140-
for _, b := range bytes {
141-
if !unicode.IsSpace(rune(b)) {
138+
for _, line := range strings.Split(string(y), "\n") {
139+
trimmed := strings.TrimSpace(line)
140+
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
141+
continue
142+
}
143+
// We don't want to return an empty document with only separators that
144+
// have nothing in-between.
145+
if empty && trimmed != "---" && trimmed != "..." {
142146
empty = false
143-
break
144147
}
148+
lines = append(lines, line)
149+
}
150+
if empty {
151+
return nil
145152
}
146-
return empty
153+
return []byte(strings.Join(lines, "\n"))
147154
}
148155

149156
// annotateErr annotates an error if the reader is an AnnotatedReadCloser.

pkg/parser/parser_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ metadata:
5555

5656
deployBytes = []byte(`apiVersion: apps/v1
5757
kind: Deployment
58+
metadata:
59+
name: test`)
60+
61+
commentedOutBytes = []byte(`# apiVersion: apps/v1
62+
# kind: Deployment
63+
# metadata:
64+
# name: test`)
65+
manifestWithComments = []byte(`
66+
apiVersion: apiextensions.k8s.io/v1beta1
67+
# Some Comment
68+
kind: CustomResourceDefinition
5869
metadata:
5970
name: test`)
6071

@@ -79,6 +90,9 @@ func TestParser(t *testing.T) {
7990
emptyFs := afero.NewMemMapFs()
8091
_ = afero.WriteFile(emptyFs, "empty.yaml", []byte(""), 0o644)
8192
_ = afero.WriteFile(emptyFs, "bad.yam", []byte("definitely not yaml"), 0o644)
93+
commentedFs := afero.NewMemMapFs()
94+
_ = afero.WriteFile(commentedFs, "commented.yaml", commentedOutBytes, 0o644)
95+
_ = afero.WriteFile(commentedFs, ".crossplane/realmanifest.yaml", manifestWithComments, 0o644)
8296
objScheme := runtime.NewScheme()
8397
_ = apiextensions.AddToScheme(objScheme)
8498
metaScheme := runtime.NewScheme()
@@ -128,6 +142,24 @@ func TestParser(t *testing.T) {
128142
objects: []runtime.Object{crd, crd, crd, crd},
129143
},
130144
},
145+
"FsBackendCommentedOut": {
146+
reason: "should parse filesystem successfully even if all the files are commented out",
147+
parser: New(metaScheme, objScheme),
148+
backend: NewFsBackend(commentedFs, FsDir("."), FsFilters(SkipDirs(), SkipNotYAML(), SkipPath(".crossplane/*"))),
149+
pkg: &Package{
150+
meta: nil,
151+
objects: nil,
152+
},
153+
},
154+
"FsBackendWithComments": {
155+
reason: "should parse filesystem successfully when some of the manifests contain comments",
156+
parser: New(metaScheme, objScheme),
157+
backend: NewFsBackend(commentedFs, FsDir("."), FsFilters(SkipDirs(), SkipNotYAML())),
158+
pkg: &Package{
159+
meta: nil,
160+
objects: []runtime.Object{crd},
161+
},
162+
},
131163
"FsBackendAll": {
132164
reason: "should parse filesystem successfully with multiple objects in single file",
133165
parser: New(metaScheme, objScheme),

0 commit comments

Comments
 (0)