Skip to content

Commit cbb60e1

Browse files
Add --normalize-manifests flag to control manifest normalization behavior
1 parent bdb0ab0 commit cbb60e1

File tree

6 files changed

+88
-75
lines changed

6 files changed

+88
-75
lines changed

cmd/release.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ 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
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+
normalizeManifests bool
2425
}
2526

2627
const releaseCmdLongUsage = `
@@ -79,6 +80,7 @@ func releaseCmd() *cobra.Command {
7980
releaseCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
8081
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
8182
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.")
83+
releaseCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
8284

8385
releaseCmd.SuggestionsMinimumDistance = 1
8486

@@ -115,8 +117,8 @@ func (d *release) differentiateHelm3() error {
115117

116118
if releaseChart1 == releaseChart2 {
117119
seenAnyChanges := diff.Releases(
118-
manifest.Parse(string(releaseResponse1), namespace, excludes...),
119-
manifest.Parse(string(releaseResponse2), namespace, excludes...),
120+
manifest.Parse(string(releaseResponse1), namespace, d.normalizeManifests, excludes...),
121+
manifest.Parse(string(releaseResponse2), namespace, d.normalizeManifests, excludes...),
120122
d.suppressedKinds,
121123
d.showSecrets,
122124
d.outputContext,
@@ -149,8 +151,8 @@ func (d *release) differentiate() error {
149151

150152
if releaseResponse1.Release.Chart.Metadata.Name == releaseResponse2.Release.Chart.Metadata.Name {
151153
seenAnyChanges := diff.Releases(
152-
manifest.ParseRelease(releaseResponse1.Release, d.includeTests),
153-
manifest.ParseRelease(releaseResponse2.Release, d.includeTests),
154+
manifest.ParseRelease(releaseResponse1.Release, d.includeTests, d.normalizeManifests),
155+
manifest.ParseRelease(releaseResponse2.Release, d.includeTests, d.normalizeManifests),
154156
d.suppressedKinds,
155157
d.showSecrets,
156158
d.outputContext,

cmd/revision.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ 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
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+
normalizeManifests bool
2627
}
2728

2829
const revisionCmdLongUsage = `
@@ -89,6 +90,7 @@ func revisionCmd() *cobra.Command {
8990
revisionCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
9091
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
9192
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.")
93+
revisionCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
9294

9395
revisionCmd.SuggestionsMinimumDistance = 1
9496

@@ -120,8 +122,8 @@ func (d *revision) differentiateHelm3() error {
120122
}
121123

122124
diff.Manifests(
123-
manifest.Parse(string(revisionResponse), namespace, excludes...),
124-
manifest.Parse(string(releaseResponse), namespace, excludes...),
125+
manifest.Parse(string(revisionResponse), namespace, d.normalizeManifests, excludes...),
126+
manifest.Parse(string(releaseResponse), namespace, d.normalizeManifests, excludes...),
125127
d.suppressedKinds,
126128
d.showSecrets,
127129
d.outputContext,
@@ -146,8 +148,8 @@ func (d *revision) differentiateHelm3() error {
146148
}
147149

148150
seenAnyChanges := diff.Manifests(
149-
manifest.Parse(string(revisionResponse1), namespace, excludes...),
150-
manifest.Parse(string(revisionResponse2), namespace, excludes...),
151+
manifest.Parse(string(revisionResponse1), namespace, d.normalizeManifests, excludes...),
152+
manifest.Parse(string(revisionResponse2), namespace, d.normalizeManifests, excludes...),
151153
d.suppressedKinds,
152154
d.showSecrets,
153155
d.outputContext,
@@ -185,8 +187,8 @@ func (d *revision) differentiate() error {
185187
}
186188

187189
diff.Manifests(
188-
manifest.ParseRelease(revisionResponse.Release, d.includeTests),
189-
manifest.ParseRelease(releaseResponse.Release, d.includeTests),
190+
manifest.ParseRelease(revisionResponse.Release, d.includeTests, d.normalizeManifests),
191+
manifest.ParseRelease(releaseResponse.Release, d.includeTests, d.normalizeManifests),
190192
d.suppressedKinds,
191193
d.showSecrets,
192194
d.outputContext,
@@ -211,8 +213,8 @@ func (d *revision) differentiate() error {
211213
}
212214

213215
seenAnyChanges := diff.Manifests(
214-
manifest.ParseRelease(revisionResponse1.Release, d.includeTests),
215-
manifest.ParseRelease(revisionResponse2.Release, d.includeTests),
216+
manifest.ParseRelease(revisionResponse1.Release, d.includeTests, d.normalizeManifests),
217+
manifest.ParseRelease(revisionResponse2.Release, d.includeTests, d.normalizeManifests),
216218
d.suppressedKinds,
217219
d.showSecrets,
218220
d.outputContext,

cmd/rollback.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ 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
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+
normalizeManifests bool
2627
}
2728

2829
const rollbackCmdLongUsage = `
@@ -81,6 +82,7 @@ func rollbackCmd() *cobra.Command {
8182
rollbackCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
8283
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
8384
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.")
85+
rollbackCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
8486

8587
rollbackCmd.SuggestionsMinimumDistance = 1
8688

@@ -113,8 +115,8 @@ func (d *rollback) backcastHelm3() error {
113115

114116
// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
115117
seenAnyChanges := diff.Manifests(
116-
manifest.Parse(string(releaseResponse), namespace, excludes...),
117-
manifest.Parse(string(revisionResponse), namespace, excludes...),
118+
manifest.Parse(string(releaseResponse), namespace, d.normalizeManifests, excludes...),
119+
manifest.Parse(string(revisionResponse), namespace, d.normalizeManifests, excludes...),
118120
d.suppressedKinds,
119121
d.showSecrets,
120122
d.outputContext,
@@ -149,8 +151,8 @@ func (d *rollback) backcast() error {
149151

150152
// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
151153
seenAnyChanges := diff.Manifests(
152-
manifest.ParseRelease(releaseResponse.Release, d.includeTests),
153-
manifest.ParseRelease(revisionResponse.Release, d.includeTests),
154+
manifest.ParseRelease(releaseResponse.Release, d.includeTests, d.normalizeManifests),
155+
manifest.ParseRelease(revisionResponse.Release, d.includeTests, d.normalizeManifests),
154156
d.suppressedKinds,
155157
d.showSecrets,
156158
d.outputContext,

cmd/upgrade.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type diffCmd struct {
3939
postRenderer string
4040
output string
4141
install bool
42+
normalizeManifests bool
4243
}
4344

4445
func (d *diffCmd) isAllowUnreleased() bool {
@@ -117,6 +118,7 @@ func newChartCommand() *cobra.Command {
117118
f.BoolVar(&diff.dryRun, "dry-run", false, "disables cluster access and show diff as if it was install. Implies --install, --reset-values, and --disable-validation")
118119
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")
119120
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.")
121+
f.BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
120122
if !isHelm3() {
121123
f.StringVar(&diff.namespace, "namespace", "default", "namespace to assume the release to be installed into")
122124
}
@@ -173,16 +175,16 @@ func (d *diffCmd) runHelm3() error {
173175
releaseManifest = append(releaseManifest, hooks...)
174176
}
175177
if d.includeTests {
176-
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace)
178+
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace, d.normalizeManifests)
177179
} else {
178-
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace, helm3TestHook, helm2TestSuccessHook)
180+
currentSpecs = manifest.Parse(string(releaseManifest), d.namespace, d.normalizeManifests, helm3TestHook, helm2TestSuccessHook)
179181
}
180182
}
181183
var newSpecs map[string]*manifest.MappingResult
182184
if d.includeTests {
183-
newSpecs = manifest.Parse(string(installManifest), d.namespace)
185+
newSpecs = manifest.Parse(string(installManifest), d.namespace, d.normalizeManifests)
184186
} else {
185-
newSpecs = manifest.Parse(string(installManifest), d.namespace, helm3TestHook, helm2TestSuccessHook)
187+
newSpecs = manifest.Parse(string(installManifest), d.namespace, d.normalizeManifests, helm3TestHook, helm2TestSuccessHook)
186188
}
187189
seenAnyChanges := diff.Manifests(currentSpecs, newSpecs, d.suppressedKinds, d.showSecrets, d.outputContext, d.output, os.Stdout)
188190

@@ -247,7 +249,7 @@ func (d *diffCmd) run() error {
247249
}
248250

249251
currentSpecs = make(map[string]*manifest.MappingResult)
250-
newSpecs = manifest.Parse(installResponse.Release.Manifest, installResponse.Release.Namespace)
252+
newSpecs = manifest.Parse(installResponse.Release.Manifest, installResponse.Release.Namespace, d.normalizeManifests)
251253
} else {
252254
upgradeResponse, err := d.client.UpdateRelease(
253255
d.release,
@@ -262,11 +264,11 @@ func (d *diffCmd) run() error {
262264
}
263265

264266
if d.noHooks {
265-
currentSpecs = manifest.Parse(releaseResponse.Release.Manifest, releaseResponse.Release.Namespace)
266-
newSpecs = manifest.Parse(upgradeResponse.Release.Manifest, upgradeResponse.Release.Namespace)
267+
currentSpecs = manifest.Parse(releaseResponse.Release.Manifest, releaseResponse.Release.Namespace, d.normalizeManifests)
268+
newSpecs = manifest.Parse(upgradeResponse.Release.Manifest, upgradeResponse.Release.Namespace, d.normalizeManifests)
267269
} else {
268-
currentSpecs = manifest.ParseRelease(releaseResponse.Release, d.includeTests)
269-
newSpecs = manifest.ParseRelease(upgradeResponse.Release, d.includeTests)
270+
currentSpecs = manifest.ParseRelease(releaseResponse.Release, d.includeTests, d.normalizeManifests)
271+
newSpecs = manifest.ParseRelease(upgradeResponse.Release, d.includeTests, d.normalizeManifests)
270272
}
271273
}
272274

manifest/parse.go

Lines changed: 20 additions & 15 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)
@@ -135,7 +135,7 @@ func parseContent(content string, defaultNamespace string, excludedHooks ...stri
135135

136136
if parsedMetadata.Kind == "List" {
137137
type ListV1 struct {
138-
Items []map[interface{}]interface{} `yaml:"items"`
138+
Items []yaml.MapSlice `yaml:"items"`
139139
}
140140

141141
var list ListV1
@@ -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,15 +163,20 @@ func parseContent(content string, defaultNamespace string, excludedHooks ...stri
163163
return result, nil
164164
}
165165

166-
var object map[interface{}]interface{}
167-
if err := yaml.Unmarshal([]byte(content), &object); err != nil {
168-
log.Fatalf("YAML unmarshal error: %s\nCan't unmarshal %s", err, content)
169-
}
170-
normalizedContent, err := yaml.Marshal(object)
171-
if err != nil {
172-
log.Fatalf("YAML marshal error: %s\nCan't marshal %v", err, object)
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)
173179
}
174-
content = string(normalizedContent)
175180

176181
if isHook(parsedMetadata, excludedHooks...) {
177182
return nil, nil

0 commit comments

Comments
 (0)