Skip to content

feature Implementation: Diff between Revisions #6 #22

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
Apr 26, 2018
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
118 changes: 118 additions & 0 deletions cmd/revision.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package cmd

import (
"errors"
"fmt"
"os"
"strconv"

"github.com/databus23/helm-diff/diff"
"github.com/databus23/helm-diff/manifest"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
)

type revision struct {
release string
client helm.Interface
suppressedKinds []string
revisions []string
}

const revisionCmdLongUsage = `
This command compares the manifests details of a named release.

It can be used to compare the manifests of

- lastest REVISION with specified REVISION
$ helm diff revision [flags] RELEASE REVISION1
Example:
$ helm diff revision my-release 2

- REVISION1 with REVISION2
$ helm diff revision [flags] RELEASE REVISION1 REVISION2
Example:
$ helm diff revision my-release 2 3
`

func revisionCmd() *cobra.Command {
diff := revision{}
revisionCmd := &cobra.Command{
Use: "revision [flags] RELEASE REVISION1 [REVISION2]",
Short: "Shows diff between revision's manifests",
Long: revisionCmdLongUsage,
RunE: func(cmd *cobra.Command, args []string) error {
if v, _ := cmd.Flags().GetBool("version"); v {
fmt.Println(Version)
return nil
}

switch {
case len(args) < 2:
return errors.New("Too few arguments to Command \"revision\".\nMinimum 2 arguments required: release name, revision")
case len(args) > 3:
return errors.New("Too many arguments to Command \"revision\".\nMaximum 3 arguments allowed: release name, revision1, revision2")
}

if q, _ := cmd.Flags().GetBool("suppress-secrets"); q {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can move this to a global flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my point of view, for executing suppress-secrets as a global pre-run , we might need to have a common diff object across all the subcommands and it must be made available in root.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opinions on this..? can this be done in some other way..?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, you are right. Haven't thought of that, maybe leave it as it is for now. I think its more important to have the command cleanly separated. We can deduplicate later.

diff.suppressedKinds = append(diff.suppressedKinds, "Secret")
}

diff.release = args[0]
diff.revisions = args[1:]
if diff.client == nil {
diff.client = helm.NewClient(helm.Host(os.Getenv("TILLER_HOST")), helm.ConnectTimeout(int64(30)))
}
return diff.differentiate()
},
}

revisionCmd.Flags().BoolP("suppress-secrets", "q", false, "suppress secrets in the output")
revisionCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
revisionCmd.SuggestionsMinimumDistance = 1
return revisionCmd
}

func (d *revision) differentiate() error {

switch len(d.revisions) {
case 1:
releaseResponse, err := d.client.ReleaseContent(d.release)

if err != nil {
return prettyError(err)
}

revision, _ := strconv.Atoi(d.revisions[0])
revisionResponse, err := d.client.ReleaseContent(d.release, helm.ContentReleaseVersion(int32(revision)))
if err != nil {
return prettyError(err)
}

diff.DiffManifests(manifest.Parse(revisionResponse.Release.Manifest), manifest.Parse(releaseResponse.Release.Manifest), d.suppressedKinds, os.Stdout)

case 2:
revision1, _ := strconv.Atoi(d.revisions[0])
revision2, _ := strconv.Atoi(d.revisions[1])
if revision1 > revision2 {
revision1, revision2 = revision2, revision1
}

revisionResponse1, err := d.client.ReleaseContent(d.release, helm.ContentReleaseVersion(int32(revision1)))
if err != nil {
return prettyError(err)
}

revisionResponse2, err := d.client.ReleaseContent(d.release, helm.ContentReleaseVersion(int32(revision2)))
if err != nil {
return prettyError(err)
}

diff.DiffManifests(manifest.Parse(revisionResponse1.Release.Manifest), manifest.Parse(revisionResponse2.Release.Manifest), d.suppressedKinds, os.Stdout)

default:
return errors.New("Invalid Arguments")
}

return nil
}
86 changes: 86 additions & 0 deletions cmd/rollback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cmd

import (
"fmt"
"os"
"strconv"

"github.com/databus23/helm-diff/diff"
"github.com/databus23/helm-diff/manifest"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
)

type rollback struct {
release string
client helm.Interface
suppressedKinds []string
revisions []string
}

const rollbackCmdLongUsage = `
This command compares the laset manifests details of a named release
with specific revision values to rollback.

It forecasts/visualizes changes, that a helm rollback could perform.
`

