From 066c1c30af663e315c7deaa5bbff7a35e56ad93e Mon Sep 17 00:00:00 2001 From: Daniel Flook Date: Fri, 3 Dec 2021 19:31:43 +0000 Subject: [PATCH] Add `json_plan_path` and `text_plan_path` for dflook/terraform-apply --- .github/workflows/test-apply.yaml | 174 +++++++++++++++++++++++++---- .github/workflows/test-plan.yaml | 14 +-- .github/workflows/test-remote.yaml | 20 ++++ image/entrypoints/apply.sh | 18 +++ terraform-apply/README.md | 34 ++++-- terraform-apply/action.yaml | 8 ++ terraform-plan/README.md | 2 +- 7 files changed, 230 insertions(+), 40 deletions(-) diff --git a/.github/workflows/test-apply.yaml b/.github/workflows/test-apply.yaml index 217b167e..a2701e6e 100644 --- a/.github/workflows/test-apply.yaml +++ b/.github/workflows/test-apply.yaml @@ -26,6 +26,16 @@ jobs: echo "::error:: output my_string not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.my_string.actions[0] "${{ steps.output.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi apply_error: runs-on: ubuntu-latest @@ -53,6 +63,17 @@ jobs: echo "::error:: failure-reason not set correctly" exit 1 fi + + if [[ -n "${{ steps.apply.outputs.json_plan_path }}" ]]; then + echo "::error:: json_plan_path should not be set" + exit 1 + fi + + if [[ -n "${{ steps.apply.outputs.text_plan_path }}" ]]; then + echo "::error:: text_plan_path should not be set" + exit 1 + fi + apply_apply_error: runs-on: ubuntu-latest @@ -90,6 +111,16 @@ jobs: echo "::error:: failure-reason not set correctly" exit 1 fi + + if [[ $(jq -r .format_version "${{ steps.apply.outputs.json_plan_path }}") != "0.2" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "Terraform will perform the following actions" '${{ steps.apply.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi apply_no_token: runs-on: ubuntu-latest @@ -143,6 +174,39 @@ jobs: echo "::error:: output s not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.output_string.actions[0] "${{ steps.output.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "Terraform will perform the following actions" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi + + - name: Apply + uses: ./terraform-apply + id: output + with: + path: tests/apply/changes + + - name: Verify outputs + run: | + if [[ "${{ steps.output.outputs.output_string }}" != "the_string" ]]; then + echo "::error:: output s not set correctly" + exit 1 + fi + + if [[ $(jq -r .format_version "${{ steps.output.outputs.json_plan_path }}") != "0.2" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi apply_variables: runs-on: ubuntu-latest @@ -215,6 +279,16 @@ jobs: echo "::error:: output complex_output not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.output_string.actions[0] "${{ steps.output.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "Terraform will perform the following actions" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi backend_config_12: runs-on: ubuntu-latest @@ -246,6 +320,16 @@ jobs: echo "::error:: output from backend_config file not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.test.actions[0] "${{ steps.backend_config_file_12.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.backend_config_file_12.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi - name: Plan uses: ./terraform-plan @@ -272,6 +356,16 @@ jobs: echo "::error:: Output from backend_config not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.test.actions[0] "${{ steps.backend_config_12.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.backend_config_file_12.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi backend_config_13: runs-on: ubuntu-latest @@ -303,6 +397,16 @@ jobs: echo "::error:: output from backend_config file not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.test.actions[0] "${{ steps.backend_config_file_13.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.backend_config_file_13.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi - name: Plan uses: ./terraform-plan @@ -329,6 +433,16 @@ jobs: echo "::error:: Output from backend_config not set correctly" exit 1 fi + + if [[ $(jq -r .output_changes.test.actions[0] "${{ steps.backend_config_13.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.backend_config_13.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi apply_label: runs-on: ubuntu-latest @@ -362,31 +476,17 @@ jobs: echo "::error:: output s not set correctly" exit 1 fi - - apply_changes_already_applied: - runs-on: ubuntu-latest - name: Apply when changes are already applied - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - needs: - - apply - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Apply - uses: ./terraform-apply - id: output - with: - path: tests/apply/changes - - - name: Verify outputs - run: | - if [[ "${{ steps.output.outputs.output_string }}" != "the_string" ]]; then - echo "::error:: output s not set correctly" + + if [[ $(jq -r .output_changes.output_string.actions[0] "${{ steps.output.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" exit 1 fi + if ! grep -q "Terraform will perform the following actions" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi + apply_no_changes: runs-on: ubuntu-latest name: Apply when there are no planned changes @@ -410,6 +510,16 @@ jobs: echo "::error:: output my_string not set correctly" exit 1 fi + + if [[ $(jq -r .format_version "${{ steps.output.outputs.json_plan_path }}") != "0.2" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "No changes" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi apply_no_plan: runs-on: ubuntu-latest @@ -433,6 +543,16 @@ jobs: echo "Apply did not fail correctly" exit 1 fi + + if [[ $(jq -r .format_version "${{ steps.apply.outputs.json_plan_path }}") != "0.2" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "Terraform will perform the following actions" '${{ steps.apply.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi apply_user_token: runs-on: ubuntu-latest @@ -463,6 +583,16 @@ jobs: exit 1 fi + if [[ $(jq -r .output_changes.output_string.actions[0] "${{ steps.output.outputs.json_plan_path }}") != "create" ]]; then + echo "::error:: json_plan_path not set correctly" + exit 1 + fi + + if ! grep -q "Terraform will perform the following actions" '${{ steps.output.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi + apply_vars: runs-on: ubuntu-latest name: Apply approved changes with deprecated vars diff --git a/.github/workflows/test-plan.yaml b/.github/workflows/test-plan.yaml index c85066b5..c71451bd 100644 --- a/.github/workflows/test-plan.yaml +++ b/.github/workflows/test-plan.yaml @@ -127,7 +127,7 @@ jobs: cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi @@ -162,7 +162,7 @@ jobs: cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi @@ -198,7 +198,7 @@ jobs: cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi @@ -234,7 +234,7 @@ jobs: cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi @@ -269,7 +269,7 @@ jobs: cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi @@ -304,7 +304,7 @@ jobs: cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi @@ -333,7 +333,7 @@ jobs: run: | cat '${{ steps.plan.outputs.json_plan_path }}' if [[ $(jq -r .output_changes.s.actions[0] "${{ steps.plan.outputs.json_plan_path }}") != "create" ]]; then - echo "::error:: json not set correctly" + echo "::error:: json_plan_path not set correctly" exit 1 fi diff --git a/.github/workflows/test-remote.yaml b/.github/workflows/test-remote.yaml index 71faa417..1bde0009 100644 --- a/.github/workflows/test-remote.yaml +++ b/.github/workflows/test-remote.yaml @@ -60,6 +60,16 @@ jobs: echo "::error:: Variables not set correctly" exit 1 fi + + if [[ -n "${{ steps.auto_apply.outputs.text_plan_path }}" ]]; then + echo "::error:: text_plan_path should not be set" + exit 1 + fi + + if [[ -n "${{ steps.auto_apply.outputs.json_plan_path }}" ]]; then + echo "::error:: json_plan_path should not be set" + exit 1 + fi - name: Check no changes uses: ./terraform-check @@ -160,6 +170,16 @@ jobs: echo "::error:: Variables not set correctly" exit 1 fi + + if ! grep -q "Terraform will perform the following actions" '${{ steps.apply.outputs.text_plan_path }}'; then + echo "::error:: text_plan_path not set correctly" + exit 1 + fi + + if [[ -n "${{ steps.apply.outputs.json_plan_path }}" ]]; then + echo "::error:: json_plan_path should not be set" + exit 1 + fi - name: Destroy the last workspace uses: ./terraform-destroy-workspace diff --git a/image/entrypoints/apply.sh b/image/entrypoints/apply.sh index b1385973..3bf8890e 100755 --- a/image/entrypoints/apply.sh +++ b/image/entrypoints/apply.sh @@ -73,6 +73,24 @@ if [[ $PLAN_EXIT -eq 1 ]]; then exit 1 fi +if [[ -z "$PLAN_OUT" && "$INPUT_AUTO_APPROVE" == "true" ]]; then + # Since we are doing an auto approved remote apply there is no point in planning beforehand + # No text_plan_path output for this run + : +else + mkdir -p "$GITHUB_WORKSPACE/$WORKSPACE_TMP_DIR" + cp "$STEP_TMP_DIR/plan.txt" "$GITHUB_WORKSPACE/$WORKSPACE_TMP_DIR/plan.txt" + set_output text_plan_path "$WORKSPACE_TMP_DIR/plan.txt" +fi + +if [[ -n "$PLAN_OUT" ]]; then + if (cd "$INPUT_PATH" && terraform show -json "$PLAN_OUT") >"$GITHUB_WORKSPACE/$WORKSPACE_TMP_DIR/plan.json" 2>"$STEP_TMP_DIR/terraform_show.stderr"; then + set_output json_plan_path "$WORKSPACE_TMP_DIR/plan.json" + else + debug_file "$STEP_TMP_DIR/terraform_show.stderr" + fi +fi + ### Apply the plan if [[ "$INPUT_AUTO_APPROVE" == "true" || $PLAN_EXIT -eq 0 ]]; then diff --git a/terraform-apply/README.md b/terraform-apply/README.md index d5d0b59b..1982fc20 100644 --- a/terraform-apply/README.md +++ b/terraform-apply/README.md @@ -202,6 +202,30 @@ These input values must be the same as any `terraform-plan` for the same configu ## Outputs +* `json_plan_path` + + This is the path to the generated plan in [JSON Output Format](https://www.terraform.io/docs/internals/json-format.html) + The path is relative to the Actions workspace. + + This is not available when using terraform 0.11 or earlier. + This also won't be set if the backend type is `remote` - Terraform does not support saving remote plans. + +* `text_plan_path` + + This is the path to the generated plan in a human-readable format. + The path is relative to the Actions workspace. + This won't be set if `auto_approve` is true while using a `remote` backend. + +* `failure-reason` + + When the job outcome is `failure`, this output may be set. The value may be one of: + + - `apply-failed` - The Terraform apply operation failed. + - `plan-changed` - The approved plan is no longer accurate, so the apply will not be attempted. + + If the job fails for any other reason this will not be set. + This can be used with the Actions expression syntax to conditionally run steps. + * Terraform Outputs An action output will be created for each output of the terraform configuration. @@ -216,16 +240,6 @@ These input values must be the same as any `terraform-plan` for the same configu Running this action will produce a `service_hostname` output with the same value. See [terraform-output](https://github.com/dflook/terraform-github-actions/tree/master/terraform-output) for details. -* `failure-reason` - - When the job outcome is `failure`, this output may be set. The value may be one of: - - - `apply-failed` - The terraform apply operation failed. - - `plan-changed` - The approved plan is no longer accurate, so the apply will not be attempted. - - If the job fails for any other reason this will not be set. - This can be used with the Actions expression syntax to conditionally run steps. - ## Environment Variables * `GITHUB_TOKEN` diff --git a/terraform-apply/action.yaml b/terraform-apply/action.yaml index f2558a43..8e509920 100644 --- a/terraform-apply/action.yaml +++ b/terraform-apply/action.yaml @@ -51,6 +51,14 @@ inputs: required: false default: "" +outputs: + text_plan_path: + description: Path to a file in the workspace containing the generated plan in human readble format. This won't be set if the backend type is `remote` and `auto_approve` is `true` + json_plan_path: + description: Path to a file in the workspace containing the generated plan in JSON format. This won't be set if the backend type is `remote`. + failure-reason: + description: The reason for the build failure. May be `apply-failed` or `plan-changed`. + runs: using: docker image: ../image/Dockerfile diff --git a/terraform-plan/README.md b/terraform-plan/README.md index 318e18fb..7bc49590 100644 --- a/terraform-plan/README.md +++ b/terraform-plan/README.md @@ -327,7 +327,7 @@ The [dflook/terraform-apply](https://github.com/dflook/terraform-github-actions/ * `text_plan_path` - This is the path to the generated plan in a human readable format. + This is the path to the generated plan in a human-readable format. The path is relative to the Actions workspace. ## Example usage