Skip to content

feat: JSON output #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ PKG:= github.com/databus23/helm-diff
LDFLAGS := -X $(PKG)/cmd.Version=$(VERSION)

# Clear the "unreleased" string in BuildMetadata
LDFLAGS += -X $(PKG)/vendor/k8s.io/helm/pkg/version.BuildMetadata=
LDFLAGS += -X $(PKG)/vendor/k8s.io/helm/pkg/version.Version=$(shell grep -A1 "package: k8s.io/helm" go.mod | sed -n -e 's/[ ]*version:.*\(v[.0-9]*\).*/\1/p')
LDFLAGS += -X k8s.io/helm/pkg/version.BuildMetadata=
LDFLAGS += -X k8s.io/helm/pkg/version.Version=$(shell ./scripts/dep-helm-version.sh)

.PHONY: format
format:
test -z "$$(find . -path ./vendor -prune -type f -o -name '*.go' -exec gofmt -d {} + | tee /dev/stderr)" || \
test -z "$$(find . -path ./vendor -prune -type f -o -name '*.go' -exec gofmt -w {} + | tee /dev/stderr)"
test -z "$$(find . -type f -o -name '*.go' -exec gofmt -d {} + | tee /dev/stderr)" || \
test -z "$$(find . -type f -o -name '*.go' -exec gofmt -w {} + | tee /dev/stderr)"

.PHONY: install
install: build
Expand Down
2 changes: 1 addition & 1 deletion cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func newChartCommand() *cobra.Command {
f.IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
f.BoolVar(&diff.disableOpenAPIValidation, "disable-openapi-validation", false, "disables rendered templates validation against the Kubernetes OpenAPI Schema")
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")
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.")
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.")
if !isHelm3() {
f.StringVar(&diff.namespace, "namespace", "default", "namespace to assume the release to be installed into")
}
Expand Down
10 changes: 5 additions & 5 deletions diff/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ const defaultTemplateReport = `[
{{- $global := . -}}
{{- range $idx, $entry := . -}}
{
"Api": "{{ $entry.API }}",
"Kind": "{{ $entry.Kind }}",
"Namespace": "{{ $entry.Namespace }}",
"Name": "{{ $entry.Name }}",
"Change": "{{ $entry.Change }}"
"api": "{{ $entry.API }}",
"kind": "{{ $entry.Kind }}",
"namespace": "{{ $entry.Namespace }}",
"name": "{{ $entry.Name }}",
"change": "{{ $entry.Change }}"
}{{ if not (last $idx $global) }},{{ end }}
{{- end }}]`
35 changes: 27 additions & 8 deletions diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,31 @@ Plan: 0 to add, 1 to change, 0 to destroy.
}

require.Equal(t, `[{
"Api": "apps",
"Kind": "Deployment",
"Namespace": "default",
"Name": "nginx",
"Change": "MODIFY"
}]`, buf1.String())
"api": "apps",
"kind": "Deployment",
"namespace": "default",
"name": "nginx",
"change": "MODIFY"
}]
`, buf1.String())
})

t.Run("OnChangeJSON", func(t *testing.T) {

var buf1 bytes.Buffer

if changesSeen := Manifests(specBeta, specRelease, []string{}, true, 10, "json", &buf1); !changesSeen {
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`")
}

require.Equal(t, `[{
"api": "apps",
"kind": "Deployment",
"namespace": "default",
"name": "nginx",
"change": "MODIFY"
}]
`, buf1.String())
})

