diff --git a/diff.go b/diff.go index eaa91ead..e944b306 100644 --- a/diff.go +++ b/diff.go @@ -7,20 +7,22 @@ import ( "github.com/aryann/difflib" "github.com/mgutz/ansi" + + "github.com/databus23/helm-diff/manifest" ) -func diffManifests(oldIndex, newIndex map[string]string, to io.Writer) { +func diffManifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressedKinds []string, to io.Writer) { for key, oldContent := range oldIndex { if newContent, ok := newIndex[key]; ok { - if oldContent != newContent { + if oldContent.Content != newContent.Content { // modified fmt.Fprintf(to, ansi.Color("%s has changed:", "yellow")+"\n", key) - printDiff(oldContent, newContent, to) + printDiff(suppressedKinds, oldContent.Kind, oldContent.Content, newContent.Content, to) } } else { // removed fmt.Fprintf(to, ansi.Color("%s has been removed:", "yellow")+"\n", key) - printDiff(oldContent, "", to) + printDiff(suppressedKinds, oldContent.Kind, oldContent.Content, "", to) } } @@ -28,14 +30,22 @@ func diffManifests(oldIndex, newIndex map[string]string, to io.Writer) { if _, ok := oldIndex[key]; !ok { // added fmt.Fprintf(to, ansi.Color("%s has been added:", "yellow")+"\n", key) - printDiff("", newContent, to) + printDiff(suppressedKinds, newContent.Kind, "", newContent.Content, to) } } } -func printDiff(before, after string, to io.Writer) { +func printDiff(suppressedKinds []string, kind, before, after string, to io.Writer) { diffs := difflib.Diff(strings.Split(before, "\n"), strings.Split(after, "\n")) + for _, ckind := range suppressedKinds { + if ckind == kind { + str := fmt.Sprintf("+ Changes suppressed on sensitive content of type %s\n", kind) + fmt.Fprintf(to, ansi.Color(str, "yellow")) + return + } + } + for _, diff := range diffs { text := diff.Payload @@ -48,5 +58,4 @@ func printDiff(before, after string, to io.Writer) { fmt.Fprintf(to, "%s\n", " "+text) } } - } diff --git a/main.go b/main.go index cc0beb60..c9b98f2e 100644 --- a/main.go +++ b/main.go @@ -19,21 +19,20 @@ This can be used visualize what changes a helm upgrade will perform. ` -var Version string = "HEAD" +// Version identifier populated via the CI/CD process. +var Version = "HEAD" type diffCmd struct { - release string - chart string - // out io.Writer - client helm.Interface - // version int32 - valueFiles valueFiles - values []string - reuseValues bool + release string + chart string + client helm.Interface + valueFiles valueFiles + values []string + reuseValues bool + suppressedKinds []string } func main() { - diff := diffCmd{} cmd := &cobra.Command{ @@ -45,10 +44,15 @@ func main() { fmt.Println(Version) return nil } + if err := checkArgsLength(len(args), "release name", "chart path"); err != nil { return err } + if q, _ := cmd.Flags().GetBool("suppress-secrets"); q { + diff.suppressedKinds = append(diff.suppressedKinds, "Secret") + } + diff.release = args[0] diff.chart = args[1] if diff.client == nil { @@ -60,9 +64,11 @@ func main() { f := cmd.Flags() f.BoolP("version", "v", false, "show version") + f.BoolP("suppress-secrets", "q", false, "suppress secrets in the output") f.VarP(&diff.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") f.StringArrayVar(&diff.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.BoolVar(&diff.reuseValues, "reuse-values", false, "reuse the last release's values and merge in any new values") + f.StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output") if err := cmd.Execute(); err != nil { os.Exit(1) @@ -100,7 +106,7 @@ func (d *diffCmd) run() error { currentSpecs := manifest.Parse(releaseResponse.Release.Manifest) newSpecs := manifest.Parse(upgradeResponse.Release.Manifest) - diffManifests(currentSpecs, newSpecs, os.Stdout) + diffManifests(currentSpecs, newSpecs, d.suppressedKinds, os.Stdout) return nil } diff --git a/manifest/parse.go b/manifest/parse.go index d8ce6eda..b513fa00 100644 --- a/manifest/parse.go +++ b/manifest/parse.go @@ -12,6 +12,12 @@ import ( var yamlSeperator = []byte("\n---\n") +type MappingResult struct { + Name string + Kind string + Content string +} + type metadata struct { ApiVersion string `yaml:"apiVersion"` Kind string @@ -47,7 +53,7 @@ func splitSpec(token string) (string, string) { return "", "" } -func Parse(manifest string) map[string]string { +func Parse(manifest string) map[string]*MappingResult { scanner := bufio.NewScanner(strings.NewReader(manifest)) scanner.Split(scanYamlSpecs) //Allow for tokens (specs) up to 1M in size @@ -55,7 +61,7 @@ func Parse(manifest string) map[string]string { //Discard the first result, we only care about everything after the first seperator scanner.Scan() - result := make(map[string]string) + result := make(map[string]*MappingResult) for scanner.Scan() { content := scanner.Text() @@ -70,7 +76,11 @@ func Parse(manifest string) map[string]string { if _, ok := result[name]; ok { log.Println("Error: Found duplicate key %#v in manifest", name) } else { - result[name] = content + result[name] = &MappingResult{ + Name: name, + Kind: metadata.Kind, + Content: content, + } } } return result