Skip to content

Commit

Permalink
feat: outline of plan output changes (#213)
Browse files Browse the repository at this point in the history
* initial draft

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* amend `comment_outline` reference

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* retry in action.yaml instead now

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* fix missing `shell: bash`

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* retry

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* retry

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* remove unused code

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* only add outline if present

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* fix rogue `const`

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* fix erroneous reference

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* fix missing brace

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* retry with tweaked conditional

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* try without any comment_outline

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* drastically shorten changed_lines length

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* try `substring` instead of `slice`

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* y

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* retry

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

* ready for review

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>

---------

Signed-off-by: Rishav Dhar <19497993+rdhar@users.noreply.github.com>
  • Loading branch information
RDhar committed May 19, 2024
1 parent 2db47a4 commit 85327f7
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ Use-case: Provision resources with a backend, followed by destruction without co
| `cli_uses`</br>Example: tofu | String name of TF CLI to use and override default assumption from wrapper environment variable. |
| `command_input`</br>Example: -tf=plan -workspace=dev | String input to run TF CLI command with arguments directly via workflow automation. |
| `fmt_enable`</br>Default: true | Boolean flag to enable TF fmt command and display diff of changes. |
| `plan_outline`</br>Default: true | Boolean flag to output TF plan outline of changes. |
| `recreate_comment`</br>Default: true | Boolean flag to recreate PR comment on update instead of editing the existing one. |
| `validate_enable`</br>Default: false | Boolean flag to enable TF validate command check. |
| `var_file_from_workspace`</br>Default: false | Boolean flag to re-use TF `-workspace` as `-var-file` argument, if supplied. |
Expand Down
15 changes: 10 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ inputs:
fmt_enable:
description: Boolean flag to enable TF fmt command and display diff of changes.
default: true
plan_outline:
description: Boolean flag to output TF plan outline of changes.
default: true
recreate_comment:
description: Boolean flag to recreate PR comment on update instead of editing the existing one.
default: true
Expand Down Expand Up @@ -306,24 +309,24 @@ runs:
shell: bash
run: |
# Remove lines related to fetching the state of resources and truncate
# before the last 66000 characters to capture the final change summary.
# before the last 48000 characters to capture the final change summary.
tf_output_raw=$(cat <<'EOTF'
${{ steps.apply.outputs.stderr || steps.apply.outputs.stdout || steps.plan.outputs.stderr || steps.plan.outputs.stdout || steps.force_unlock.outputs.stderr || steps.force_unlock.outputs.stdout || steps.workspace.outputs.stderr || steps.validate.outputs.stderr || steps.init.outputs.stderr }}
EOTF
)
echo 'tf_output<<EOTF' >> $GITHUB_OUTPUT
echo "$tf_output_raw" |
grep -vE ': Creating...|: Creation complete after|: Destroying...|: Destruction complete after|: Modifications complete after|: Modifying...|: Provisioning with|: Read complete after|: Reading...|: Refreshing state...|: Still creating...|: Still destroying...|: Still modifying...|: Still reading...|. This may take a few moments...' |
tail -c 66000 >> $GITHUB_OUTPUT
tail -c 48000 >> $GITHUB_OUTPUT
echo 'EOTF' >> $GITHUB_OUTPUT
# This time, truncate after the first 12000 characters instead.
# This time, truncate after the first 6000 characters instead.
tf_fmt_raw=$(cat <<'EOTF'
${{ steps.fmt.outputs.stdout }}
EOTF
)
echo 'tf_fmt<<EOTF' >> $GITHUB_OUTPUT
echo "$tf_fmt_raw" | head -c 12000 >> $GITHUB_OUTPUT
echo "$tf_fmt_raw" | head -c 6000 >> $GITHUB_OUTPUT
echo 'EOTF' >> $GITHUB_OUTPUT
# Add or update PR comment with rendered TF output before exiting.
Expand All @@ -335,13 +338,15 @@ runs:
matrix: ${{ toJSON(matrix) }}
recreate_comment: ${{ inputs.recreate_comment }}
run_attempt: ${{ github.run_attempt }}
tf_chdir: ${{ steps.arguments.outputs.tf_cwd }}
tf_command: ${{ steps.parsed.outputs.command }}
tf_fmt: ${{ steps.render.outputs.tf_fmt }}
tf_output: ${{ steps.render.outputs.tf_output }}
tf_plan_id: ${{ steps.arguments.outputs.tf_plan_id }}
tf_plan_outline: ${{ inputs.plan_outline && steps.plan.outcome == 'success' }}
with:
retries: 3
script: await require(`${process.env.GITHUB_ACTION_PATH}/scripts/comment_tf_output.js`)({ github, context, core });
script: await require(`${process.env.GITHUB_ACTION_PATH}/scripts/comment_tf_output.js`)({ github, context, core, exec });

# Remove PR comment reaction to indicate that the workflow has ended.
- name: Remove reaction
Expand Down
39 changes: 37 additions & 2 deletions scripts/comment_tf_output.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = async ({ github, context, core }) => {
module.exports = async ({ github, context, core, exec }) => {
// Display latest TF change summary as the output header.
const comment_summary = process.env.tf_output
.split("\n")
Expand Down Expand Up @@ -39,9 +39,43 @@ ${process.env.tf_fmt}
repo: context.repo.repo,
});

// Parse the TFplan file to extract an outline of changes.
let comment_outline = "";
if (process.env.tf_plan_outline) {
// Parse TFplan file.
let tfplan = "";
const data_handler = (data) => {
tfplan += data.toString();
};
const options = {
listeners: {
stdout: data_handler,
stderr: data_handler,
},
};
await exec.exec(process.env.TF_CLI_USES, [`-chdir=${process.env.tf_chdir}`, "show", "-no-color", "tfplan"], options);

// Create a summary from lines starting with ' # ' without this prefix.
// prefix from the first 12000 characters.
const changed_lines = tfplan
.split("\n")
.filter((line) => line.startsWith(" # "))
.map((line) => line.slice(4));

// Create a collapsible summary of changes if any.
comment_outline = changed_lines.length
? `<details><summary>Outline of changes.</summary>
\`\`\`hcl
${changed_lines.join("\n").substring(0, 12000)}
\`\`\`
</details>`
: "";
}

// Display the: TF command, TF output, and workflow authorip.
const comment_output = `
<details><summary>${comment_summary}</br>
<details><summary>${comment_summary}</br>
###### ${context.workflow} by @${context.actor} via [${context.eventName}](${check_url}) at ${context.payload.pull_request?.updated_at || context.payload.comment?.updated_at}.</summary>
Expand All @@ -57,6 +91,7 @@ ${process.env.tf_output}
<!-- pre_output -->
${comment_fmt}
${comment_outline}
${comment_output}
<!-- post_output -->
Expand Down

0 comments on commit 85327f7

Please sign in to comment.