Skip to content

Commit fae3716

Browse files
authored
Merge pull request #273 from tommasopozzetti/normalize-yaml
Normalize YAML manifests before running diff
2 parents 818e596 + 3ce490e commit fae3716

File tree

6 files changed

+92
-69
lines changed

6 files changed

+92
-69
lines changed

cmd/release.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@ import (
1313
)
1414

1515
type release struct {
16-
client helm.Interface
17-
detailedExitCode bool
18-
suppressedKinds []string
19-
releases []string
20-
outputContext int
21-
includeTests bool
22-
showSecrets bool
23-
output string
24-
stripTrailingCR bool
16+
client helm.Interface
17+
detailedExitCode bool
18+
suppressedKinds []string
19+
releases []string
20+
outputContext int
21+
includeTests bool
22+
showSecrets bool
23+
output string
24+
stripTrailingCR bool
25+
normalizeManifests bool
2526
}
2627

2728
const releaseCmdLongUsage = `
@@ -81,6 +82,7 @@ func releaseCmd() *cobra.Command {
8182
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
8283
releaseCmd.Flags().StringVar(&diff.output, "output", "diff", "Possible values: diff, simple, template. When set to \"template\", use the env var HELM_DIFF_TPL to specify the template.")
8384
releaseCmd.Flags().BoolVar(&diff.stripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input")
85+
releaseCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
8486

8587
releaseCmd.SuggestionsMinimumDistance = 1
8688

@@ -117,8 +119,8 @@ func (d *release) differentiateHelm3() error {
117119

118120
if releaseChart1 == releaseChart2 {
119121
seenAnyChanges := diff.Releases(
120-
manifest.Parse(string(releaseResponse1), namespace, excludes...),
121-
manifest.Parse(string(releaseResponse2), namespace, excludes...),
122+
manifest.Parse(string(releaseResponse1), namespace, d.normalizeManifests, excludes...),
123+
manifest.Parse(string(releaseResponse2), namespace, d.normalizeManifests, excludes...),
122124
d.suppressedKinds,
123125
d.showSecrets,
124126
d.outputContext,
@@ -152,8 +154,8 @@ func (d *release) differentiate() error {
152154

153155
if releaseResponse1.Release.Chart.Metadata.Name == releaseResponse2.Release.Chart.Metadata.Name {
154156
seenAnyChanges := diff.Releases(
155-
manifest.ParseRelease(releaseResponse1.Release, d.includeTests),
156-
manifest.ParseRelease(releaseResponse2.Release, d.includeTests),
157+
manifest.ParseRelease(releaseResponse1.Release, d.includeTests, d.normalizeManifests),
158+
manifest.ParseRelease(releaseResponse2.Release, d.includeTests, d.normalizeManifests),
157159
d.suppressedKinds,
158160
d.showSecrets,
159161
d.outputContext,

cmd/revision.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@ import (
1414
)
1515

1616
type revision struct {
17-
release string
18-
client helm.Interface
19-
detailedExitCode bool
20-
suppressedKinds []string
21-
revisions []string
22-
outputContext int
23-
includeTests bool
24-
showSecrets bool
25-
output string
26-
stripTrailingCR bool
17+
release string
18+
client helm.Interface
19+
detailedExitCode bool
20+
suppressedKinds []string
21+
revisions []string
22+
outputContext int
23+
includeTests bool
24+
showSecrets bool
25+
output string
26+
stripTrailingCR bool
27+
normalizeManifests bool
2728
}
2829

2930
const revisionCmdLongUsage = `
@@ -91,6 +92,7 @@ func revisionCmd() *cobra.Command {
9192
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
9293
revisionCmd.Flags().StringVar(&diff.output, "output", "diff", "Possible values: diff, simple, template. When set to \"template\", use the env var HELM_DIFF_TPL to specify the template.")
9394
revisionCmd.Flags().BoolVar(&diff.stripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input")
95+
revisionCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
9496

9597
revisionCmd.SuggestionsMinimumDistance = 1
9698

@@ -122,8 +124,8 @@ func (d *revision) differentiateHelm3() error {
122124
}
123125

124126
diff.Manifests(
125-
manifest.Parse(string(revisionResponse), namespace, excludes...),
126-
manifest.Parse(string(releaseResponse), namespace, excludes...),
127+
manifest.Parse(string(revisionResponse), namespace, d.normalizeManifests, excludes...),
128+
manifest.Parse(string(releaseResponse), namespace, d.normalizeManifests, excludes...),
127129
d.suppressedKinds,
128130
d.showSecrets,
129131
d.outputContext,
@@ -149,8 +151,8 @@ func (d *revision) differentiateHelm3() error {
149151
}
150152

151153
seenAnyChanges := diff.Manifests(
152-
manifest.Parse(string(revisionResponse1), namespace, excludes...),
153-
manifest.Parse(string(revisionResponse2), namespace, excludes...),
154+
manifest.Parse(string(revisionResponse1), namespace, d.normalizeManifests, excludes...),
155+
manifest.Parse(string(revisionResponse2), namespace, d.normalizeManifests, excludes...),
154156
d.suppressedKinds,
155157
d.showSecrets,
156158
d.outputContext,
@@ -189,8 +191,8 @@ func (d *revision) differentiate() error {
189191
}
190192

191193
diff.Manifests(
192-
manifest.ParseRelease(revisionResponse.Release, d.includeTests),
193-
manifest.ParseRelease(releaseResponse.Release, d.includeTests),
194+
manifest.ParseRelease(revisionResponse.Release, d.includeTests, d.normalizeManifests),
195+
manifest.ParseRelease(releaseResponse.Release, d.includeTests, d.normalizeManifests),
194196
d.suppressedKinds,
195197
d.showSecrets,
196198
d.outputContext,
@@ -216,8 +218,8 @@ func (d *revision) differentiate() error {
216218
}
217219

218220
seenAnyChanges := diff.Manifests(
219-
manifest.ParseRelease(revisionResponse1.Release, d.includeTests),
220-
manifest.ParseRelease(revisionResponse2.Release, d.includeTests),
221+
manifest.ParseRelease(revisionResponse1.Release, d.includeTests, d.normalizeManifests),
222+
manifest.ParseRelease(revisionResponse2.Release, d.includeTests, d.normalizeManifests),
221223
d.suppressedKinds,
222224
d.showSecrets,
223225
d.outputContext,

cmd/rollback.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@ import (
1414
)
1515

1616
type rollback struct {
17-
release string
18-
client helm.Interface
19-
detailedExitCode bool
20-
suppressedKinds []string
21-
revisions []string
22-
outputContext int
23-
includeTests bool
24-
showSecrets bool
25-
output string
26-
stripTrailingCR bool
17+
release string
18+
client helm.Interface
19+
detailedExitCode bool
20+
suppressedKinds []string
21+
revisions []string
22+
outputContext int
23+
includeTests bool
24+
showSecrets bool
25+
output string
26+
stripTrailingCR bool
27+
normalizeManifests bool
2728
}
2829

2930
const rollbackCmdLongUsage = `
@@ -83,6 +84,7 @@ func rollbackCmd() *cobra.Command {
8384
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
8485
rollbackCmd.Flags().StringVar(&diff.output, "output", "diff", "Possible values: diff, simple, template. When set to \"template\", use the env var HELM_DIFF_TPL to specify the template.")
8586
rollbackCmd.Flags().BoolVar(&diff.stripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input")
87+
rollbackCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
8688

8789
rollbackCmd.SuggestionsMinimumDistance = 1
8890

@@ -115,8 +117,8 @@ func (d *rollback) backcastHelm3() error {
115117

116118
// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
117119
seenAnyChanges := diff.Manifests(
118-
manifest.Parse(string(releaseResponse), namespace, excludes...),
119-
manifest.Parse(string(revisionResponse), namespace, excludes...),
120+
manifest.Parse(string(releaseResponse), namespace, d.normalizeManifests, excludes...),
121+
manifest.Parse(string(revisionResponse), namespace, d.normalizeManifests, excludes...),
120122
d.suppressedKinds,
121123
d.showSecrets,
122124
d.outputContext,
@@ -152,8 +154,8 @@ func (d *rollback) backcast() error {
152154

153155
// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
154156
seenAnyChanges := diff.Manifests(
155-
manifest.ParseRelease(releaseResponse.Release, d.includeTests),
156-
manifest.ParseRelease(revisionResponse.Release, d.includeTests),
157+
manifest.ParseRelease(releaseResponse.Release, d.includeTests, d.normalizeManifests),
158+
manifest.ParseRelease(revisionResponse.Release, d.includeTests, d.normalizeManifests),
157159
d.suppressedKinds,
158160
d.showSecrets,
159161
d.outputContext,

cmd/upgrade.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type diffCmd struct {
4141
output string
4242
install bool
4343
stripTrailingCR bool
44+
normalizeManifests bool
4445
}
4546

4647
func (d *diffCmd) isAllowUnreleased() bool {
@@ -121,6 +122,7 @@ func newChartCommand() *cobra.Command {
121122
f.StringVar(&diff.postRenderer, "post-renderer", "", "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
122123
f.StringVar(&diff.output, "output", "diff", "Possible values: diff, simple, json, template. When set to \"template\", use the env var HELM_DIFF_TPL to specify the template.")
123124
f.BoolVar(&diff.stripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input")
125+
f.BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
124126
if !isHelm3() {
125127
f.StringVar(&diff.namespace, "namespace", "default", "namespace to assume the release to be installed into")
126128
}
@@ -177,16 +179,16 @@ func (d *diffCmd) runHelm3() error {
177179
releaseManifest = append(releaseManifest, hooks...)
178180
}
179181
if d.includeTests {
180-
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace)
182+
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace, d.normalizeManifests)
181183
} else {
182-
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace, helm3TestHook, helm2TestSuccessHook)
184+
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace, d.normalizeManifests, helm3TestHook, helm2TestSuccessHook)
183185
}
184186
}
185187
var newSpecs map[string]*manifest.MappingResult
186188
if d.includeTests {
187-
newSpecs = manifest.Parse(string(installManifest), d.namespace)
189+
newSpecs = manifest.Parse(string(installManifest), d.namespace, d.normalizeManifests)
188190
} else {
189-
newSpecs = manifest.Parse(string(installManifest), d.namespace, helm3TestHook, helm2TestSuccessHook)
191+
newSpecs = manifest.Parse(string(installManifest), d.namespace, d.normalizeManifests, helm3TestHook, helm2TestSuccessHook)
190192
}
191193
seenAnyChanges := diff.Manifests(currentSpecs, newSpecs, d.suppressedKinds, d.showSecrets, d.outputContext, d.output, d.stripTrailingCR, os.Stdout)
192194

@@ -251,7 +253,7 @@ func (d *diffCmd) run() error {
251253
}
252254

253255
currentSpecs = make(map[string]*manifest.MappingResult)
254-
newSpecs = manifest.Parse(installResponse.Release.Manifest, installResponse.Release.Namespace)
256+
newSpecs = manifest.Parse(installResponse.Release.Manifest, installResponse.Release.Namespace, d.normalizeManifests)
255257
} else {
256258
upgradeResponse, err := d.client.UpdateRelease(
257259
d.release,
@@ -266,11 +268,11 @@ func (d *diffCmd) run() error {
266268
}
267269

268270
if d.noHooks {
269-
currentSpecs = manifest.Parse(releaseResponse.Release.Manifest, releaseResponse.Release.Namespace)
270-
newSpecs = manifest.Parse(upgradeResponse.Release.Manifest, upgradeResponse.Release.Namespace)
271+
currentSpecs = manifest.Parse(releaseResponse.Release.Manifest, releaseResponse.Release.Namespace, d.normalizeManifests)
272+
newSpecs = manifest.Parse(upgradeResponse.Release.Manifest, upgradeResponse.Release.Namespace, d.normalizeManifests)
271273
} else {
272-
currentSpecs = manifest.ParseRelease(releaseResponse.Release, d.includeTests)
273-
newSpecs = manifest.ParseRelease(upgradeResponse.Release, d.includeTests)
274+
currentSpecs = manifest.ParseRelease(releaseResponse.Release, d.includeTests, d.normalizeManifests)
275+
newSpecs = manifest.ParseRelease(upgradeResponse.Release, d.includeTests, d.normalizeManifests)
274276
}
275277
}
276278

manifest/parse.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func splitSpec(token string) (string, string) {
6868
}
6969

7070
// ParseRelease parses release objects into MappingResult
71-
func ParseRelease(release *release.Release, includeTests bool) map[string]*MappingResult {
71+
func ParseRelease(release *release.Release, includeTests bool, normalizeManifests bool) map[string]*MappingResult {
7272
manifest := release.Manifest
7373
for _, hook := range release.Hooks {
7474
if !includeTests && isTestHook(hook.Events) {
@@ -79,11 +79,11 @@ func ParseRelease(release *release.Release, includeTests bool) map[string]*Mappi
7979
manifest += fmt.Sprintf("# Source: %s\n", hook.Path)
8080
manifest += hook.Manifest
8181
}
82-
return Parse(manifest, release.Namespace)
82+
return Parse(manifest, release.Namespace, normalizeManifests)
8383
}
8484

8585
// Parse parses manifest strings into MappingResult
86-
func Parse(manifest string, defaultNamespace string, excludedHooks ...string) map[string]*MappingResult {
86+
func Parse(manifest string, defaultNamespace string, normalizeManifests bool, excludedHooks ...string) map[string]*MappingResult {
8787
// Ensure we have a newline in front of the yaml seperator
8888
scanner := bufio.NewScanner(strings.NewReader("\n" + manifest))
8989
scanner.Split(scanYamlSpecs)
@@ -100,7 +100,7 @@ func Parse(manifest string, defaultNamespace string, excludedHooks ...string) ma
100100
continue
101101
}
102102

103-
parsed, err := parseContent(content, defaultNamespace, excludedHooks...)
103+
parsed, err := parseContent(content, defaultNamespace, normalizeManifests, excludedHooks...)
104104
if err != nil {
105105
log.Fatalf("%v", err)
106106
}
@@ -121,7 +121,7 @@ func Parse(manifest string, defaultNamespace string, excludedHooks ...string) ma
121121
return result
122122
}
123123

124-
func parseContent(content string, defaultNamespace string, excludedHooks ...string) ([]*MappingResult, error) {
124+
func parseContent(content string, defaultNamespace string, normalizeManifests bool, excludedHooks ...string) ([]*MappingResult, error) {
125125
var parsedMetadata metadata
126126
if err := yaml.Unmarshal([]byte(content), &parsedMetadata); err != nil {
127127
log.Fatalf("YAML unmarshal error: %s\nCan't unmarshal %s", err, content)
@@ -152,7 +152,7 @@ func parseContent(content string, defaultNamespace string, excludedHooks ...stri
152152
log.Printf("YAML marshal error: %s\nCan't marshal %v", err, item)
153153
}
154154

155-
subs, err := parseContent(string(subcontent), defaultNamespace, excludedHooks...)
155+
subs, err := parseContent(string(subcontent), defaultNamespace, normalizeManifests, excludedHooks...)
156156
if err != nil {
157157
return nil, fmt.Errorf("Parsing YAML list item: %v", err)
158158
}
@@ -163,6 +163,21 @@ func parseContent(content string, defaultNamespace string, excludedHooks ...stri
163163
return result, nil
164164
}
165165

166+
if normalizeManifests {
167+
// Unmarshal and marshal again content to normalize yaml structure
168+
// This avoids style differences to show up as diffs but it can
169+
// make the output different from the original template (since it is in normalized form)
170+
var object map[interface{}]interface{}
171+
if err := yaml.Unmarshal([]byte(content), &object); err != nil {
172+
log.Fatalf("YAML unmarshal error: %s\nCan't unmarshal %s", err, content)
173+
}
174+
normalizedContent, err := yaml.Marshal(object)
175+
if err != nil {
176+
log.Fatalf("YAML marshal error: %s\nCan't marshal %v", err, object)
177+
}
178+
content = string(normalizedContent)
179+
}
180+
166181
if isHook(parsedMetadata, excludedHooks...) {
167182
return nil, nil
168183
}

0 commit comments

Comments
 (0)