Skip to content

Commit 55d7572

Browse files
semoacmumoshu
andauthored
feat: Add support for custom output formats (#221)
Signed-off-by: Sergio Morales <[email protected]> Co-authored-by: KUOKA Yusuke <[email protected]>
1 parent 36dc2ff commit 55d7572

File tree

9 files changed

+315
-14
lines changed

9 files changed

+315
-14
lines changed

cmd/release.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type release struct {
2020
outputContext int
2121
includeTests bool
2222
showSecrets bool
23+
output string
2324
}
2425

2526
const releaseCmdLongUsage = `
@@ -77,6 +78,8 @@ func releaseCmd() *cobra.Command {
7778
releaseCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
7879
releaseCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
7980
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
81+
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.")
82+
8083
releaseCmd.SuggestionsMinimumDistance = 1
8184

8285
if !isHelm3() {
@@ -117,6 +120,7 @@ func (d *release) differentiateHelm3() error {
117120
d.suppressedKinds,
118121
d.showSecrets,
119122
d.outputContext,
123+
d.output,
120124
os.Stdout)
121125

122126
if d.detailedExitCode && seenAnyChanges {
@@ -150,6 +154,7 @@ func (d *release) differentiate() error {
150154
d.suppressedKinds,
151155
d.showSecrets,
152156
d.outputContext,
157+
d.output,
153158
os.Stdout)
154159

155160
if d.detailedExitCode && seenAnyChanges {

cmd/revision.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type revision struct {
2222
outputContext int
2323
includeTests bool
2424
showSecrets bool
25+
output string
2526
}
2627

2728
const revisionCmdLongUsage = `
@@ -87,6 +88,8 @@ func revisionCmd() *cobra.Command {
8788
revisionCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
8889
revisionCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
8990
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
91+
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.")
92+
9093
revisionCmd.SuggestionsMinimumDistance = 1
9194

9295
if !isHelm3() {
@@ -122,6 +125,7 @@ func (d *revision) differentiateHelm3() error {
122125
d.suppressedKinds,
123126
d.showSecrets,
124127
d.outputContext,
128+
d.output,
125129
os.Stdout)
126130

127131
case 2:
@@ -147,6 +151,7 @@ func (d *revision) differentiateHelm3() error {
147151
d.suppressedKinds,
148152
d.showSecrets,
149153
d.outputContext,
154+
d.output,
150155
os.Stdout)
151156

152157
if d.detailedExitCode && seenAnyChanges {
@@ -185,6 +190,7 @@ func (d *revision) differentiate() error {
185190
d.suppressedKinds,
186191
d.showSecrets,
187192
d.outputContext,
193+
d.output,
188194
os.Stdout)
189195

190196
case 2:
@@ -210,6 +216,7 @@ func (d *revision) differentiate() error {
210216
d.suppressedKinds,
211217
d.showSecrets,
212218
d.outputContext,
219+
d.output,
213220
os.Stdout)
214221

215222
if d.detailedExitCode && seenAnyChanges {

cmd/rollback.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type rollback struct {
2222
outputContext int
2323
includeTests bool
2424
showSecrets bool
25+
output string
2526
}
2627

2728
const rollbackCmdLongUsage = `
@@ -79,6 +80,8 @@ func rollbackCmd() *cobra.Command {
7980
rollbackCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
8081
rollbackCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
8182
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
83+
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.")
84+
8285
rollbackCmd.SuggestionsMinimumDistance = 1
8386

8487
if !isHelm3() {
@@ -115,6 +118,7 @@ func (d *rollback) backcastHelm3() error {
115118
d.suppressedKinds,
116119
d.showSecrets,
117120
d.outputContext,
121+
d.output,
118122
os.Stdout)
119123

120124
if d.detailedExitCode && seenAnyChanges {
@@ -150,6 +154,7 @@ func (d *rollback) backcast() error {
150154
d.suppressedKinds,
151155
d.showSecrets,
152156
d.outputContext,
157+
d.output,
153158
os.Stdout)
154159

155160
if d.detailedExitCode && seenAnyChanges {

cmd/upgrade.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type diffCmd struct {
3535
outputContext int
3636
showSecrets bool
3737
postRenderer string
38+
output string
3839
install bool
3940
}
4041

@@ -111,6 +112,7 @@ func newChartCommand() *cobra.Command {
111112
f.IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
112113
f.BoolVar(&diff.disableOpenAPIValidation, "disable-openapi-validation", false, "disables rendered templates validation against the Kubernetes OpenAPI Schema")
113114
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")
115+
f.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.")
114116
if !isHelm3() {
115117
f.StringVar(&diff.namespace, "namespace", "default", "namespace to assume the release to be installed into")
116118
}
@@ -171,8 +173,7 @@ func (d *diffCmd) runHelm3() error {
171173
} else {
172174
newSpecs = manifest.Parse(string(installManifest), d.namespace, helm3TestHook, helm2TestSuccessHook)
173175
}
174-
175-
seenAnyChanges := diff.Manifests(currentSpecs, newSpecs, d.suppressedKinds, d.showSecrets, d.outputContext, os.Stdout)
176+
seenAnyChanges := diff.Manifests(currentSpecs, newSpecs, d.suppressedKinds, d.showSecrets, d.outputContext, d.output, os.Stdout)
176177

177178
if d.detailedExitCode && seenAnyChanges {
178179
return Error{
@@ -258,7 +259,7 @@ func (d *diffCmd) run() error {
258259
}
259260
}
260261

261-
seenAnyChanges := diff.Manifests(currentSpecs, newSpecs, d.suppressedKinds, d.showSecrets, d.outputContext, os.Stdout)
262+
seenAnyChanges := diff.Manifests(currentSpecs, newSpecs, d.suppressedKinds, d.showSecrets, d.outputContext, d.output, os.Stdout)
262263

263264
if d.detailedExitCode && seenAnyChanges {
264265
return Error{

diff/constant.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package diff
2+
3+
const defaultTemplateReport = `[
4+
{{- $global := . -}}
5+
{{- range $idx, $entry := . -}}
6+
{
7+
"Api": "{{ $entry.API }}",
8+
"Kind": "{{ $entry.Kind }}",
9+
"Namespace": "{{ $entry.Namespace }}",
10+
"Name": "{{ $entry.Name }}",
11+
"Change": "{{ $entry.Change }}"
12+
}{{ if not (last $idx $global) }},{{ end }}
13+
{{- end }}]`

diff/diff.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ import (
1919
)
2020

2121
// Manifests diff on manifests
22-
func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressedKinds []string, showSecrets bool, context int, to io.Writer) bool {
22+
func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressedKinds []string, showSecrets bool, context int, output string, to io.Writer) bool {
23+
report.setupReportFormat(output)
2324
seenAnyChanges := false
2425
emptyMapping := &manifest.MappingResult{}
2526
for key, oldContent := range oldIndex {
2627
if newContent, ok := newIndex[key]; ok {
2728
if oldContent.Content != newContent.Content {
2829
// modified
29-
fmt.Fprintf(to, ansi.Color("%s has changed:", "yellow")+"\n", key)
3030
if !showSecrets {
3131
redactSecrets(oldContent, newContent)
3232
}
@@ -35,11 +35,10 @@ func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressed
3535
if len(diffs) > 0 {
3636
seenAnyChanges = true
3737
}
38-
printDiffRecords(suppressedKinds, oldContent.Kind, context, diffs, to)
38+
report.addEntry(key, suppressedKinds, oldContent.Kind, context, diffs, "MODIFY")
3939
}
4040
} else {
4141
// removed
42-
fmt.Fprintf(to, ansi.Color("%s has been removed:", "yellow")+"\n", key)
4342
if !showSecrets {
4443
redactSecrets(oldContent, nil)
4544

@@ -48,24 +47,25 @@ func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressed
4847
if len(diffs) > 0 {
4948
seenAnyChanges = true
5049
}
51-
printDiffRecords(suppressedKinds, oldContent.Kind, context, diffs, to)
50+
report.addEntry(key, suppressedKinds, oldContent.Kind, context, diffs, "REMOVE")
5251
}
5352
}
5453

5554
for key, newContent := range newIndex {
5655
if _, ok := oldIndex[key]; !ok {
5756
// added
58-
fmt.Fprintf(to, ansi.Color("%s has been added:", "yellow")+"\n", key)
5957
if !showSecrets {
6058
redactSecrets(nil, newContent)
6159
}
6260
diffs := diffMappingResults(emptyMapping, newContent)
6361
if len(diffs) > 0 {
6462
seenAnyChanges = true
6563
}
66-
printDiffRecords(suppressedKinds, newContent.Kind, context, diffs, to)
64+
report.addEntry(key, suppressedKinds, newContent.Kind, context, diffs, "ADD")
6765
}
6866
}
67+
report.print(to)
68+
report.clean()
6969
return seenAnyChanges
7070
}
7171

@@ -138,10 +138,10 @@ func getComment(s string) string {
138138
}
139139

140140
// Releases reindex the content based on the template names and pass it to Manifests
141-
func Releases(oldIndex, newIndex map[string]*manifest.MappingResult, suppressedKinds []string, showSecrets bool, context int, to io.Writer) bool {
141+
func Releases(oldIndex, newIndex map[string]*manifest.MappingResult, suppressedKinds []string, showSecrets bool, context int, output string, to io.Writer) bool {
142142
oldIndex = reIndexForRelease(oldIndex)
143143
newIndex = reIndexForRelease(newIndex)
144-
return Manifests(oldIndex, newIndex, suppressedKinds, showSecrets, context, to)
144+
return Manifests(oldIndex, newIndex, suppressedKinds, showSecrets, context, output, to)
145145
}
146146

147147
func diffMappingResults(oldContent *manifest.MappingResult, newContent *manifest.MappingResult) []difflib.DiffRecord {

diff/diff_test.go

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package diff
22

33
import (
44
"bytes"
5+
"os"
56
"testing"
67

78
"github.com/mgutz/ansi"
@@ -158,7 +159,7 @@ metadata:
158159

159160
var buf1 bytes.Buffer
160161

161-
if changesSeen := Manifests(specBeta, specRelease, []string{}, true, 10, &buf1); !changesSeen {
162+
if changesSeen := Manifests(specBeta, specRelease, []string{}, true, 10, "diff", &buf1); !changesSeen {
162163
t.Error("Unexpected return value from Manifests: Expected the return value to be `true` to indicate that it has seen any change(s), but was `false`")
163164
}
164165

@@ -176,10 +177,70 @@ metadata:
176177
t.Run("OnNoChange", func(t *testing.T) {
177178
var buf2 bytes.Buffer
178179

179-
if changesSeen := Manifests(specRelease, specRelease, []string{}, true, 10, &buf2); changesSeen {
180+
if changesSeen := Manifests(specRelease, specRelease, []string{}, true, 10, "diff", &buf2); changesSeen {
180181
t.Error("Unexpected return value from Manifests: Expected the return value to be `false` to indicate that it has NOT seen any change(s), but was `true`")
181182
}
182183

183184
require.Equal(t, ``, buf2.String())
184185
})
186+
187+
t.Run("OnChangeSimple", func(t *testing.T) {
188+
189+
var buf1 bytes.Buffer
190+
191+
if changesSeen := Manifests(specBeta, specRelease, []string{}, true, 10, "simple", &buf1); !changesSeen {
192+
t.Error("Unexpected return value from Manifests: Expected the return value to be `true` to indicate that it has seen any change(s), but was `false`")
193+
}
194+
195+
require.Equal(t, `default, nginx, Deployment (apps) to be changed.
196+
Plan: 0 to add, 1 to change, 0 to destroy.
197+
`, buf1.String())
198+
})
199+
200+
t.Run("OnNoChangeSimple", func(t *testing.T) {
201+
var buf2 bytes.Buffer
202+
203+
if changesSeen := Manifests(specRelease, specRelease, []string{}, true, 10, "simple", &buf2); changesSeen {
204+
t.Error("Unexpected return value from Manifests: Expected the return value to be `false` to indicate that it has NOT seen any change(s), but was `true`")
205+
}
206+
207+
require.Equal(t, "Plan: 0 to add, 0 to change, 0 to destroy.\n", buf2.String())
208+
})
209+
210+
t.Run("OnChangeTemplate", func(t *testing.T) {
211+
212+
var buf1 bytes.Buffer
213+
214+
if changesSeen := Manifests(specBeta, specRelease, []string{}, true, 10, "template", &buf1); !changesSeen {
215+
t.Error("Unexpected return value from Manifests: Expected the return value to be `true` to indicate that it has seen any change(s), but was `false`")
216+
}
217+
218+
require.Equal(t, `[{
219+
"Api": "apps",
220+
"Kind": "Deployment",
221+
"Namespace": "default",
222+
"Name": "nginx",
223+
"Change": "MODIFY"
224+
}]`, buf1.String())
225+
})
226+
227+
t.Run("OnNoChangeTemplate", func(t *testing.T) {
228+
var buf2 bytes.Buffer
229+
230+
if changesSeen := Manifests(specRelease, specRelease, []string{}, true, 10, "template", &buf2); changesSeen {
231+
t.Error("Unexpected return value from Manifests: Expected the return value to be `false` to indicate that it has NOT seen any change(s), but was `true`")
232+
}
233+
234+
require.Equal(t, "[]", buf2.String())
235+
})
236+
237+
t.Run("OnChangeCustomTemplate", func(t *testing.T) {
238+
var buf1 bytes.Buffer
239+
os.Setenv("HELM_DIFF_TPL", "testdata/customTemplate.tpl")
240+
if changesSeen := Manifests(specBeta, specRelease, []string{}, true, 10, "template", &buf1); !changesSeen {
241+
t.Error("Unexpected return value from Manifests: Expected the return value to be `false` to indicate that it has NOT seen any change(s), but was `true`")
242+
}
243+
244+
require.Equal(t, "Resource name: nginx", buf1.String())
245+
})
185246
}

0 commit comments

Comments
 (0)