diff --git a/Makefile b/Makefile
index 861ea7c..58f8882 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,19 @@
TERRAFORM_VERSION:=$(shell cat example/.terraform-version)
+define generate-example
+ docker run \
+ --interactive \
+ --tty \
+ --volume $(shell pwd):/src \
+ --workdir /src/example \
+ --entrypoint /bin/sh \
+ hashicorp/terraform:$(1) \
+ -c \
+ "terraform init && \
+ terraform plan -out tfplan && \
+ terraform show -json tfplan > tfplan.json"
+endef
+
.PHONY: help
help: ## prints help (only for tasks with comment)
@grep -E '^[a-zA-Z._-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
@@ -13,28 +27,14 @@ build: ## build the binary
install: build ## build and install to /usr/local/bin/
cp $(EXECUTABLE_NAME) /usr/local/bin/$(EXECUTABLE_NAME)
-test: lint
- go test ./...
+test: lint ## go test
+ go test ./... -count=1
i: install ## build and install to /usr/local/bin/
-lint:
+lint: ## lint source code
golangci-lint run --timeout 10m -v
-define generate-example
- docker run \
- --interactive \
- --tty \
- --volume $(shell pwd):/src \
- --workdir /src/example \
- --entrypoint /bin/sh \
- hashicorp/terraform:$(1) \
- -c \
- "terraform init && \
- terraform plan -out tfplan && \
- terraform show -json tfplan > tfplan.json"
-endef
-
-example:
+example: ## generate example Terraform plan
$(call generate-example,$(TERRAFORM_VERSION))
.PHONY: example
diff --git a/README.md b/README.md
index 9402cfe..b141845 100644
--- a/README.md
+++ b/README.md
@@ -110,10 +110,16 @@ Usage of tf-summarize [args] [tf-plan.json|tfplan]
-draw
[Optional, used only with -tree or -separate-tree] draw trees instead of plain tree
+ -html
+ [Optional] print changes in html format
+ -json
+ [Optional] print changes in json format
+ -md
+ [Optional, used only with table view] output table as markdown
-out string
[Optional] write output to file
-separate-tree
- [Optional] print changes in tree format for each add/delete/change/recreate changes
+ [Optional] print changes in tree format for add/delete/change/recreate changes
-tree
[Optional] print changes in tree format
-v print version
diff --git a/example/.terraform.lock.hcl b/example/.terraform.lock.hcl
index b28c736..485328c 100644
--- a/example/.terraform.lock.hcl
+++ b/example/.terraform.lock.hcl
@@ -4,6 +4,7 @@
provider "registry.terraform.io/hashicorp/github" {
version = "4.23.0"
hashes = [
+ "h1:C8mQRZrHenfru/LKN+qqwAI6aEIGbu9iWaWVmGFwcy4=",
"h1:eylJFdBYJIxdyyElE1mV7cMcv2HjUYzv+pFZjg/aRLU=",
"zh:003f67dcb506ea50b34acce92f575cd04560a21c57bb63de1c9b3874dda10337",
"zh:1b9e77fb728e3d2c8d25d04ac613e7587714c63c54532ac96787b4d351b164de",
@@ -25,6 +26,7 @@ provider "registry.terraform.io/integrations/github" {
version = "4.23.0"
constraints = "4.23.0"
hashes = [
+ "h1:C8mQRZrHenfru/LKN+qqwAI6aEIGbu9iWaWVmGFwcy4=",
"h1:eylJFdBYJIxdyyElE1mV7cMcv2HjUYzv+pFZjg/aRLU=",
"zh:003f67dcb506ea50b34acce92f575cd04560a21c57bb63de1c9b3874dda10337",
"zh:1b9e77fb728e3d2c8d25d04ac613e7587714c63c54532ac96787b4d351b164de",
diff --git a/example/github/main.tf b/example/github/main.tf
index d19c6ce..1a83d41 100644
--- a/example/github/main.tf
+++ b/example/github/main.tf
@@ -20,4 +20,8 @@ resource "github_branch" "main" {
resource "github_branch" "development" {
repository = github_repository.repository.name
branch = "development"
-}
\ No newline at end of file
+}
+
+output "repository_name" {
+ value = github_repository.repository.name
+}
diff --git a/example/main.tf b/example/main.tf
index bd26518..84c8e72 100644
--- a/example/main.tf
+++ b/example/main.tf
@@ -58,3 +58,7 @@ resource "github_repository" "terraform_plan_summary" {
has_wiki = true
vulnerability_alerts = false
}
+
+output "terraform_plan_summary_repository_name" {
+ value = github_repository.terraform_plan_summary.name
+}
diff --git a/example/tfplan.json b/example/tfplan.json
index a151ff1..c937d9d 100644
--- a/example/tfplan.json
+++ b/example/tfplan.json
@@ -1 +1 @@
-{"format_version":"1.0","terraform_version":"1.1.4","planned_values":{"root_module":{"resources":[{"address":"github_repository.terraform_plan_summary","mode":"managed","type":"github_repository","name":"terraform_plan_summary","provider_name":"registry.terraform.io/integrations/github","schema_version":0,"values":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"sensitive_values":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}],"child_modules":[{"resources":[{"address":"module.github[\"demo-repository\"].github_branch.development","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"development","repository":"demo-repository","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"demo-repository\"].github_branch.main","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"main","repository":"demo-repository","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"demo-repository\"].github_repository.repository","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"description of the repo","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"demo-repository","pages":[],"template":[],"topics":["tags"],"visibility":"public","vulnerability_alerts":false},"sensitive_values":{"branches":[],"pages":[],"template":[],"topics":[false]}}],"address":"module.github[\"demo-repository\"]"},{"resources":[{"address":"module.github[\"terraform-plan-summary\"].github_branch.demo","mode":"managed","type":"github_branch","name":"demo","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"sensitive_values":false},{"address":"module.github[\"terraform-plan-summary\"].github_branch.development","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"development","repository":"terraform-plan-summary","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.main","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"main","repository":"terraform-plan-summary","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"terraform-plan-summary\"].github_repository.repository","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"sensitive_values":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}],"address":"module.github[\"terraform-plan-summary\"]"}]}},"resource_drift":[{"address":"module.github[\"terraform-plan-summary\"].github_branch.demo","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"demo","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["delete"],"before":{"branch":"demo","etag":"W/\"2c138304ec0f031d3ffd19d45dae737be855a74a8d7e48f4fae4fc9213a6dbf6\"","id":"terraform-plan-summary:demo","ref":"refs/heads/demo","repository":"terraform-plan-summary","sha":"2e3d2c0b4513373c72b96b29592b62581e271af9","source_branch":"main","source_sha":null},"after":null,"after_unknown":{},"before_sensitive":{},"after_sensitive":false}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.main","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["delete"],"before":{"branch":"main","etag":"W/\"4d429c1f4818d4314dcd07dd1e034b2bab0014a46bf9088635e37fd6decc64b8\"","id":"terraform-plan-summary:main","ref":"refs/heads/main","repository":"terraform-plan-summary","sha":"ad0cb343cc26f08985e5517bd2da8f0483beaa4b","source_branch":"main","source_sha":null},"after":null,"after_unknown":{},"before_sensitive":{},"after_sensitive":false}},{"address":"module.github[\"terraform-plan-summary\"].github_repository.repository","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["delete"],"before":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":false,"branches":[{"name":"main","protected":false},{"name":"trail","protected":false}],"default_branch":"main","delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","etag":"W/\"7536d6c2714d2e49890a3d1ebed0a31e89b6412f973e0d631089836e25229f29\"","full_name":"dineshba/terraform-plan-summary","git_clone_url":"git://github.com/dineshba/terraform-plan-summary.git","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":"","html_url":"https://github.com/dineshba/terraform-plan-summary","http_clone_url":"https://github.com/dineshba/terraform-plan-summary.git","id":"terraform-plan-summary","ignore_vulnerability_alerts_during_read":null,"is_template":false,"license_template":null,"name":"terraform-plan-summary","node_id":"R_kgDOGq54_w","pages":[],"private":false,"repo_id":447641855,"ssh_clone_url":"git@github.com:dineshba/terraform-plan-summary.git","svn_url":"https://github.com/dineshba/terraform-plan-summary","template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":true},"after":null,"after_unknown":{},"before_sensitive":{"branches":[{},{}],"pages":[],"template":[],"topics":[false,false]},"after_sensitive":false}}],"resource_changes":[{"address":"github_repository.terraform_plan_summary","mode":"managed","type":"github_repository","name":"terraform_plan_summary","provider_name":"registry.terraform.io/integrations/github","change":{"actions":["create"],"before":null,"after":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"after_unknown":{"branches":true,"default_branch":true,"etag":true,"full_name":true,"git_clone_url":true,"html_url":true,"http_clone_url":true,"id":true,"node_id":true,"pages":[],"private":true,"repo_id":true,"ssh_clone_url":true,"svn_url":true,"template":[],"topics":[false,false]},"before_sensitive":false,"after_sensitive":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}},{"address":"module.github[\"demo-repository\"].github_branch.development","module_address":"module.github[\"demo-repository\"]","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"development","repository":"demo-repository","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"demo-repository\"].github_branch.main","module_address":"module.github[\"demo-repository\"]","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"main","repository":"demo-repository","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"demo-repository\"].github_repository.repository","module_address":"module.github[\"demo-repository\"]","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"description of the repo","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"demo-repository","pages":[],"template":[],"topics":["tags"],"visibility":"public","vulnerability_alerts":false},"after_unknown":{"branches":true,"default_branch":true,"etag":true,"full_name":true,"git_clone_url":true,"html_url":true,"http_clone_url":true,"id":true,"node_id":true,"pages":[],"private":true,"repo_id":true,"ssh_clone_url":true,"svn_url":true,"template":[],"topics":[false]},"before_sensitive":false,"after_sensitive":{"branches":[],"pages":[],"template":[],"topics":[false]}}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.demo","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"demo","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["no-op"],"before":null,"after":null,"after_unknown":{},"before_sensitive":false,"after_sensitive":false},"action_reason":"delete_because_no_resource_config"},{"address":"module.github[\"terraform-plan-summary\"].github_branch.development","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"development","repository":"terraform-plan-summary","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.main","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"main","repository":"terraform-plan-summary","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"terraform-plan-summary\"].github_repository.repository","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"after_unknown":{"branches":true,"default_branch":true,"etag":true,"full_name":true,"git_clone_url":true,"html_url":true,"http_clone_url":true,"id":true,"node_id":true,"pages":[],"private":true,"repo_id":true,"ssh_clone_url":true,"svn_url":true,"template":[],"topics":[false,false]},"before_sensitive":false,"after_sensitive":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}}],"configuration":{"provider_config":{"github":{"name":"github","version_constraint":"4.23.0","expressions":{"owner":{"constant_value":"dineshba"}}}},"root_module":{"resources":[{"address":"github_repository.terraform_plan_summary","mode":"managed","type":"github_repository","name":"terraform_plan_summary","provider_config_key":"github","expressions":{"description":{"constant_value":"A command-line utility to print the summary of the terraform plan"},"has_downloads":{"constant_value":true},"has_issues":{"constant_value":true},"has_projects":{"constant_value":true},"has_wiki":{"constant_value":true},"name":{"constant_value":"terraform-plan-summary"},"topics":{"constant_value":["summary","terraform"]},"visibility":{"constant_value":"public"},"vulnerability_alerts":{"constant_value":false}},"schema_version":0}],"module_calls":{"github":{"source":"./github","expressions":{"description":{"references":["each.value.description","each.value"]},"name":{"references":["each.key"]},"topics":{"references":["each.value.topics","each.value"]}},"for_each_expression":{"references":["local.repos"]},"module":{"resources":[{"address":"github_branch.development","mode":"managed","type":"github_branch","name":"development","provider_config_key":"github:github","expressions":{"branch":{"constant_value":"development"},"repository":{"references":["github_repository.repository.name","github_repository.repository"]}},"schema_version":0},{"address":"github_branch.main","mode":"managed","type":"github_branch","name":"main","provider_config_key":"github:github","expressions":{"branch":{"constant_value":"main"},"repository":{"references":["github_repository.repository.name","github_repository.repository"]}},"schema_version":0},{"address":"github_repository.repository","mode":"managed","type":"github_repository","name":"repository","provider_config_key":"github:github","expressions":{"description":{"references":["var.description"]},"has_downloads":{"constant_value":true},"has_issues":{"constant_value":true},"has_projects":{"constant_value":true},"has_wiki":{"constant_value":true},"name":{"references":["var.name"]},"topics":{"references":["var.topics"]},"visibility":{"constant_value":"public"},"vulnerability_alerts":{"constant_value":false}},"schema_version":0}],"variables":{"description":{},"name":{},"topics":{}}}}}}}}
+{"format_version":"1.0","terraform_version":"1.1.4","planned_values":{"outputs":{"terraform_plan_summary_repository_name":{"sensitive":false,"value":"terraform-plan-summary"}},"root_module":{"resources":[{"address":"github_repository.terraform_plan_summary","mode":"managed","type":"github_repository","name":"terraform_plan_summary","provider_name":"registry.terraform.io/integrations/github","schema_version":0,"values":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"sensitive_values":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}],"child_modules":[{"resources":[{"address":"module.github[\"demo-repository\"].github_branch.development","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"development","repository":"demo-repository","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"demo-repository\"].github_branch.main","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"main","repository":"demo-repository","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"demo-repository\"].github_repository.repository","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"description of the repo","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"demo-repository","pages":[],"template":[],"topics":["tags"],"visibility":"public","vulnerability_alerts":false},"sensitive_values":{"branches":[],"pages":[],"template":[],"topics":[false]}}],"address":"module.github[\"demo-repository\"]"},{"resources":[{"address":"module.github[\"terraform-plan-summary\"].github_branch.demo","mode":"managed","type":"github_branch","name":"demo","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"sensitive_values":false},{"address":"module.github[\"terraform-plan-summary\"].github_branch.development","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"development","repository":"terraform-plan-summary","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.main","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"branch":"main","repository":"terraform-plan-summary","source_branch":"main"},"sensitive_values":{}},{"address":"module.github[\"terraform-plan-summary\"].github_repository.repository","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","schema_version":0,"values":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"sensitive_values":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}],"address":"module.github[\"terraform-plan-summary\"]"}]}},"resource_drift":[{"address":"module.github[\"terraform-plan-summary\"].github_branch.demo","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"demo","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["delete"],"before":{"branch":"demo","etag":"W/\"2c138304ec0f031d3ffd19d45dae737be855a74a8d7e48f4fae4fc9213a6dbf6\"","id":"terraform-plan-summary:demo","ref":"refs/heads/demo","repository":"terraform-plan-summary","sha":"2e3d2c0b4513373c72b96b29592b62581e271af9","source_branch":"main","source_sha":null},"after":null,"after_unknown":{},"before_sensitive":{},"after_sensitive":false}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.main","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["delete"],"before":{"branch":"main","etag":"W/\"4d429c1f4818d4314dcd07dd1e034b2bab0014a46bf9088635e37fd6decc64b8\"","id":"terraform-plan-summary:main","ref":"refs/heads/main","repository":"terraform-plan-summary","sha":"ad0cb343cc26f08985e5517bd2da8f0483beaa4b","source_branch":"main","source_sha":null},"after":null,"after_unknown":{},"before_sensitive":{},"after_sensitive":false}},{"address":"module.github[\"terraform-plan-summary\"].github_repository.repository","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["delete"],"before":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":false,"branches":[{"name":"main","protected":false},{"name":"trail","protected":false}],"default_branch":"main","delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","etag":"W/\"7536d6c2714d2e49890a3d1ebed0a31e89b6412f973e0d631089836e25229f29\"","full_name":"dineshba/terraform-plan-summary","git_clone_url":"git://github.com/dineshba/terraform-plan-summary.git","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":"","html_url":"https://github.com/dineshba/terraform-plan-summary","http_clone_url":"https://github.com/dineshba/terraform-plan-summary.git","id":"terraform-plan-summary","ignore_vulnerability_alerts_during_read":null,"is_template":false,"license_template":null,"name":"terraform-plan-summary","node_id":"R_kgDOGq54_w","pages":[],"private":false,"repo_id":447641855,"ssh_clone_url":"git@github.com:dineshba/terraform-plan-summary.git","svn_url":"https://github.com/dineshba/terraform-plan-summary","template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":true},"after":null,"after_unknown":{},"before_sensitive":{"branches":[{},{}],"pages":[],"template":[],"topics":[false,false]},"after_sensitive":false}}],"resource_changes":[{"address":"github_repository.terraform_plan_summary","mode":"managed","type":"github_repository","name":"terraform_plan_summary","provider_name":"registry.terraform.io/integrations/github","change":{"actions":["create"],"before":null,"after":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"after_unknown":{"branches":true,"default_branch":true,"etag":true,"full_name":true,"git_clone_url":true,"html_url":true,"http_clone_url":true,"id":true,"node_id":true,"pages":[],"private":true,"repo_id":true,"ssh_clone_url":true,"svn_url":true,"template":[],"topics":[false,false]},"before_sensitive":false,"after_sensitive":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}},{"address":"module.github[\"demo-repository\"].github_branch.development","module_address":"module.github[\"demo-repository\"]","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"development","repository":"demo-repository","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"demo-repository\"].github_branch.main","module_address":"module.github[\"demo-repository\"]","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"main","repository":"demo-repository","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"demo-repository\"].github_repository.repository","module_address":"module.github[\"demo-repository\"]","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"description of the repo","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"demo-repository","pages":[],"template":[],"topics":["tags"],"visibility":"public","vulnerability_alerts":false},"after_unknown":{"branches":true,"default_branch":true,"etag":true,"full_name":true,"git_clone_url":true,"html_url":true,"http_clone_url":true,"id":true,"node_id":true,"pages":[],"private":true,"repo_id":true,"ssh_clone_url":true,"svn_url":true,"template":[],"topics":[false]},"before_sensitive":false,"after_sensitive":{"branches":[],"pages":[],"template":[],"topics":[false]}}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.demo","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"demo","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["no-op"],"before":null,"after":null,"after_unknown":{},"before_sensitive":false,"after_sensitive":false},"action_reason":"delete_because_no_resource_config"},{"address":"module.github[\"terraform-plan-summary\"].github_branch.development","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"development","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"development","repository":"terraform-plan-summary","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"terraform-plan-summary\"].github_branch.main","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_branch","name":"main","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"branch":"main","repository":"terraform-plan-summary","source_branch":"main"},"after_unknown":{"etag":true,"id":true,"ref":true,"sha":true,"source_sha":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.github[\"terraform-plan-summary\"].github_repository.repository","module_address":"module.github[\"terraform-plan-summary\"]","mode":"managed","type":"github_repository","name":"repository","provider_name":"registry.terraform.io/hashicorp/github","change":{"actions":["create"],"before":null,"after":{"allow_auto_merge":false,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_squash_merge":true,"archive_on_destroy":null,"archived":false,"auto_init":null,"delete_branch_on_merge":false,"description":"A command-line utility to print the summary of the terraform plan","gitignore_template":null,"has_downloads":true,"has_issues":true,"has_projects":true,"has_wiki":true,"homepage_url":null,"ignore_vulnerability_alerts_during_read":null,"is_template":null,"license_template":null,"name":"terraform-plan-summary","pages":[],"template":[],"topics":["summary","terraform"],"visibility":"public","vulnerability_alerts":false},"after_unknown":{"branches":true,"default_branch":true,"etag":true,"full_name":true,"git_clone_url":true,"html_url":true,"http_clone_url":true,"id":true,"node_id":true,"pages":[],"private":true,"repo_id":true,"ssh_clone_url":true,"svn_url":true,"template":[],"topics":[false,false]},"before_sensitive":false,"after_sensitive":{"branches":[],"pages":[],"template":[],"topics":[false,false]}}}],"output_changes":{"terraform_plan_summary_repository_name":{"actions":["create"],"before":null,"after":"terraform-plan-summary","after_unknown":false,"before_sensitive":false,"after_sensitive":false}},"prior_state":{"format_version":"1.0","terraform_version":"1.1.4","values":{"outputs":{"terraform_plan_summary_repository_name":{"sensitive":false,"value":"terraform-plan-summary"}},"root_module":{}}},"configuration":{"provider_config":{"github":{"name":"github","version_constraint":"4.23.0","expressions":{"owner":{"constant_value":"dineshba"}}}},"root_module":{"outputs":{"terraform_plan_summary_repository_name":{"expression":{"references":["github_repository.terraform_plan_summary.name","github_repository.terraform_plan_summary"]}}},"resources":[{"address":"github_repository.terraform_plan_summary","mode":"managed","type":"github_repository","name":"terraform_plan_summary","provider_config_key":"github","expressions":{"description":{"constant_value":"A command-line utility to print the summary of the terraform plan"},"has_downloads":{"constant_value":true},"has_issues":{"constant_value":true},"has_projects":{"constant_value":true},"has_wiki":{"constant_value":true},"name":{"constant_value":"terraform-plan-summary"},"topics":{"constant_value":["summary","terraform"]},"visibility":{"constant_value":"public"},"vulnerability_alerts":{"constant_value":false}},"schema_version":0}],"module_calls":{"github":{"source":"./github","expressions":{"description":{"references":["each.value.description","each.value"]},"name":{"references":["each.key"]},"topics":{"references":["each.value.topics","each.value"]}},"for_each_expression":{"references":["local.repos"]},"module":{"outputs":{"repository_name":{"expression":{"references":["github_repository.repository.name","github_repository.repository"]}}},"resources":[{"address":"github_branch.development","mode":"managed","type":"github_branch","name":"development","provider_config_key":"github:github","expressions":{"branch":{"constant_value":"development"},"repository":{"references":["github_repository.repository.name","github_repository.repository"]}},"schema_version":0},{"address":"github_branch.main","mode":"managed","type":"github_branch","name":"main","provider_config_key":"github:github","expressions":{"branch":{"constant_value":"main"},"repository":{"references":["github_repository.repository.name","github_repository.repository"]}},"schema_version":0},{"address":"github_repository.repository","mode":"managed","type":"github_repository","name":"repository","provider_config_key":"github:github","expressions":{"description":{"references":["var.description"]},"has_downloads":{"constant_value":true},"has_issues":{"constant_value":true},"has_projects":{"constant_value":true},"has_wiki":{"constant_value":true},"name":{"references":["var.name"]},"topics":{"references":["var.topics"]},"visibility":{"constant_value":"public"},"vulnerability_alerts":{"constant_value":false}},"schema_version":0}],"variables":{"description":{},"name":{},"topics":{}}}}}}}}
diff --git a/main.go b/main.go
index 837c137..f517699 100644
--- a/main.go
+++ b/main.go
@@ -18,6 +18,7 @@ func main() {
printVersion := flag.Bool("v", false, "print version")
tree := flag.Bool("tree", false, "[Optional] print changes in tree format")
json := flag.Bool("json", false, "[Optional] print changes in json format")
+ html := flag.Bool("html", false, "[Optional] print changes in html format")
separateTree := flag.Bool("separate-tree", false, "[Optional] print changes in tree format for add/delete/change/recreate changes")
drawable := flag.Bool("draw", false, "[Optional, used only with -tree or -separate-tree] draw trees instead of plain tree")
md := flag.Bool("md", false, "[Optional, used only with table view] output table as markdown")
@@ -35,7 +36,7 @@ func main() {
}
args := flag.Args()
- err := validateFlags(*tree, *separateTree, *drawable, *md, args)
+ err := validateFlags(*tree, *separateTree, *drawable, *md, *json, *html, args)
logIfErrorAndExit("invalid input flags: %s\n", err, flag.Usage)
newReader, err := reader.CreateReader(args)
@@ -52,7 +53,7 @@ func main() {
terraformstate.FilterNoOpResources(&terraformState)
- newWriter := writer.CreateWriter(*tree, *separateTree, *drawable, *md, *json, terraformState)
+ newWriter := writer.CreateWriter(*tree, *separateTree, *drawable, *md, *json, *html, terraformState)
var outputFile io.Writer = os.Stdout
@@ -83,7 +84,7 @@ func logIfErrorAndExit(format string, err error, callback func()) {
}
}
-func validateFlags(tree, separateTree, drawable bool, md bool, args []string) error {
+func validateFlags(tree, separateTree, drawable bool, md bool, json bool, html bool, args []string) error {
if tree && md {
return fmt.Errorf("both -tree and -md should not be provided")
}
@@ -96,8 +97,23 @@ func validateFlags(tree, separateTree, drawable bool, md bool, args []string) er
if !tree && !separateTree && drawable {
return fmt.Errorf("drawable should be provided with -tree or -seperate-tree")
}
+ if multipleTrueVals(md, json, html) {
+ return fmt.Errorf("only one of -md, -json, or -html should be provided")
+ }
if len(args) > 1 {
return fmt.Errorf("only one argument is allowed which is filename, but got %v", args)
}
return nil
}
+
+func multipleTrueVals(vals ...bool) bool {
+ v := []bool{}
+
+ for _, val := range vals {
+ if val {
+ v = append(v, val)
+ }
+ }
+
+ return len(v) > 1
+}
diff --git a/main_test.go b/main_test.go
index 80ec18a..d7c50c9 100644
--- a/main_test.go
+++ b/main_test.go
@@ -61,13 +61,20 @@ func TestTFSummarize(t *testing.T) {
}, {
command: fmt.Sprintf("cat example/tfplan.json | ./%s -md", testExecutable),
expectedOutput: "basic.txt",
+ }, {
+ command: fmt.Sprintf("cat example/tfplan.json | ./%s -html", testExecutable),
+ expectedOutput: "basic.html",
+ }, {
+ command: fmt.Sprintf("cat example/tfplan.json | ./%s -md -html", testExecutable),
+ expectedError: fmt.Errorf("exit status 1"),
+ expectedOutput: "multiple_format_flags_error.txt",
}}
for _, test := range tests {
t.Run(fmt.Sprintf("when tf-summarize is passed '%q'", test.command), func(t *testing.T) {
- output, err := exec.Command("/bin/sh", "-c", test.command).CombinedOutput()
- if err != nil && test.expectedError == nil {
- t.Errorf("expected '%s' not to error; got '%v'", test.command, err)
+ output, cmdErr := exec.Command("/bin/sh", "-c", test.command).CombinedOutput()
+ if cmdErr != nil && test.expectedError == nil {
+ t.Errorf("expected '%s' not to error; got '%v'", test.command, cmdErr)
}
b, err := os.ReadFile(fmt.Sprintf("testdata/%s", test.expectedOutput))
@@ -77,12 +84,12 @@ func TestTFSummarize(t *testing.T) {
expected := string(b)
- if test.expectedError != nil && err == nil {
- t.Errorf("expected error '%s'; got '%v'", test.expectedError.Error(), err)
+ if test.expectedError != nil && cmdErr == nil {
+ t.Errorf("expected error '%s'; got '%v'", test.expectedError.Error(), cmdErr)
}
- if test.expectedError != nil && err != nil && test.expectedError.Error() != err.Error() {
- t.Errorf("expected error '%s'; got '%v'", test.expectedError.Error(), err.Error())
+ if test.expectedError != nil && cmdErr != nil && test.expectedError.Error() != cmdErr.Error() {
+ t.Errorf("expected error '%s'; got '%v'", test.expectedError.Error(), cmdErr.Error())
}
if string(output) != expected {
diff --git a/testdata/basic.html b/testdata/basic.html
new file mode 100644
index 0000000..e842168
--- /dev/null
+++ b/testdata/basic.html
@@ -0,0 +1,34 @@
+
+
+ CHANGE |
+ RESOURCE |
+
+
+ add |
+
+
+ github_repository.terraform_plan_summary
+ module.github["demo-repository"].github_branch.development
+ module.github["demo-repository"].github_branch.main
+ module.github["demo-repository"].github_repository.repository
+ module.github["terraform-plan-summary"].github_branch.development
+ module.github["terraform-plan-summary"].github_branch.main
+ module.github["terraform-plan-summary"].github_repository.repository
+
+ |
+
+
+
+
+ CHANGE |
+ OUTPUT |
+
+
+ add |
+
+
+ terraform_plan_summary_repository_name
+
+ |
+
+
diff --git a/testdata/basic.txt b/testdata/basic.txt
index bb145c0..755c332 100644
--- a/testdata/basic.txt
+++ b/testdata/basic.txt
@@ -7,3 +7,7 @@
| | `module.github["terraform-plan-summary"].github_branch.development` |
| | `module.github["terraform-plan-summary"].github_branch.main` |
| | `module.github["terraform-plan-summary"].github_repository.repository` |
+
+| CHANGE | OUTPUT |
+|--------|------------------------------------------|
+| add | `terraform_plan_summary_repository_name` |
diff --git a/testdata/multiple_format_flags_error.txt b/testdata/multiple_format_flags_error.txt
new file mode 100644
index 0000000..4556cf1
--- /dev/null
+++ b/testdata/multiple_format_flags_error.txt
@@ -0,0 +1,19 @@
+invalid input flags: only one of -md, -json, or -html should be provided
+
+Usage of ./tf-summarize-test [args] [tf-plan.json|tfplan]
+
+ -draw
+ [Optional, used only with -tree or -separate-tree] draw trees instead of plain tree
+ -html
+ [Optional] print changes in html format
+ -json
+ [Optional] print changes in json format
+ -md
+ [Optional, used only with table view] output table as markdown
+ -out string
+ [Optional] write output to file
+ -separate-tree
+ [Optional] print changes in tree format for add/delete/change/recreate changes
+ -tree
+ [Optional] print changes in tree format
+ -v print version
diff --git a/writer/html.go b/writer/html.go
new file mode 100644
index 0000000..66ee3b5
--- /dev/null
+++ b/writer/html.go
@@ -0,0 +1,50 @@
+package writer
+
+import (
+ "io"
+ "path"
+ "text/template"
+
+ "github.com/dineshba/tf-summarize/terraformstate"
+)
+
+// HTMLWriter is a Writer that writes HTML.
+type HTMLWriter struct {
+ ResourceChanges map[string]terraformstate.ResourceChanges
+ OutputChanges map[string][]string
+}
+
+// Write outputs the HTML summary to the io.Writer it's passed.
+func (t HTMLWriter) Write(writer io.Writer) error {
+ templatesDir := "templates"
+ rcTmpl := "resourceChanges.html"
+ tmpl, err := template.New(rcTmpl).ParseFS(templates, path.Join(templatesDir, rcTmpl))
+ if err != nil {
+ return err
+ }
+
+ err = tmpl.Execute(writer, t)
+ if err != nil {
+ return err
+ }
+
+ if !hasOutputChanges(t.OutputChanges) {
+ return nil
+ }
+
+ ocTmpl := "outputChanges.html"
+ outputTmpl, err := template.New(ocTmpl).ParseFS(templates, path.Join(templatesDir, ocTmpl))
+ if err != nil {
+ return err
+ }
+
+ return outputTmpl.Execute(writer, t)
+}
+
+// NewHTMLWriter returns a new HTMLWriter with the configuration it's passed.
+func NewHTMLWriter(changes map[string]terraformstate.ResourceChanges, outputChanges map[string][]string) Writer {
+ return HTMLWriter{
+ ResourceChanges: changes,
+ OutputChanges: outputChanges,
+ }
+}
diff --git a/writer/table.go b/writer/table.go
index 05b0adf..33c2b0d 100644
--- a/writer/table.go
+++ b/writer/table.go
@@ -44,7 +44,7 @@ func (t TableWriter) Write(writer io.Writer) error {
table.Render()
// Disable the Output Summary if there are no outputs to display
- if len(t.outputChanges["add"]) > 0 || len(t.outputChanges["delete"]) > 0 || len(t.outputChanges["update"]) > 0 {
+ if hasOutputChanges(t.outputChanges) {
tableString = make([][]string, 0, 4)
for _, change := range tableOrder {
changedOutputs := t.outputChanges[change]
diff --git a/writer/templates/outputChanges.html b/writer/templates/outputChanges.html
new file mode 100644
index 0000000..cae9b49
--- /dev/null
+++ b/writer/templates/outputChanges.html
@@ -0,0 +1,14 @@
+
+
+ CHANGE |
+ OUTPUT |
+
{{ range $change, $outputs := .OutputChanges }}{{ $length := len $outputs }}{{ if gt $length 0 }}
+
+ {{ $change }} |
+
+ {{ range $i, $o := $outputs }}
+ {{ $o }} {{ end }}
+
+ |
+
{{ end }}{{ end }}
+
diff --git a/writer/templates/resourceChanges.html b/writer/templates/resourceChanges.html
new file mode 100644
index 0000000..8f4f4ab
--- /dev/null
+++ b/writer/templates/resourceChanges.html
@@ -0,0 +1,14 @@
+
+
+ CHANGE |
+ RESOURCE |
+
{{ range $change, $resources := .ResourceChanges }}{{ $length := len $resources }}{{ if gt $length 0 }}
+
+ {{ $change }} |
+
+ {{ range $i, $r := $resources }}
+ {{ $r.Address }} {{ end }}
+
+ |
+
{{ end }}{{ end }}
+
diff --git a/writer/util.go b/writer/util.go
new file mode 100644
index 0000000..fa08542
--- /dev/null
+++ b/writer/util.go
@@ -0,0 +1,21 @@
+package writer
+
+import "embed"
+
+// Embed the templates directory in the compiled binary.
+//
+//go:embed templates
+var templates embed.FS
+
+func hasOutputChanges(opChanges map[string][]string) bool {
+ hasChanges := false
+
+ for _, v := range opChanges {
+ if len(v) > 0 {
+ hasChanges = true
+ break
+ }
+ }
+
+ return hasChanges
+}
diff --git a/writer/writer.go b/writer/writer.go
index dd9d0a7..383bf13 100644
--- a/writer/writer.go
+++ b/writer/writer.go
@@ -11,8 +11,7 @@ type Writer interface {
Write(writer io.Writer) error
}
-func CreateWriter(tree, separateTree, drawable, mdEnabled, json bool, plan tfjson.Plan) Writer {
-
+func CreateWriter(tree, separateTree, drawable, mdEnabled, json, html bool, plan tfjson.Plan) Writer {
if tree {
return NewTreeWriter(plan.ResourceChanges, drawable)
}
@@ -22,6 +21,9 @@ func CreateWriter(tree, separateTree, drawable, mdEnabled, json bool, plan tfjso
if json {
return NewJSONWriter(plan.ResourceChanges)
}
+ if html {
+ return NewHTMLWriter(terraformstate.GetAllResourceChanges(plan), terraformstate.GetAllOutputChanges(plan))
+ }
return NewTableWriter(terraformstate.GetAllResourceChanges(plan), terraformstate.GetAllOutputChanges(plan), mdEnabled)
}