Repository: aws-cloudformation/rain
Pull request #20 (2020-05-27 13:22:07)

Hide nested stacks by default in `ls` output. Add a flag to show them…
… indented.

*Issue #, if available:*

*Description of changes:*


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.



Patch:
diff --git a/cmd/ls.go b/cmd/ls.go
index fcc5ec87..51f8ca38 100644
--- a/cmd/ls.go
+++ b/cmd/ls.go
@@ -3,6 +3,7 @@ package cmd
 import (
 	"fmt"
 	"sort"
+	"strings"
 
 	"github.com/aws-cloudformation/rain/client"
 	"github.com/aws-cloudformation/rain/client/cfn"
@@ -14,6 +15,27 @@ import (
 )
 
 var allRegions = false
+var showNested = false
+
+func formatStack(stack cloudformation.StackSummary, stackMap map[string]cloudformation.StackSummary) string {
+	out := strings.Builder{}
+
+	out.WriteString(fmt.Sprintf("%s: %s\n",
+		*stack.StackName,
+		colouriseStatus(string(stack.StackStatus)),
+	))
+
+	if showNested {
+		for _, otherStack := range stackMap {
+			if otherStack.ParentId != nil && *otherStack.ParentId == *stack.StackId {
+				out.WriteString(indent("- ", formatStack(otherStack, stackMap)))
+				out.WriteString("\n")
+			}
+		}
+	}
+
+	return out.String()
+}
 
 var lsCmd = &cobra.Command{
 	Use:                   "ls <stack>",
@@ -64,6 +86,7 @@ var lsCmd = &cobra.Command{
 				for _, stack := range stacks {
 					stackNames = append(stackNames, *stack.StackName)
 					stackMap[*stack.StackName] = stack
+					fmt.Println(stack)
 				}
 				sort.Strings(stackNames)
 
@@ -71,10 +94,11 @@ var lsCmd = &cobra.Command{
 
 				fmt.Println(text.Yellow(fmt.Sprintf("CloudFormation stacks in %s:", region)))
 				for _, stackName := range stackNames {
-					fmt.Printf("  %s: %s\n",
-						stackName,
-						colouriseStatus(string(stackMap[stackName].StackStatus)),
-					)
+					stack := stackMap[stackName]
+
+					if stack.ParentId == nil {
+						fmt.Println(indent("  ", formatStack(stack, stackMap)))
+					}
 				}
 				fmt.Println()
 			}
@@ -84,5 +108,6 @@ var lsCmd = &cobra.Command{
 
 func init() {
 	lsCmd.Flags().BoolVarP(&allRegions, "all", "a", false, "List stacks across all regions")
+	lsCmd.Flags().BoolVarP(&showNested, "nested", "n", false, "Show nested stacks (hidden by default)")
 	Root.AddCommand(lsCmd)
 }
diff --git a/cmd/util.go b/cmd/util.go
index 6e81774f..34bac137 100644
--- a/cmd/util.go
+++ b/cmd/util.go
@@ -19,6 +19,10 @@ import (
 	"github.com/aws/aws-sdk-go-v2/service/cloudformation"
 )
 
+func indent(prefix string, in string) string {
+	return prefix + strings.Join(strings.Split(strings.TrimSpace(in), "\n"), "\n"+prefix)
+}
+
 func colouriseStatus(status string) text.Text {
 	switch {
 	case strings.HasSuffix(status, "_FAILED"):


Test patch:
diff --git a/cmd/ls_test.go b/cmd/ls_test.go
index f2b4c5c0..f259a8cb 100644
--- a/cmd/ls_test.go
+++ b/cmd/ls_test.go
@@ -24,8 +24,9 @@ func Example_ls_help() {
 	//   ls, list
 	//
 	// Flags:
-	//   -a, --all    List stacks across all regions
-	//   -h, --help   help for ls
+	//   -a, --all      List stacks across all regions
+	//   -h, --help     help for ls
+	//   -n, --nested   Show nested stacks (hidden by default)
 	//
 	// Global Flags:
 	//       --debug            Output debugging information
diff --git a/cmd/util_test.go b/cmd/util_test.go
index d048c4cd..78017ae5 100644
--- a/cmd/util_test.go
+++ b/cmd/util_test.go
@@ -5,6 +5,8 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/google/go-cmp/cmp"
+
 	"github.com/aws-cloudformation/rain/cfn/diff"
 	"github.com/aws-cloudformation/rain/console"
 	"github.com/aws-cloudformation/rain/console/text"
@@ -97,3 +99,22 @@ func TestStatusIsSettled(t *testing.T) {
 		}
 	}
 }
+
+func TestIndent(t *testing.T) {
+	input := `This
+has
+multiple
+lines
+`
+
+	expected := `  This
+  has
+  multiple
+  lines` // Should chomp ending blank lines
+
+	actual := indent("  ", input)
+
+	if d := cmp.Diff(actual, expected); d != "" {
+		t.Errorf(d)
+	}
+}