func rollbackCmd() *cobra.Command {
diff := rollback{}
rollbackCmd := &cobra.Command{
Use: "rollback [flags] [RELEASE] [REVISION]",
Short: "Show a diff explaining what a helm rollback could perform",
Long: rollbackCmdLongUsage,
Example: " helm diff rollback my-release 2",
RunE: func(cmd *cobra.Command, args []string) error {
if v, _ := cmd.Flags().GetBool("version"); v {
fmt.Println(Version)
return nil
}

if err := checkArgsLength(len(args), "release name", "revision number"); err != nil {
return err
}

if q, _ := cmd.Flags().GetBool("suppress-secrets"); q {
diff.suppressedKinds = append(diff.suppressedKinds, "Secret")
}

diff.release = args[0]
diff.revisions = args[1:]

if diff.client == nil {
diff.client = helm.NewClient(helm.Host(os.Getenv("TILLER_HOST")), helm.ConnectTimeout(int64(30)))
}

return diff.backcast()
},
}

rollbackCmd.Flags().BoolP("suppress-secrets", "q", false, "suppress secrets in the output")
rollbackCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
rollbackCmd.SuggestionsMinimumDistance = 1
return rollbackCmd
}

func (d *rollback) backcast() error {

// get manifest of the latest release
releaseResponse, err := d.client.ReleaseContent(d.release)

if err != nil {
return prettyError(err)
}

// get manifest of the release to rollback
revision, _ := strconv.Atoi(d.revisions[0])
revisionResponse, err := d.client.ReleaseContent(d.release, helm.ContentReleaseVersion(int32(revision)))
if err != nil {
return prettyError(err)
}

// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
diff.DiffManifests(manifest.Parse(releaseResponse.Release.Manifest), manifest.Parse(revisionResponse.Release.Manifest), d.suppressedKinds, os.Stdout)

return nil
}
38 changes: 27 additions & 11 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
package cmd

import "github.com/spf13/cobra"
import (
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
)

func New() *cobra.Command {

chartCommand := newChartCommand()

cmd := &cobra.Command{
Use: "diff",
Short: "Show manifest differences",
//Alias root command to chart subcommand
Args: chartCommand.Args,
// parse the flags and check for actions like suppress-secrets, no-colors
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if nc, _ := cmd.Flags().GetBool("no-color"); nc {
ansi.DisableColors(true)
}
},
RunE: func(cmd *cobra.Command, args []string) error {
cmd.Println(`Command "helm diff" is deprecated, use "helm diff upgrade" instead`)
return chartCommand.RunE(cmd, args)
},
}

chartCommand := newChartCommand()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, why remove all this? The aliasing is done to keep backward compatibility. I would like to keep that for a while to make that this doesn't break existing CI systems.

Copy link
Contributor Author

@codenio codenio Apr 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops...!! I didn't remove it. just rearranged the code syntatically.
It is there, just fitted chartCommand.Args it inside, cobra.command and placed chartCommand := newChartCommand() above it

	chartCommand := newChartCommand()

	cmd := &cobra.Command{
		Use:   "diff",
		Short: "Show manifest differences",
		//Alias root command to chart subcommand
		Args: chartCommand.Args,

Copy link
Contributor Author

@codenio codenio Apr 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need changes/reverting..?, its exactly the same code..!!

Copy link
Owner

@databus23 databus23 Apr 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok my Mistake, thanks for clearing this up. LGTM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed it

cmd.AddCommand(newVersionCmd(), chartCommand)
//Alias root command to chart subcommand
cmd.Args = chartCommand.Args
// add no-color as global flag
cmd.PersistentFlags().Bool("no-color", false, "remove colors from the output")
// add flagset from chartCommand
cmd.Flags().AddFlagSet(chartCommand.Flags())
cmd.RunE = func(cmd *cobra.Command, args []string) error {
cmd.Println(`Command "helm diff" is deprecated, use "helm diff upgrade" instead`)
return chartCommand.RunE(cmd, args)
}
cmd.AddCommand(newVersionCmd(), chartCommand)
// add subcommands
cmd.AddCommand(
revisionCmd(),
rollbackCmd(),
)
cmd.SetHelpCommand(&cobra.Command{}) // Disable the help command

return cmd

}
6 changes: 0 additions & 6 deletions cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/databus23/helm-diff/diff"
"github.com/databus23/helm-diff/manifest"
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/helm"
)
Expand Down Expand Up @@ -47,10 +46,6 @@ func newChartCommand() *cobra.Command {
diff.suppressedKinds = append(diff.suppressedKinds, "Secret")
}

if nc, _ := cmd.Flags().GetBool("no-color"); nc {
ansi.DisableColors(true)
}

diff.release = args[0]
diff.chart = args[1]
if diff.client == nil {
Expand All @@ -63,7 +58,6 @@ func newChartCommand() *cobra.Command {
f := cmd.Flags()
f.StringVar(&diff.chartVersion, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used")
f.BoolP("suppress-secrets", "q", false, "suppress secrets in the output")
f.Bool("no-color", false, "remove colors from 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")
Expand Down