From 384efe63fa4c10f0e4d24b1146606bbeda15b5ba Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+RDhar@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:59:27 +0100 Subject: [PATCH 01/12] introduce new input parameter for toggle control Signed-off-by: Rishav Dhar <19497993+RDhar@users.noreply.github.com> --- action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/action.yml b/action.yml index 74b8eb9f..44b3309c 100644 --- a/action.yml +++ b/action.yml @@ -16,6 +16,10 @@ inputs: description: Boolean flag to add PR comment of TF command output. required: false default: "true" + compare_plans: + description: Boolean flag to compare previous TF plan file with current plan before applying. + required: false + default: "false" encrypt_passphrase: description: String passphrase to encrypt the TF plan file. required: false From fb84afa341e5c4a6434be3578ae3a8131acf3630 Mon Sep 17 00:00:00 2001 From: Kamil Sitnik <72462886+ksitnik-tc@users.noreply.github.com> Date: Thu, 29 Aug 2024 15:26:28 -0400 Subject: [PATCH 02/12] Update action.yml (#291) --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 44b3309c..c2ac7d44 100644 --- a/action.yml +++ b/action.yml @@ -16,7 +16,7 @@ inputs: description: Boolean flag to add PR comment of TF command output. required: false default: "true" - compare_plans: + plan_parity: description: Boolean flag to compare previous TF plan file with current plan before applying. required: false default: "false" From 109dba01fbc24e74e9fabcd2352200db08b47fee Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 18:42:54 +0100 Subject: [PATCH 03/12] remove `outline_enable` option in order to enable by default Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- README.md | 1 - action.js | 98 +++++++++++++++++++++---------------------- action.yml | 5 --- sample/bucket/tfplan | Bin 0 -> 18495 bytes 4 files changed, 47 insertions(+), 57 deletions(-) create mode 100644 sample/bucket/tfplan diff --git a/README.md b/README.md index edeecd64..18d0317c 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,6 @@ In order to locally decrypt the TF plan file, use the following command (noting | `encrypt_passphrase`
Example: `${{ secrets.KEY }}` | String passphrase to encrypt the TF plan file. | | `fmt_enable`
Default: `true` | Boolean flag to enable TF fmt command and display diff of changes. | | `label_pr`
Default: `true` | Boolean flag to add PR label of TF command to run. | -| `outline_enable`
Default: `true` | Boolean flag to add an outline diff of TF plan file. | | `tf_tool`
Default: `terraform` | String name of the TF tool to use and override default assumption from wrapper environment variable. | | `tf_version`
Example: `~>` 1.8.0 | String version constraint of the TF tool to install and use. | | `update_comment`
Default: `false` | Boolean flag to update existing PR comment instead of creating a new comment and deleting the old one. | diff --git a/action.js b/action.js index a64438e2..9e669ba8 100644 --- a/action.js +++ b/action.js @@ -247,24 +247,22 @@ module.exports = async ({ context, core, exec, github }) => { 3 ); - if (/^true$/i.test(process.env.outline_enable)) { - result_outline = cli_result - .split("\n") - .filter((line) => line.startsWith(" # ")) - .map((line) => { - const diff_line = line.slice(4); - if (diff_line.includes(" created")) return "+ " + diff_line; - if (diff_line.includes(" destroyed")) return "- " + diff_line; - if (diff_line.includes(" updated") || diff_line.includes(" replaced")) - return "! " + diff_line; - return "# " + diff_line; - }) - .join("\n"); - if (result_outline?.length >= result_outline_limit) { - result_outline = result_outline.substring(0, result_outline_limit) + "…"; - } - core.setOutput("outline", result_outline); + result_outline = cli_result + .split("\n") + .filter((line) => line.startsWith(" # ")) + .map((line) => { + const diff_line = line.slice(4); + if (diff_line.includes(" created")) return "+ " + diff_line; + if (diff_line.includes(" destroyed")) return "- " + diff_line; + if (diff_line.includes(" updated") || diff_line.includes(" replaced")) + return "! " + diff_line; + return "# " + diff_line; + }) + .join("\n"); + if (result_outline?.length >= result_outline_limit) { + result_outline = result_outline.substring(0, result_outline_limit) + "…"; } + core.setOutput("outline", result_outline); } // TF apply. @@ -329,36 +327,35 @@ module.exports = async ({ context, core, exec, github }) => { } } - if (/^true$/i.test(process.env.outline_enable)) { - await exec_tf( - [process.env.arg_chdir, "show", process.env.arg_out.replace(/^-out=/, "")], - [ - "show", - process.env.arg_chdir, - process.env.arg_workspace_alt, - process.env.arg_backend_config, - process.env.arg_var_file, - process.env.arg_destroy, - ], - 2 - ); - result_outline = cli_result - .split("\n") - .filter((line) => line.startsWith(" # ")) - .map((line) => { - const diff_line = line.slice(4); - if (diff_line.includes(" created")) return "+ " + diff_line; - if (diff_line.includes(" destroyed")) return "- " + diff_line; - if (diff_line.includes(" updated") || diff_line.includes(" replaced")) - return "! " + diff_line; - return "# " + diff_line; - }) - .join("\n"); - if (result_outline?.length >= result_outline_limit) { - result_outline = result_outline.substring(0, result_outline_limit) + "…"; - } - core.setOutput("outline", result_outline); + await exec_tf( + [process.env.arg_chdir, "show", process.env.arg_out.replace(/^-out=/, "")], + [ + "show", + process.env.arg_chdir, + process.env.arg_workspace_alt, + process.env.arg_backend_config, + process.env.arg_var_file, + process.env.arg_destroy, + ], + 2 + ); + result_outline = cli_result + .split("\n") + .filter((line) => line.startsWith(" # ")) + .map((line) => { + const diff_line = line.slice(4); + if (diff_line.includes(" created")) return "+ " + diff_line; + if (diff_line.includes(" destroyed")) return "- " + diff_line; + if (diff_line.includes(" updated") || diff_line.includes(" replaced")) + return "! " + diff_line; + return "# " + diff_line; + }) + .join("\n"); + if (result_outline?.length >= result_outline_limit) { + result_outline = result_outline.substring(0, result_outline_limit) + "…"; } + core.setOutput("outline", result_outline); + await exec_tf( [ @@ -423,8 +420,8 @@ module.exports = async ({ context, core, exec, github }) => { // Render the TF fmt command output. const output_fmt = process.env.arg_command === "plan" && - /^true$/i.test(process.env.fmt_enable) && - fmt_result?.length + /^true$/i.test(process.env.fmt_enable) && + fmt_result?.length ? `
Format diff check. \`\`\`diff @@ -456,11 +453,10 @@ ${output_outline}
${result_summary}
-###### ${context.workflow} by @${context.actor} via [${context.eventName}](${check_url}) at ${ - context.payload.pull_request?.updated_at || +###### ${context.workflow} by @${context.actor} via [${context.eventName}](${check_url}) at ${context.payload.pull_request?.updated_at || context.payload.head_commit?.timestamp || context.payload.merge_group?.head_commit.timestamp - }. + }.
\`\`\`hcl diff --git a/action.yml b/action.yml index c2ac7d44..ddde3aad 100644 --- a/action.yml +++ b/action.yml @@ -32,10 +32,6 @@ inputs: description: Boolean flag to add PR label of TF command to run. required: false default: "true" - outline_enable: - description: Boolean flag to add an outline diff of TF plan file. - required: false - default: "true" tf_tool: description: String name of the TF tool to use and override default assumption from wrapper environment variable. required: false @@ -289,7 +285,6 @@ runs: encrypt_passphrase: ${{ inputs.encrypt_passphrase }} fmt_enable: ${{ inputs.fmt_enable }} label_pr: ${{ inputs.label_pr }} - outline_enable: ${{ inputs.outline_enable }} tf_tool: ${{ inputs.tf_tool }} update_comment: ${{ inputs.update_comment }} validate_enable: ${{ inputs.validate_enable }} diff --git a/sample/bucket/tfplan b/sample/bucket/tfplan new file mode 100644 index 0000000000000000000000000000000000000000..55b66dd96f78cb77bc16b0013fdb81bf16eb7202 GIT binary patch literal 18495 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 Date: Sun, 8 Sep 2024 18:52:16 +0100 Subject: [PATCH 04/12] update readme with new input parameter Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- README.md | 1 + action.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 18d0317c..b82ee8b2 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ In order to locally decrypt the TF plan file, use the following command (noting | `encrypt_passphrase`
Example: `${{ secrets.KEY }}` | String passphrase to encrypt the TF plan file. | | `fmt_enable`
Default: `true` | Boolean flag to enable TF fmt command and display diff of changes. | | `label_pr`
Default: `true` | Boolean flag to add PR label of TF command to run. | +| `plan_parity`
Default: `false` | Boolean flag to compare previous TF plan file with current plan before applying in a queue. | | `tf_tool`
Default: `terraform` | String name of the TF tool to use and override default assumption from wrapper environment variable. | | `tf_version`
Example: `~>` 1.8.0 | String version constraint of the TF tool to install and use. | | `update_comment`
Default: `false` | Boolean flag to update existing PR comment instead of creating a new comment and deleting the old one. | diff --git a/action.yml b/action.yml index fe0f5f4e..ed6bb063 100644 --- a/action.yml +++ b/action.yml @@ -17,7 +17,7 @@ inputs: required: false default: "true" plan_parity: - description: Boolean flag to compare previous TF plan file with current plan before applying. + description: Boolean flag to compare previous TF plan file with current plan before applying in a queue. required: false default: "false" encrypt_passphrase: From f8a9c698a5cf0125537da3a6672de0f2d24b92a8 Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 19:50:35 +0100 Subject: [PATCH 05/12] add logic Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- action.js | 138 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 29 deletions(-) diff --git a/action.js b/action.js index 9e669ba8..10043df9 100644 --- a/action.js +++ b/action.js @@ -269,6 +269,39 @@ module.exports = async ({ context, core, exec, github }) => { if (process.env.arg_command === "apply") { // Download the TF plan file if not auto-approved. if (!/^true$/i.test(process.env.auto_approve)) { + // TF plan anew for later comparison if plan_parity is enabled. + if (/^true$/i.test(process.env.plan_parity)) { + await exec_tf( + [ + process.env.arg_chdir, + "plan", + process.env.arg_out + ".new", + process.env.arg_var_file, + process.env.arg_destroy, + process.env.arg_compact_warnings, + process.env.arg_concise, + process.env.arg_detailed_exitcode, + process.env.arg_generate_config_out, + process.env.arg_json, + process.env.arg_lock_timeout, + process.env.arg_lock, + process.env.arg_parallelism, + process.env.arg_refresh_only, + process.env.arg_refresh, + process.env.arg_replace, + process.env.arg_target, + process.env.arg_var, + ], + [ + "plan", + process.env.arg_chdir, + process.env.arg_workspace_alt, + process.env.arg_backend_config, + ], + 3 + ); + } + process.env.arg_auto_approve = process.env.arg_out.replace(/^-out=/, ""); process.env.arg_var_file = process.env.arg_var = ""; @@ -325,37 +358,84 @@ module.exports = async ({ context, core, exec, github }) => { `mv ${working_directory}.decrypted ${working_directory}`, ]); } - } - await exec_tf( - [process.env.arg_chdir, "show", process.env.arg_out.replace(/^-out=/, "")], - [ - "show", - process.env.arg_chdir, - process.env.arg_workspace_alt, - process.env.arg_backend_config, - process.env.arg_var_file, - process.env.arg_destroy, - ], - 2 - ); - result_outline = cli_result - .split("\n") - .filter((line) => line.startsWith(" # ")) - .map((line) => { - const diff_line = line.slice(4); - if (diff_line.includes(" created")) return "+ " + diff_line; - if (diff_line.includes(" destroyed")) return "- " + diff_line; - if (diff_line.includes(" updated") || diff_line.includes(" replaced")) - return "! " + diff_line; - return "# " + diff_line; - }) - .join("\n"); - if (result_outline?.length >= result_outline_limit) { - result_outline = result_outline.substring(0, result_outline_limit) + "…"; - } - core.setOutput("outline", result_outline); + // Generate an outline of the TF plan. + await exec_tf( + [process.env.arg_chdir, "show", process.env.arg_out.replace(/^-out=/, "")], + [ + "show", + process.env.arg_chdir, + process.env.arg_workspace_alt, + process.env.arg_backend_config, + process.env.arg_var_file, + process.env.arg_destroy, + ], + 2 + ); + result_outline = cli_result + .split("\n") + .filter((line) => line.startsWith(" # ")) + .map((line) => { + const diff_line = line.slice(4); + if (diff_line.includes(" created")) return "+ " + diff_line; + if (diff_line.includes(" destroyed")) return "- " + diff_line; + if (diff_line.includes(" updated") || diff_line.includes(" replaced")) + return "! " + diff_line; + return "# " + diff_line; + }) + .join("\n"); + + // Compare normalized output of the old TF plan with the new one. + // If they match, then replace the old TF plan with the new one to avoid stale apply. + // Otherwise, proceed with the stale apply. + if (/^true$/i.test(process.env.plan_parity)) { + await exec_tf( + [process.env.arg_chdir, "show", process.env.arg_out.replace(/^-out=/, "") + ".new"], + [ + "show", + process.env.arg_chdir, + process.env.arg_workspace_alt, + process.env.arg_backend_config, + process.env.arg_var_file, + process.env.arg_destroy, + ], + 2 + ); + + const result_outline_old = result_outline.split("\n").sort().join("\n"); + const result_outline_new = cli_result + .split("\n") + .filter((line) => line.startsWith(" # ")) + .map((line) => { + const diff_line = line.slice(4); + if (diff_line.includes(" created")) return "+ " + diff_line; + if (diff_line.includes(" destroyed")) return "- " + diff_line; + if (diff_line.includes(" updated") || diff_line.includes(" replaced")) + return "! " + diff_line; + return "# " + diff_line; + }) + .sort() + .join("\n"); + + if (result_outline_old === result_outline_new) { + await exec.exec("/bin/bash", [ + "-c", + `mv ${process.env.arg_chdir.replace(/^-chdir=/, "")}/${process.env.arg_out.replace( + /^-out=/, + "" + )}.new ${process.env.arg_chdir.replace(/^-chdir=/, "")}/${process.env.arg_out.replace( + /^-out=/, + "" + )}`, + ]); + } + } + if (result_outline?.length >= result_outline_limit) { + result_outline = result_outline.substring(0, result_outline_limit) + "…"; + } + core.setOutput("outline", result_outline); + } await exec_tf( [ From 758473d9c91cab9ad7bfa70b58759621a55ac4de Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 19:51:02 +0100 Subject: [PATCH 06/12] remove artifact Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- sample/bucket/tfplan | Bin 18495 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sample/bucket/tfplan diff --git a/sample/bucket/tfplan b/sample/bucket/tfplan deleted file mode 100644 index 55b66dd96f78cb77bc16b0013fdb81bf16eb7202..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18495 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 Date: Sun, 8 Sep 2024 19:53:54 +0100 Subject: [PATCH 07/12] update `merge_matrix` example Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- .github/examples/pr_merge_matrix.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/examples/pr_merge_matrix.yaml b/.github/examples/pr_merge_matrix.yaml index bf75e313..14a80c24 100644 --- a/.github/examples/pr_merge_matrix.yaml +++ b/.github/examples/pr_merge_matrix.yaml @@ -37,3 +37,4 @@ jobs: arg_lock: ${{ github.event_name == 'merge_group' && 'true' || 'false' }} arg_var_file: env/${{ matrix.deployment }}.tfvars arg_workspace: ${{ matrix.deployment }} + plan_parity: true From 2e7888be6188de2a52d8fb3fe40c3d495d8e9016 Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 19:56:43 +0100 Subject: [PATCH 08/12] test `plan_parity` Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- .github/workflows/tf_tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tf_tests.yaml b/.github/workflows/tf_tests.yaml index 898d18b7..5b02e1c7 100644 --- a/.github/workflows/tf_tests.yaml +++ b/.github/workflows/tf_tests.yaml @@ -51,6 +51,7 @@ jobs: arg_lock: ${{ github.event.pull_request.merged && 'true' || 'false' }} tf_tool: ${{ matrix.tool }} tf_version: ~> 1.8.0 + plan_parity: true - name: Echo TF run: | From c11f6f26d049621289a23d0aa66e71e40a36a03a Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 19:58:54 +0100 Subject: [PATCH 09/12] test `tf_tests` apply with `plan_parity` enabled Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- .github/workflows/tf_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tf_tests.yaml b/.github/workflows/tf_tests.yaml index 5b02e1c7..59bc05d1 100644 --- a/.github/workflows/tf_tests.yaml +++ b/.github/workflows/tf_tests.yaml @@ -47,7 +47,7 @@ jobs: uses: ./ with: arg_chdir: tests/${{ matrix.path }} - arg_command: ${{ github.event.pull_request.merged && 'apply' || 'plan' }} + arg_command: apply # ${{ github.event.pull_request.merged && 'apply' || 'plan' }} arg_lock: ${{ github.event.pull_request.merged && 'true' || 'false' }} tf_tool: ${{ matrix.tool }} tf_version: ~> 1.8.0 From 64b41bd435d6ec14664f4ba2f6b93419f0b51e37 Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:00:58 +0100 Subject: [PATCH 10/12] pass `plan_parity` as env var Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index ed6bb063..ea194cf2 100644 --- a/action.yml +++ b/action.yml @@ -282,6 +282,7 @@ runs: # Input parameters. cache_hit: ${{ steps.cache_plugins.outputs.cache-hit }} comment_pr: ${{ inputs.comment_pr }} + plan_parity: ${{ inputs.plan_parity }} encrypt_passphrase: ${{ inputs.encrypt_passphrase }} fmt_enable: ${{ inputs.fmt_enable }} label_pr: ${{ inputs.label_pr }} From 0399347ad1ed5d709b455e6b9ed89acd1814b828 Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:03:29 +0100 Subject: [PATCH 11/12] ready to merge Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- .github/workflows/tf_tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tf_tests.yaml b/.github/workflows/tf_tests.yaml index 59bc05d1..62466509 100644 --- a/.github/workflows/tf_tests.yaml +++ b/.github/workflows/tf_tests.yaml @@ -46,12 +46,12 @@ jobs: continue-on-error: true uses: ./ with: + plan_parity: true arg_chdir: tests/${{ matrix.path }} - arg_command: apply # ${{ github.event.pull_request.merged && 'apply' || 'plan' }} + arg_command: ${{ github.event.pull_request.merged && 'apply' || 'plan' }} arg_lock: ${{ github.event.pull_request.merged && 'true' || 'false' }} tf_tool: ${{ matrix.tool }} tf_version: ~> 1.8.0 - plan_parity: true - name: Echo TF run: | From d0aa7e3ec051848f5311ece5872ebba05b59d376 Mon Sep 17 00:00:00 2001 From: Rishav Dhar <19497993+rdhar@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:08:24 +0100 Subject: [PATCH 12/12] doc wording Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com> --- README.md | 2 +- action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b82ee8b2..c2b9e097 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ In order to locally decrypt the TF plan file, use the following command (noting | `encrypt_passphrase`
Example: `${{ secrets.KEY }}` | String passphrase to encrypt the TF plan file. | | `fmt_enable`
Default: `true` | Boolean flag to enable TF fmt command and display diff of changes. | | `label_pr`
Default: `true` | Boolean flag to add PR label of TF command to run. | -| `plan_parity`
Default: `false` | Boolean flag to compare previous TF plan file with current plan before applying in a queue. | +| `plan_parity`
Default: `false` | Boolean flag to compare the TF plan file with a newly-generated one to prevent stale apply. | | `tf_tool`
Default: `terraform` | String name of the TF tool to use and override default assumption from wrapper environment variable. | | `tf_version`
Example: `~>` 1.8.0 | String version constraint of the TF tool to install and use. | | `update_comment`
Default: `false` | Boolean flag to update existing PR comment instead of creating a new comment and deleting the old one. | diff --git a/action.yml b/action.yml index ea194cf2..951c007b 100644 --- a/action.yml +++ b/action.yml @@ -17,7 +17,7 @@ inputs: required: false default: "true" plan_parity: - description: Boolean flag to compare previous TF plan file with current plan before applying in a queue. + description: Boolean flag to compare the TF plan file with a newly-generated one to prevent stale apply. required: false default: "false" encrypt_passphrase: