diff --git a/pkg/cmd/scan/output/console.go b/pkg/cmd/scan/output/console.go index 42fa96a9..870086f9 100644 --- a/pkg/cmd/scan/output/console.go +++ b/pkg/cmd/scan/output/console.go @@ -36,10 +36,10 @@ func NewConsole() *Console { func (c *Console) Write(analysis *analyser.Analysis) error { if analysis.Summary().TotalDeleted > 0 { fmt.Println("Found missing resources:") - deletedByType := groupByType(analysis.Deleted()) - for ty, resources := range deletedByType { + deletedByType, keys := groupByType(analysis.Deleted()) + for _, ty := range keys { fmt.Printf(" %s:\n", ty) - for _, res := range resources { + for _, res := range deletedByType[ty] { humanString := fmt.Sprintf(" - %s", res.TerraformId()) if humanAttrs := formatResourceAttributes(res); humanAttrs != "" { humanString += fmt.Sprintf("\n %s", humanAttrs) @@ -51,10 +51,10 @@ func (c *Console) Write(analysis *analyser.Analysis) error { if analysis.Summary().TotalUnmanaged > 0 { fmt.Println("Found resources not covered by IaC:") - unmanagedByType := groupByType(analysis.Unmanaged()) - for ty, resource := range unmanagedByType { + unmanagedByType, keys := groupByType(analysis.Unmanaged()) + for _, ty := range keys { fmt.Printf(" %s:\n", ty) - for _, res := range resource { + for _, res := range unmanagedByType[ty] { humanString := fmt.Sprintf(" - %s", res.TerraformId()) if humanAttrs := formatResourceAttributes(res); humanAttrs != "" { humanString += fmt.Sprintf("\n %s", humanAttrs) @@ -174,7 +174,7 @@ func prettify(resource interface{}) string { return awsutil.Prettify(resource) } -func groupByType(resources []resource.Resource) map[string][]resource.Resource { +func groupByType(resources []resource.Resource) (map[string][]resource.Resource, []string) { result := map[string][]resource.Resource{} for _, res := range resources { if result[res.TerraformType()] == nil { @@ -183,7 +183,14 @@ func groupByType(resources []resource.Resource) map[string][]resource.Resource { } result[res.TerraformType()] = append(result[res.TerraformType()], res) } - return result + + keys := make([]string, 0, len(result)) + for k := range result { + keys = append(keys, k) + } + sort.Strings(keys) + + return result, keys } func jsonDiff(a, b interface{}, prefix string) string { diff --git a/pkg/cmd/scan/output/console_test.go b/pkg/cmd/scan/output/console_test.go index 9447f631..92168363 100644 --- a/pkg/cmd/scan/output/console_test.go +++ b/pkg/cmd/scan/output/console_test.go @@ -29,8 +29,31 @@ func TestConsole_Write(t *testing.T) { { name: "test console output", goldenfile: "output.txt", - args: args{analysis: fakeAnalysis()}, - wantErr: false, + args: args{analysis: func() *analyser.Analysis { + a := fakeAnalysis() + a.AddDeleted( + &testresource.FakeResource{ + Id: "test-id-1", + Type: "aws_test_resource", + }, + &testresource.FakeResource{ + Id: "test-id-2", + Type: "aws_test_resource", + }, + ) + a.AddUnmanaged( + &testresource.FakeResource{ + Id: "test-id-1", + Type: "aws_testing_resource", + }, + &testresource.FakeResource{ + Id: "test-id-2", + Type: "aws_resource", + }, + ) + return a + }()}, + wantErr: false, }, { name: "test console output no drift", @@ -101,7 +124,7 @@ func TestConsole_Write(t *testing.T) { }() // back to normal state - w.Close() + assert.Nil(t, w.Close()) os.Stdout = stdout // restoring the real stdout os.Stderr = stderr out := <-outC diff --git a/pkg/cmd/scan/output/testdata/output.txt b/pkg/cmd/scan/output/testdata/output.txt index c9876659..a56601c0 100644 --- a/pkg/cmd/scan/output/testdata/output.txt +++ b/pkg/cmd/scan/output/testdata/output.txt @@ -2,7 +2,14 @@ Found missing resources: aws_deleted_resource: - deleted-id-1 - deleted-id-2 + aws_test_resource: + - test-id-1 + - test-id-2 Found resources not covered by IaC: + aws_resource: + - test-id-2 + aws_testing_resource: + - test-id-1 aws_unmanaged_resource: - unmanaged-id-1 - unmanaged-id-2 @@ -11,9 +18,9 @@ Found changed resources: ~ updated.field: "foobar" => "barfoo" + new.field: => "newValue" - a: "oldValue" => -Found 6 resource(s) - - 33% coverage +Found 10 resource(s) + - 20% coverage - 2 covered by IaC - - 2 not covered by IaC - - 2 missing on cloud provider + - 4 not covered by IaC + - 4 missing on cloud provider - 1/2 changed outside of IaC