diff --git a/README.md b/README.md index 66e412d0..0f776493 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,10 @@ Notice that there is no output, despite the fact that we might have recognized a By default Pluto will scan for all components in the versionsList that it can find. If you wish to only see deprecations for a specific component, you can use the `--components` flag to specify a list. +### Only Show Removed + +If you are targeting an upgrade, you may only wish to see apiVersions that have been `removed` rather than both `deprecated` and `removed`. You can pass the `--only-show-removed` or `-r` flag for this. It will remove any detections that are deprecated, but not yet removed. This will affect the exit code of the command as well as the json and yaml output. + ### Adding Custom Version Checks If you want to check additional apiVersions and/or types, you can pass an additional file with the `--additional-versions` or `-f` flag. diff --git a/cmd/root.go b/cmd/root.go index 0086e72c..7b748f00 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -46,6 +46,7 @@ var ( targetVersions map[string]string customColumns []string componentsFromUser []string + onlyShowRemoved bool ) var outputOptions = []string{ @@ -59,6 +60,7 @@ var outputOptions = []string{ func init() { rootCmd.PersistentFlags().BoolVar(&ignoreDeprecations, "ignore-deprecations", false, "Ignore the default behavior to exit 2 if deprecated apiVersions are found.") rootCmd.PersistentFlags().BoolVar(&ignoreRemovals, "ignore-removals", false, "Ignore the default behavior to exit 3 if removed apiVersions are found.") + rootCmd.PersistentFlags().BoolVarP(&onlyShowRemoved, "only-show-removed", "r", false, "Only display the apiVersions that have been removed in the target version.") rootCmd.PersistentFlags().StringVarP(&additionalVersionsFile, "additional-versions", "f", "", "Additional deprecated versions file to add to the list. Cannot contain any existing versions") rootCmd.PersistentFlags().StringToStringVarP(&targetVersions, "target-versions", "t", targetVersions, "A map of targetVersions to use. This flag supersedes all defaults in version files.") rootCmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "normal", "The output format to use. (normal|wide|custom|json|yaml)") @@ -200,6 +202,7 @@ var rootCmd = &cobra.Command{ CustomColumns: customColumns, IgnoreDeprecations: ignoreDeprecations, IgnoreRemovals: ignoreRemovals, + OnlyShowRemoved: onlyShowRemoved, DeprecatedVersions: deprecatedVersionList, Components: componentList, } diff --git a/e2e/tests/00_static_files.yaml b/e2e/tests/00_static_files.yaml index f9aa2929..c564fdf9 100644 --- a/e2e/tests/00_static_files.yaml +++ b/e2e/tests/00_static_files.yaml @@ -10,6 +10,13 @@ testcases: - result.systemout ShouldContainSubstring "utilities Deployment extensions/v1beta1 apps/v1 false true" - result.systemout ShouldNotContainSubstring "utilities Deployment apps/v1 false false" +- name: static files only show removed + steps: + - script: pluto detect-files -d assets/ --target-versions k8s=v1.15.0 -r + assertions: + - result.code ShouldEqual 0 + - result.systemout ShouldEqual "No output to display" + - name: helm template steps: - script: helm template assets/chart | pluto detect - diff --git a/pkg/api/output.go b/pkg/api/output.go index 31f8815f..255b0d46 100644 --- a/pkg/api/output.go +++ b/pkg/api/output.go @@ -37,6 +37,7 @@ type Instance struct { Outputs []*Output `json:"items,omitempty" yaml:"items,omitempty"` IgnoreDeprecations bool `json:"-" yaml:"-"` IgnoreRemovals bool `json:"-" yaml:"-"` + OnlyShowRemoved bool `json:"-" yaml:"-"` OutputFormat string `json:"-" yaml:"-"` TargetVersions map[string]string `json:"target-versions,omitempty" yaml:"target-versions,omitempty"` DeprecatedVersions []Version `json:"-" yaml:"-"` @@ -50,6 +51,7 @@ func (instance *Instance) DisplayOutput() error { fmt.Println("There were no resources found with known deprecated apiVersions.") return nil } + instance.filterOutput() var err error var outData []byte @@ -97,22 +99,32 @@ func (instance *Instance) DisplayOutput() error { // first it fills out the Deprecated and Removed booleans // then it returns the outputs that are either deprecated or removed // and in the component list +// additionally, if instance.OnlyShowDeprecated is true, it will remove the +// apiVersions that are deprecated but not removed func (instance *Instance) filterOutput() { var usableOutputs []*Output for _, output := range instance.Outputs { output.Deprecated = output.APIVersion.isDeprecatedIn(instance.TargetVersions) output.Removed = output.APIVersion.isRemovedIn(instance.TargetVersions) - - if output.Deprecated || output.Removed { - if StringInSlice(output.APIVersion.Component, instance.Components) { - usableOutputs = append(usableOutputs, output) + switch instance.OnlyShowRemoved { + case false: + if output.Deprecated || output.Removed { + if StringInSlice(output.APIVersion.Component, instance.Components) { + usableOutputs = append(usableOutputs, output) + } + } + case true: + if output.Removed { + if StringInSlice(output.APIVersion.Component, instance.Components) { + usableOutputs = append(usableOutputs, output) + } } } } instance.Outputs = usableOutputs - } +// removeDeprecatedOnly is a list replacement operation func (instance *Instance) tabOut(columns columnList) *tabwriter.Writer { w := new(tabwriter.Writer) w.Init(os.Stdout, 0, 15, 2, padChar, 0) diff --git a/pkg/api/output_test.go b/pkg/api/output_test.go index b270a4b5..988e46b5 100644 --- a/pkg/api/output_test.go +++ b/pkg/api/output_test.go @@ -57,6 +57,18 @@ var testOutputNoOutput = &Output{ }, } +var testOutputDeprecatedNotRemoved = &Output{ + Name: "deprecated not removed", + APIVersion: &Version{ + Name: "apps/v1", + Kind: "Deployment", + DeprecatedIn: "v1.16.0", + RemovedIn: "", + ReplacementAPI: "none", + Component: "foo", + }, +} + func init() { padChar = byte('-') } @@ -69,6 +81,30 @@ func ExampleInstance_DisplayOutput_normal() { Outputs: []*Output{ testOutput1, testOutput2, + testOutputDeprecatedNotRemoved, + }, + OutputFormat: "normal", + Components: []string{"foo"}, + } + _ = instance.DisplayOutput() + + // Output: + // NAME-------------------- KIND-------- VERSION------------- REPLACEMENT-- REMOVED-- DEPRECATED-- + // some name one----------- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- + // some name two----------- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- + // deprecated not removed-- Deployment-- apps/v1------------- none--------- false---- true-------- +} + +func ExampleInstance_DisplayOutput_onlyShowRemoved() { + instance := &Instance{ + TargetVersions: map[string]string{ + "foo": "v1.16.0", + }, + OnlyShowRemoved: true, + Outputs: []*Output{ + testOutput1, + testOutput2, + testOutputDeprecatedNotRemoved, }, OutputFormat: "normal", Components: []string{"foo"},