diff --git a/diff/diff.go b/diff/diff.go index bb17f5f8..f2b63589 100644 --- a/diff/diff.go +++ b/diff/diff.go @@ -42,6 +42,23 @@ func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, options *O } func ManifestsOwnership(oldIndex, newIndex map[string]*manifest.MappingResult, newOwnedReleases map[string]OwnershipDiff, options *Options, to io.Writer) bool { + seenAnyChanges, report, err := generateReport(oldIndex, newIndex, newOwnedReleases, options) + if err != nil { + panic(err) + } + + report.print(to) + report.clean() + return seenAnyChanges +} + +func ManifestReport(oldIndex, newIndex map[string]*manifest.MappingResult, options *Options) (*Report, error) { + _, report, err := generateReport(oldIndex, newIndex, nil, options) + + return report, err +} + +func generateReport(oldIndex, newIndex map[string]*manifest.MappingResult, newOwnedReleases map[string]OwnershipDiff, options *Options) (bool, *Report, error) { report := Report{} report.setupReportFormat(options.OutputFormat) var possiblyRemoved []string @@ -83,26 +100,21 @@ func ManifestsOwnership(oldIndex, newIndex map[string]*manifest.MappingResult, n doDiff(&report, key, nil, newContent, options) } - seenAnyChanges := len(report.entries) > 0 + seenAnyChanges := len(report.Entries) > 0 report, err := doSuppress(report, options.SuppressedOutputLineRegex) - if err != nil { - panic(err) - } - report.print(to) - report.clean() - return seenAnyChanges + return seenAnyChanges, &report, err } func doSuppress(report Report, suppressedOutputLineRegex []string) (Report, error) { - if len(report.entries) == 0 || len(suppressedOutputLineRegex) == 0 { + if len(report.Entries) == 0 || len(suppressedOutputLineRegex) == 0 { return report, nil } filteredReport := Report{} filteredReport.format = report.format - filteredReport.entries = []ReportEntry{} + filteredReport.Entries = []ReportEntry{} var suppressOutputRegexes []*regexp.Regexp @@ -115,11 +127,11 @@ func doSuppress(report Report, suppressedOutputLineRegex []string) (Report, erro suppressOutputRegexes = append(suppressOutputRegexes, regex) } - for _, entry := range report.entries { + for _, entry := range report.Entries { var diffs []difflib.DiffRecord DIFFS: - for _, diff := range entry.diffs { + for _, diff := range entry.Diffs { for _, suppressOutputRegex := range suppressOutputRegexes { if suppressOutputRegex.MatchString(diff.Payload) { continue DIFFS @@ -143,11 +155,11 @@ func doSuppress(report Report, suppressedOutputLineRegex []string) (Report, erro switch { case containsDiff: diffRecords = diffs - case entry.changeType == "MODIFY": - entry.changeType = "MODIFY_SUPPRESSED" + case entry.ChangeType == "MODIFY": + entry.ChangeType = "MODIFY_SUPPRESSED" } - filteredReport.addEntry(entry.key, entry.suppressedKinds, entry.kind, entry.context, diffRecords, entry.changeType) + filteredReport.addEntry(entry.Key, entry.SuppressedKinds, entry.Kind, entry.Context, diffRecords, entry.ChangeType) } return filteredReport, nil @@ -247,9 +259,9 @@ func preHandleSecrets(old, new *manifest.MappingResult) (v1.Secret, v1.Secret, e if oldSecretDecodeErr != nil { old.Content = fmt.Sprintf("Error parsing old secret: %s", oldSecretDecodeErr) } else { - //if we have a Secret containing `stringData`, apply the same - //transformation that the apiserver would do with it (this protects - //stringData keys from being overwritten down below) + // if we have a Secret containing `stringData`, apply the same + // transformation that the apiserver would do with it (this protects + // stringData keys from being overwritten down below) if len(oldSecret.StringData) > 0 && oldSecret.Data == nil { oldSecret.Data = make(map[string][]byte, len(oldSecret.StringData)) } @@ -263,7 +275,7 @@ func preHandleSecrets(old, new *manifest.MappingResult) (v1.Secret, v1.Secret, e if newSecretDecodeErr != nil { new.Content = fmt.Sprintf("Error parsing new secret: %s", newSecretDecodeErr) } else { - //same as above + // same as above if len(newSecret.StringData) > 0 && newSecret.Data == nil { newSecret.Data = make(map[string][]byte, len(newSecret.StringData)) } diff --git a/diff/diff_test.go b/diff/diff_test.go index 3bdb4ec0..56b844f7 100644 --- a/diff/diff_test.go +++ b/diff/diff_test.go @@ -172,7 +172,6 @@ func TestManifests(t *testing.T) { specBeta := map[string]*manifest.MappingResult{ "default, nginx, Deployment (apps)": { - Name: "default, nginx, Deployment (apps)", Kind: "Deployment", Content: ` @@ -181,11 +180,11 @@ kind: Deployment metadata: name: nginx `, - }} + }, + } specRelease := map[string]*manifest.MappingResult{ "default, nginx, Deployment (apps)": { - Name: "default, nginx, Deployment (apps)", Kind: "Deployment", Content: ` @@ -194,11 +193,11 @@ kind: Deployment metadata: name: nginx `, - }} + }, + } specReleaseSpec := map[string]*manifest.MappingResult{ "default, nginx, Deployment (apps)": { - Name: "default, nginx, Deployment (apps)", Kind: "Deployment", Content: ` @@ -209,11 +208,11 @@ metadata: spec: replicas: 3 `, - }} + }, + } specReleaseRenamed := map[string]*manifest.MappingResult{ "default, nginx-renamed, Deployment (apps)": { - Name: "default, nginx-renamed, Deployment (apps)", Kind: "Deployment", Content: ` @@ -224,11 +223,11 @@ metadata: spec: replicas: 3 `, - }} + }, + } specReleaseRenamedAndUpdated := map[string]*manifest.MappingResult{ "default, nginx-renamed, Deployment (apps)": { - Name: "default, nginx-renamed, Deployment (apps)", Kind: "Deployment", Content: ` @@ -239,11 +238,11 @@ metadata: spec: replicas: 1 `, - }} + }, + } specReleaseRenamedAndAdded := map[string]*manifest.MappingResult{ "default, nginx-renamed, Deployment (apps)": { - Name: "default, nginx-renamed, Deployment (apps)", Kind: "Deployment", Content: ` @@ -257,11 +256,11 @@ spec: matchLabels: app: nginx-renamed `, - }} + }, + } specReleaseKeep := map[string]*manifest.MappingResult{ "default, nginx, Deployment (apps)": { - Name: "default, nginx, Deployment (apps)", Kind: "Deployment", Content: ` @@ -273,7 +272,8 @@ annotations: helm.sh/resource-policy: keep `, ResourcePolicy: "keep", - }} + }, + } t.Run("OnChange", func(t *testing.T) { var buf1 bytes.Buffer @@ -603,7 +603,8 @@ data: key2: dmFsdWUy key3: dmFsdWUz `, - }} + }, + } specSecretWithByteDataChanged := map[string]*manifest.MappingResult{ "default, foobar, Secret (v1)": { @@ -620,7 +621,8 @@ data: key2: dmFsdWUy key4: dmFsdWU0 `, - }} + }, + } specSecretWithStringData := map[string]*manifest.MappingResult{ "default, foobar, Secret (v1)": { @@ -637,7 +639,8 @@ stringData: key2: value2 key3: value3 `, - }} + }, + } specSecretWithStringDataChanged := map[string]*manifest.MappingResult{ "default, foobar, Secret (v1)": { @@ -654,17 +657,18 @@ stringData: key2: value2 key4: value4 `, - }} + }, + } t.Run("OnChangeSecretWithByteData", func(t *testing.T) { var buf1 bytes.Buffer - diffOptions := Options{"diff", 10, false, false, false, []string{}, 0.5, []string{}} //NOTE: ShowSecrets = false + diffOptions := Options{"diff", 10, false, false, false, []string{}, 0.5, []string{}} // NOTE: ShowSecrets = false if changesSeen := Manifests(specSecretWithByteData, specSecretWithByteDataChanged, &diffOptions, &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`") } - //TODO: Why is there no empty line between the header and the start of the diff, like in the other diffs? + // TODO: Why is there no empty line between the header and the start of the diff, like in the other diffs? require.Equal(t, `default, foobar, Secret (v1) has changed: apiVersion: v1 kind: Secret @@ -683,7 +687,7 @@ stringData: t.Run("OnChangeSecretWithStringData", func(t *testing.T) { var buf1 bytes.Buffer - diffOptions := Options{"diff", 10, false, false, false, []string{}, 0.5, []string{}} //NOTE: ShowSecrets = false + diffOptions := Options{"diff", 10, false, false, false, []string{}, 0.5, []string{}} // NOTE: ShowSecrets = false if changesSeen := Manifests(specSecretWithStringData, specSecretWithStringDataChanged, &diffOptions, &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`") @@ -722,17 +726,17 @@ func TestDoSuppress(t *testing.T) { { name: "simple", input: Report{ - entries: []ReportEntry{ + Entries: []ReportEntry{ { - diffs: diffStrings("hello: world", "hello: world2", false), + Diffs: diffStrings("hello: world", "hello: world2", false), }, }, }, supressRegex: []string{}, expected: Report{ - entries: []ReportEntry{ + Entries: []ReportEntry{ { - diffs: diffStrings("hello: world", "hello: world2", false), + Diffs: diffStrings("hello: world", "hello: world2", false), }, }, }, @@ -740,17 +744,17 @@ func TestDoSuppress(t *testing.T) { { name: "ignore all", input: Report{ - entries: []ReportEntry{ + Entries: []ReportEntry{ { - diffs: diffStrings("hello: world", "hello: world2", false), + Diffs: diffStrings("hello: world", "hello: world2", false), }, }, }, supressRegex: []string{".*world2?"}, expected: Report{ - entries: []ReportEntry{ + Entries: []ReportEntry{ { - diffs: []difflib.DiffRecord{}, + Diffs: []difflib.DiffRecord{}, }, }, }, @@ -758,17 +762,17 @@ func TestDoSuppress(t *testing.T) { { name: "ignore partial", input: Report{ - entries: []ReportEntry{ + Entries: []ReportEntry{ { - diffs: diffStrings("hello: world", "hello: world2", false), + Diffs: diffStrings("hello: world", "hello: world2", false), }, }, }, supressRegex: []string{".*world2"}, expected: Report{ - entries: []ReportEntry{ + Entries: []ReportEntry{ { - diffs: []difflib.DiffRecord{ + Diffs: []difflib.DiffRecord{ { Payload: "hello: world", Delta: difflib.LeftOnly, @@ -803,11 +807,12 @@ metadata: data: key1: value1 `, - }} + }, + } t.Run("OnChangeOwnershipWithoutSpecChange", func(t *testing.T) { var buf1 bytes.Buffer - diffOptions := Options{"diff", 10, false, true, false, []string{}, 0.5, []string{}} //NOTE: ShowSecrets = false + diffOptions := Options{"diff", 10, false, true, false, []string{}, 0.5, []string{}} // NOTE: ShowSecrets = false newOwnedReleases := map[string]OwnershipDiff{ "default, foobar, ConfigMap (v1)": { @@ -827,7 +832,7 @@ data: t.Run("OnChangeOwnershipWithSpecChange", func(t *testing.T) { var buf1 bytes.Buffer - diffOptions := Options{"diff", 10, false, true, false, []string{}, 0.5, []string{}} //NOTE: ShowSecrets = false + diffOptions := Options{"diff", 10, false, true, false, []string{}, 0.5, []string{}} // NOTE: ShowSecrets = false specNew := map[string]*manifest.MappingResult{ "default, foobar, ConfigMap (v1)": { @@ -841,7 +846,8 @@ metadata: data: key1: newValue1 `, - }} + }, + } newOwnedReleases := map[string]OwnershipDiff{ "default, foobar, ConfigMap (v1)": { @@ -869,6 +875,7 @@ default, foobar, ConfigMap (v1) has changed: `, buf1.String()) }) } + func TestDecodeSecrets(t *testing.T) { ansi.DisableColors(true) diff --git a/diff/report.go b/diff/report.go index d3f79f8d..ac456365 100644 --- a/diff/report.go +++ b/diff/report.go @@ -20,17 +20,17 @@ import ( // Report to store report data and format type Report struct { format ReportFormat - entries []ReportEntry + Entries []ReportEntry } // ReportEntry to store changes between releases type ReportEntry struct { - key string - suppressedKinds []string - kind string - context int - diffs []difflib.DiffRecord - changeType string + Key string + SuppressedKinds []string + Kind string + Context int + Diffs []difflib.DiffRecord + ChangeType string } // ReportFormat to the context to make a changes report @@ -84,10 +84,10 @@ func printDyffReport(r *Report, to io.Writer) { _ = os.Remove(newFile.Name()) }() - for _, entry := range r.entries { + for _, entry := range r.Entries { _, _ = currentFile.WriteString("---\n") _, _ = newFile.WriteString("---\n") - for _, record := range entry.diffs { + for _, record := range entry.Diffs { switch record.Delta { case difflib.Common: _, _ = currentFile.WriteString(record.Payload + "\n") @@ -123,7 +123,7 @@ func (r *Report) addEntry(key string, suppressedKinds []string, kind string, con diffs, changeType, } - r.entries = append(r.entries, entry) + r.Entries = append(r.Entries, entry) } // print: prints entries added to the report. @@ -133,7 +133,7 @@ func (r *Report) print(to io.Writer) { // clean: needed for testing func (r *Report) clean() { - r.entries = nil + r.Entries = nil } // setup report for default output: diff @@ -149,14 +149,14 @@ func setupDiffReport(r *Report) { // print report for default output: diff func printDiffReport(r *Report, to io.Writer) { - for _, entry := range r.entries { + for _, entry := range r.Entries { _, _ = fmt.Fprintf( to, - ansi.Color("%s %s", r.format.changestyles[entry.changeType].color)+"\n", - entry.key, - r.format.changestyles[entry.changeType].message, + ansi.Color("%s %s", r.format.changestyles[entry.ChangeType].color)+"\n", + entry.Key, + r.format.changestyles[entry.ChangeType].message, ) - printDiffRecords(entry.suppressedKinds, entry.kind, entry.context, entry.diffs, to) + printDiffRecords(entry.SuppressedKinds, entry.Kind, entry.Context, entry.Diffs, to) } } @@ -173,26 +173,26 @@ func setupSimpleReport(r *Report) { // print report for simple output func printSimpleReport(r *Report, to io.Writer) { - var summary = map[string]int{ + summary := map[string]int{ "ADD": 0, "REMOVE": 0, "MODIFY": 0, "OWNERSHIP": 0, "MODIFY_SUPPRESSED": 0, } - for _, entry := range r.entries { - _, _ = fmt.Fprintf(to, ansi.Color("%s %s", r.format.changestyles[entry.changeType].color)+"\n", - entry.key, - r.format.changestyles[entry.changeType].message, + for _, entry := range r.Entries { + _, _ = fmt.Fprintf(to, ansi.Color("%s %s", r.format.changestyles[entry.ChangeType].color)+"\n", + entry.Key, + r.format.changestyles[entry.ChangeType].message, ) - summary[entry.changeType]++ + summary[entry.ChangeType]++ } _, _ = fmt.Fprintf(to, "Plan: %d to add, %d to change, %d to destroy, %d to change ownership.\n", summary["ADD"], summary["MODIFY"], summary["REMOVE"], summary["OWNERSHIP"]) } func newTemplate(name string) *template.Template { // Prepare template functions - var funcsMap = template.FuncMap{ + funcsMap := template.FuncMap{ "last": func(x int, a interface{}) bool { return x == reflect.ValueOf(a).Len()-1 }, @@ -269,13 +269,13 @@ 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 { + for _, entry := range r.Entries { templateData := ReportTemplateSpec{} - err := templateData.loadFromKey(entry.key) + err := templateData.loadFromKey(entry.Key) if err != nil { log.Println("error processing report entry") } else { - templateData.Change = entry.changeType + templateData.Change = entry.ChangeType templateDataArray = append(templateDataArray, templateData) } }