From 3000b5e2ab15a0a721b2f2f68414b7eec1d90f25 Mon Sep 17 00:00:00 2001
From: Simon Heather <32168619+X-Guardian@users.noreply.github.com>
Date: Tue, 2 Jan 2024 09:07:07 +0000
Subject: [PATCH] feat: Add Summaries to Plan And Apply PR Comments (#3889)
---
.../automerge/exp-output-autoplan.txt | 4 +
.../exp-output-autoplan.txt | 4 +
.../exp-output-plan-again.txt | 4 +
.../modules-yaml/exp-output-autoplan.txt | 4 +
.../exp-output-apply.txt | 5 +-
.../exp-output-autoplan.txt | 4 +
.../repo-config-file/exp-output-apply.txt | 5 +-
.../repo-config-file/exp-output-autoplan.txt | 4 +
.../server-side-cfg/exp-output-autoplan.txt | 4 +
.../simple-yaml/exp-output-apply-all.txt | 5 +-
.../simple-yaml/exp-output-autoplan.txt | 4 +
.../simple/exp-output-apply-var-all.txt | 5 +-
.../exp-output-autoplan.txt | 4 +
.../exp-output-plan-again.txt | 4 +
.../exp-output-plan.txt | 4 +
.../tfvars-yaml/exp-output-autoplan.txt | 4 +
.../exp-output-autoplan-production.txt | 4 +
.../exp-output-autoplan-staging.txt | 4 +
server/events/apply_command_runner_test.go | 10 +-
server/events/markdown_renderer.go | 43 ++++-
server/events/markdown_renderer_test.go | 168 +++++++++++++-----
.../events/templates/multi_project_apply.tmpl | 3 +-
.../templates/multi_project_apply_footer.tmpl | 7 +
.../events/templates/multi_project_plan.tmpl | 13 +-
.../templates/multi_project_plan_footer.tmpl | 13 ++
.../templates/multi_project_policy.tmpl | 23 +++
.../templates/single_project_apply.tmpl | 2 +-
.../single_project_import_success.tmpl | 2 +-
.../single_project_plan_success.tmpl | 2 +-
.../single_project_plan_unsuccessful.tmpl | 2 +-
server/events/templates/unwrapped_err.tmpl | 10 +-
31 files changed, 294 insertions(+), 80 deletions(-)
create mode 100644 server/events/templates/multi_project_apply_footer.tmpl
create mode 100644 server/events/templates/multi_project_plan_footer.tmpl
create mode 100644 server/events/templates/multi_project_policy.tmpl
diff --git a/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt
index 4f8bbe1fa0..c32ed6dfdc 100644
--- a/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/automerge/exp-output-autoplan.txt
@@ -49,6 +49,10 @@ Plan: 1 to add, 0 to change, 0 to destroy.
* `atlantis plan -d dir2`
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt
index 6d3aa862ab..7f0f5f45a8 100644
--- a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-autoplan.txt
@@ -69,6 +69,10 @@ Plan: 1 to add, 0 to change, 0 to destroy.
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt
index ce5547f08a..c9a7d87124 100644
--- a/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt
+++ b/server/controllers/events/testdata/test-repos/import-multiple-project/exp-output-plan-again.txt
@@ -53,6 +53,10 @@ Plan: 1 to add, 0 to change, 0 to destroy.
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 1 with changes, 1 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt
index 25fe0e6121..1e55d623b5 100644
--- a/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/modules-yaml/exp-output-autoplan.txt
@@ -63,6 +63,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt
index 34121591c1..eb6bda8987 100644
--- a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt
+++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-apply.txt
@@ -19,4 +19,7 @@ workspace = "default"
### 2. dir: `dir2` workspace: `default`
**Apply Failed**: All policies must pass for project before running apply.
----
\ No newline at end of file
+---
+### Apply Summary
+
+2 projects, 1 successful, 1 failed, 0 errored
\ No newline at end of file
diff --git a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt
index 55d2149939..098c4eba93 100644
--- a/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/policy-checks-multi-projects/exp-output-autoplan.txt
@@ -63,6 +63,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt
index 8490f306d7..a136ff9691 100644
--- a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt
+++ b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-apply.txt
@@ -20,4 +20,7 @@ null_resource.staging[0]: Creation complete after *s [id=*******************]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```
----
\ No newline at end of file
+---
+### Apply Summary
+
+2 projects, 2 successful, 0 failed, 0 errored
\ No newline at end of file
diff --git a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt
index 4f48c365d6..29f5f76dae 100644
--- a/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/repo-config-file/exp-output-autoplan.txt
@@ -49,6 +49,10 @@ Plan: 1 to add, 0 to change, 0 to destroy.
* `atlantis plan -d infrastructure/production`
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt
index 615a3f4c61..ad9591b8ae 100644
--- a/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/server-side-cfg/exp-output-autoplan.txt
@@ -71,6 +71,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt
index 711bf571ce..61eac2271a 100644
--- a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt
+++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-apply-all.txt
@@ -38,4 +38,7 @@ postapply
----
\ No newline at end of file
+---
+### Apply Summary
+
+2 projects, 2 successful, 0 failed, 0 errored
\ No newline at end of file
diff --git a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt
index 88eda9d431..dcbb45bf78 100644
--- a/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/simple-yaml/exp-output-autoplan.txt
@@ -70,6 +70,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt
index bd6526fa8c..2977099b55 100644
--- a/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt
+++ b/server/controllers/events/testdata/test-repos/simple/exp-output-apply-var-all.txt
@@ -46,4 +46,7 @@ workspace = "new_workspace"
----
\ No newline at end of file
+---
+### Apply Summary
+
+2 projects, 2 successful, 0 failed, 0 errored
\ No newline at end of file
diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt
index df46d869e6..49c4dc2673 100644
--- a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-autoplan.txt
@@ -69,6 +69,10 @@ Plan: 1 to add, 0 to change, 0 to destroy.
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt
index df46d869e6..49c4dc2673 100644
--- a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt
+++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan-again.txt
@@ -69,6 +69,10 @@ Plan: 1 to add, 0 to change, 0 to destroy.
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt
index 2766ea44de..fb3cfdbbd7 100644
--- a/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt
+++ b/server/controllers/events/testdata/test-repos/state-rm-multiple-project/exp-output-plan.txt
@@ -37,6 +37,10 @@ and found no differences, so no changes are needed.
* `atlantis plan -d dir2`
---
+### Plan Summary
+
+2 projects, 0 with changes, 2 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt
index d8a084bd85..82ce193d9f 100644
--- a/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt
+++ b/server/controllers/events/testdata/test-repos/tfvars-yaml/exp-output-autoplan.txt
@@ -67,6 +67,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt
index 73d66792e4..cd4e8e0b95 100644
--- a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt
+++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-production.txt
@@ -63,6 +63,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt
index 73d66792e4..cd4e8e0b95 100644
--- a/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt
+++ b/server/controllers/events/testdata/test-repos/workspace-parallel-yaml/exp-output-autoplan-staging.txt
@@ -63,6 +63,10 @@ Changes to Outputs:
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* `atlantis apply`
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
diff --git a/server/events/apply_command_runner_test.go b/server/events/apply_command_runner_test.go
index 27b1efa4fe..838ca3e299 100644
--- a/server/events/apply_command_runner_test.go
+++ b/server/events/apply_command_runner_test.go
@@ -258,7 +258,7 @@ func TestApplyCommandRunner_ExecutionOrder(t *testing.T) {
},
ExpComment: "Ran Apply for 2 projects:\n\n" +
"1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " +
- "2. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---",
+ "2. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored",
},
{
Description: "When first apply fails, the second not will run",
@@ -343,7 +343,7 @@ func TestApplyCommandRunner_ExecutionOrder(t *testing.T) {
},
ExpComment: "Ran Apply for 2 projects:\n\n" +
"1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " +
- "2. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---",
+ "2. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored",
},
{
Description: "When one out of two fails, the following two will not run",
@@ -398,7 +398,7 @@ func TestApplyCommandRunner_ExecutionOrder(t *testing.T) {
"1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n\n### 1. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " +
"2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### " +
"3. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### " +
- "4. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---",
+ "4. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n4 projects, 3 successful, 0 failed, 1 errored",
},
{
Description: "Don't block when parallel is not set",
@@ -430,7 +430,7 @@ func TestApplyCommandRunner_ExecutionOrder(t *testing.T) {
},
ExpComment: "Ran Apply for 2 projects:\n\n" +
"1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n\n### 1. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### " +
- "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---",
+ "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored",
},
{
Description: "Don't block when abortOnExcecutionOrderFail is not set",
@@ -460,7 +460,7 @@ func TestApplyCommandRunner_ExecutionOrder(t *testing.T) {
},
ExpComment: "Ran Apply for 2 projects:\n\n" +
"1. dir: `` workspace: ``\n1. dir: `` workspace: ``\n\n### 1. dir: `` workspace: ``\n**Apply Error**\n```\nshabang\n```\n\n---\n### " +
- "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---",
+ "2. dir: `` workspace: ``\n```diff\nGreat success!\n```\n\n---\n### Apply Summary\n\n2 projects, 1 successful, 0 failed, 1 errored",
},
}
diff --git a/server/events/markdown_renderer.go b/server/events/markdown_renderer.go
index 17328852d3..74a72c6719 100644
--- a/server/events/markdown_renderer.go
+++ b/server/events/markdown_renderer.go
@@ -93,6 +93,22 @@ type resultData struct {
commonData
}
+type planResultData struct {
+ Results []projectResultTmplData
+ commonData
+ NumPlansWithChanges int
+ NumPlansWithNoChanges int
+ NumPlanFailures int
+}
+
+type applyResultData struct {
+ Results []projectResultTmplData
+ commonData
+ NumApplySuccesses int
+ NumApplyFailures int
+ NumApplyErrors int
+}
+
type planSuccessData struct {
models.PlanSuccess
PlanSummary string
@@ -187,6 +203,11 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
numPolicyCheckSuccesses := 0
numPolicyApprovalSuccesses := 0
numVersionSuccesses := 0
+ numPlansWithChanges := 0
+ numPlansWithNoChanges := 0
+ numApplySuccesses := 0
+ numApplyFailures := 0
+ numApplyErrors := 0
templates := m.markdownTemplates
@@ -213,6 +234,11 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("planSuccessUnwrapped"), data)
}
resultData.NoChanges = result.PlanSuccess.NoChanges()
+ if result.PlanSuccess.NoChanges() {
+ numPlansWithNoChanges++
+ } else {
+ numPlansWithChanges++
+ }
numPlanSuccesses++
} else if result.PolicyCheckResults != nil && common.Command == policyCheckCommandTitle {
policyCheckResults := policyCheckResultsData{
@@ -255,6 +281,7 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
} else {
resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("applyUnwrappedSuccess"), struct{ Output string }{output})
}
+ numApplySuccesses++
} else if result.VersionSuccess != "" {
output := strings.TrimSpace(result.VersionSuccess)
if m.shouldUseWrappedTmpl(vcsHost, output) {
@@ -289,8 +316,14 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
tmpl = templates.Lookup("wrappedErr")
}
resultData.Rendered = m.renderTemplateTrimSpace(tmpl, errData{result.Error.Error(), resultData.Rendered, common})
+ if common.Command == applyCommandTitle {
+ numApplyErrors++
+ }
} else if result.Failure != "" {
resultData.Rendered = m.renderTemplateTrimSpace(templates.Lookup("failure"), failureData{result.Failure, resultData.Rendered, common})
+ if common.Command == applyCommandTitle {
+ numApplyFailures++
+ }
}
resultsTmplData = append(resultsTmplData, resultData)
}
@@ -324,7 +357,7 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
tmpl = templates.Lookup("multiProjectPlan")
case common.Command == policyCheckCommandTitle:
if numPolicyCheckSuccesses == len(results) {
- tmpl = templates.Lookup("multiProjectPlan")
+ tmpl = templates.Lookup("multiProjectPolicy")
} else {
tmpl = templates.Lookup("multiProjectPolicyUnsuccessful")
}
@@ -350,6 +383,14 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
default:
return fmt.Sprintf("no template matched–this is a bug: command=%s", common.Command)
}
+
+ switch {
+ case common.Command == planCommandTitle:
+ numPlanFailures := len(results) - numPlanSuccesses
+ return m.renderTemplateTrimSpace(tmpl, planResultData{resultsTmplData, common, numPlansWithChanges, numPlansWithNoChanges, numPlanFailures})
+ case common.Command == applyCommandTitle:
+ return m.renderTemplateTrimSpace(tmpl, applyResultData{resultsTmplData, common, numApplySuccesses, numApplyFailures, numApplyErrors})
+ }
return m.renderTemplateTrimSpace(tmpl, resultData{resultsTmplData, common})
}
diff --git a/server/events/markdown_renderer_test.go b/server/events/markdown_renderer_test.go
index 1b048b044d..eebd1a8b87 100644
--- a/server/events/markdown_renderer_test.go
+++ b/server/events/markdown_renderer_test.go
@@ -26,6 +26,11 @@ import (
. "github.com/runatlantis/atlantis/testing"
)
+// Strip Carriage Returns, leading and trailing spaces and replace 'dollar' with 'backtick' in the string
+func normalize(s string) string {
+ return strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(s, "$", "`"), "\r", ""))
+}
+
func TestRenderErr(t *testing.T) {
err := errors.New("err")
cases := []struct {
@@ -63,9 +68,9 @@ func TestRenderErr(t *testing.T) {
t.Run(fmt.Sprintf("%s_%t", c.Description, verbose), func(t *testing.T) {
s := r.Render(res, c.Command, "", "log", verbose, models.Github)
if !verbose {
- Equals(t, strings.TrimSpace(c.Expected), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, c.Expected+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected)+"\n\nLog
\n \n\n```\nlog```\n
", normalize(s))
}
})
}
@@ -108,9 +113,9 @@ func TestRenderFailure(t *testing.T) {
t.Run(fmt.Sprintf("%s_%t", c.Description, verbose), func(t *testing.T) {
s := r.Render(res, c.Command, "", "log", verbose, models.Github)
if !verbose {
- Equals(t, strings.TrimSpace(c.Expected), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, c.Expected+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
@@ -124,7 +129,7 @@ func TestRenderErrAndFailure(t *testing.T) {
Failure: "failure",
}
s := r.Render(res, command.Plan, "", "", false, models.Github)
- Equals(t, "**Plan Error**\n```\nerror\n```", s)
+ Equals(t, "**Plan Error**\n```\nerror\n```", normalize(s))
}
func TestRenderProjectResults(t *testing.T) {
@@ -424,7 +429,8 @@ $$$
:put_litter_in_its_place: A plan file was discarded. Re-plan would be required before applying.
* :repeat: To **plan** this project again, comment:
- * $atlantis plan -d path -w workspace$`,
+ * $atlantis plan -d path -w workspace$
+`,
},
{
"single successful state rm",
@@ -470,7 +476,8 @@ $$$
$$$diff
success
-$$$`,
+$$$
+`,
},
{
"single successful apply with project name",
@@ -489,7 +496,8 @@ $$$`,
$$$diff
success
-$$$`,
+$$$
+`,
},
{
"multiple successful plans",
@@ -548,6 +556,10 @@ $$$
* $atlantis plan -d path2 -w workspace$
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
@@ -667,6 +679,9 @@ success2
$$$
---
+### Apply Summary
+
+2 projects, 2 successful, 0 failed, 0 errored
`,
},
{
@@ -686,7 +701,8 @@ $$$
**Plan Error**
$$$
error
-$$$`,
+$$$
+`,
},
{
"single failed plan",
@@ -702,7 +718,8 @@ $$$`,
models.Github,
`Ran Plan for dir: $path$ workspace: $workspace$
-**Plan Failed**: failure`,
+**Plan Failed**: failure
+`,
},
{
"successful, failed, and errored plan",
@@ -761,6 +778,10 @@ error
$$$
---
+### Plan Summary
+
+3 projects, 1 with changes, 0 with no changes, 2 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
@@ -911,6 +932,9 @@ error
$$$
---
+### Apply Summary
+
+3 projects, 1 successful, 1 failed, 1 errored
`,
},
{
@@ -958,6 +982,9 @@ error
$$$
---
+### Apply Summary
+
+3 projects, 1 successful, 1 failed, 1 errored
`,
},
}
@@ -971,11 +998,10 @@ $$$
for _, verbose := range []bool{true, false} {
t.Run(c.Description, func(t *testing.T) {
s := r.Render(res, c.Command, c.SubCommand, "log", verbose, c.VCSHost)
- expWithBackticks := strings.Replace(c.Expected, "$", "`", -1)
if !verbose {
- Equals(t, strings.TrimSpace(expWithBackticks), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, expWithBackticks+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
@@ -1094,6 +1120,7 @@ $$$
* :repeat: To **plan** this project again, comment:
* $atlantis plan -d path -w workspace$
+---
### 2. project: $projectname$ dir: $path2$ workspace: $workspace$
$$$diff
terraform-output2
@@ -1105,6 +1132,10 @@ $$$
* :repeat: To **plan** this project again, comment:
* $atlantis plan -d path2 -w workspace$
+---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
`,
},
}
@@ -1127,11 +1158,10 @@ $$$
for _, verbose := range []bool{true, false} {
t.Run(c.Description, func(t *testing.T) {
s := r.Render(res, c.Command, "", "log", verbose, c.VCSHost)
- expWithBackticks := strings.Replace(c.Expected, "$", "`", -1)
if !verbose {
- Equals(t, strings.TrimSpace(expWithBackticks), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, expWithBackticks+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
@@ -1244,6 +1274,7 @@ $$$
* :repeat: To **plan** this project again, comment:
* $atlantis plan -d path -w workspace$
+---
### 2. project: $projectname$ dir: $path2$ workspace: $workspace$
$$$diff
terraform-output2
@@ -1253,6 +1284,10 @@ $$$
* :repeat: To **plan** this project again, comment:
* $atlantis plan -d path2 -w workspace$
+---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
`,
},
}
@@ -1276,11 +1311,10 @@ $$$
for _, verbose := range []bool{true, false} {
t.Run(c.Description, func(t *testing.T) {
s := r.Render(res, c.Command, "", "log", verbose, c.VCSHost)
- expWithBackticks := strings.Replace(c.Expected, "$", "`", -1)
if !verbose {
- Equals(t, strings.TrimSpace(expWithBackticks), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, expWithBackticks+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
@@ -1342,8 +1376,7 @@ $$$
* :repeat: To re-run policies **plan** this project again by commenting:
* $atlantis plan -d path -w workspace$`
- expWithBackticks := strings.Replace(exp, "$", "`", -1)
- Equals(t, expWithBackticks, rendered)
+ Equals(t, normalize(exp), normalize(rendered))
}
// Test that if folding is disabled that it's not used.
@@ -1480,9 +1513,7 @@ $$$
` + c.Output + `
$$$`
}
-
- expWithBackticks := strings.Replace(exp, "$", "`", -1)
- Equals(t, expWithBackticks, rendered)
+ Equals(t, normalize(exp), normalize(rendered))
})
}
}
@@ -1656,8 +1687,7 @@ $$$`
}
}
- expWithBackticks := strings.Replace(exp, "$", "`", -1)
- Equals(t, expWithBackticks, rendered)
+ Equals(t, normalize(exp), normalize(rendered))
})
}
}
@@ -1714,9 +1744,12 @@ $$$
----`
- expWithBackticks := strings.Replace(exp, "$", "`", -1)
- Equals(t, expWithBackticks, rendered)
+---
+### Apply Summary
+
+2 projects, 2 successful, 0 failed, 0 errored
+`
+ Equals(t, normalize(exp), normalize(rendered))
}
func TestRenderProjectResults_MultiProjectPlanWrapped(t *testing.T) {
@@ -1793,12 +1826,16 @@ $$$
Plan: 1 to add, 0 to change, 0 to destroy.
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
- * $atlantis unlock$`
- expWithBackticks := strings.Replace(exp, "$", "`", -1)
- Equals(t, expWithBackticks, rendered)
+ * $atlantis unlock$
+`
+ Equals(t, normalize(exp), normalize(rendered))
}
// Test rendering when there was an error in one of the plans and we deleted
@@ -1851,7 +1888,11 @@ func TestRenderProjectResults_PlansDeleted(t *testing.T) {
### 2. dir: $.$ workspace: $production$
**Plan Failed**: failure
----`,
+---
+### Plan Summary
+
+2 projects, 0 with changes, 0 with no changes, 2 failed
+`,
},
"one failure, one success": {
cr: command.Result{
@@ -1890,7 +1931,11 @@ $$$
This plan was not saved because one or more projects failed and automerge requires all plans pass.
----`,
+---
+### Plan Summary
+
+2 projects, 1 with changes, 0 with no changes, 1 failed
+`,
},
}
@@ -1908,8 +1953,7 @@ This plan was not saved because one or more projects failed and automerge requir
false, // hideUnchangedPlanComments
)
rendered := mr.Render(c.cr, command.Plan, "", "log", false, models.Github)
- expWithBackticks := strings.Replace(c.exp, "$", "`", -1)
- Equals(t, expWithBackticks, rendered)
+ Equals(t, normalize(c.exp), normalize(rendered))
})
}
}
@@ -2051,7 +2095,8 @@ $$$
$$$diff
success
-$$$`,
+$$$
+`,
},
{
"single successful apply with project name",
@@ -2069,7 +2114,8 @@ $$$`,
$$$diff
success
-$$$`,
+$$$
+`,
},
{
"multiple successful plans",
@@ -2125,6 +2171,10 @@ $$$
* $atlantis plan -d path2 -w workspace$
---
+### Plan Summary
+
+2 projects, 2 with changes, 0 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
@@ -2165,6 +2215,9 @@ success2
$$$
---
+### Apply Summary
+
+2 projects, 2 successful, 0 failed, 0 errored
`,
},
{
@@ -2183,7 +2236,8 @@ $$$
**Plan Error**
$$$
error
-$$$`,
+$$$
+`,
},
{
"single failed plan",
@@ -2198,7 +2252,8 @@ $$$`,
models.Github,
`Ran Plan for dir: $path$ workspace: $workspace$
-**Plan Failed**: failure`,
+**Plan Failed**: failure
+`,
},
{
"successful, failed, and errored plan",
@@ -2255,6 +2310,10 @@ error
$$$
---
+### Plan Summary
+
+3 projects, 1 with changes, 0 with no changes, 2 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
@@ -2305,6 +2364,9 @@ error
$$$
---
+### Apply Summary
+
+3 projects, 1 successful, 1 failed, 1 errored
`,
},
{
@@ -2351,6 +2413,9 @@ error
$$$
---
+### Apply Summary
+
+3 projects, 1 successful, 1 failed, 1 errored
`,
},
}
@@ -2374,11 +2439,10 @@ $$$
for _, verbose := range []bool{true, false} {
t.Run(c.Description, func(t *testing.T) {
s := r.Render(res, c.Command, "", "log", verbose, c.VCSHost)
- expWithBackticks := strings.Replace(c.Expected, "$", "`", -1)
if !verbose {
- Equals(t, strings.TrimSpace(expWithBackticks), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, expWithBackticks+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
@@ -2812,11 +2876,10 @@ func TestRenderProjectResultsWithEnableDiffMarkdownFormat(t *testing.T) {
for _, verbose := range []bool{true, false} {
t.Run(c.Description, func(t *testing.T) {
s := r.Render(res, c.Command, "", "log", verbose, c.VCSHost)
- expWithBackticks := strings.Replace(c.Expected, "$", "`", -1)
if !verbose {
- Equals(t, strings.TrimSpace(expWithBackticks), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, expWithBackticks+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
@@ -2937,6 +3000,10 @@ $$$
* $atlantis plan -d path3 -w workspace$
---
+### Plan Summary
+
+3 projects, 2 with changes, 1 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
@@ -2988,6 +3055,10 @@ $$$
1. project: $projectname$ dir: $path2$ workspace: $workspace$
1. project: $projectname2$ dir: $path3$ workspace: $workspace$
+### Plan Summary
+
+3 projects, 0 with changes, 3 with no changes, 0 failed
+
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
* $atlantis apply$
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
@@ -3005,11 +3076,10 @@ $$$
for _, verbose := range []bool{true, false} {
t.Run(c.Description, func(t *testing.T) {
s := r.Render(res, c.Command, c.SubCommand, "log", verbose, c.VCSHost)
- expWithBackticks := strings.Replace(c.Expected, "$", "`", -1)
if !verbose {
- Equals(t, strings.TrimSpace(expWithBackticks), strings.TrimSpace(s))
+ Equals(t, normalize(c.Expected), normalize(s))
} else {
- Equals(t, expWithBackticks+"\nLog
\n \n\n```\nlog```\n
", s)
+ Equals(t, normalize(c.Expected+"\nLog
\n \n\n```\nlog```\n
"), normalize(s))
}
})
}
diff --git a/server/events/templates/multi_project_apply.tmpl b/server/events/templates/multi_project_apply.tmpl
index 701d766971..50038555b3 100644
--- a/server/events/templates/multi_project_apply.tmpl
+++ b/server/events/templates/multi_project_apply.tmpl
@@ -6,5 +6,6 @@
---
{{ end -}}
-{{- template "log" . -}}
+{{ template "multiProjectApplyFooter" . -}}
+{{ template "log" . -}}
{{ end -}}
diff --git a/server/events/templates/multi_project_apply_footer.tmpl b/server/events/templates/multi_project_apply_footer.tmpl
new file mode 100644
index 0000000000..58299868ce
--- /dev/null
+++ b/server/events/templates/multi_project_apply_footer.tmpl
@@ -0,0 +1,7 @@
+{{ define "multiProjectApplyFooter" -}}
+{{ if (gt (len .Results) 1) -}}
+### Apply Summary
+
+{{ len .Results }} projects, {{ .NumApplySuccesses }} successful, {{ .NumApplyFailures }} failed, {{ .NumApplyErrors }} errored
+{{ end -}}
+{{ end -}}
diff --git a/server/events/templates/multi_project_plan.tmpl b/server/events/templates/multi_project_plan.tmpl
index 456b0ecf61..9c3898ad48 100644
--- a/server/events/templates/multi_project_plan.tmpl
+++ b/server/events/templates/multi_project_plan.tmpl
@@ -7,17 +7,8 @@
### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}`
{{ $result.Rendered }}
-{{ if ne $disableApplyAll true -}}
---
{{ end -}}
-{{ end -}}
-{{ if ne .DisableApplyAll true -}}
-{{ if and (gt (len .Results) 0) (not .PlansDeleted) -}}
-* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
- * `{{ .ExecutableName }} apply`
-* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
- * `{{ .ExecutableName }} unlock`
-{{ end -}}
-{{ end -}}
-{{- template "log" . -}}
+{{ template "multiProjectPlanFooter" . -}}
+{{ template "log" . -}}
{{ end -}}
diff --git a/server/events/templates/multi_project_plan_footer.tmpl b/server/events/templates/multi_project_plan_footer.tmpl
new file mode 100644
index 0000000000..41683ab018
--- /dev/null
+++ b/server/events/templates/multi_project_plan_footer.tmpl
@@ -0,0 +1,13 @@
+{{ define "multiProjectPlanFooter" -}}
+{{ if and (gt (len .Results) 0) -}}
+### Plan Summary
+
+{{ len .Results }} projects, {{ .NumPlansWithChanges }} with changes, {{ .NumPlansWithNoChanges }} with no changes, {{ .NumPlanFailures }} failed
+{{ if and (not .PlansDeleted) (ne .DisableApplyAll true) }}
+* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
+ * `{{ .ExecutableName }} apply`
+* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
+ * `{{ .ExecutableName }} unlock`
+{{ end -}}
+{{ end -}}
+{{ end -}}
diff --git a/server/events/templates/multi_project_policy.tmpl b/server/events/templates/multi_project_policy.tmpl
new file mode 100644
index 0000000000..c34c59f896
--- /dev/null
+++ b/server/events/templates/multi_project_policy.tmpl
@@ -0,0 +1,23 @@
+{{ define "multiProjectPolicy" -}}
+{{ template "multiProjectHeader" . }}
+{{ $disableApplyAll := .DisableApplyAll -}}
+{{ $hideUnchangedPlans := .HideUnchangedPlanComments -}}
+{{ range $i, $result := .Results -}}
+{{ if (and $hideUnchangedPlans $result.NoChanges) }}{{continue}}{{end -}}
+### {{ add $i 1 }}. {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}`
+{{ $result.Rendered }}
+
+{{ if ne $disableApplyAll true -}}
+---
+{{ end -}}
+{{ end -}}
+{{ if ne .DisableApplyAll true -}}
+{{ if and (gt (len .Results) 0) (not .PlansDeleted) -}}
+* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
+ * `{{ .ExecutableName }} apply`
+* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
+ * `{{ .ExecutableName }} unlock`
+{{ end -}}
+{{ end -}}
+{{ template "log" . -}}
+{{ end -}}
diff --git a/server/events/templates/single_project_apply.tmpl b/server/events/templates/single_project_apply.tmpl
index a963641b81..173bb46847 100644
--- a/server/events/templates/single_project_apply.tmpl
+++ b/server/events/templates/single_project_apply.tmpl
@@ -3,5 +3,5 @@
Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}`
{{ $result.Rendered }}
-{{- template "log" . -}}
+{{ template "log" . -}}
{{ end -}}
diff --git a/server/events/templates/single_project_import_success.tmpl b/server/events/templates/single_project_import_success.tmpl
index 7e0fbd65c1..e03b53de5e 100644
--- a/server/events/templates/single_project_import_success.tmpl
+++ b/server/events/templates/single_project_import_success.tmpl
@@ -3,5 +3,5 @@
Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectName }}` {{ end }}dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}`
{{ $result.Rendered }}
-{{- template "log" . -}}
+{{ template "log" . -}}
{{ end -}}
diff --git a/server/events/templates/single_project_plan_success.tmpl b/server/events/templates/single_project_plan_success.tmpl
index 46c1b6640a..afbe3d5701 100644
--- a/server/events/templates/single_project_plan_success.tmpl
+++ b/server/events/templates/single_project_plan_success.tmpl
@@ -10,5 +10,5 @@ Ran {{ .Command }} for {{ if $result.ProjectName }}project: `{{ $result.ProjectN
* :put_litter_in_its_place: To **delete** all plans and locks for the PR, comment:
* `{{ .ExecutableName }} unlock`
{{ end -}}
-{{- template "log" . -}}
+{{ template "log" . -}}
{{ end -}}
diff --git a/server/events/templates/single_project_plan_unsuccessful.tmpl b/server/events/templates/single_project_plan_unsuccessful.tmpl
index 45c5c54926..1dd0cd9643 100644
--- a/server/events/templates/single_project_plan_unsuccessful.tmpl
+++ b/server/events/templates/single_project_plan_unsuccessful.tmpl
@@ -3,5 +3,5 @@
Ran {{ .Command }} for dir: `{{ $result.RepoRelDir }}` workspace: `{{ $result.Workspace }}`
{{ $result.Rendered }}
-{{- template "log" . -}}
+{{ template "log" . -}}
{{ end -}}
diff --git a/server/events/templates/unwrapped_err.tmpl b/server/events/templates/unwrapped_err.tmpl
index 1be0a7ef29..37b201ab93 100644
--- a/server/events/templates/unwrapped_err.tmpl
+++ b/server/events/templates/unwrapped_err.tmpl
@@ -1,9 +1,9 @@
{{ define "unwrappedErr" -}}
-**{{.Command}} Error**
+**{{ .Command }} Error**
```
-{{.Error}}
+{{ .Error }}
```
-{{- if ne .RenderedContext ""}}
+{{ if ne .RenderedContext "" -}}
{{ .RenderedContext }}
-{{- end }}
-{{- end }}
+{{ end -}}
+{{ end -}}