From 66808fd1d184c7cd0287ef8d20be26b0098c16c1 Mon Sep 17 00:00:00 2001 From: FireDrunk Date: Tue, 19 Mar 2024 13:39:37 +0100 Subject: [PATCH 1/3] Added JSON support --- cmd/commands.go | 18 ++++++++-- internal/parser/parser.go | 74 +++++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/cmd/commands.go b/cmd/commands.go index 99598ad..12f2923 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -21,6 +21,8 @@ var ( showUnchanged bool compact bool useMarkdown bool + useJson bool + metrics bool ) func init() { @@ -28,20 +30,32 @@ func init() { summarizeCmd.Flags().BoolVarP(&showUnchanged, "show-unchanged", "u", false, "Show resources with no changes") summarizeCmd.Flags().BoolVarP(&compact, "compact", "c", false, "Use compact formatting") summarizeCmd.Flags().BoolVarP(&useMarkdown, "markdown", "m", false, "Use markdown formatting") + summarizeCmd.Flags().BoolVarP(&useJson, "json", "j", false, "Use JSON output") + summarizeCmd.Flags().BoolVarP(&metrics, "metrics", "s", false, "Output metrics") } -// summarizeCmd will parse the tf plan output json to scrape created|updated|deleted resources in a clear outout +// summarizeCmd will parse the tf plan output useJson to scrape created|updated|deleted resources in a clear outout var summarizeCmd = &cobra.Command{ Use: "summarize", Short: "Get a summary of terraform/terragrunt output", Long: "Get a summary of terraform/terragrunt output plan (created|updated|destroyed...)", Run: func(cmd *cobra.Command, args []string) { + if useMarkdown && useJson { + fmt.Println("-m (Markdown output) and -j (JSON output) are mutually exclusive") + os.Exit(1) + } + + if metrics && !useJson { + fmt.Println("Metric output can only be used with JSON output") + os.Exit(1) + } + output, err := reader.Reader(os.Stdin) if err != nil { panic(err) } - parser.Parser(output, showTags, showUnchanged, compact, useMarkdown) + parser.Parser(output, showTags, showUnchanged, compact, useMarkdown, useJson, metrics) }, } diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 26fa261..6f6960e 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -20,7 +20,7 @@ var ( resourcesList = make(map[string][]string) ) -func Parser(output []byte, showTags, showUnchanged, compact, useMarkdown bool) { +func Parser(output []byte, showTags, showUnchanged, compact, useMarkdown bool, useJson bool, metrics bool) { var data tfjson.Plan if err := json.Unmarshal(output, &data); err != nil { fmt.Printf("Error unmarshalling plan: %v\n", err) @@ -31,7 +31,7 @@ func Parser(output []byte, showTags, showUnchanged, compact, useMarkdown bool) { processResourceChange(resourceChange, showTags) } - PrintPlanSummary(showTags, showUnchanged, compact, useMarkdown) + PrintPlanSummary(showTags, showUnchanged, compact, useMarkdown, useJson, metrics) } func processResourceChange(resourceChange *tfjson.ResourceChange, showTags bool) { @@ -140,16 +140,70 @@ func PrintResources(message string, resources []string, bulletSymbol string, col } } -func PrintPlanSummary(showTags, showUnchanged, compact, useMarkdown bool) { - if showUnchanged { - PrintResources("🔵 Unchanged:", resourcesList[NOOP], "•", color.New(color.FgBlue), compact, useMarkdown) +func PrintPlanSummary(showTags, showUnchanged, compact, useMarkdown bool, useJson bool, metrics bool) { + if !useJson { + if showUnchanged { + PrintResources("🔵 Unchanged:", resourcesList[NOOP], "•", color.New(color.FgBlue), compact, useMarkdown) + fmt.Println(",") + } + if showTags { + PrintResources("🟣 Tag/Untag:", resourcesList[TAG], "#", color.New(color.FgMagenta), compact, useMarkdown) + fmt.Println(",") + } + PrintResources("🟢 Create:", resourcesList[CREATE], "+", color.New(color.FgGreen), compact, useMarkdown) + fmt.Println(",") + PrintResources("🟡 Update:", resourcesList[UPDATE], "~", color.New(color.FgYellow), compact, useMarkdown) + fmt.Println(",") + PrintResources("🔴 Destroy:", resourcesList[DELETE], "-", color.New(color.FgRed), compact, useMarkdown) + } else { + PrintResourcesJson(showTags, showUnchanged, metrics) } - if showTags { - PrintResources("🟣 Tag/Untag:", resourcesList[TAG], "#", color.New(color.FgMagenta), compact, useMarkdown) +} + +func PrintResourcesJson(showTags bool, showUnchanged bool, metrics bool) { + if metrics { + var metricsData = make(map[string]int) + + if showUnchanged { + metricsData["unchanged"] = len(resourcesList[NOOP]) + } + + if showTags { + metricsData["tag"] = len(resourcesList[TAG]) + } + + metricsData["create"] = len(resourcesList[CREATE]) + metricsData["update"] = len(resourcesList[UPDATE]) + metricsData["delete"] = len(resourcesList[DELETE]) + + result, _ := json.Marshal(metricsData) + fmt.Println(string(result)) + } else { + var data = make(map[string][]string) + + if showUnchanged && len(resourcesList[NOOP]) > 0 { + data["unchanged"] = resourcesList[NOOP] + } + + if showTags && len(resourcesList[TAG]) > 0 { + data["tag"] = resourcesList[TAG] + } + + if len(resourcesList[CREATE]) > 0 { + data["create"] = resourcesList[CREATE] + } + + if len(resourcesList[UPDATE]) > 0 { + data["update"] = resourcesList[UPDATE] + } + + if len(resourcesList[DELETE]) > 0 { + data["delete"] = resourcesList[DELETE] + } + + result, _ := json.Marshal(data) + fmt.Println(string(result)) } - PrintResources("🟢 Create:", resourcesList[CREATE], "+", color.New(color.FgGreen), compact, useMarkdown) - PrintResources("🟡 Update:", resourcesList[UPDATE], "~", color.New(color.FgYellow), compact, useMarkdown) - PrintResources("🔴 Destroy:", resourcesList[DELETE], "-", color.New(color.FgRed), compact, useMarkdown) } func checkOnlyTagChanges(resourceChange *tfjson.ResourceChange) (bool, error) { From dbc1f7a03fb6dd8b7007c41bf7364904b965886d Mon Sep 17 00:00:00 2001 From: FireDrunk Date: Tue, 19 Mar 2024 13:42:06 +0100 Subject: [PATCH 2/3] Fix some minor issues --- cmd/commands.go | 2 +- internal/parser/parser.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd/commands.go b/cmd/commands.go index 12f2923..809db07 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -34,7 +34,7 @@ func init() { summarizeCmd.Flags().BoolVarP(&metrics, "metrics", "s", false, "Output metrics") } -// summarizeCmd will parse the tf plan output useJson to scrape created|updated|deleted resources in a clear outout +// summarizeCmd will parse the tf plan output json to scrape created|updated|deleted resources in a clear outout var summarizeCmd = &cobra.Command{ Use: "summarize", Short: "Get a summary of terraform/terragrunt output", diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 6f6960e..9b57154 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -144,16 +144,12 @@ func PrintPlanSummary(showTags, showUnchanged, compact, useMarkdown bool, useJso if !useJson { if showUnchanged { PrintResources("🔵 Unchanged:", resourcesList[NOOP], "•", color.New(color.FgBlue), compact, useMarkdown) - fmt.Println(",") } if showTags { PrintResources("🟣 Tag/Untag:", resourcesList[TAG], "#", color.New(color.FgMagenta), compact, useMarkdown) - fmt.Println(",") } PrintResources("🟢 Create:", resourcesList[CREATE], "+", color.New(color.FgGreen), compact, useMarkdown) - fmt.Println(",") PrintResources("🟡 Update:", resourcesList[UPDATE], "~", color.New(color.FgYellow), compact, useMarkdown) - fmt.Println(",") PrintResources("🔴 Destroy:", resourcesList[DELETE], "-", color.New(color.FgRed), compact, useMarkdown) } else { PrintResourcesJson(showTags, showUnchanged, metrics) From f87bf929f857b2d8654e8a7089b2c96b536eaa7d Mon Sep 17 00:00:00 2001 From: FireDrunk Date: Fri, 22 Mar 2024 13:48:18 +0100 Subject: [PATCH 3/3] Pin version --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b56d585..88d8ef6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/containerscrew/tftools -go 1.21.5 +go 1.21 require ( github.com/charmbracelet/glamour v0.6.0