t.Run("OnNoChangeTemplate", func(t *testing.T) {
Expand All @@ -231,7 +250,7 @@ Plan: 0 to add, 1 to change, 0 to destroy.
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`")
}

require.Equal(t, "[]", buf2.String())
require.Equal(t, "[]\n", buf2.String())
})

t.Run("OnChangeCustomTemplate", func(t *testing.T) {
Expand All @@ -241,6 +260,6 @@ Plan: 0 to add, 1 to change, 0 to destroy.
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`")
}

require.Equal(t, "Resource name: nginx", buf1.String())
require.Equal(t, "Resource name: nginx\n", buf1.String())
})
}
113 changes: 67 additions & 46 deletions diff/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type ReportEntry struct {

// ReportFormat to the context to make a changes report
type ReportFormat struct {
output string
output func(r *Report, to io.Writer)
changestyles map[string]ChangeStyle
}

Expand Down Expand Up @@ -61,6 +61,8 @@ func (r *Report) setupReportFormat(format string) {
setupSimpleReport(&report)
case "template":
setupTemplateReport(&report)
case "json":
setupJSONReport(&report)
default:
setupDiffReport(&report)
}
Expand All @@ -81,14 +83,7 @@ func (r *Report) addEntry(key string, suppressedKinds []string, kind string, con

// print: prints entries added to the report.
func (r *Report) print(to io.Writer) {
switch r.format.output {
case "simple":
printSimpleReport(r, to)
case "template":
printTemplateReport(r, to)
default:
printDiffReport(r, to)
}
r.format.output(r, to)
}

// clean: needed for testing
Expand All @@ -98,7 +93,7 @@ func (r *Report) clean() {

// setup report for default output: diff
func setupDiffReport(r *Report) {
r.format.output = "diff"
r.format.output = printDiffReport
r.format.changestyles = make(map[string]ChangeStyle)
r.format.changestyles["ADD"] = ChangeStyle{color: "green", message: "has been added:"}
r.format.changestyles["REMOVE"] = ChangeStyle{color: "red", message: "has been removed:"}
Expand All @@ -116,7 +111,7 @@ func printDiffReport(r *Report, to io.Writer) {

// setup report for simple output.
func setupSimpleReport(r *Report) {
r.format.output = "simple"
r.format.output = printSimpleReport
r.format.changestyles = make(map[string]ChangeStyle)
r.format.changestyles["ADD"] = ChangeStyle{color: "green", message: "to be added."}
r.format.changestyles["REMOVE"] = ChangeStyle{color: "red", message: "to be removed."}
Expand All @@ -140,9 +135,55 @@ func printSimpleReport(r *Report, to io.Writer) {
fmt.Fprintf(to, "Plan: %d to add, %d to change, %d to destroy.\n", summary["ADD"], summary["MODIFY"], summary["REMOVE"])
}

func newTemplate(name string) *template.Template {
// Prepare template functions
var funcsMap = template.FuncMap{
"last": func(x int, a interface{}) bool {
return x == reflect.ValueOf(a).Len()-1
},
}

return template.New(name).Funcs(funcsMap)
}

// setup report for json output
func setupJSONReport(r *Report) {
t, err := newTemplate("entries").Parse(defaultTemplateReport)
if err != nil {
log.Fatalf("Error loadding default template: %v", err)
}

r.format.output = templateReportPrinter(t)
r.format.changestyles = make(map[string]ChangeStyle)
r.format.changestyles["ADD"] = ChangeStyle{color: "green", message: ""}
r.format.changestyles["REMOVE"] = ChangeStyle{color: "red", message: ""}
r.format.changestyles["MODIFY"] = ChangeStyle{color: "yellow", message: ""}
}

// setup report for template output
func setupTemplateReport(r *Report) {
r.format.output = "template"
var tpl *template.Template

{
tplFile, present := os.LookupEnv("HELM_DIFF_TPL")
if present {
t, err := newTemplate(filepath.Base(tplFile)).ParseFiles(tplFile)
if err != nil {
fmt.Println(err)
log.Fatalf("Error loadding custom template")
}
tpl = t
} else {
// Render
t, err := newTemplate("entries").Parse(defaultTemplateReport)
if err != nil {
log.Fatalf("Error loadding default template")
}
tpl = t
}
}

r.format.output = templateReportPrinter(tpl)
r.format.changestyles = make(map[string]ChangeStyle)
r.format.changestyles["ADD"] = ChangeStyle{color: "green", message: ""}
r.format.changestyles["REMOVE"] = ChangeStyle{color: "red", message: ""}
Expand All @@ -165,42 +206,22 @@ func (t *ReportTemplateSpec) loadFromKey(key string) error {
}

// load and print report for template output
func printTemplateReport(r *Report, to io.Writer) {
var templateDataArray []ReportTemplateSpec

for _, entry := range r.entries {
templateData := ReportTemplateSpec{}
err := templateData.loadFromKey(entry.key)
if err != nil {
log.Println("error processing report entry")
} else {
templateData.Change = entry.changeType
templateDataArray = append(templateDataArray, templateData)
func templateReportPrinter(t *template.Template) func(r *Report, to io.Writer) {
return func(r *Report, to io.Writer) {
var templateDataArray []ReportTemplateSpec

for _, entry := range r.entries {
templateData := ReportTemplateSpec{}
err := templateData.loadFromKey(entry.key)
if err != nil {
log.Println("error processing report entry")
} else {
templateData.Change = entry.changeType
templateDataArray = append(templateDataArray, templateData)
}
}
}

// Prepare template functions
var funcsMap = template.FuncMap{
"last": func(x int, a interface{}) bool {
return x == reflect.ValueOf(a).Len()-1
},
}

tplFile, present := os.LookupEnv("HELM_DIFF_TPL")
if present {
t, err := template.New(filepath.Base(tplFile)).Funcs(funcsMap).ParseFiles(tplFile)
if err != nil {
fmt.Println(err)
log.Fatalf("Error loadding custom template")
}
t.Execute(to, templateDataArray)
} else {
// Render
t, err := template.New("entries").Funcs(funcsMap).Parse(defaultTemplateReport)
if err != nil {
log.Fatalf("Error loadding default template")
} else {
t.Execute(to, templateDataArray)
}
_, _ = to.Write([]byte("\n"))
}
}