From b5ba0489ef2e5462b3a5243ced1c6b18b000b243 Mon Sep 17 00:00:00 2001 From: Ali Khajeh-Hosseini Date: Tue, 24 May 2022 04:09:42 -0700 Subject: [PATCH] feat: update to use Infracost v0.10 (actions v2) (#65) * docs: change examples to use hcl by default * chore: use v0.10.0-beta.1 release * docs: fix version in setup README * test: fix example tests test: fix tests to checkout the correct version for the setup task test: don't compare against the base branch in tests test: update tests so they also update the var files to test changes test: fix example test golden files test: fix private terraform module test * docs: make examples consistent with GitLab (#64) * docs: make examples consistent with GitLab * docs: update example step comments * docs: update golden files and examples to be more consistent * docs: add commented out example for TFC * docs: use consistent terminology with migration guide * docs: update examples to use `--flag=value` instead of `--flag value` This gives better error messages if the value is an empty env variable. * docs: simplify comments Co-authored-by: Ali * docs: add setup comment for Docker image * docs: move setup action first * docs: fix indentation * chore: use v0.10 version Co-authored-by: Hugo Co-authored-by: Alistair Scott --- .github/workflows/comment_test.yml | 49 -- .github/workflows/examples_test.yml | 656 ++++++++++++------ .github/workflows/get_comment_test.yml | 60 -- CONTRIBUTING.md | 2 +- README.md | 162 ++--- action.yml | 58 +- comment/README.md | 50 -- comment/action.yml | 44 -- examples/README.md | 36 +- examples/multi-project-config-file/README.md | 66 ++ .../multi-project-config-file/code/.gitignore | 2 + .../multi-project-config-file/code/dev.tfvars | 1 + .../code/dev/main.tf | 22 + .../code/infracost.yml | 9 + .../code/modules/example/main.tf | 0 .../code/prod.tfvars | 1 + .../code/prod/main.tf | 22 + examples/multi-project/README.md | 142 ---- examples/multi-project/code/infracost.yml | 11 - examples/multi-terraform-workspace/README.md | 52 -- .../multi-terraform-workspace/code/dev.tfvars | 6 - .../code/infracost.yml | 16 - .../plan-json/multi-project-matrix/README.md | 103 +++ .../multi-workspace-matrix/README.md | 104 +++ .../multi-workspace-matrix/code/.gitignore | 2 + .../multi-workspace-matrix/code/dev.tfvars | 1 + .../multi-workspace-matrix}/code/main.tf | 2 + .../multi-workspace-matrix}/code/prod.tfvars | 0 .../terraform-cloud-enterprise/README.md | 83 +++ .../code/.gitignore | 2 + .../terraform-cloud-enterprise/code/main.tf | 0 examples/plan-json/terragrunt/README.md | 93 +++ examples/plan-json/terragrunt/code/.gitignore | 1 + .../terragrunt/code/dev/terragrunt.hcl | 0 .../plan-json/terragrunt/code/infracost.yml | 6 + .../terragrunt/code/modules/example/main.tf | 0 .../terragrunt/code/prod/terragrunt.hcl | 0 .../terragrunt/code/terragrunt.hcl | 0 examples/private-terraform-module/README.md | 78 ++- .../private-terraform-module/code/.gitignore | 2 + examples/sentinel/README.md | 32 +- examples/sentinel/code/plan.json | 400 ----------- examples/slack/README.md | 64 +- examples/slack/code/plan.json | 1 - examples/terraform-cloud-enterprise/README.md | 54 -- examples/terraform-directory/README.md | 48 -- examples/terraform-directory/code/main.tf | 31 - examples/terraform-plan-json/README.md | 41 -- examples/terraform-plan-json/code/plan.json | 1 - examples/terraform-project/README.md | 70 ++ examples/terraform-project/code/.gitignore | 2 + .../code/dev/main.tf | 4 +- .../code/modules/example/main.tf | 48 ++ .../code/prod/main.tf | 4 +- examples/terragrunt/README.md | 53 -- get-comment/README.md | 43 -- get-comment/action.yml | 30 - package-lock.json | 8 +- scripts/generateExamplesTests.js | 71 +- scripts/testExamples.js | 4 +- setup/README.md | 4 +- setup/action.yml | 2 +- setup/package-lock.json | 2 +- setup/package.json | 2 +- testdata/comment/simple_breakdown.json | 1 - ...ulti-project-config-file_comment_golden.md | 96 +-- ...lti-project-matrix-merge_comment_golden.md | 12 +- ...-workspace-matrix-merge_comment_golden.md} | 12 +- ...private-terraform-module_comment_golden.md | 25 +- testdata/slack_comment_golden.md | 70 +- testdata/slack_slack_message_golden.json | 50 +- ...rraform-cloud-enterprise_comment_golden.md | 6 +- .../terraform-directory_comment_golden.md | 73 -- .../terraform-plan-json_comment_golden.md | 73 -- testdata/terraform-project_comment_golden.md | 75 ++ ...d => terragrunt-project_comment_golden.md} | 12 +- 76 files changed, 1582 insertions(+), 1886 deletions(-) delete mode 100644 .github/workflows/comment_test.yml delete mode 100644 .github/workflows/get_comment_test.yml delete mode 100644 comment/README.md delete mode 100644 comment/action.yml create mode 100644 examples/multi-project-config-file/README.md create mode 100644 examples/multi-project-config-file/code/.gitignore create mode 100644 examples/multi-project-config-file/code/dev.tfvars create mode 100644 examples/multi-project-config-file/code/dev/main.tf create mode 100644 examples/multi-project-config-file/code/infracost.yml rename examples/{multi-project => multi-project-config-file}/code/modules/example/main.tf (100%) create mode 100644 examples/multi-project-config-file/code/prod.tfvars create mode 100644 examples/multi-project-config-file/code/prod/main.tf delete mode 100644 examples/multi-project/README.md delete mode 100644 examples/multi-project/code/infracost.yml delete mode 100644 examples/multi-terraform-workspace/README.md delete mode 100644 examples/multi-terraform-workspace/code/dev.tfvars delete mode 100644 examples/multi-terraform-workspace/code/infracost.yml create mode 100644 examples/plan-json/multi-project-matrix/README.md create mode 100644 examples/plan-json/multi-workspace-matrix/README.md create mode 100644 examples/plan-json/multi-workspace-matrix/code/.gitignore create mode 100644 examples/plan-json/multi-workspace-matrix/code/dev.tfvars rename examples/{multi-terraform-workspace => plan-json/multi-workspace-matrix}/code/main.tf (91%) rename examples/{multi-terraform-workspace => plan-json/multi-workspace-matrix}/code/prod.tfvars (100%) create mode 100644 examples/plan-json/terraform-cloud-enterprise/README.md create mode 100644 examples/plan-json/terraform-cloud-enterprise/code/.gitignore rename examples/{ => plan-json}/terraform-cloud-enterprise/code/main.tf (100%) create mode 100644 examples/plan-json/terragrunt/README.md create mode 100644 examples/plan-json/terragrunt/code/.gitignore rename examples/{ => plan-json}/terragrunt/code/dev/terragrunt.hcl (100%) create mode 100644 examples/plan-json/terragrunt/code/infracost.yml rename examples/{ => plan-json}/terragrunt/code/modules/example/main.tf (100%) rename examples/{ => plan-json}/terragrunt/code/prod/terragrunt.hcl (100%) rename examples/{ => plan-json}/terragrunt/code/terragrunt.hcl (100%) create mode 100644 examples/private-terraform-module/code/.gitignore delete mode 100644 examples/sentinel/code/plan.json delete mode 100644 examples/slack/code/plan.json delete mode 100644 examples/terraform-cloud-enterprise/README.md delete mode 100644 examples/terraform-directory/README.md delete mode 100644 examples/terraform-directory/code/main.tf delete mode 100644 examples/terraform-plan-json/README.md delete mode 100644 examples/terraform-plan-json/code/plan.json create mode 100644 examples/terraform-project/README.md create mode 100644 examples/terraform-project/code/.gitignore rename examples/{multi-project => terraform-project}/code/dev/main.tf (80%) create mode 100644 examples/terraform-project/code/modules/example/main.tf rename examples/{multi-project => terraform-project}/code/prod/main.tf (81%) delete mode 100644 examples/terragrunt/README.md delete mode 100644 get-comment/README.md delete mode 100644 get-comment/action.yml delete mode 100644 testdata/comment/simple_breakdown.json rename testdata/{terragrunt_comment_golden.md => multi-workspace-matrix-merge_comment_golden.md} (82%) delete mode 100644 testdata/terraform-directory_comment_golden.md delete mode 100644 testdata/terraform-plan-json_comment_golden.md create mode 100644 testdata/terraform-project_comment_golden.md rename testdata/{multi-terraform-workspace-config-file_comment_golden.md => terragrunt-project_comment_golden.md} (84%) diff --git a/.github/workflows/comment_test.yml b/.github/workflows/comment_test.yml deleted file mode 100644 index 73852a4..0000000 --- a/.github/workflows/comment_test.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Test Comment - -on: - push: - branches: - - master - paths: - - "comment/**" - pull_request: - -defaults: - run: - shell: bash - -jobs: - test_pr: - name: Test PR Comment - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup infracost - uses: ./setup - with: - api-key: abcdefg123456 - - name: Infracost comment - uses: ./comment - with: - path: ./testdata/comment/simple_breakdown.json - tag: "infracost-pull-request" - behavior: new - test_commit: - name: Test Commit Comment - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup infracost - uses: ./setup - with: - api-key: abcdefg123456 - - name: Infracost comment - uses: ./comment - with: - path: "./testdata/comment/*.json" - target-type: commit - tag: "infracost-commit" - behavior: new diff --git a/.github/workflows/examples_test.yml b/.github/workflows/examples_test.yml index 5d97bf5..d9f508e 100644 --- a/.github/workflows/examples_test.yml +++ b/.github/workflows/examples_test.yml @@ -11,33 +11,46 @@ jobs: multi-project-config-file: name: Multi-project config file runs-on: ubuntu-latest + env: + TF_ROOT: examples/multi-project-config-file/code steps: - - uses: actions/checkout@v2 - - name: Install Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false + - name: Checkout source code so we can install the action locally + uses: actions/checkout@v2 - name: Setup Infracost uses: ./setup with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost + - name: Checkout base branch + uses: actions/checkout@v2 + with: {} + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --config-file=${TF_ROOT}/infracost.yml \ + --format=json \ + --out-file=/tmp/infracost-base.json + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Replace m5 instance run: >- - infracost breakdown - --config-file=examples/multi-project/code/infracost.yml --format=json - --out-file=/tmp/infracost.json - env: - DEV_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_DEV_AWS_ACCESS_KEY_ID }} - DEV_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY }} - PROD_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_PROD_AWS_ACCESS_KEY_ID }} - PROD_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY }} + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --config-file=${TF_ROOT}/infracost.yml \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json - name: Post Infracost comment run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ --dry-run true \ > /tmp/infracost_comment.md - run: >- @@ -53,37 +66,55 @@ jobs: multi-project-matrix: name: Multi-project matrix runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code strategy: matrix: include: - - dir: dev + - project: dev aws_access_key_id_secret: EXAMPLE_DEV_AWS_ACCESS_KEY_ID aws_secret_access_key_secret: EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY - - dir: prod + - project: prod aws_access_key_id_secret: EXAMPLE_PROD_AWS_ACCESS_KEY_ID aws_secret_access_key_secret: EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY steps: - uses: actions/checkout@v2 - name: Install Terraform - uses: hashicorp/setup-terraform@v1 + uses: hashicorp/setup-terraform@v2 with: terraform_wrapper: false + - name: Terraform init + run: terraform init + working-directory: ${{ env.TF_ROOT }}/${{ matrix.project }} + - name: Generate plan JSON + run: | + terraform plan -out=plan.cache + terraform show -json plan.cache > plan.json + working-directory: ${{ env.TF_ROOT }}/${{ matrix.project }} - name: Setup Infracost uses: ./setup with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost + - name: Replace m5 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff run: >- - infracost breakdown --path=examples/multi-project/code/${{ matrix.dir - }} --format=json --out-file=/tmp/infracost_${{ matrix.dir }}.json + infracost diff --path=${TF_ROOT}/${{ matrix.project }}/plan.json + --format=json --out-file=/tmp/infracost_${{ matrix.project }}.json env: AWS_ACCESS_KEY_ID: ${{ secrets[matrix.aws_access_key_id_secret] }} AWS_SECRET_ACCESS_KEY: ${{ secrets[matrix.aws_secret_access_key_secret] }} - name: Upload Infracost breakdown uses: actions/upload-artifact@v2 with: - name: infracost_jsons - path: /tmp/infracost_${{ matrix.dir }}.json + name: infracost_project_jsons + path: /tmp/infracost_${{ matrix.project }}.json if: github.actor != 'nektos/act' multi-project-matrix-merge: name: Multi-project matrix merge @@ -95,6 +126,7 @@ jobs: - name: Download all Infracost breakdown files uses: actions/download-artifact@v2 with: + name: infracost_project_jsons path: /tmp - name: Setup Infracost uses: ./setup @@ -102,11 +134,11 @@ jobs: api-key: ${{ secrets.INFRACOST_API_KEY }} - name: Post Infracost comment run: |- - infracost comment github --path "/tmp/infracost_jsons/*.json" \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ + infracost comment github --path="/tmp/infracost_*.json" \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ --dry-run true \ > /tmp/infracost_comment.md - run: >- @@ -120,83 +152,334 @@ jobs: ./testdata/multi-project-matrix-merge_comment_golden.md if: env.UPDATE_GOLDEN_FILES == 'true' if: github.actor != 'nektos/act' - multi-terraform-workspace-config-file: - name: Multi-Terraform workspace config file + multi-workspace-matrix: + name: Multi-workspace matrix runs-on: ubuntu-latest + env: + TF_ROOT: examples/plan-json/multi-workspace-matrix/code + strategy: + matrix: + include: + - tf_workspace: dev + aws_access_key_id_secret: EXAMPLE_DEV_AWS_ACCESS_KEY_ID + aws_secret_access_key_secret: EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY + - tf_workspace: prod + aws_access_key_id_secret: EXAMPLE_PROD_AWS_ACCESS_KEY_ID + aws_secret_access_key_secret: EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY steps: - uses: actions/checkout@v2 - name: Install Terraform - uses: hashicorp/setup-terraform@v1 + uses: hashicorp/setup-terraform@v2 with: terraform_wrapper: false + - name: Terraform init + run: terraform init + working-directory: ${{ env.TF_ROOT }} + - name: Generate plan JSON + run: > + terraform plan -out=${{ matrix.tf_workspace }}-plan.cache + -var-file=${{ matrix.tf_workspace }}.tfvars + + terraform show -json ${{ matrix.tf_workspace }}-plan.cache > ${{ + matrix.tf_workspace }}-plan.json + env: + TF_WORKSPACE: ${{ matrix.tf_workspace }} + working-directory: ${{ env.TF_ROOT }} - name: Setup Infracost uses: ./setup with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost + - name: Replace m5 instance run: >- - infracost breakdown - --config-file=examples/multi-terraform-workspace/code/infracost.yml - --format=json --out-file=/tmp/infracost.json + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: >- + infracost diff --path=${TF_ROOT}/${{ matrix.tf_workspace }}-plan.json + --format=json --out-file=/tmp/infracost_${{ matrix.tf_workspace + }}.json env: - DEV_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_DEV_AWS_ACCESS_KEY_ID }} - DEV_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY }} - PROD_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_PROD_AWS_ACCESS_KEY_ID }} - PROD_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY }} + AWS_ACCESS_KEY_ID: ${{ secrets[matrix.aws_access_key_id_secret] }} + AWS_SECRET_ACCESS_KEY: ${{ secrets[matrix.aws_secret_access_key_secret] }} + - name: Upload Infracost breakdown + uses: actions/upload-artifact@v2 + with: + name: infracost_workspace_jsons + path: /tmp/infracost_${{ matrix.tf_workspace }}.json + if: github.actor != 'nektos/act' + multi-workspace-matrix-merge: + name: Multi-workspace matrix merge + runs-on: ubuntu-latest + needs: + - multi-workspace-matrix + steps: + - uses: actions/checkout@v2 + - name: Download all Infracost breakdown files + uses: actions/download-artifact@v2 + with: + name: infracost_workspace_jsons + path: /tmp + - name: Setup Infracost + uses: ./setup + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} - name: Post Infracost comment run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ + infracost comment github --path="/tmp/infracost_*.json" \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ --dry-run true \ > /tmp/infracost_comment.md - run: >- - diff -y - ./testdata/multi-terraform-workspace-config-file_comment_golden.md + diff -y ./testdata/multi-workspace-matrix-merge_comment_golden.md /tmp/infracost_comment.md name: Check the comment if: env.UPDATE_GOLDEN_FILES != 'true' - name: Update the golden comment file run: >- cp /tmp/infracost_comment.md - ./testdata/multi-terraform-workspace-config-file_comment_golden.md + ./testdata/multi-workspace-matrix-merge_comment_golden.md if: env.UPDATE_GOLDEN_FILES == 'true' - private-terraform-module: - name: Private Terraform module + if: github.actor != 'nektos/act' + terraform-cloud-enterprise: + name: Terraform Cloud/Enterprise runs-on: ubuntu-latest + env: + TF_ROOT: examples/plan-json/terraform-cloud-enterprise/code + TFC_HOST: app.terraform.io steps: - - uses: actions/checkout@v2 - - name: Install terraform - uses: hashicorp/setup-terraform@v1 + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 with: + cli_config_credentials_token: ${{ secrets.TFC_TOKEN }} + cli_config_credentials_hostname: ${{ env.TFC_HOST }} terraform_wrapper: false - - name: add GIT_SSH_KEY + - name: Terraform init + run: terraform init + working-directory: ${{ env.TF_ROOT }} + - name: Retrieve plan JSONs run: > - mkdir -p .ssh + echo "Running terraform plan" - echo "${{ secrets.GIT_SSH_KEY }}" > .ssh/git_ssh_key + terraform plan -no-color | tee /tmp/plan_logs.txt - chmod 400 .ssh/git_ssh_key - echo "GIT_SSH_COMMAND=ssh -i $(pwd)/.ssh/git_ssh_key -o - 'StrictHostKeyChecking=no'" >> $GITHUB_ENV + echo "Parsing the run URL and ID from the logs" + + run_url=$(grep -A1 'To view this run' /tmp/plan_logs.txt | tail -n 1) + + run_id=$(basename $run_url) + + + echo "Getting the run plan response from + https://$TFC_HOST/api/v2/runs/$run_id/plan" + + run_plan_resp=$(wget -q -O - --header="Authorization: Bearer ${{ + secrets.TFC_TOKEN }}" "https://$TFC_HOST/api/v2/runs/$run_id/plan") + + echo "Extracting the plan JSON path" + + plan_json_path=$(echo $run_plan_resp | sed + 's/.*\"json-output\":\"\([^\"]*\)\".*/\1/') + + + echo "Downloading the plan JSON from https://$TFC_HOST$plan_json_path" + + wget -q -O plan.json --header="Authorization: Bearer ${{ + secrets.TFC_TOKEN }}" "https://$TFC_HOST$plan_json_path" + working-directory: ${{ env.TF_ROOT }} - name: Setup Infracost uses: ./setup with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost + - name: Replace m5 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance run: >- - infracost breakdown --path=examples/private-terraform-module/code - --format=json --out-file=/tmp/infracost.json + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT}/plan.json \ + --format=json \ + --out-file=/tmp/infracost.json - name: Post Infracost comment run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ + --dry-run true \ + > /tmp/infracost_comment.md + - run: >- + diff -y ./testdata/terraform-cloud-enterprise_comment_golden.md + /tmp/infracost_comment.md + name: Check the comment + if: env.UPDATE_GOLDEN_FILES != 'true' + - name: Update the golden comment file + run: >- + cp /tmp/infracost_comment.md + ./testdata/terraform-cloud-enterprise_comment_golden.md + if: env.UPDATE_GOLDEN_FILES == 'true' + terragrunt-project: + name: Terragrunt project + runs-on: ubuntu-latest + env: + TF_ROOT: examples/plan-json/terragrunt/code + steps: + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false + - name: Setup Terragrunt + uses: autero1/action-terragrunt@v1.1.0 + with: + terragrunt_version: 0.37.0 + - name: Generate plan JSONs + run: > + terragrunt run-all --terragrunt-ignore-external-dependencies plan + -out=plan.cache + + + # Find the plan files + + plans=($(find . -name plan.cache | tr '\n' ' ')) + + + # Generate plan JSON files by running terragrunt show for each plan + file + + planjsons=() + + for plan in "${plans[@]}"; do + # Find the Terraform working directory for running terragrunt show + # We want to take the dir of the plan file and strip off anything after the .terraform-cache dir + # to find the location of the Terraform working directory that contains the Terraform code + dir=$(dirname $plan) + dir=$(echo "$dir" | sed 's/\(.*\)\/\.terragrunt-cache\/.*/\1/') + + echo "Running terragrunt show for $(basename $plan) for $dir"; + terragrunt show -json $(basename $plan) --terragrunt-working-dir=$dir --terragrunt-no-auto-init > $dir/plan.json + planjsons=(${planjsons[@]} "$dir/plan.json") + done + + + # Sort the plan JSONs so we get consistent project ordering in the + config file + + IFS=$'\n' planjsons=($(sort <<<"${planjsons[*]}")) + + + # Generate Infracost config file + + echo -e "version: 0.1\n\nprojects:\n" > infracost.yml + + for planjson in "${planjsons[@]}"; do + echo -e " - path: ${TF_ROOT}/$planjson" >> infracost.yml + done + working-directory: ${{ env.TF_ROOT }} + - name: Setup Infracost + uses: ./setup + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + - name: Replace m5 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --config-file=${TF_ROOT}/infracost.yml \ + --format=json \ + --out-file=/tmp/infracost.json + - name: Post Infracost comment + run: |- + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ + --dry-run true \ + > /tmp/infracost_comment.md + - run: >- + diff -y ./testdata/terragrunt-project_comment_golden.md + /tmp/infracost_comment.md + name: Check the comment + if: env.UPDATE_GOLDEN_FILES != 'true' + - name: Update the golden comment file + run: >- + cp /tmp/infracost_comment.md + ./testdata/terragrunt-project_comment_golden.md + if: env.UPDATE_GOLDEN_FILES == 'true' + private-terraform-module: + name: Private Terraform module + runs-on: ubuntu-latest + env: + TF_ROOT: examples/private-terraform-module/code + steps: + - name: Checkout source code so we can install the action locally + uses: actions/checkout@v2 + - name: Setup Infracost + uses: ./setup + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + - name: Checkout base branch + uses: actions/checkout@v2 + with: {} + - name: add GIT_SSH_KEY + run: > + mkdir -p ~/.ssh + + echo "${{ secrets.GIT_SSH_KEY }}" > ~/.ssh/git_ssh_key + + chmod 400 ~/.ssh/git_ssh_key + + echo "GIT_SSH_COMMAND=ssh -i ~/.ssh/git_ssh_key -o + 'StrictHostKeyChecking=no'" >> $GITHUB_ENV + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Replace m5 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + - name: Post Infracost comment + run: |- + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ --dry-run true \ > /tmp/infracost_comment.md - run: >- @@ -212,6 +495,8 @@ jobs: sentinel: name: Sentinel runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code steps: - uses: actions/checkout@v2 - name: Setup Infracost @@ -228,10 +513,30 @@ jobs: unzip -d /tmp/sentinel /tmp/sentinel/sentinel.zip echo "/tmp/sentinel" >> $GITHUB_PATH - - name: Run Infracost + - name: Checkout base branch + uses: actions/checkout@v2 + with: {} + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Replace m5 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance run: >- - infracost breakdown --path=examples/sentinel/code/plan.json - --format=json --out-file=/tmp/infracost.json + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json - name: Run Sentinel run: >- sentinel apply -global breakdown="$(cat /tmp/infracost.json)" @@ -248,23 +553,46 @@ jobs: slack: name: Slack runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code steps: - - uses: actions/checkout@v2 + - name: Checkout source code so we can install the action locally + uses: actions/checkout@v2 - name: Setup Infracost uses: ./setup with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Generate Infracost JSON + - name: Checkout base branch + uses: actions/checkout@v2 + with: {} + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Replace m5 instance + run: >- + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance run: >- - infracost breakdown --path=examples/slack/code/plan.json --format json - --out-file /tmp/infracost.json + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json - name: Post Infracost comment run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ --dry-run true \ > /tmp/infracost_comment.md - run: diff -y ./testdata/slack_comment_golden.md /tmp/infracost_comment.md @@ -276,8 +604,8 @@ jobs: - name: Generate Slack message id: infracost-slack run: > - echo "::set-output name=slack-message::$(infracost output --path - /tmp/infracost.json --format slack-message --show-skipped)" + echo "::set-output name=slack-message::$(infracost output + --path=/tmp/infracost.json --format=slack-message --show-skipped)" echo "::set-output name=diffTotalMonthlyCost::$(jq '(.diffTotalMonthlyCost // 0) | tonumber' /tmp/infracost.json)" @@ -295,148 +623,58 @@ jobs: jq --sort-keys . /tmp/infracost_slack_message.json > ./testdata/slack_slack_message_golden.json if: env.UPDATE_GOLDEN_FILES == 'true' - terraform-cloud-enterprise: - name: Terraform Cloud/Enterprise + terraform-project: + name: Terraform project runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code steps: - - uses: actions/checkout@v2 - - name: Install terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false - cli_config_credentials_token: ${{ secrets.TFC_TOKEN }} + - name: Checkout source code so we can install the action locally + uses: actions/checkout@v2 - name: Setup Infracost uses: ./setup with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost - run: >- - infracost breakdown --path=examples/terraform-cloud-enterprise/code - --format=json --out-file=/tmp/infracost.json - env: - INFRACOST_TERRAFORM_CLOUD_TOKEN: ${{ secrets.TFC_TOKEN }} - - name: Post Infracost comment - run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ - --dry-run true \ - > /tmp/infracost_comment.md - - run: >- - diff -y ./testdata/terraform-cloud-enterprise_comment_golden.md - /tmp/infracost_comment.md - name: Check the comment - if: env.UPDATE_GOLDEN_FILES != 'true' - - name: Update the golden comment file - run: >- - cp /tmp/infracost_comment.md - ./testdata/terraform-cloud-enterprise_comment_golden.md - if: env.UPDATE_GOLDEN_FILES == 'true' - terraform-directory: - name: Terraform directory - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Install terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false - - name: Setup Infracost - uses: ./setup - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost - run: >- - infracost breakdown --path=examples/terraform-directory/code - --format=json --out-file=/tmp/infracost.json - - name: Post Infracost comment - run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ - --dry-run true \ - > /tmp/infracost_comment.md - - run: >- - diff -y ./testdata/terraform-directory_comment_golden.md - /tmp/infracost_comment.md - name: Check the comment - if: env.UPDATE_GOLDEN_FILES != 'true' - - name: Update the golden comment file + - name: Checkout base branch + uses: actions/checkout@v2 + with: {} + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + - name: Checkout PR branch + uses: actions/checkout@v2 + - name: Replace m5 instance run: >- - cp /tmp/infracost_comment.md - ./testdata/terraform-directory_comment_golden.md - if: env.UPDATE_GOLDEN_FILES == 'true' - terraform-plan-json: - name: Terraform plan JSON - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup Infracost - uses: ./setup - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/m5.4xlarge/m5.8xlarge/g' + - name: Replace t2 instance run: >- - infracost breakdown --path=examples/terraform-plan-json/code/plan.json - --format=json --out-file=/tmp/infracost.json + find examples -type f -name '*.tf' -o -name '*.hcl' -o -name + '*.tfvars' | xargs sed -i 's/t2.micro/t2.medium/g' + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json - name: Post Infracost comment run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=1 \ + --behavior=update \ --dry-run true \ > /tmp/infracost_comment.md - run: >- - diff -y ./testdata/terraform-plan-json_comment_golden.md + diff -y ./testdata/terraform-project_comment_golden.md /tmp/infracost_comment.md name: Check the comment if: env.UPDATE_GOLDEN_FILES != 'true' - name: Update the golden comment file run: >- cp /tmp/infracost_comment.md - ./testdata/terraform-plan-json_comment_golden.md - if: env.UPDATE_GOLDEN_FILES == 'true' - terragrunt: - name: Terragrunt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Install Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false - - name: Setup Terragrunt - uses: autero1/action-terragrunt@v1.1.0 - with: - terragrunt_version: 0.35.9 - - name: Setup Infracost - uses: ./setup - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Run Infracost - run: >- - infracost breakdown --path=examples/terragrunt/code --format=json - --out-file=/tmp/infracost.json - - name: Post Infracost comment - run: |- - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request 1 \ - --behavior update \ - --dry-run true \ - > /tmp/infracost_comment.md - - run: >- - diff -y ./testdata/terragrunt_comment_golden.md - /tmp/infracost_comment.md - name: Check the comment - if: env.UPDATE_GOLDEN_FILES != 'true' - - name: Update the golden comment file - run: cp /tmp/infracost_comment.md ./testdata/terragrunt_comment_golden.md + ./testdata/terraform-project_comment_golden.md if: env.UPDATE_GOLDEN_FILES == 'true' diff --git a/.github/workflows/get_comment_test.yml b/.github/workflows/get_comment_test.yml deleted file mode 100644 index 11e04e6..0000000 --- a/.github/workflows/get_comment_test.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Test Comment - -on: - push: - branches: - - master - paths: - - "get-comment/**" - pull_request: - -defaults: - run: - shell: bash - -jobs: - test_get_comment: - name: Test Get Comment - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup infracost - uses: ./setup - with: - api-key: abcdefg123456 - - - name: Save comment output - run: | - infracost comment github --path ./testdata/comment/simple_breakdown.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior new \ - --dry-run true \ - > expected.md - - head -n -2 expected.md > tmp.txt && mv tmp.txt expected.md - - - name: Infracost comment - id: post-comment - uses: ./comment - with: - path: ./testdata/comment/simple_breakdown.json - tag: "custom-tag" - behavior: new - - - name: Infracost get comment - id: get-comment - uses: ./get-comment - with: - tag: "custom-tag" - - - run: | - actual=$(cat <<\EOF - ${{ steps.get-comment.outputs.body }} - EOF - ) - diff -y <(echo "$actual") expected.md - name: Check the comment \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf639fb..2ccd4a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ jobs: ```` The examples are then modified in two ways: -1. Use local paths for any Infracost actions, e.g. replace `uses: infracost/actions/setup@v1` with `./setup`. +1. Use local paths for any Infracost actions, e.g. replace `uses: infracost/actions/setup@v2` with `./setup`. 2. Replace any `infracost/actions/comment` steps with steps to generate and test the content of the comment using golden files from the [./testdata](./testdata) directory. All the examples are then added to the `examples_test` GitHub Actions workflow as separate jobs. diff --git a/README.md b/README.md index 7e58a84..bbd71a5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Infracost GitHub Actions -This project provides a set of GitHub Actions for Infracost, so you can see cloud cost estimates for Terraform in pull requests šŸ’° +This project provide a GitHub Action and examples for Infracost, so you can see cloud cost estimates for Terraform in pull requests šŸ’° Example screenshot @@ -12,85 +12,72 @@ The following steps assume a simple Terraform directory is being used, we recomm 2. [Create a repo secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository) called `INFRACOST_API_KEY` with your API key. -3. Create required repo secrets for any cloud credentials that are needed for Terraform to run. If you have multiple projects/workspaces, consider using an Infracost [config-file](https://www.infracost.io/docs/multi_project/config_file) to define the projects. +3. Create a new file in `.github/workflows/infracost.yml` in your repo with the following content. - - **Terraform Cloud/Enterprise users**: if you use Remote Execution Mode, you should follow [setup-terraform](https://github.com/hashicorp/setup-terraform) instructions to set the inputs `cli_config_credentials_token`, and `cli_config_credentials_hostname` for Terraform Enterprise. - - **AWS users**: use [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials), the [Terraform docs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables) explain other options. - - **Azure users**: the [Terraform docs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret) explain the options. The [Azure/login](https://github.com/Azure/login) GitHub Actions might also be useful; we haven't tested these with Terraform. - - **Google users**: the [Terraform docs](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#full-reference) explain the options, e.g. using `GOOGLE_CREDENTIALS`. - -4. Create a new file in `.github/workflows/infracost.yml` in your repo with the following content. - - ```yaml + ```yaml # The GitHub Actions docs (https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#on) # describe other options for 'on', 'pull_request' is a good default. on: [pull_request] jobs: infracost: - runs-on: ubuntu-latest # The following are JavaScript actions (not Docker) + name: Infracost + runs-on: ubuntu-latest + env: - working-directory: PATH/TO/TERRAFORM/CODE # Update this! - - name: Run Infracost - steps: - - name: Check out repository - uses: actions/checkout@v2 - - # Typically the Infracost actions will be used in conjunction with - # https://github.com/hashicorp/setup-terraform. Subsequent steps - # can run Terraform commands as they would in the shell. - - name: Install terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - - # IMPORTANT: add any required steps here to setup cloud credentials so Terraform can run - - - name: Terraform init - run: terraform init - working-directory: ${{ env.working-directory }} - - - name: Terraform plan - run: terraform plan -out tfplan.binary - working-directory: ${{ env.working-directory }} - - - name: Terraform show - run: terraform show -json tfplan.binary > plan.json - working-directory: ${{ env.working-directory }} - - # Install the Infracost CLI, see https://github.com/infracost/actions/tree/master/setup - # for other inputs such as version, and pricing-api-endpoint (for self-hosted users). - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - # Generate Infracost JSON output, the following docs might be useful: - # Multi-project/workspaces: https://www.infracost.io/docs/features/config_file - # Combine Infracost JSON files: https://www.infracost.io/docs/features/cli_commands/#combined-output-formats - - name: Generate Infracost JSON - run: infracost breakdown --path plan.json --format json --out-file /tmp/infracost.json - working-directory: ${{ env.working-directory }} - # Env vars can be set using the usual GitHub Actions syntax - # See the list of supported Infracost env vars here: https://www.infracost.io/docs/integrations/environment_variables/ - # env: - # MY_ENV: ${{ secrets.MY_ENV }} - - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update - ``` + TF_ROOT: examples/terraform-project/code + # If you're using Terraform Cloud/Enterprise and have variables stored on there + # you can specify the following to automatically retrieve the variables: + # INFRACOST_TERRAFORM_CLOUD_TOKEN: ${{ secrets.TFC_TOKEN }} + # INFRACOST_TERRAFORM_CLOUD_HOST: app.terraform.io # Change this if you're using Terraform Enterprise + + steps: + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Checkout the base branch of the pull request (e.g. main/master). + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' + + # Generate Infracost JSON file as the baseline. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + + # Checkout the current PR branch so we can create a diff. + - name: Checkout PR branch + uses: actions/checkout@v2 + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update + ``` 5. šŸŽ‰ That's it! Send a new pull request to change something in Terraform that costs money. You should see a pull request comment that gets updated, e.g. the šŸ“‰ and šŸ“ˆ emojis will update as changes are pushed! @@ -98,18 +85,21 @@ The following steps assume a simple Terraform directory is being used, we recomm 6. Follow [the docs](https://www.infracost.io/usage-file) if you'd also like to show cost for of usage-based resources such as AWS Lambda or S3. The usage for these resources are fetched from CloudWatch/cloud APIs and used to calculate an estimate. +### Troubleshooting + +#### Permissions issue + +If you receive an error when running the `infracost comment` command in your pipeline, it's probably related to `${{ github.token }}`. This is the default GitHub token available to actions and is used to post comments. The default [token permissions](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#permissions) work fine but `pull-requests: write` is required if you need to customize these. If you are using SAML single sign-on, you must first [authorize the token](https://docs.github.com/en/enterprise-cloud@latest/authentication/authenticating-with-saml-single-sign-on/authorizing-a-personal-access-token-for-use-with-saml-single-sign-on). + ## Examples -The [examples](examples) directory demonstrates how these actions can be used in different workflows, including: - - [Terraform directory](examples/terraform-directory): a Terraform directory containing HCL code - - [Terraform plan JSON](examples/terraform-plan-json): a Terraform plan JSON file - - [Terragrunt](examples/terragrunt): a Terragrunt project - - [Terraform Cloud/Enterprise](examples/terraform-cloud-enterprise): a Terraform project using Terraform Cloud/Enterprise - - [Multi-project using config file](examples/multi-project/README.md#using-an-infracost-config-file): multiple Terraform projects using the Infracost [config file](https://www.infracost.io/docs/multi_project/config_file) - - [Multi-project using build matrix](examples/multi-project/README.md#using-github-actions-build-matrix): multiple Terraform projects using GitHub Actions build matrix - - [Multi-Terraform workspace](examples/multi-terraform-workspace): multiple Terraform workspaces using the Infracost [config file](https://www.infracost.io/docs/multi_project/config_file) +The [examples](examples) directory demonstrates how these actions can be used for different projects. They all work by using the default Infracost CLI option that parses HCL, thus a Terraform plan JSON is not needed. + - [Terraform/Terragrunt projects (single or multi)](examples/terraform-project): a repository containing one or more (e.g. mono repos) Terraform or Terragrunt projects + - [Multi-projects using a config file](examples/multi-project-config-file): repository containing multiple Terraform projects that need different inputs, i.e. variable files or Terraform workspaces - [Private Terraform module](examples/private-terraform-module): a Terraform project using a private Terraform module - - [Slack](examples/slack): [send cost estimates to Slack](examples/slack) + - [Slack](examples/slack): send cost estimates to Slack + +For advanced use cases where the estimate needs to be generated from Terraform plan JSON files, see the [plan JSON examples here](examples#plan-json-examples). ### Cost policies @@ -119,14 +109,6 @@ Infracost policies enable centralized teams, who are often helping others with c If you use HashiCorp Sentinel, follow [our example](examples/sentinel) to output the policy pass/fail results into CI/CD logs. -## Actions - -We recommend you use the above [quick start](#quick-start) guide and examples, which uses the [setup](setup) action. This downloads and installs the Infracost CLI in your GitHub Actions workflow. - -The following actions are **deprecated** and will be removed in the V2 of the GitHub action: -- [comment](comment): adds comments to pull requests; you should use the [`infracost comment`](https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests) command directly. -- [get-comment](get-comment): reads a comment from a pull request. This action was not widely used and is deprecated. - ## Contributing Issues and pull requests are welcome! For development details, see the [contributing](CONTRIBUTING.md) guide. For major changes, including interface changes, please open an issue first to discuss what you would like to change. [Join our community Slack channel](https://www.infracost.io/community-chat), we are a friendly bunch and happy to help you get started :) diff --git a/action.yml b/action.yml index 6fe2700..e94f763 100644 --- a/action.yml +++ b/action.yml @@ -11,7 +11,7 @@ inputs: description: Your Infracost API key. It can be retrieved by running `infracost configure get api_key`. We recommend using your same API key in all environments. If you don't have one, download Infracost (https://www.infracost.io/docs/#quick-start) and run `infracost register` to get a free API key. required: true path: - description: The path that will be passed to `infracost breakdown`. This may be a path to a Terraform plan JSON or a Terraform project. Project support requires Terraform to have been installed with hashicorp/setup-terraform@v1. + description: The path that will be passed to `infracost breakdown`. This may be a path to a Terraform plan JSON or a Terraform project. required: true behavior: description: The behavior to use when posting cost estimate comments. Must be one of 'update' | 'delete-and-new' | 'hide-and-new' | 'new'. @@ -20,28 +20,48 @@ inputs: runs: using: "composite" steps: + # Checkout the branch you want Infracost to compare costs against, most commonly the target branch. + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' + # Install the Infracost CLI, see https://github.com/infracost/actions/tree/master/setup # for other inputs such as version, and pricing-api-endpoint (for self-hosted users). - name: Setup Infracost - uses: infracost/actions/setup@v1 + uses: infracost/actions/setup@v2 with: - api-key: ${{ inputs.api-key }} + api-key: ${{ inputs.api_key }} + + # Generate an Infracost output JSON from the comparison branch, so that Infracost can compare the cost difference. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=examples/terraform-directory/code \ + --format=json \ + --out-file=/tmp/infracost-base.json - # Generate Infracost JSON output, the following docs might be useful: - # Multi-project/workspaces: https://www.infracost.io/docs/multi_project/config_file - # Combine Infracost JSON files: https://www.infracost.io/docs/features/config_file/ - - name: Generate Infracost JSON - shell: bash - run: infracost breakdown --path ${{ inputs.path }} --format json --out-file /tmp/infracost.json - # Env vars can be set using the usual GitHub Actions syntax - # env: - # MY_ENV: ${{ secrets.MY_ENV }} - # See https://github.com/infracost/actions/tree/master/comment - # for other inputs such as target-type. + # Checkout the PR branch with your infrastructure changes. + - uses: actions/checkout@v2 + + - name: Run Infracost + run: | + infracost breakdown --path=examples/terraform-directory/code \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + - name: Post Infracost comment - uses: infracost/actions/comment@v1 - with: - path: /tmp/infracost.json - # Choose the commenting behavior, 'update' is a good default: - behavior: ${{ inputs.behavior }} + run: | + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=${{inputs.behavior}} diff --git a/comment/README.md b/comment/README.md deleted file mode 100644 index 9a2471f..0000000 --- a/comment/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Infracost Comment Action - -This GitHub Action takes `infracost breakdown` JSON output and posts it as a GitHub comment. It assumes the `infracost` binary has already been installed using the [setup](../setup) action. It uses the default GitHub token, which is available for actions, to post comments (you can override it with inputs). This action uses the [compost](https://github.com/infracost/compost) CLI tool internally. - -## Usage - -The action can be used as follows. See the [top-level readme](https://github.com/infracost/actions) for examples of how this actions can be combined with the setup action to run Infracost. - -```yml -steps: - - name: Infracost comment - uses: infracost/actions/comment@v1 - with: - path: /tmp/infracost.json -``` - -## Inputs - -The action supports the following inputs: - -- `path`: Required. The path to the `infracost breakdown` JSON that will be passed to `infracost output`. For multiple paths, pass a glob pattern (e.g. "infracost_*.json", glob needs quotes) or a JSON array of paths. - -- `behavior`: Optional, defaults to `update`. The behavior to use when posting cost estimate comments. Must be one of the following: - - `update`: Create a single comment and update it on changes. This is the "quietest" option. The GitHub comments UI shows what/when changed when the comment is updated. Pull request followers will only be notified on the comment create (not updates), and the comment will stay at the same location in the comment history. - - `delete-and-new`: Delete previous cost estimate comments and create a new one. Pull request followers will be notified on each comment. - - `hide-and-new`: Minimize previous cost estimate comments and create a new one. Pull request followers will be notified on each comment. - - `new`: Create a new cost estimate comment. Pull request followers will be notified on each comment. - -- `target-type`: Optional. Which objects should be commented on, either `pull-request` or `commit`. - -- `tag`: Optional. Customize the comment tag. This is added to the comment as a markdown comment (hidden) to detect the previously posted comments. This is useful if you have multiple workflows that post comments to the same pull request or commit. - -- `github-token`: Optional, default to `${{ github.token }}`. This is the default GitHub token available to actions and is used to post comments. The default [token permissions](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#permissions) work fine; `pull-requests: write` is required if you need to customize these. If you are using SAML single sign-on, you must first [authorize the token](https://docs.github.com/en/enterprise-cloud@latest/authentication/authenticating-with-saml-single-sign-on/authorizing-a-personal-access-token-for-use-with-saml-single-sign-on). - - ```yml - steps: - - name: Infracost comment - uses: infracost/actions/comment@v1 - with: - ... - permissions: - pull-requests: write - ``` - -## Outputs - -This action sets the following output: - -- `body`: The body of comment that was posted. - diff --git a/comment/action.yml b/comment/action.yml deleted file mode 100644 index d245c67..0000000 --- a/comment/action.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: "Infracost Comment" -description: Posts a comment to GitHub pull request showing cloud cost estimates for Terraform. Requires infracost/actions/setup to have been run. -inputs: - path: - description: The path to the `infracost breakdown` JSON that will be passed to `infracost output`. For multiple paths, pass a glob pattern (e.g. "infracost_*.json", glob needs quotes) or a JSON array of paths. - required: true - behavior: - description: The behavior to use when posting cost estimate comments. Must be one of 'update' | 'delete-and-new' | 'hide-and-new' | 'new'. - required: false - default: update - target-type: - description: Which objects should be commented on, either `pull-request` or `commit`. - required: false - tag: - description: 'Customize the comment tag. This is added to the comment as a markdown comment (hidden) to detect the previously posted comments. This is useful if you have multiple workflows that post comments to the same pull request or commit.' - required: false - github-token: - description: 'Default to {{ github.token }}. This is the default GitHub token available to actions and is used to post comments. The default token permissions (https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#permissions) work fine; `pull-requests: write` is required if you need to customize these.' - default: '${{ github.token }}' - required: false -runs: - using: "composite" - steps: - - name: Post a Infracost comment to a GitHub pull request - if: ${{ (inputs.target-type != 'commit') && (github.event.pull_request.number != '') }} - shell: bash - run: | - infracost comment github --path ${{inputs.path}} \ - --repo $GITHUB_REPOSITORY \ - --tag "${{inputs.tag}}" \ - --github-token ${{inputs.github-token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior ${{inputs.behavior}} - - - name: Post a Infracost comment to a commit SHA - if: ${{ (inputs.target-type == 'commit') }} - shell: bash - run: | - infracost comment github --path ${{inputs.path}} \ - --repo $GITHUB_REPOSITORY \ - --tag "${{inputs.tag}}" \ - --github-token ${{inputs.github-token}} \ - --commit $GITHUB_SHA \ - --behavior ${{inputs.behavior}} diff --git a/examples/README.md b/examples/README.md index 1bc62e9..13e7ee7 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,18 +1,28 @@ # Examples -All examples post a single comment on pull requests, which gets updated as more changes are pushed. The examples show how to run the actions with: - -- [Terraform directory](terraform-directory): a Terraform project containing HCL code -- [Terraform plan JSON](terraform-plan-json): a Terraform plan JSON file -- [Terragrunt](terragrunt): a Terragrunt project -- [Terraform Cloud/Enterprise](terraform-cloud-enterprise): a Terraform project using Terraform Cloud/Enterprise -- [Multi-project using config file](multi-project/README.md#using-an-infracost-config-file): multiple Terraform projects using the Infracost config file -- [Multi-project using build matrix](multi-project/README.md#using-github-actions-build-matrix): multiple Terraform projects using GitHub Actions build matrix -- [Multi-Terraform workspace](multi-terraform-workspace): multiple Terraform workspaces using the Infracost config file -- [Slack](slack): send cost estimates to Slack - -Cost policy examples: +All examples post a single comment on merge requests, which gets updated as more changes are pushed. + +## Terraform project examples + +These examples work by using the default Infracost CLI option that parses HCL, thus a Terraform Plan JSON is not needed. + + - [Terraform/Terragrunt projects (single or multi)](terraform-project): a repository containing one or more (e.g. mono repos) Terraform or Terragrunt projects + - [Multi-projects using a config file](multi-project-config-file): repository containing multiple Terraform projects that need different inputs, i.e. variable files or Terraform workspaces + - [Private Terraform module](private-terraform-module): a Terraform project using a private Terraform module + - [Slack](slack): send cost estimates to Slack + +## Plan JSON examples + +These examples are for advanced use cases where the estimate is generated from Terraform plan JSON files. + +- [Terragrunt](plan-json/terragrunt): Generate plan JSONs for a Terragrunt project +- [Terraform Cloud/Enterprise](plan-json/terraform-cloud-enterprise): Generate a plan JSON for a Terraform project using Terraform Cloud/Enterprise +- [Multi-project using parallel matrix jobs](plan-json/multi-project-matrix): Generate multiple plan JSONs for different Terraform projects using parallel matrix jobs +- [Multi-Terraform workspaces using parallel matrix jobs](plan-json/multi-workspace-matrix): Generate multiple plan JSONs for different Terraform workspaces using parallel matrix jobs + +## Cost policy examples + - [OPA](https://www.infracost.io/docs/features/cost_policies/): check Infracost cost estimates against policies using Open Policy Agent -- [Sentinel](sentinel): check Infracost cost estimates against policies using Hashicorp's Sentinel +- [Sentinel](sentinel): check Infracost cost estimates against policies using Hashicorp's Sentinel See the [contributing](../CONTRIBUTING.md) guide if you'd like to add an example. diff --git a/examples/multi-project-config-file/README.md b/examples/multi-project-config-file/README.md new file mode 100644 index 0000000..1876bbd --- /dev/null +++ b/examples/multi-project-config-file/README.md @@ -0,0 +1,66 @@ +# Multi-project using config file + +This example shows how to run Infracost in GitHub Actions with multiple Terraform projects using a config file. The [config file]((https://www.infracost.io/docs/config_file/)) can be used to specify variable files or the Terraform workspaces for different projects. + +[//]: <> (BEGIN EXAMPLE) +```yml +name: Multi-project config file +on: [pull_request] + +jobs: + multi-project-config-file: + name: Multi-project config file + runs-on: ubuntu-latest + env: + TF_ROOT: examples/multi-project-config-file/code + + steps: + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Checkout the branch you want Infracost to compare costs against.This example is using the + # target PR branch. + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' + + # Generate Infracost JSON file as the baseline. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --config-file=${TF_ROOT}/infracost.yml \ + --format=json \ + --out-file=/tmp/infracost-base.json + + # Checkout the current PR branch so we can create a diff. + - name: Checkout PR branch + uses: actions/checkout@v2 + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --config-file=${TF_ROOT}/infracost.yml \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update +``` +[//]: <> (END EXAMPLE) diff --git a/examples/multi-project-config-file/code/.gitignore b/examples/multi-project-config-file/code/.gitignore new file mode 100644 index 0000000..be4aaeb --- /dev/null +++ b/examples/multi-project-config-file/code/.gitignore @@ -0,0 +1,2 @@ +plan.cache +plan.json diff --git a/examples/multi-project-config-file/code/dev.tfvars b/examples/multi-project-config-file/code/dev.tfvars new file mode 100644 index 0000000..2d019c8 --- /dev/null +++ b/examples/multi-project-config-file/code/dev.tfvars @@ -0,0 +1 @@ +instance_type = "t2.micro" diff --git a/examples/multi-project-config-file/code/dev/main.tf b/examples/multi-project-config-file/code/dev/main.tf new file mode 100644 index 0000000..4f7605d --- /dev/null +++ b/examples/multi-project-config-file/code/dev/main.tf @@ -0,0 +1,22 @@ +provider "aws" { + region = "us-east-1" + skip_credentials_validation = true + skip_requesting_account_id = true + access_key = "mock_access_key" + secret_key = "mock_secret_key" +} + +variable "instance_type" { + type = "string" +} + +module "base" { + source = "../modules/example" + + instance_type = var.instance_type + root_block_device_volume_size = 50 + block_device_volume_size = 100 + block_device_iops = 400 + + hello_world_function_memory_size = 512 +} diff --git a/examples/multi-project-config-file/code/infracost.yml b/examples/multi-project-config-file/code/infracost.yml new file mode 100644 index 0000000..45b8b5b --- /dev/null +++ b/examples/multi-project-config-file/code/infracost.yml @@ -0,0 +1,9 @@ +version: 0.1 + +projects: + - path: examples/multi-project-config-file/code/dev + terraform_var_files: + - "../dev.tfvars" + - path: examples/multi-project-config-file/code/prod + terraform_var_files: + - "../prod.tfvars" diff --git a/examples/multi-project/code/modules/example/main.tf b/examples/multi-project-config-file/code/modules/example/main.tf similarity index 100% rename from examples/multi-project/code/modules/example/main.tf rename to examples/multi-project-config-file/code/modules/example/main.tf diff --git a/examples/multi-project-config-file/code/prod.tfvars b/examples/multi-project-config-file/code/prod.tfvars new file mode 100644 index 0000000..81f9b1c --- /dev/null +++ b/examples/multi-project-config-file/code/prod.tfvars @@ -0,0 +1 @@ +instance_type = "m5.4xlarge" diff --git a/examples/multi-project-config-file/code/prod/main.tf b/examples/multi-project-config-file/code/prod/main.tf new file mode 100644 index 0000000..4d4b764 --- /dev/null +++ b/examples/multi-project-config-file/code/prod/main.tf @@ -0,0 +1,22 @@ +provider "aws" { + region = "us-east-1" + skip_credentials_validation = true + skip_requesting_account_id = true + access_key = "mock_access_key" + secret_key = "mock_secret_key" +} + +variable "instance_type" { + type = "string" +} + +module "base" { + source = "../modules/example" + + instance_type = var.instance_type + root_block_device_volume_size = 100 + block_device_volume_size = 1000 + block_device_iops = 800 + + hello_world_function_memory_size = 1024 +} diff --git a/examples/multi-project/README.md b/examples/multi-project/README.md deleted file mode 100644 index d90ccde..0000000 --- a/examples/multi-project/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# Multi-project - -These examples show how to run Infracost actions against a multi-project setup using either an [Infracost config file](https://www.infracost.io/docs/multi_project/config_file) or a GitHub Actions build matrix. - -## Using an Infracost config file - -This example shows how to run Infracost actions with multiple Terraform projects using an [Infracost config file](https://www.infracost.io/docs/multi_project/config_file). - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Multi-project config file -on: [pull_request] - -jobs: - multi-project-config-file: - name: Multi-project config file - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --config-file=examples/multi-project/code/infracost.yml --format=json --out-file=/tmp/infracost.json - env: - # IMPORTANT: add any required secrets to setup cloud credentials so Terraform can run - DEV_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_DEV_AWS_ACCESS_KEY_ID }} - DEV_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY }} - PROD_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_PROD_AWS_ACCESS_KEY_ID }} - PROD_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY }} - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) - -## Using GitHub Actions build matrix - -This example shows how to run Infracost actions with multiple Terraform projects using a GitHub Actions build matrix. The first job uses a build matrix to generate multiple Infracost output JSON files and upload them as artifacts. The second job downloads these JSON files and posts a combined comment to the PR using `infracost comment` glob support. - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Multi-project matrix -on: [pull_request] - -jobs: - multi-project-matrix: - name: Multi-project matrix - runs-on: ubuntu-latest - - strategy: - matrix: - include: - # IMPORTANT: add any required secrets to setup cloud credentials so Terraform can run - - dir: dev - # GitHub actions doesn't support secrets in matrix values, so we use the name of the secret instead - aws_access_key_id_secret: EXAMPLE_DEV_AWS_ACCESS_KEY_ID - aws_secret_access_key_secret: EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY - - dir: prod - aws_access_key_id_secret: EXAMPLE_PROD_AWS_ACCESS_KEY_ID - aws_secret_access_key_secret: EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY - - steps: - - uses: actions/checkout@v2 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --path=examples/multi-project/code/${{ matrix.dir }} --format=json --out-file=/tmp/infracost_${{ matrix.dir }}.json - env: - AWS_ACCESS_KEY_ID: ${{ secrets[matrix.aws_access_key_id_secret] }} - AWS_SECRET_ACCESS_KEY: ${{ secrets[matrix.aws_secret_access_key_secret] }} - - - name: Upload Infracost breakdown - uses: actions/upload-artifact@v2 - with: - name: infracost_jsons - path: /tmp/infracost_${{ matrix.dir }}.json - - multi-project-matrix-merge: - name: Multi-project matrix merge - runs-on: ubuntu-latest - needs: [multi-project-matrix] - - steps: - - uses: actions/checkout@v2 - - - name: Download all Infracost breakdown files - uses: actions/download-artifact@v2 - with: - path: /tmp - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path "/tmp/infracost_jsons/*.json" \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) diff --git a/examples/multi-project/code/infracost.yml b/examples/multi-project/code/infracost.yml deleted file mode 100644 index 86f929b..0000000 --- a/examples/multi-project/code/infracost.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 0.1 - -projects: - - path: examples/multi-project/code/dev - env: - AWS_ACCESS_KEY_ID: ${DEV_AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${DEV_AWS_SECRET_ACCESS_KEY} - - path: examples/multi-project/code/prod - env: - AWS_ACCESS_KEY_ID: ${PROD_AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${PROD_AWS_SECRET_ACCESS_KEY} diff --git a/examples/multi-terraform-workspace/README.md b/examples/multi-terraform-workspace/README.md deleted file mode 100644 index 9ac7d29..0000000 --- a/examples/multi-terraform-workspace/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Multi-Terraform workspace - -This example shows how to run Infracost actions against a Terraform project that uses multiple workspaces using an [Infracost config file](https://www.infracost.io/docs/multi_project/config_file). - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Multi-terraform workspace config file -on: [pull_request] - -jobs: - multi-terraform-workspace-config-file: - name: Multi-Terraform workspace config file - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --config-file=examples/multi-terraform-workspace/code/infracost.yml --format=json --out-file=/tmp/infracost.json - env: - # IMPORTANT: add any required secrets to setup cloud credentials so Terraform can run - DEV_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_DEV_AWS_ACCESS_KEY_ID }} - DEV_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY }} - PROD_AWS_ACCESS_KEY_ID: ${{ secrets.EXAMPLE_PROD_AWS_ACCESS_KEY_ID }} - PROD_AWS_SECRET_ACCESS_KEY: ${{ secrets.EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY }} - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) diff --git a/examples/multi-terraform-workspace/code/dev.tfvars b/examples/multi-terraform-workspace/code/dev.tfvars deleted file mode 100644 index 0ed9be4..0000000 --- a/examples/multi-terraform-workspace/code/dev.tfvars +++ /dev/null @@ -1,6 +0,0 @@ -instance_type = "t2.micro" -root_block_device_volume_size = 50 -block_device_volume_size = 100 -block_device_iops = 400 - -hello_world_function_memory_size = 512 diff --git a/examples/multi-terraform-workspace/code/infracost.yml b/examples/multi-terraform-workspace/code/infracost.yml deleted file mode 100644 index 95fba74..0000000 --- a/examples/multi-terraform-workspace/code/infracost.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: 0.1 - -projects: - - path: examples/multi-terraform-workspace/code - terraform_workspace: dev - terraform_plan_flags: "-var-file=dev.tfvars" - env: - AWS_ACCESS_KEY_ID: ${DEV_AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${DEV_AWS_SECRET_ACCESS_KEY} - - - path: examples/multi-terraform-workspace/code - terraform_workspace: prod - terraform_plan_flags: "-var-file=prod.tfvars" - env: - AWS_ACCESS_KEY_ID: ${PROD_AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${PROD_AWS_SECRET_ACCESS_KEY} diff --git a/examples/plan-json/multi-project-matrix/README.md b/examples/plan-json/multi-project-matrix/README.md new file mode 100644 index 0000000..b22f724 --- /dev/null +++ b/examples/plan-json/multi-project-matrix/README.md @@ -0,0 +1,103 @@ +# Multi-project with matrix jobs + +This example shows how to run Infracost in GitHub Actions with multiple Terraform projects using parallel matrix jobs. The first job uses a matrix to generate the plan JSONs and the second job uses another matrix to generate multiple Infracost output JSON files. The last job uses these JSON files, and passes them to the comment script which combines them into a single comment. + + +[//]: <> (BEGIN EXAMPLE) +```yml +name: Multi-project matrix +on: [pull_request] + +jobs: + multi-project-matrix: + name: Multi-project matrix + runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code + + strategy: + matrix: + include: + # IMPORTANT: add any required secrets to setup cloud credentials so Terraform can run + - project: dev + # GitHub actions doesn't support secrets in matrix values, so we use the name of the secret instead + aws_access_key_id_secret: EXAMPLE_DEV_AWS_ACCESS_KEY_ID + aws_secret_access_key_secret: EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY + - project: prod + aws_access_key_id_secret: EXAMPLE_PROD_AWS_ACCESS_KEY_ID + aws_secret_access_key_secret: EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY + + steps: + - name: Checkout PR branch + uses: actions/checkout@v2 + + - name: Install Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON + + - name: Terraform init + run: terraform init + working-directory: ${{ env.TF_ROOT }}/${{ matrix.project }} + + - name: Generate plan JSON + run: | + terraform plan -out=plan.cache + terraform show -json plan.cache > plan.json + working-directory: ${{ env.TF_ROOT }}/${{ matrix.project }} + + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: infracost diff --path=${TF_ROOT}/${{ matrix.project }}/plan.json --format=json --out-file=/tmp/infracost_${{ matrix.project }}.json + env: + AWS_ACCESS_KEY_ID: ${{ secrets[matrix.aws_access_key_id_secret] }} + AWS_SECRET_ACCESS_KEY: ${{ secrets[matrix.aws_secret_access_key_secret] }} + + - name: Upload Infracost breakdown + uses: actions/upload-artifact@v2 + with: + name: infracost_project_jsons + path: /tmp/infracost_${{ matrix.project }}.json + + multi-project-matrix-merge: + name: Multi-project matrix merge + runs-on: ubuntu-latest + needs: [multi-project-matrix] + + steps: + - uses: actions/checkout@v2 + + - name: Download all Infracost breakdown files + uses: actions/download-artifact@v2 + with: + name: infracost_project_jsons + path: /tmp + + - name: Setup Infracost + uses: infracost/actions/setup@v2 + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path="/tmp/infracost_*.json" \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update +``` +[//]: <> (END EXAMPLE) diff --git a/examples/plan-json/multi-workspace-matrix/README.md b/examples/plan-json/multi-workspace-matrix/README.md new file mode 100644 index 0000000..c34d2d2 --- /dev/null +++ b/examples/plan-json/multi-workspace-matrix/README.md @@ -0,0 +1,104 @@ +# Multi-Terraform workspace with matrix jobs + +This example shows how to run Infracost in GitHub Actions against a Terraform project that uses multiple workspaces using parallel matrix jobs. The first job uses a matrix to generate the plan JSONs and the second job uses another matrix to generate multiple Infracost output JSON files. `infracost comment` command in the last job combines the Infracost JSON files and posts a single comment. + +[//]: <> (BEGIN EXAMPLE) +```yml +name: Multi-workspace matrix +on: [pull_request] + +jobs: + multi-workspace-matrix: + name: Multi-workspace matrix + runs-on: ubuntu-latest + env: + TF_ROOT: examples/plan-json/multi-workspace-matrix/code + + strategy: + matrix: + include: + # IMPORTANT: add any required secrets to setup cloud credentials so Terraform can run + - tf_workspace: dev + # GitHub actions doesn't support secrets in matrix values, so we use the name of the secret instead + aws_access_key_id_secret: EXAMPLE_DEV_AWS_ACCESS_KEY_ID + aws_secret_access_key_secret: EXAMPLE_DEV_AWS_SECRET_ACCESS_KEY + - tf_workspace: prod + aws_access_key_id_secret: EXAMPLE_PROD_AWS_ACCESS_KEY_ID + aws_secret_access_key_secret: EXAMPLE_PROD_AWS_SECRET_ACCESS_KEY + + steps: + - name: Checkout PR branch + uses: actions/checkout@v2 + + - name: Install Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON + + - name: Terraform init + run: terraform init + working-directory: ${{ env.TF_ROOT }} + + - name: Generate plan JSON + run: | + terraform plan -out=${{ matrix.tf_workspace }}-plan.cache -var-file=${{ matrix.tf_workspace }}.tfvars + terraform show -json ${{ matrix.tf_workspace }}-plan.cache > ${{ matrix.tf_workspace }}-plan.json + env: + TF_WORKSPACE: ${{ matrix.tf_workspace }} + working-directory: ${{ env.TF_ROOT }} + + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: infracost diff --path=${TF_ROOT}/${{ matrix.tf_workspace }}-plan.json --format=json --out-file=/tmp/infracost_${{ matrix.tf_workspace }}.json + env: + AWS_ACCESS_KEY_ID: ${{ secrets[matrix.aws_access_key_id_secret] }} + AWS_SECRET_ACCESS_KEY: ${{ secrets[matrix.aws_secret_access_key_secret] }} + + - name: Upload Infracost breakdown + uses: actions/upload-artifact@v2 + with: + name: infracost_workspace_jsons + path: /tmp/infracost_${{ matrix.tf_workspace }}.json + + multi-workspace-matrix-merge: + name: Multi-workspace matrix merge + runs-on: ubuntu-latest + needs: [multi-workspace-matrix] + + steps: + - uses: actions/checkout@v2 + + - name: Download all Infracost breakdown files + uses: actions/download-artifact@v2 + with: + name: infracost_workspace_jsons + path: /tmp + + - name: Setup Infracost + uses: infracost/actions/setup@v2 + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path="/tmp/infracost_*.json" \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update +``` +[//]: <> (END EXAMPLE) diff --git a/examples/plan-json/multi-workspace-matrix/code/.gitignore b/examples/plan-json/multi-workspace-matrix/code/.gitignore new file mode 100644 index 0000000..be4aaeb --- /dev/null +++ b/examples/plan-json/multi-workspace-matrix/code/.gitignore @@ -0,0 +1,2 @@ +plan.cache +plan.json diff --git a/examples/plan-json/multi-workspace-matrix/code/dev.tfvars b/examples/plan-json/multi-workspace-matrix/code/dev.tfvars new file mode 100644 index 0000000..2d019c8 --- /dev/null +++ b/examples/plan-json/multi-workspace-matrix/code/dev.tfvars @@ -0,0 +1 @@ +instance_type = "t2.micro" diff --git a/examples/multi-terraform-workspace/code/main.tf b/examples/plan-json/multi-workspace-matrix/code/main.tf similarity index 91% rename from examples/multi-terraform-workspace/code/main.tf rename to examples/plan-json/multi-workspace-matrix/code/main.tf index 639c0e1..def46d1 100644 --- a/examples/multi-terraform-workspace/code/main.tf +++ b/examples/plan-json/multi-workspace-matrix/code/main.tf @@ -22,6 +22,8 @@ provider "aws" { region = "us-east-1" skip_credentials_validation = true skip_requesting_account_id = true + access_key = "mock_access_key" + secret_key = "mock_secret_key" } resource "aws_instance" "web_app" { diff --git a/examples/multi-terraform-workspace/code/prod.tfvars b/examples/plan-json/multi-workspace-matrix/code/prod.tfvars similarity index 100% rename from examples/multi-terraform-workspace/code/prod.tfvars rename to examples/plan-json/multi-workspace-matrix/code/prod.tfvars diff --git a/examples/plan-json/terraform-cloud-enterprise/README.md b/examples/plan-json/terraform-cloud-enterprise/README.md new file mode 100644 index 0000000..710277d --- /dev/null +++ b/examples/plan-json/terraform-cloud-enterprise/README.md @@ -0,0 +1,83 @@ +# Terraform Cloud/Enterprise + +This example shows how to run Infracost on GitHub CI with Terraform Cloud and Terraform Enterprise. It assumes you have set a GitHub secret for the Terraform Cloud token (`TFC_TOKEN`), which is used to run a speculative plan and fetch the plan JSON from Terraform Cloud. + +[//]: <> (BEGIN EXAMPLE) +```yml +name: Terraform Cloud/Enterprise +on: [pull_request] + +jobs: + terraform-cloud-enterprise: + name: Terraform Cloud/Enterprise + runs-on: ubuntu-latest + env: + TF_ROOT: examples/plan-json/terraform-cloud-enterprise/code + TFC_HOST: app.terraform.io # Change this if you're using Terraform Enterprise + + steps: + - name: Checkout PR branch + uses: actions/checkout@v2 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + cli_config_credentials_token: ${{ secrets.TFC_TOKEN }} + cli_config_credentials_hostname: ${{ env.TFC_HOST }} + terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON + + # IMPORTANT: add any required steps here to setup cloud credentials so Terraform can run + - name: Terraform init + run: terraform init + working-directory: ${{ env.TF_ROOT }} + + # When using TFC remote execution, terraform doesn't allow us to save the plan output. + # So we have to save the plan logs so we can parse out the run ID and fetch the plan JSON + - name: Retrieve plan JSONs + run: | + echo "Running terraform plan" + terraform plan -no-color | tee /tmp/plan_logs.txt + + echo "Parsing the run URL and ID from the logs" + run_url=$(grep -A1 'To view this run' /tmp/plan_logs.txt | tail -n 1) + run_id=$(basename $run_url) + + echo "Getting the run plan response from https://$TFC_HOST/api/v2/runs/$run_id/plan" + run_plan_resp=$(wget -q -O - --header="Authorization: Bearer ${{ secrets.TFC_TOKEN }}" "https://$TFC_HOST/api/v2/runs/$run_id/plan") + echo "Extracting the plan JSON path" + plan_json_path=$(echo $run_plan_resp | sed 's/.*\"json-output\":\"\([^\"]*\)\".*/\1/') + + echo "Downloading the plan JSON from https://$TFC_HOST$plan_json_path" + wget -q -O plan.json --header="Authorization: Bearer ${{ secrets.TFC_TOKEN }}" "https://$TFC_HOST$plan_json_path" + working-directory: ${{ env.TF_ROOT }} + + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT}/plan.json \ + --format=json \ + --out-file=/tmp/infracost.json + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update +``` +[//]: <> (END EXAMPLE) diff --git a/examples/plan-json/terraform-cloud-enterprise/code/.gitignore b/examples/plan-json/terraform-cloud-enterprise/code/.gitignore new file mode 100644 index 0000000..be4aaeb --- /dev/null +++ b/examples/plan-json/terraform-cloud-enterprise/code/.gitignore @@ -0,0 +1,2 @@ +plan.cache +plan.json diff --git a/examples/terraform-cloud-enterprise/code/main.tf b/examples/plan-json/terraform-cloud-enterprise/code/main.tf similarity index 100% rename from examples/terraform-cloud-enterprise/code/main.tf rename to examples/plan-json/terraform-cloud-enterprise/code/main.tf diff --git a/examples/plan-json/terragrunt/README.md b/examples/plan-json/terragrunt/README.md new file mode 100644 index 0000000..a31f5b8 --- /dev/null +++ b/examples/plan-json/terragrunt/README.md @@ -0,0 +1,93 @@ +# Terragrunt + +This example shows how to run Infracost in GitHub Actions with Terragrunt. + +[//]: <> (BEGIN EXAMPLE) +```yml +name: Terragrunt project +on: [pull_request] + +jobs: + terragrunt-project: + name: Terragrunt project + runs-on: ubuntu-latest + env: + TF_ROOT: examples/plan-json/terragrunt/code + + steps: + - name: Checkout PR branch + uses: actions/checkout@v2 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON + + - name: Setup Terragrunt + uses: autero1/action-terragrunt@v1.1.0 + with: + terragrunt_version: 0.37.0 + + # Generate plan JSON files for all Terragrunt modules and + # add them to an Infracost config file + - name: Generate plan JSONs + run: | + terragrunt run-all --terragrunt-ignore-external-dependencies plan -out=plan.cache + + # Find the plan files + plans=($(find . -name plan.cache | tr '\n' ' ')) + + # Generate plan JSON files by running terragrunt show for each plan file + planjsons=() + for plan in "${plans[@]}"; do + # Find the Terraform working directory for running terragrunt show + # We want to take the dir of the plan file and strip off anything after the .terraform-cache dir + # to find the location of the Terraform working directory that contains the Terraform code + dir=$(dirname $plan) + dir=$(echo "$dir" | sed 's/\(.*\)\/\.terragrunt-cache\/.*/\1/') + + echo "Running terragrunt show for $(basename $plan) for $dir"; + terragrunt show -json $(basename $plan) --terragrunt-working-dir=$dir --terragrunt-no-auto-init > $dir/plan.json + planjsons=(${planjsons[@]} "$dir/plan.json") + done + + # Sort the plan JSONs so we get consistent project ordering in the config file + IFS=$'\n' planjsons=($(sort <<<"${planjsons[*]}")) + + # Generate Infracost config file + echo -e "version: 0.1\n\nprojects:\n" > infracost.yml + for planjson in "${planjsons[@]}"; do + echo -e " - path: ${TF_ROOT}/$planjson" >> infracost.yml + done + working-directory: ${{ env.TF_ROOT }} + + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --config-file=${TF_ROOT}/infracost.yml \ + --format=json \ + --out-file=/tmp/infracost.json + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update +``` +[//]: <> (END EXAMPLE) diff --git a/examples/plan-json/terragrunt/code/.gitignore b/examples/plan-json/terragrunt/code/.gitignore new file mode 100644 index 0000000..82f26e4 --- /dev/null +++ b/examples/plan-json/terragrunt/code/.gitignore @@ -0,0 +1 @@ +plan.json diff --git a/examples/terragrunt/code/dev/terragrunt.hcl b/examples/plan-json/terragrunt/code/dev/terragrunt.hcl similarity index 100% rename from examples/terragrunt/code/dev/terragrunt.hcl rename to examples/plan-json/terragrunt/code/dev/terragrunt.hcl diff --git a/examples/plan-json/terragrunt/code/infracost.yml b/examples/plan-json/terragrunt/code/infracost.yml new file mode 100644 index 0000000..f22c908 --- /dev/null +++ b/examples/plan-json/terragrunt/code/infracost.yml @@ -0,0 +1,6 @@ +version: 0.1 + +projects: + + - path: examples/plan-json/terragrunt/code/./dev/plan.json + - path: examples/plan-json/terragrunt/code/./prod/plan.json diff --git a/examples/terragrunt/code/modules/example/main.tf b/examples/plan-json/terragrunt/code/modules/example/main.tf similarity index 100% rename from examples/terragrunt/code/modules/example/main.tf rename to examples/plan-json/terragrunt/code/modules/example/main.tf diff --git a/examples/terragrunt/code/prod/terragrunt.hcl b/examples/plan-json/terragrunt/code/prod/terragrunt.hcl similarity index 100% rename from examples/terragrunt/code/prod/terragrunt.hcl rename to examples/plan-json/terragrunt/code/prod/terragrunt.hcl diff --git a/examples/terragrunt/code/terragrunt.hcl b/examples/plan-json/terragrunt/code/terragrunt.hcl similarity index 100% rename from examples/terragrunt/code/terragrunt.hcl rename to examples/plan-json/terragrunt/code/terragrunt.hcl diff --git a/examples/private-terraform-module/README.md b/examples/private-terraform-module/README.md index fe83f54..b3412c4 100644 --- a/examples/private-terraform-module/README.md +++ b/examples/private-terraform-module/README.md @@ -1,55 +1,73 @@ # Private Terraform module -This example shows how to run Infracost actions with a Terraform project that uses a private Terraform module. This requires a secret to be added to your GitHub repository called `GIT_SSH_KEY` containing a private key so that Terraform can access the private repository. +This example shows how to run Infracost in GitHub Actions with a Terraform project that uses a private Terraform module. This requires a secret to be added to your GitHub repository called `GIT_SSH_KEY` containing a private key so that Infracost can access the private repository. [//]: <> (BEGIN EXAMPLE) ```yml name: Private Terraform module on: [pull_request] + jobs: private-terraform-module: name: Private Terraform module runs-on: ubuntu-latest + env: + TF_ROOT: examples/private-terraform-module/code steps: - - uses: actions/checkout@v2 - - - name: Install terraform - uses: hashicorp/setup-terraform@v1 + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON + api-key: ${{ secrets.INFRACOST_API_KEY }} - # IMPORTANT: add any required steps here to setup cloud credentials so Terraform can run + # Checkout the base branch of the pull request (e.g. main/master). + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' - # Add your git SSH key so Terraform can checkout the private modules + # Add your git SSH key so Infracost can checkout the private modules - name: add GIT_SSH_KEY run: | - mkdir -p .ssh - echo "${{ secrets.GIT_SSH_KEY }}" > .ssh/git_ssh_key - chmod 400 .ssh/git_ssh_key - echo "GIT_SSH_COMMAND=ssh -i $(pwd)/.ssh/git_ssh_key -o 'StrictHostKeyChecking=no'" >> $GITHUB_ENV + mkdir -p ~/.ssh + echo "${{ secrets.GIT_SSH_KEY }}" > ~/.ssh/git_ssh_key + chmod 400 ~/.ssh/git_ssh_key + echo "GIT_SSH_COMMAND=ssh -i ~/.ssh/git_ssh_key -o 'StrictHostKeyChecking=no'" >> $GITHUB_ENV - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} + # Generate Infracost JSON file as the baseline. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json - - name: Run Infracost - run: infracost breakdown --path=examples/private-terraform-module/code --format=json --out-file=/tmp/infracost.json + # Checkout the current PR branch so we can create a diff. + - name: Checkout PR branch + uses: actions/checkout@v2 + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - name: Post Infracost comment run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update ``` [//]: <> (END EXAMPLE) diff --git a/examples/private-terraform-module/code/.gitignore b/examples/private-terraform-module/code/.gitignore new file mode 100644 index 0000000..be4aaeb --- /dev/null +++ b/examples/private-terraform-module/code/.gitignore @@ -0,0 +1,2 @@ +plan.cache +plan.json diff --git a/examples/sentinel/README.md b/examples/sentinel/README.md index 538ea5b..f2a8b23 100644 --- a/examples/sentinel/README.md +++ b/examples/sentinel/README.md @@ -66,12 +66,16 @@ jobs: sentinel: name: Sentinel runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code steps: - uses: actions/checkout@v2 - name: Setup Infracost - uses: infracost/actions/setup@v1 + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd with: api-key: ${{ secrets.INFRACOST_API_KEY }} @@ -82,8 +86,30 @@ jobs: unzip -d /tmp/sentinel /tmp/sentinel/sentinel.zip echo "/tmp/sentinel" >> $GITHUB_PATH - - name: Run Infracost - run: infracost breakdown --path=examples/sentinel/code/plan.json --format=json --out-file=/tmp/infracost.json + # Checkout the base branch of the pull request (e.g. main/master). + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' + + # Generate Infracost JSON file as the baseline. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + + # Checkout the current PR branch so we can create a diff. + - name: Checkout PR branch + uses: actions/checkout@v2 + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json - name: Run Sentinel run: sentinel apply -global breakdown="$(cat /tmp/infracost.json)" examples/sentinel/policy/policy.policy | tee /tmp/sentinel.out diff --git a/examples/sentinel/code/plan.json b/examples/sentinel/code/plan.json deleted file mode 100644 index 5528dd9..0000000 --- a/examples/sentinel/code/plan.json +++ /dev/null @@ -1,400 +0,0 @@ -{ - "format_version": "0.2", - "terraform_version": "1.0.2", - "planned_values": { - "root_module": { - "resources": [ - { - "address": "aws_instance.web_app", - "mode": "managed", - "type": "aws_instance", - "name": "web_app", - "provider_name": "registry.terraform.io/hashicorp/aws", - "schema_version": 1, - "values": { - "ami": "ami-674cbc1e", - "credit_specification": [], - "disable_api_termination": null, - "ebs_block_device": [ - { - "delete_on_termination": true, - "device_name": "my_data", - "iops": 800, - "tags": null, - "volume_size": 1000, - "volume_type": "io1" - } - ], - "ebs_optimized": null, - "get_password_data": false, - "hibernation": null, - "iam_instance_profile": null, - "instance_type": "m5.4xlarge", - "monitoring": null, - "root_block_device": [ - { - "delete_on_termination": true, - "tags": null, - "volume_size": 50 - } - ], - "source_dest_check": true, - "tags": null, - "timeouts": null, - "user_data": null, - "user_data_base64": null, - "volume_tags": null - }, - "sensitive_values": { - "capacity_reservation_specification": [], - "credit_specification": [], - "ebs_block_device": [ - {} - ], - "enclave_options": [], - "ephemeral_block_device": [], - "ipv6_addresses": [], - "metadata_options": [], - "network_interface": [], - "root_block_device": [ - {} - ], - "secondary_private_ips": [], - "security_groups": [], - "tags_all": {}, - "vpc_security_group_ids": [] - } - }, - { - "address": "aws_lambda_function.hello_world", - "mode": "managed", - "type": "aws_lambda_function", - "name": "hello_world", - "provider_name": "registry.terraform.io/hashicorp/aws", - "schema_version": 0, - "values": { - "code_signing_config_arn": null, - "dead_letter_config": [], - "description": null, - "environment": [], - "file_system_config": [], - "filename": null, - "function_name": "hello_world", - "handler": "exports.test", - "image_config": [], - "image_uri": null, - "kms_key_arn": null, - "layers": null, - "memory_size": 1024, - "package_type": "Zip", - "publish": false, - "reserved_concurrent_executions": -1, - "role": "arn:aws:lambda:us-east-1:account-id:resource-id", - "runtime": "nodejs12.x", - "s3_bucket": null, - "s3_key": null, - "s3_object_version": null, - "tags": null, - "timeout": 3, - "timeouts": null, - "vpc_config": [] - }, - "sensitive_values": { - "dead_letter_config": [], - "environment": [], - "file_system_config": [], - "image_config": [], - "tags_all": {}, - "tracing_config": [], - "vpc_config": [] - } - } - ] - } - }, - "resource_changes": [ - { - "address": "aws_instance.web_app", - "mode": "managed", - "type": "aws_instance", - "name": "web_app", - "provider_name": "registry.terraform.io/hashicorp/aws", - "change": { - "actions": [ - "create" - ], - "before": null, - "after": { - "ami": "ami-674cbc1e", - "credit_specification": [], - "disable_api_termination": null, - "ebs_block_device": [ - { - "delete_on_termination": true, - "device_name": "my_data", - "iops": 800, - "tags": null, - "volume_size": 1000, - "volume_type": "io1" - } - ], - "ebs_optimized": null, - "get_password_data": false, - "hibernation": null, - "iam_instance_profile": null, - "instance_type": "m5.4xlarge", - "monitoring": null, - "root_block_device": [ - { - "delete_on_termination": true, - "tags": null, - "volume_size": 50 - } - ], - "source_dest_check": true, - "tags": null, - "timeouts": null, - "user_data": null, - "user_data_base64": null, - "volume_tags": null - }, - "after_unknown": { - "arn": true, - "associate_public_ip_address": true, - "availability_zone": true, - "capacity_reservation_specification": true, - "cpu_core_count": true, - "cpu_threads_per_core": true, - "credit_specification": [], - "ebs_block_device": [ - { - "encrypted": true, - "kms_key_id": true, - "snapshot_id": true, - "throughput": true, - "volume_id": true - } - ], - "enclave_options": true, - "ephemeral_block_device": true, - "host_id": true, - "id": true, - "instance_initiated_shutdown_behavior": true, - "instance_state": true, - "ipv6_address_count": true, - "ipv6_addresses": true, - "key_name": true, - "metadata_options": true, - "network_interface": true, - "outpost_arn": true, - "password_data": true, - "placement_group": true, - "primary_network_interface_id": true, - "private_dns": true, - "private_ip": true, - "public_dns": true, - "public_ip": true, - "root_block_device": [ - { - "device_name": true, - "encrypted": true, - "iops": true, - "kms_key_id": true, - "throughput": true, - "volume_id": true, - "volume_type": true - } - ], - "secondary_private_ips": true, - "security_groups": true, - "subnet_id": true, - "tags_all": true, - "tenancy": true, - "vpc_security_group_ids": true - }, - "before_sensitive": false, - "after_sensitive": { - "capacity_reservation_specification": [], - "credit_specification": [], - "ebs_block_device": [ - {} - ], - "enclave_options": [], - "ephemeral_block_device": [], - "ipv6_addresses": [], - "metadata_options": [], - "network_interface": [], - "root_block_device": [ - {} - ], - "secondary_private_ips": [], - "security_groups": [], - "tags_all": {}, - "vpc_security_group_ids": [] - } - } - }, - { - "address": "aws_lambda_function.hello_world", - "mode": "managed", - "type": "aws_lambda_function", - "name": "hello_world", - "provider_name": "registry.terraform.io/hashicorp/aws", - "change": { - "actions": [ - "create" - ], - "before": null, - "after": { - "code_signing_config_arn": null, - "dead_letter_config": [], - "description": null, - "environment": [], - "file_system_config": [], - "filename": null, - "function_name": "hello_world", - "handler": "exports.test", - "image_config": [], - "image_uri": null, - "kms_key_arn": null, - "layers": null, - "memory_size": 1024, - "package_type": "Zip", - "publish": false, - "reserved_concurrent_executions": -1, - "role": "arn:aws:lambda:us-east-1:account-id:resource-id", - "runtime": "nodejs12.x", - "s3_bucket": null, - "s3_key": null, - "s3_object_version": null, - "tags": null, - "timeout": 3, - "timeouts": null, - "vpc_config": [] - }, - "after_unknown": { - "arn": true, - "dead_letter_config": [], - "environment": [], - "file_system_config": [], - "id": true, - "image_config": [], - "invoke_arn": true, - "last_modified": true, - "qualified_arn": true, - "signing_job_arn": true, - "signing_profile_version_arn": true, - "source_code_hash": true, - "source_code_size": true, - "tags_all": true, - "tracing_config": true, - "version": true, - "vpc_config": [] - }, - "before_sensitive": false, - "after_sensitive": { - "dead_letter_config": [], - "environment": [], - "file_system_config": [], - "image_config": [], - "tags_all": {}, - "tracing_config": [], - "vpc_config": [] - } - } - } - ], - "configuration": { - "provider_config": { - "aws": { - "name": "aws", - "version_constraint": "3.50.0", - "expressions": { - "access_key": { - "constant_value": "mock_access_key" - }, - "region": { - "constant_value": "us-east-1" - }, - "secret_key": { - "constant_value": "mock_secret_key" - }, - "skip_credentials_validation": { - "constant_value": true - }, - "skip_requesting_account_id": { - "constant_value": true - } - } - } - }, - "root_module": { - "resources": [ - { - "address": "aws_instance.web_app", - "mode": "managed", - "type": "aws_instance", - "name": "web_app", - "provider_config_key": "aws", - "expressions": { - "ami": { - "constant_value": "ami-674cbc1e" - }, - "ebs_block_device": [ - { - "device_name": { - "constant_value": "my_data" - }, - "iops": { - "constant_value": 800 - }, - "volume_size": { - "constant_value": 1000 - }, - "volume_type": { - "constant_value": "io1" - } - } - ], - "instance_type": { - "constant_value": "m5.4xlarge" - }, - "root_block_device": [ - { - "volume_size": { - "constant_value": 50 - } - } - ] - }, - "schema_version": 1 - }, - { - "address": "aws_lambda_function.hello_world", - "mode": "managed", - "type": "aws_lambda_function", - "name": "hello_world", - "provider_config_key": "aws", - "expressions": { - "function_name": { - "constant_value": "hello_world" - }, - "handler": { - "constant_value": "exports.test" - }, - "memory_size": { - "constant_value": 1024 - }, - "role": { - "constant_value": "arn:aws:lambda:us-east-1:account-id:resource-id" - }, - "runtime": { - "constant_value": "nodejs12.x" - } - }, - "schema_version": 0 - } - ] - } - } -} diff --git a/examples/slack/README.md b/examples/slack/README.md index a8e5f4b..baa30bd 100644 --- a/examples/slack/README.md +++ b/examples/slack/README.md @@ -1,11 +1,9 @@ # Slack Example -This example shows how to send cost estimates to Slack by combining the Infracost actions with the official [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) repo. +This example shows how to send cost estimates to Slack by combining the Infracost GitHub Action with the official [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) repo. Slack message blocks have a 3000 char limit so the Infracost CLI automatically truncates the middle of `slack-message` output formats. -For simplicity, this is based off the terraform-plan-json example, which does not require Terraform to be installed. - Example screenshot [//]: <> (BEGIN EXAMPLE) @@ -17,37 +15,61 @@ jobs: slack: name: Slack runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code steps: - - uses: actions/checkout@v2 - - name: Setup Infracost - uses: infracost/actions/setup@v1 + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd with: api-key: ${{ secrets.INFRACOST_API_KEY }} - - name: Generate Infracost JSON - run: infracost breakdown --path=examples/slack/code/plan.json --format json --out-file /tmp/infracost.json + # Checkout the base branch of the pull request (e.g. main/master). + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' + + # Generate Infracost JSON file as the baseline. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + + # Checkout the current PR branch so we can create a diff. + - name: Checkout PR branch + uses: actions/checkout@v2 + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - name: Post Infracost comment run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update - name: Generate Slack message id: infracost-slack run: | - echo "::set-output name=slack-message::$(infracost output --path /tmp/infracost.json --format slack-message --show-skipped)" + echo "::set-output name=slack-message::$(infracost output --path=/tmp/infracost.json --format=slack-message --show-skipped)" echo "::set-output name=diffTotalMonthlyCost::$(jq '(.diffTotalMonthlyCost // 0) | tonumber' /tmp/infracost.json)" - name: Send cost estimate to Slack diff --git a/examples/slack/code/plan.json b/examples/slack/code/plan.json deleted file mode 100644 index 3e45036..0000000 --- a/examples/slack/code/plan.json +++ /dev/null @@ -1 +0,0 @@ -{"format_version":"0.2","terraform_version":"1.0.2","planned_values":{"root_module":{"resources":[{"address":"aws_instance.web_app","mode":"managed","type":"aws_instance","name":"web_app","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":1,"values":{"ami":"ami-674cbc1e","credit_specification":[],"disable_api_termination":null,"ebs_block_device":[{"delete_on_termination":true,"device_name":"my_data","iops":800,"tags":null,"volume_size":1000,"volume_type":"io1"}],"ebs_optimized":null,"get_password_data":false,"hibernation":null,"iam_instance_profile":null,"instance_type":"m5.4xlarge","monitoring":null,"root_block_device":[{"delete_on_termination":true,"tags":null,"volume_size":50}],"source_dest_check":true,"tags":null,"timeouts":null,"user_data":null,"user_data_base64":null,"volume_tags":null},"sensitive_values":{"capacity_reservation_specification":[],"credit_specification":[],"ebs_block_device":[{}],"enclave_options":[],"ephemeral_block_device":[],"ipv6_addresses":[],"metadata_options":[],"network_interface":[],"root_block_device":[{}],"secondary_private_ips":[],"security_groups":[],"tags_all":{},"vpc_security_group_ids":[]}},{"address":"aws_lambda_function.hello_world","mode":"managed","type":"aws_lambda_function","name":"hello_world","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"code_signing_config_arn":null,"dead_letter_config":[],"description":null,"environment":[],"file_system_config":[],"filename":null,"function_name":"hello_world","handler":"exports.test","image_config":[],"image_uri":null,"kms_key_arn":null,"layers":null,"memory_size":1024,"package_type":"Zip","publish":false,"reserved_concurrent_executions":-1,"role":"arn:aws:lambda:us-east-1:account-id:resource-id","runtime":"nodejs12.x","s3_bucket":null,"s3_key":null,"s3_object_version":null,"tags":null,"timeout":3,"timeouts":null,"vpc_config":[]},"sensitive_values":{"dead_letter_config":[],"environment":[],"file_system_config":[],"image_config":[],"tags_all":{},"tracing_config":[],"vpc_config":[]}}]}},"resource_changes":[{"address":"aws_instance.web_app","mode":"managed","type":"aws_instance","name":"web_app","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"ami":"ami-674cbc1e","credit_specification":[],"disable_api_termination":null,"ebs_block_device":[{"delete_on_termination":true,"device_name":"my_data","iops":800,"tags":null,"volume_size":1000,"volume_type":"io1"}],"ebs_optimized":null,"get_password_data":false,"hibernation":null,"iam_instance_profile":null,"instance_type":"m5.4xlarge","monitoring":null,"root_block_device":[{"delete_on_termination":true,"tags":null,"volume_size":50}],"source_dest_check":true,"tags":null,"timeouts":null,"user_data":null,"user_data_base64":null,"volume_tags":null},"after_unknown":{"arn":true,"associate_public_ip_address":true,"availability_zone":true,"capacity_reservation_specification":true,"cpu_core_count":true,"cpu_threads_per_core":true,"credit_specification":[],"ebs_block_device":[{"encrypted":true,"kms_key_id":true,"snapshot_id":true,"throughput":true,"volume_id":true}],"enclave_options":true,"ephemeral_block_device":true,"host_id":true,"id":true,"instance_initiated_shutdown_behavior":true,"instance_state":true,"ipv6_address_count":true,"ipv6_addresses":true,"key_name":true,"metadata_options":true,"network_interface":true,"outpost_arn":true,"password_data":true,"placement_group":true,"primary_network_interface_id":true,"private_dns":true,"private_ip":true,"public_dns":true,"public_ip":true,"root_block_device":[{"device_name":true,"encrypted":true,"iops":true,"kms_key_id":true,"throughput":true,"volume_id":true,"volume_type":true}],"secondary_private_ips":true,"security_groups":true,"subnet_id":true,"tags_all":true,"tenancy":true,"vpc_security_group_ids":true},"before_sensitive":false,"after_sensitive":{"capacity_reservation_specification":[],"credit_specification":[],"ebs_block_device":[{}],"enclave_options":[],"ephemeral_block_device":[],"ipv6_addresses":[],"metadata_options":[],"network_interface":[],"root_block_device":[{}],"secondary_private_ips":[],"security_groups":[],"tags_all":{},"vpc_security_group_ids":[]}}},{"address":"aws_lambda_function.hello_world","mode":"managed","type":"aws_lambda_function","name":"hello_world","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"code_signing_config_arn":null,"dead_letter_config":[],"description":null,"environment":[],"file_system_config":[],"filename":null,"function_name":"hello_world","handler":"exports.test","image_config":[],"image_uri":null,"kms_key_arn":null,"layers":null,"memory_size":1024,"package_type":"Zip","publish":false,"reserved_concurrent_executions":-1,"role":"arn:aws:lambda:us-east-1:account-id:resource-id","runtime":"nodejs12.x","s3_bucket":null,"s3_key":null,"s3_object_version":null,"tags":null,"timeout":3,"timeouts":null,"vpc_config":[]},"after_unknown":{"arn":true,"dead_letter_config":[],"environment":[],"file_system_config":[],"id":true,"image_config":[],"invoke_arn":true,"last_modified":true,"qualified_arn":true,"signing_job_arn":true,"signing_profile_version_arn":true,"source_code_hash":true,"source_code_size":true,"tags_all":true,"tracing_config":true,"version":true,"vpc_config":[]},"before_sensitive":false,"after_sensitive":{"dead_letter_config":[],"environment":[],"file_system_config":[],"image_config":[],"tags_all":{},"tracing_config":[],"vpc_config":[]}}}],"configuration":{"provider_config":{"aws":{"name":"aws","version_constraint":"3.50.0","expressions":{"access_key":{"constant_value":"mock_access_key"},"region":{"constant_value":"us-east-1"},"secret_key":{"constant_value":"mock_secret_key"},"skip_credentials_validation":{"constant_value":true},"skip_requesting_account_id":{"constant_value":true}}}},"root_module":{"resources":[{"address":"aws_instance.web_app","mode":"managed","type":"aws_instance","name":"web_app","provider_config_key":"aws","expressions":{"ami":{"constant_value":"ami-674cbc1e"},"ebs_block_device":[{"device_name":{"constant_value":"my_data"},"iops":{"constant_value":800},"volume_size":{"constant_value":1000},"volume_type":{"constant_value":"io1"}}],"instance_type":{"constant_value":"m5.4xlarge"},"root_block_device":[{"volume_size":{"constant_value":50}}]},"schema_version":1},{"address":"aws_lambda_function.hello_world","mode":"managed","type":"aws_lambda_function","name":"hello_world","provider_config_key":"aws","expressions":{"function_name":{"constant_value":"hello_world"},"handler":{"constant_value":"exports.test"},"memory_size":{"constant_value":1024},"role":{"constant_value":"arn:aws:lambda:us-east-1:account-id:resource-id"},"runtime":{"constant_value":"nodejs12.x"}},"schema_version":0}]}}} diff --git a/examples/terraform-cloud-enterprise/README.md b/examples/terraform-cloud-enterprise/README.md deleted file mode 100644 index 5f9fe8c..0000000 --- a/examples/terraform-cloud-enterprise/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Terraform Cloud/Enterprise - -This example shows how to run Infracost actions with Terraform Cloud and Terraform Enterprise. It assumes you have set a GitHub repo secret for the Terraform Cloud token (`TFC_TOKEN`). This token is used by the Infracost CLI run a speculative plan and fetch the plan JSON from Terraform Cloud to generate the cost estimate comment. - -In the future, we'll add an example of how you can trigger the Infracost actions from Terraform Cloud's GitHub status checks. - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Terraform Cloud/Enterprise -on: [pull_request] - -jobs: - terraform-cloud-enterprise: - name: Terraform Cloud/Enterprise - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Install terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - cli_config_credentials_token: ${{ secrets.TFC_TOKEN }} - # cli_config_credentials_hostname: my-tfe-host.com # For Terraform Enterprise users only - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --path=examples/terraform-cloud-enterprise/code --format=json --out-file=/tmp/infracost.json - env: - # TODO: the following two envs be removed once https://github.com/infracost/infracost/pull/1148 is released in v0.9.14 of the CLI (https://github.com/infracost/infracost/releases) - INFRACOST_TERRAFORM_CLOUD_TOKEN: ${{ secrets.TFC_TOKEN }} - # INFRACOST_TERRAFORM_CLOUD_HOST: my-tfe-host.com # For Terraform Enterprise users only. - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) diff --git a/examples/terraform-directory/README.md b/examples/terraform-directory/README.md deleted file mode 100644 index 0b2fa42..0000000 --- a/examples/terraform-directory/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Terraform directory - -This example shows how to run Infracost actions with a Terraform project containing HCL code. - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Terraform directory -on: [pull_request] - -jobs: - terraform-directory: - name: Terraform directory - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Install terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - - # IMPORTANT: add any required steps here to setup cloud credentials so Terraform can run - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --path=examples/terraform-directory/code --format=json --out-file=/tmp/infracost.json - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) diff --git a/examples/terraform-directory/code/main.tf b/examples/terraform-directory/code/main.tf deleted file mode 100644 index de63dd0..0000000 --- a/examples/terraform-directory/code/main.tf +++ /dev/null @@ -1,31 +0,0 @@ -provider "aws" { - region = "us-east-1" - skip_credentials_validation = true - skip_requesting_account_id = true - access_key = "mock_access_key" - secret_key = "mock_secret_key" -} - -resource "aws_instance" "web_app" { - ami = "ami-674cbc1e" - instance_type = "m5.4xlarge" - - root_block_device { - volume_size = 50 - } - - ebs_block_device { - device_name = "my_data" - volume_type = "io1" - volume_size = 1000 - iops = 800 - } -} - -resource "aws_lambda_function" "hello_world" { - function_name = "hello_world" - role = "arn:aws:lambda:us-east-1:account-id:resource-id" - handler = "exports.test" - runtime = "nodejs12.x" - memory_size = 1024 -} diff --git a/examples/terraform-plan-json/README.md b/examples/terraform-plan-json/README.md deleted file mode 100644 index 36815ca..0000000 --- a/examples/terraform-plan-json/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Terraform plan JSON - -This example shows how to run Infracost actions with a Terraform plan JSON file. Installing Terraform is not needed since the Infracost CLI can use the plan JSON directly. - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Terraform plan JSON -on: [pull_request] - -jobs: - terraform-plan-json: - name: Terraform plan JSON - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --path=examples/terraform-plan-json/code/plan.json --format=json --out-file=/tmp/infracost.json - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) diff --git a/examples/terraform-plan-json/code/plan.json b/examples/terraform-plan-json/code/plan.json deleted file mode 100644 index 3e45036..0000000 --- a/examples/terraform-plan-json/code/plan.json +++ /dev/null @@ -1 +0,0 @@ -{"format_version":"0.2","terraform_version":"1.0.2","planned_values":{"root_module":{"resources":[{"address":"aws_instance.web_app","mode":"managed","type":"aws_instance","name":"web_app","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":1,"values":{"ami":"ami-674cbc1e","credit_specification":[],"disable_api_termination":null,"ebs_block_device":[{"delete_on_termination":true,"device_name":"my_data","iops":800,"tags":null,"volume_size":1000,"volume_type":"io1"}],"ebs_optimized":null,"get_password_data":false,"hibernation":null,"iam_instance_profile":null,"instance_type":"m5.4xlarge","monitoring":null,"root_block_device":[{"delete_on_termination":true,"tags":null,"volume_size":50}],"source_dest_check":true,"tags":null,"timeouts":null,"user_data":null,"user_data_base64":null,"volume_tags":null},"sensitive_values":{"capacity_reservation_specification":[],"credit_specification":[],"ebs_block_device":[{}],"enclave_options":[],"ephemeral_block_device":[],"ipv6_addresses":[],"metadata_options":[],"network_interface":[],"root_block_device":[{}],"secondary_private_ips":[],"security_groups":[],"tags_all":{},"vpc_security_group_ids":[]}},{"address":"aws_lambda_function.hello_world","mode":"managed","type":"aws_lambda_function","name":"hello_world","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"code_signing_config_arn":null,"dead_letter_config":[],"description":null,"environment":[],"file_system_config":[],"filename":null,"function_name":"hello_world","handler":"exports.test","image_config":[],"image_uri":null,"kms_key_arn":null,"layers":null,"memory_size":1024,"package_type":"Zip","publish":false,"reserved_concurrent_executions":-1,"role":"arn:aws:lambda:us-east-1:account-id:resource-id","runtime":"nodejs12.x","s3_bucket":null,"s3_key":null,"s3_object_version":null,"tags":null,"timeout":3,"timeouts":null,"vpc_config":[]},"sensitive_values":{"dead_letter_config":[],"environment":[],"file_system_config":[],"image_config":[],"tags_all":{},"tracing_config":[],"vpc_config":[]}}]}},"resource_changes":[{"address":"aws_instance.web_app","mode":"managed","type":"aws_instance","name":"web_app","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"ami":"ami-674cbc1e","credit_specification":[],"disable_api_termination":null,"ebs_block_device":[{"delete_on_termination":true,"device_name":"my_data","iops":800,"tags":null,"volume_size":1000,"volume_type":"io1"}],"ebs_optimized":null,"get_password_data":false,"hibernation":null,"iam_instance_profile":null,"instance_type":"m5.4xlarge","monitoring":null,"root_block_device":[{"delete_on_termination":true,"tags":null,"volume_size":50}],"source_dest_check":true,"tags":null,"timeouts":null,"user_data":null,"user_data_base64":null,"volume_tags":null},"after_unknown":{"arn":true,"associate_public_ip_address":true,"availability_zone":true,"capacity_reservation_specification":true,"cpu_core_count":true,"cpu_threads_per_core":true,"credit_specification":[],"ebs_block_device":[{"encrypted":true,"kms_key_id":true,"snapshot_id":true,"throughput":true,"volume_id":true}],"enclave_options":true,"ephemeral_block_device":true,"host_id":true,"id":true,"instance_initiated_shutdown_behavior":true,"instance_state":true,"ipv6_address_count":true,"ipv6_addresses":true,"key_name":true,"metadata_options":true,"network_interface":true,"outpost_arn":true,"password_data":true,"placement_group":true,"primary_network_interface_id":true,"private_dns":true,"private_ip":true,"public_dns":true,"public_ip":true,"root_block_device":[{"device_name":true,"encrypted":true,"iops":true,"kms_key_id":true,"throughput":true,"volume_id":true,"volume_type":true}],"secondary_private_ips":true,"security_groups":true,"subnet_id":true,"tags_all":true,"tenancy":true,"vpc_security_group_ids":true},"before_sensitive":false,"after_sensitive":{"capacity_reservation_specification":[],"credit_specification":[],"ebs_block_device":[{}],"enclave_options":[],"ephemeral_block_device":[],"ipv6_addresses":[],"metadata_options":[],"network_interface":[],"root_block_device":[{}],"secondary_private_ips":[],"security_groups":[],"tags_all":{},"vpc_security_group_ids":[]}}},{"address":"aws_lambda_function.hello_world","mode":"managed","type":"aws_lambda_function","name":"hello_world","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"code_signing_config_arn":null,"dead_letter_config":[],"description":null,"environment":[],"file_system_config":[],"filename":null,"function_name":"hello_world","handler":"exports.test","image_config":[],"image_uri":null,"kms_key_arn":null,"layers":null,"memory_size":1024,"package_type":"Zip","publish":false,"reserved_concurrent_executions":-1,"role":"arn:aws:lambda:us-east-1:account-id:resource-id","runtime":"nodejs12.x","s3_bucket":null,"s3_key":null,"s3_object_version":null,"tags":null,"timeout":3,"timeouts":null,"vpc_config":[]},"after_unknown":{"arn":true,"dead_letter_config":[],"environment":[],"file_system_config":[],"id":true,"image_config":[],"invoke_arn":true,"last_modified":true,"qualified_arn":true,"signing_job_arn":true,"signing_profile_version_arn":true,"source_code_hash":true,"source_code_size":true,"tags_all":true,"tracing_config":true,"version":true,"vpc_config":[]},"before_sensitive":false,"after_sensitive":{"dead_letter_config":[],"environment":[],"file_system_config":[],"image_config":[],"tags_all":{},"tracing_config":[],"vpc_config":[]}}}],"configuration":{"provider_config":{"aws":{"name":"aws","version_constraint":"3.50.0","expressions":{"access_key":{"constant_value":"mock_access_key"},"region":{"constant_value":"us-east-1"},"secret_key":{"constant_value":"mock_secret_key"},"skip_credentials_validation":{"constant_value":true},"skip_requesting_account_id":{"constant_value":true}}}},"root_module":{"resources":[{"address":"aws_instance.web_app","mode":"managed","type":"aws_instance","name":"web_app","provider_config_key":"aws","expressions":{"ami":{"constant_value":"ami-674cbc1e"},"ebs_block_device":[{"device_name":{"constant_value":"my_data"},"iops":{"constant_value":800},"volume_size":{"constant_value":1000},"volume_type":{"constant_value":"io1"}}],"instance_type":{"constant_value":"m5.4xlarge"},"root_block_device":[{"volume_size":{"constant_value":50}}]},"schema_version":1},{"address":"aws_lambda_function.hello_world","mode":"managed","type":"aws_lambda_function","name":"hello_world","provider_config_key":"aws","expressions":{"function_name":{"constant_value":"hello_world"},"handler":{"constant_value":"exports.test"},"memory_size":{"constant_value":1024},"role":{"constant_value":"arn:aws:lambda:us-east-1:account-id:resource-id"},"runtime":{"constant_value":"nodejs12.x"}},"schema_version":0}]}}} diff --git a/examples/terraform-project/README.md b/examples/terraform-project/README.md new file mode 100644 index 0000000..7b23e88 --- /dev/null +++ b/examples/terraform-project/README.md @@ -0,0 +1,70 @@ +# Terraform/Terragrunt project (single or multi) + +This example shows how to run Infracost in GitHub Actions with multiple Terraform/Terragrunt projects, both single projects or mono-repos that contain multiple projects. + +[//]: <> (BEGIN EXAMPLE) +```yml +name: Terraform project +on: [pull_request] + +jobs: + terraform-project: + name: Terraform project + runs-on: ubuntu-latest + env: + TF_ROOT: examples/terraform-project/code + # If you're using Terraform Cloud/Enterprise and have variables stored on there + # you can specify the following to automatically retrieve the variables: + # INFRACOST_TERRAFORM_CLOUD_TOKEN: ${{ secrets.TFC_TOKEN }} + # INFRACOST_TERRAFORM_CLOUD_HOST: app.terraform.io # Change this if you're using Terraform Enterprise + + steps: + - name: Setup Infracost + uses: infracost/actions/setup@v2 + # See https://github.com/infracost/actions/tree/master/setup for other inputs + # If you can't use this action, see Docker images in https://infracost.io/cicd + with: + api-key: ${{ secrets.INFRACOST_API_KEY }} + + # Checkout the base branch of the pull request (e.g. main/master). + - name: Checkout base branch + uses: actions/checkout@v2 + with: + ref: '${{ github.event.pull_request.base.ref }}' + + # Generate Infracost JSON file as the baseline. + - name: Generate Infracost cost estimate baseline + run: | + infracost breakdown --path=${TF_ROOT} \ + --format=json \ + --out-file=/tmp/infracost-base.json + + # Checkout the current PR branch so we can create a diff. + - name: Checkout PR branch + uses: actions/checkout@v2 + + # Generate an Infracost diff and save it to a JSON file. + - name: Generate Infracost diff + run: | + infracost diff --path=${TF_ROOT} \ + --format=json \ + --compare-to=/tmp/infracost-base.json \ + --out-file=/tmp/infracost.json + + + # Posts a comment to the PR using the 'update' behavior. + # This creates a single comment and updates it. The "quietest" option. + # The other valid behaviors are: + # delete-and-new - Delete previous comments and create a new one. + # hide-and-new - Minimize previous comments and create a new one. + # new - Create a new cost estimate comment on every push. + # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. + - name: Post Infracost comment + run: | + infracost comment github --path=/tmp/infracost.json \ + --repo=$GITHUB_REPOSITORY \ + --github-token=${{github.token}} \ + --pull-request=${{github.event.pull_request.number}} \ + --behavior=update +``` +[//]: <> (END EXAMPLE) diff --git a/examples/terraform-project/code/.gitignore b/examples/terraform-project/code/.gitignore new file mode 100644 index 0000000..be4aaeb --- /dev/null +++ b/examples/terraform-project/code/.gitignore @@ -0,0 +1,2 @@ +plan.cache +plan.json diff --git a/examples/multi-project/code/dev/main.tf b/examples/terraform-project/code/dev/main.tf similarity index 80% rename from examples/multi-project/code/dev/main.tf rename to examples/terraform-project/code/dev/main.tf index 059835c..cfda5d6 100644 --- a/examples/multi-project/code/dev/main.tf +++ b/examples/terraform-project/code/dev/main.tf @@ -2,6 +2,8 @@ provider "aws" { region = "us-east-1" skip_credentials_validation = true skip_requesting_account_id = true + access_key = "mock_access_key" + secret_key = "mock_secret_key" } module "base" { @@ -11,6 +13,6 @@ module "base" { root_block_device_volume_size = 50 block_device_volume_size = 100 block_device_iops = 400 - + hello_world_function_memory_size = 512 } diff --git a/examples/terraform-project/code/modules/example/main.tf b/examples/terraform-project/code/modules/example/main.tf new file mode 100644 index 0000000..bcd5deb --- /dev/null +++ b/examples/terraform-project/code/modules/example/main.tf @@ -0,0 +1,48 @@ +variable "instance_type" { + description = "The EC2 instance type for the web app" + type = string +} + +variable "root_block_device_volume_size" { + description = "The size of the root block device volume for the web app EC2 instance" + type = number +} + +variable "block_device_volume_size" { + description = "The size of the block device volume for the web app EC2 instance" + type = number +} + +variable "block_device_iops" { + description = "The number of IOPS for the block device for the web app EC2 instance" + type = number +} + +variable "hello_world_function_memory_size" { + description = "The memory to allocate to the hello world Lambda function" + type = number +} + +resource "aws_instance" "web_app" { + ami = "ami-674cbc1e" + instance_type = var.instance_type + + root_block_device { + volume_size = var.root_block_device_volume_size + } + + ebs_block_device { + device_name = "my_data" + volume_type = "io1" + volume_size = var.block_device_volume_size + iops = var.block_device_iops + } +} + +resource "aws_lambda_function" "hello_world" { + function_name = "hello_world" + role = "arn:aws:lambda:us-east-1:account-id:resource-id" + handler = "exports.test" + runtime = "nodejs12.x" + memory_size = var.hello_world_function_memory_size +} diff --git a/examples/multi-project/code/prod/main.tf b/examples/terraform-project/code/prod/main.tf similarity index 81% rename from examples/multi-project/code/prod/main.tf rename to examples/terraform-project/code/prod/main.tf index 4d7e63b..bfccde2 100644 --- a/examples/multi-project/code/prod/main.tf +++ b/examples/terraform-project/code/prod/main.tf @@ -2,6 +2,8 @@ provider "aws" { region = "us-east-1" skip_credentials_validation = true skip_requesting_account_id = true + access_key = "mock_access_key" + secret_key = "mock_secret_key" } module "base" { @@ -11,6 +13,6 @@ module "base" { root_block_device_volume_size = 100 block_device_volume_size = 1000 block_device_iops = 800 - + hello_world_function_memory_size = 1024 } diff --git a/examples/terragrunt/README.md b/examples/terragrunt/README.md deleted file mode 100644 index 9f25d1d..0000000 --- a/examples/terragrunt/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Terragrunt - -This example shows how to run Infracost actions with Terragrunt. - -[//]: <> (BEGIN EXAMPLE) -```yml -name: Terragrunt -on: [pull_request] - -jobs: - terragrunt: - name: Terragrunt - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_wrapper: false # This is recommended so the `terraform show` command outputs valid JSON - - - name: Setup Terragrunt - uses: autero1/action-terragrunt@v1.1.0 - with: - terragrunt_version: 0.35.9 - - # IMPORTANT: add any required steps here to setup cloud credentials so Terraform/Terragrunt can run - - - name: Setup Infracost - uses: infracost/actions/setup@v1 - with: - api-key: ${{ secrets.INFRACOST_API_KEY }} - - - name: Run Infracost - run: infracost breakdown --path=examples/terragrunt/code --format=json --out-file=/tmp/infracost.json - - - name: Post Infracost comment - run: | - # Posts a comment to the PR using the 'update' behavior. - # This creates a single comment and updates it. The "quietest" option. - # The other valid behaviors are: - # delete-and-new - Delete previous comments and create a new one. - # hide-and-new - Minimize previous comments and create a new one. - # new - Create a new cost estimate comment on every push. - # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options. - infracost comment github --path /tmp/infracost.json \ - --repo $GITHUB_REPOSITORY \ - --github-token ${{github.token}} \ - --pull-request ${{github.event.pull_request.number}} \ - --behavior update -``` -[//]: <> (END EXAMPLE) diff --git a/get-comment/README.md b/get-comment/README.md deleted file mode 100644 index 02066cf..0000000 --- a/get-comment/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Infracost Get Comment Action - -This GitHub Action retrieves the body of the latest Github comment posted using the `infracost/actions/comment` action. We're still developing the use-cases for this action. - -## Usage - -The action can be used as follows. - -```yml -steps: - - name: Infracost get comment - id: get-comment - uses: infracost/actions/get-comment@v1 - - - name: Show comment - run: echo "${{ steps.get-comment.outputs.body }}" -``` - -## Inputs - -The action supports the following inputs: - -- `target-type`: Optional. The target-type set when the comment was posted (if any), either `pull_request` or `commit`. - -- `tag`: Optional. Customize the comment tag. This is added to the comment as a markdown comment (hidden) to detect the previously posted comments. This is useful if you have multiple workflows that post comments to the same pull request or commit. - -- `github-token`: Optional, default to `${{ github.token }}`. This is the default GitHub token available to actions and is used to get comments. The default [token permissions](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#permissions) work fine; `pull-requests: read` is required if you need to customize these. - - ```yml - steps: - - name: Infracost get comment - uses: infracost/actions/get-comment@v1 - with: - ... - permissions: - pull-requests: read - ``` - -## Outputs - -This action sets the following output: - -- `body`: The body of the latest matching comment. diff --git a/get-comment/action.yml b/get-comment/action.yml deleted file mode 100644 index 9fe3ea8..0000000 --- a/get-comment/action.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: "Infracost Get Comment" -description: Gets the latest comment posted by infracost/actions/comment. -inputs: - target-type: - description: The target-type set when the comment was posted (if any), either `pull-request` or `commit`. - required: false - tag: - description: 'Customize the comment tag. This is added to the comment as a markdown comment (hidden) to detect the previously posted comments. This is useful if you have multiple workflows that post comments to the same pull request or commit.' - required: false - github-token: - description: 'Default to {{ github.token }}. This is the default GitHub token available to actions and is used to get comments. The default token permissions (https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#permissions) work fine; `pull-requests: read` is required if you need to customize these.' - default: '${{ github.token }}' - required: false -outputs: - body: - description: 'The body of the latest matching comment.' - value: ${{ steps.get-comment.outputs.body }} -runs: - using: "composite" - steps: - - name: Get Comment - id: get-comment - uses: infracost/compost-action@master - with: - behavior: latest - target-type: ${{ inputs.target-type }} - tag: ${{ inputs.tag }} - github-token: ${{ inputs.github-token }} - - diff --git a/package-lock.json b/package-lock.json index bc790e3..3010288 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,10 +6,8 @@ "": { "name": "infracost-actions", "license": "Apache-2.0", - "dependencies": { - "dotenv": "^10.0.0" - }, "devDependencies": { + "dotenv": "^10.0.0", "js-yaml": "^4.1.0" } }, @@ -23,6 +21,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true, "engines": { "node": ">=10" } @@ -50,7 +49,8 @@ "dotenv": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true }, "js-yaml": { "version": "4.1.0", diff --git a/scripts/generateExamplesTests.js b/scripts/generateExamplesTests.js index 8e6b361..f4a0768 100755 --- a/scripts/generateExamplesTests.js +++ b/scripts/generateExamplesTests.js @@ -6,7 +6,7 @@ const fs = require('fs'); const yaml = require('js-yaml'); -const { env } = require('process'); +const {env} = require('process'); const examplesTestWorkflowPath = './.github/workflows/examples_test.yml'; const examplesDir = 'examples'; @@ -17,6 +17,8 @@ const localSkipJobs = [ // These jobs are skipped locally until https://github.com/nektos/act/issues/769 is fixed 'multi-project-matrix', 'multi-project-matrix-merge', + 'multi-workspace-matrix', + 'multi-workspace-matrix-merge', ] const workflowTemplate = { @@ -53,23 +55,18 @@ function extractAllExamples(examplesDir) { continue; } - console.log( - `Generating GitHub Actions workflow job for ${examplesDir}/${dir}` - ); - const filename = `${examplesDir}/${dir}/README.md`; - try { - if (!fs.existsSync(filename)) { - console.error(`Skipping ${dir} since no README.md file was found`); - continue; + if (fs.existsSync(filename)) { + console.error(`Found README.md file in ${dir} was found, extracting examples`); + try { + examples.push(...extractExamples(filename)); + } catch(err) { + console.error(`Error reading YAML file ${filename}: ${err}`); } - - examples.push(...extractExamples(filename)); - } catch (err) { - console.error(`Error reading YAML file ${filename}: ${err}`); - continue; } + + examples.push(...extractAllExamples(`${examplesDir}/${dir}`)); } return examples; @@ -84,13 +81,42 @@ function fixupExamples(examples) { const [jobKey, job] = jobEntry; const steps = []; + for (let i = 0; i < job.steps.length; i++) { + const step = job.steps[i]; + + if (step.name && step.name.toLowerCase() === 'checkout base branch') { + // In the tests we don't actually want to use the base branch since we might have updated + // the actual tests themselves. + if (step.with) { + delete step.with.ref; + } + + steps.push(step); + + continue; + } + + if (step.name && step.name.toLowerCase() === 'generate infracost diff') { + steps.push( + { + name: 'Replace m5 instance', + run: `find examples -type f -name '*.tf' -o -name '*.hcl' -o -name '*.tfvars' | xargs sed -i 's/m5\.4xlarge/m5\.8xlarge/g'` + }, + { + name: 'Replace t2 instance', + run: `find examples -type f -name '*.tf' -o -name '*.hcl' -o -name '*.tfvars' | xargs sed -i 's/t2\.micro/t2\.medium/g'` + }, + step, + ) + + continue; + } - for (const step of job.steps) { if (step.name && step.name.toLowerCase() === 'post infracost comment') { const goldenFilePath = `./testdata/${jobKey}_comment_golden.md`; const commentArgs = step.run .replace(/\\/g, '') - .replace(/--pull-request \$\{\{github\.event\.pull_request\.number\}\}/g, '--pull-request 1') + .replace(/--pull-request=\$\{\{github\.event\.pull_request\.number\}\}/g, '--pull-request=1') .split('\n') .map(s => s.trim()) .filter(e => !e.startsWith('#') && e !== '') @@ -140,6 +166,17 @@ function fixupExamples(examples) { continue; } + // Since we're using the local action we need to make sure the we have the code checked out before running that action + // We should only do this if the setup action is the first step + if (i == 0 && step.uses && step.uses.startsWith('infracost/actions/setup')) { + steps.push( + { + name: 'Checkout source code so we can install the action locally', + uses: 'actions/checkout@v2', + }, + ); + } + // Replace infracost/actions steps with the local path steps.push({ ...step, @@ -162,7 +199,7 @@ function fixupExamples(examples) { // Generate the workflow YAML from the examples function generateWorkflow(examples) { - const workflow = { ...workflowTemplate }; + const workflow = {...workflowTemplate}; for (const example of examples) { workflow.jobs = { diff --git a/scripts/testExamples.js b/scripts/testExamples.js index c4a7f40..9eeeaa7 100755 --- a/scripts/testExamples.js +++ b/scripts/testExamples.js @@ -27,11 +27,11 @@ console.log(`Running ${command}`); const child = spawn('bash', ['-c', command], { env: process.env }); child.stdout.on('data', (data) => { - process.stdout.write(data.toString()); + process.stdout.write(data.toString()); }); child.stderr.on('data', (data) => { - process.stderr.write(data.toString()); + process.stderr.write(data.toString()); }); child.on('exit', () => { diff --git a/setup/README.md b/setup/README.md index ff479c5..6767bd5 100644 --- a/setup/README.md +++ b/setup/README.md @@ -9,7 +9,7 @@ The action can be used as follows. You probably want to run Infracost CLI comman ```yml steps: - name: Setup Infracost - uses: infracost/actions/setup@v1 + uses: infracost/actions/setup@v2 with: api-key: ${{ secrets.INFRACOST_API_KEY }} ``` @@ -20,7 +20,7 @@ The action supports the following inputs: - `api-key`: Required. Your Infracost API key. It can be retrieved by running `infracost configure get api_key`. If you don't have one, [download Infracost](https://www.infracost.io/docs/#quick-start) and run `infracost register` to get a free API key. -- `version`: Optional, defaults to `0.9.x`. [SemVer ranges](https://www.npmjs.com/package/semver#ranges) are supported, so instead of a [full version](https://github.com/infracost/infracost/releases) string, you can use `0.9.x`. This enables you to automatically get the latest backward compatible changes in the 0.9 release (e.g. new resources or bug fixes). +- `version`: Optional, defaults to `0.10.x`. [SemVer ranges](https://www.npmjs.com/package/semver#ranges) are supported, so instead of a [full version](https://github.com/infracost/infracost/releases) string, you can use `0.10.x`. This enables you to automatically get the latest backward compatible changes in the 0.10 release (e.g. new resources or bug fixes). - `currency`: Optional. Convert output from USD to your preferred [ISO 4217 currency](https://en.wikipedia.org/wiki/ISO_4217#Active_codes), e.g. EUR, BRL or INR. diff --git a/setup/action.yml b/setup/action.yml index 897acc6..c1a6548 100644 --- a/setup/action.yml +++ b/setup/action.yml @@ -7,7 +7,7 @@ inputs: version: description: Version of Infracost CLI to install. SemVer ranges (https://www.npmjs.com/package/semver#ranges) are supported. required: false - default: 0.9.x + default: 0.10.x currency: description: Convert output from USD to your preferred ISO 4217 currency (https://en.wikipedia.org/wiki/ISO_4217#Active_codes), e.g. EUR, BRL or INR. required: false diff --git a/setup/package-lock.json b/setup/package-lock.json index 517d0ac..d57a4fa 100644 --- a/setup/package-lock.json +++ b/setup/package-lock.json @@ -1,6 +1,6 @@ { "name": "infracost-setup", - "version": "0.0.1", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/setup/package.json b/setup/package.json index 0492cf8..413e25a 100644 --- a/setup/package.json +++ b/setup/package.json @@ -1,6 +1,6 @@ { "name": "infracost-setup", - "version": "0.0.1", + "version": "2.0.0", "description": "", "main": "dist/index.js", "scripts": { diff --git a/testdata/comment/simple_breakdown.json b/testdata/comment/simple_breakdown.json deleted file mode 100644 index 00d4fe0..0000000 --- a/testdata/comment/simple_breakdown.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"0.2","currency":"USD","projects":[{"name":"infracost/infracost/examples/terraform/plan.json","metadata":{"path":"./examples/terraform/plan.json","type":"terraform_plan_json","vcsRepoUrl":"git@github.com:infracost/infracost.git","vcsSubPath":"examples/terraform/plan.json"},"pastBreakdown":{"resources":[],"totalHourlyCost":"0","totalMonthlyCost":"0"},"breakdown":{"resources":[{"name":"aws_instance.web_app","metadata":{},"hourlyCost":"75.431651854684931067041262","monthlyCost":"55065.10585392","costComponents":[{"name":"Instance usage (Linux/UNIX, on-demand, m5.4xlarge)","unit":"hours","hourlyQuantity":"1","monthlyQuantity":"730","price":"56.945493504","hourlyCost":"56.945493504","monthlyCost":"41570.21025792"}],"subresources":[{"name":"root_block_device","metadata":{},"hourlyCost":"0.5078614931506848807207","monthlyCost":"370.73889","costComponents":[{"name":"Storage (general purpose SSD, gp2)","unit":"GB","hourlyQuantity":"0.0684931506849315","monthlyQuantity":"50","price":"7.4147778","hourlyCost":"0.5078614931506848807207","monthlyCost":"370.73889"}]},{"name":"ebs_block_device[0]","metadata":{},"hourlyCost":"17.978296857534246186320562","monthlyCost":"13124.156706","costComponents":[{"name":"Storage (provisioned IOPS SSD, io1)","unit":"GB","hourlyQuantity":"1.3698630136986301","monthlyQuantity":"1000","price":"9.26847225","hourlyCost":"12.696537328767122944864725","monthlyCost":"9268.47225"},{"name":"Provisioned IOPS","unit":"IOPS","hourlyQuantity":"1.0958904109589041","monthlyQuantity":"800","price":"4.81960557","hourlyCost":"5.281759528767123241455837","monthlyCost":"3855.684456"}]}]},{"name":"aws_lambda_function.hello_world","metadata":{},"hourlyCost":null,"monthlyCost":null,"costComponents":[{"name":"Requests","unit":"1M requests","hourlyQuantity":null,"monthlyQuantity":null,"price":"14.8296","hourlyCost":null,"monthlyCost":null},{"name":"Duration","unit":"GB-seconds","hourlyQuantity":null,"monthlyQuantity":null,"price":"0.0012357988","hourlyCost":null,"monthlyCost":null}]}],"totalHourlyCost":"75.431651854684931067041262","totalMonthlyCost":"55065.10585392"},"diff":{"resources":[{"name":"aws_instance.web_app","metadata":{},"hourlyCost":"75.431651854684931067041262","monthlyCost":"55065.10585392","costComponents":[{"name":"Instance usage (Linux/UNIX, on-demand, m5.4xlarge)","unit":"hours","hourlyQuantity":"1","monthlyQuantity":"730","price":"56.945493504","hourlyCost":"56.945493504","monthlyCost":"41570.21025792"}],"subresources":[{"name":"root_block_device","metadata":{},"hourlyCost":"0.5078614931506848807207","monthlyCost":"370.73889","costComponents":[{"name":"Storage (general purpose SSD, gp2)","unit":"GB","hourlyQuantity":"0.0684931506849315","monthlyQuantity":"50","price":"7.4147778","hourlyCost":"0.5078614931506848807207","monthlyCost":"370.73889"}]},{"name":"ebs_block_device[0]","metadata":{},"hourlyCost":"17.978296857534246186320562","monthlyCost":"13124.156706","costComponents":[{"name":"Storage (provisioned IOPS SSD, io1)","unit":"GB","hourlyQuantity":"1.3698630136986301","monthlyQuantity":"1000","price":"9.26847225","hourlyCost":"12.696537328767122944864725","monthlyCost":"9268.47225"},{"name":"Provisioned IOPS","unit":"IOPS","hourlyQuantity":"1.0958904109589041","monthlyQuantity":"800","price":"4.81960557","hourlyCost":"5.281759528767123241455837","monthlyCost":"3855.684456"}]}]},{"name":"aws_lambda_function.hello_world","metadata":{},"hourlyCost":"0","monthlyCost":"0","costComponents":[{"name":"Requests","unit":"1M requests","hourlyQuantity":"0","monthlyQuantity":"0","price":"14.8296","hourlyCost":"0","monthlyCost":"0"},{"name":"Duration","unit":"GB-seconds","hourlyQuantity":"0","monthlyQuantity":"0","price":"0.0012357988","hourlyCost":"0","monthlyCost":"0"}]}],"totalHourlyCost":"75.431651854684931067041262","totalMonthlyCost":"55065.10585392"},"summary":{"totalDetectedResources":2,"totalSupportedResources":2,"totalUnsupportedResources":0,"totalUsageBasedResources":2,"totalNoPriceResources":0,"unsupportedResourceCounts":{},"noPriceResourceCounts":{}}}],"totalHourlyCost":"75.431651854684931067041262","totalMonthlyCost":"55065.10585392","pastTotalHourlyCost":"0","pastTotalMonthlyCost":"0","diffTotalHourlyCost":"75.431651854684931067041262","diffTotalMonthlyCost":"55065.10585392","timeGenerated":"2021-11-18T12:47:42.828989-05:00","summary":{"totalDetectedResources":2,"totalSupportedResources":2,"totalUnsupportedResources":0,"totalUsageBasedResources":2,"totalNoPriceResources":0,"unsupportedResourceCounts":{},"noPriceResourceCounts":{}}} diff --git a/testdata/multi-project-config-file_comment_golden.md b/testdata/multi-project-config-file_comment_golden.md index ab3e81d..d288628 100644 --- a/testdata/multi-project-config-file_comment_golden.md +++ b/testdata/multi-project-config-file_comment_golden.md @@ -1,5 +1,5 @@ -šŸ’° Infracost estimate: **monthly cost will increase by $800 šŸ“ˆ** +šŸ’° Infracost estimate: **monthly cost will increase by $586 (+73%) šŸ“ˆ** @@ -9,22 +9,22 @@ - - + - + + - - + - + + - - + +
Project
infracost/actions/examples/multi-project/code/dev$0infracost/actions/examples/multi-project-config-file/code/dev $51.97+$51.97$77.37+$25.40 (+49%)
infracost/actions/examples/multi-project/code/prod$0infracost/actions/examples/multi-project-config-file/code/prod $748+$748$1,308+$561 (+75%)
All projects$0 $800+$800$1,386+$586 (+73%)
@@ -33,76 +33,30 @@ Infracost output ``` -Project: infracost/actions/examples/multi-project/code/dev +Project: infracost/actions/examples/multi-project-config-file/code/dev -+ module.base.aws_instance.web_app - +$51.97 +~ module.base.aws_instance.web_app + +$25.40 ($51.97 ā†’ $77.37) - + Instance usage (Linux/UNIX, on-demand, t2.micro) - +$8.47 + ~ Instance usage (Linux/UNIX, on-demand, t2.micro ā†’ t2.medium) + +$25.40 ($8.47 ā†’ $33.87) - + root_block_device - - + Storage (general purpose SSD, gp2) - +$5.00 - - + ebs_block_device[0] - - + Storage (provisioned IOPS SSD, io1) - +$12.50 - - + Provisioned IOPS - +$26.00 - -+ module.base.aws_lambda_function.hello_world - Monthly cost depends on usage - - + Requests - Monthly cost depends on usage - +$0.20 per 1M requests - - + Duration - Monthly cost depends on usage - +$0.0000166667 per GB-seconds - -Monthly cost change for infracost/actions/examples/multi-project/code/dev -Amount: +$51.97 ($0.00 ā†’ $51.97) +Monthly cost change for infracost/actions/examples/multi-project-config-file/code/dev +Amount: +$25.40 ($51.97 ā†’ $77.37) +Percent: +49% ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ -Project: infracost/actions/examples/multi-project/code/prod - -+ module.base.aws_instance.web_app - +$748 - - + Instance usage (Linux/UNIX, on-demand, m5.4xlarge) - +$561 - - + root_block_device - - + Storage (general purpose SSD, gp2) - +$10.00 - - + ebs_block_device[0] - - + Storage (provisioned IOPS SSD, io1) - +$125 - - + Provisioned IOPS - +$52.00 - -+ module.base.aws_lambda_function.hello_world - Monthly cost depends on usage +Project: infracost/actions/examples/multi-project-config-file/code/prod - + Requests - Monthly cost depends on usage - +$0.20 per 1M requests +~ module.base.aws_instance.web_app + +$561 ($748 ā†’ $1,308) - + Duration - Monthly cost depends on usage - +$0.0000166667 per GB-seconds + ~ Instance usage (Linux/UNIX, on-demand, m5.4xlarge ā†’ m5.8xlarge) + +$561 ($561 ā†’ $1,121) -Monthly cost change for infracost/actions/examples/multi-project/code/prod -Amount: +$748 ($0.00 ā†’ $748) +Monthly cost change for infracost/actions/examples/multi-project-config-file/code/prod +Amount: +$561 ($748 ā†’ $1,308) +Percent: +75% ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ Key: ~ changed, + added, - removed diff --git a/testdata/multi-project-matrix-merge_comment_golden.md b/testdata/multi-project-matrix-merge_comment_golden.md index ab3e81d..e6c8769 100644 --- a/testdata/multi-project-matrix-merge_comment_golden.md +++ b/testdata/multi-project-matrix-merge_comment_golden.md @@ -9,13 +9,13 @@ - infracost/actions/examples/multi-project/code/dev + infracost/actions/examples/terraform-project/code/dev/plan.json $0 $51.97 +$51.97 - infracost/actions/examples/multi-project/code/prod + infracost/actions/examples/terraform-project/code/prod/plan.json $0 $748 +$748 @@ -33,7 +33,7 @@ Infracost output ``` -Project: infracost/actions/examples/multi-project/code/dev +Project: infracost/actions/examples/terraform-project/code/dev/plan.json + module.base.aws_instance.web_app +$51.97 @@ -65,11 +65,11 @@ Project: infracost/actions/examples/multi-project/code/dev Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/multi-project/code/dev +Monthly cost change for infracost/actions/examples/terraform-project/code/dev/plan.json Amount: +$51.97 ($0.00 ā†’ $51.97) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ -Project: infracost/actions/examples/multi-project/code/prod +Project: infracost/actions/examples/terraform-project/code/prod/plan.json + module.base.aws_instance.web_app +$748 @@ -101,7 +101,7 @@ Project: infracost/actions/examples/multi-project/code/prod Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/multi-project/code/prod +Monthly cost change for infracost/actions/examples/terraform-project/code/prod/plan.json Amount: +$748 ($0.00 ā†’ $748) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ diff --git a/testdata/terragrunt_comment_golden.md b/testdata/multi-workspace-matrix-merge_comment_golden.md similarity index 82% rename from testdata/terragrunt_comment_golden.md rename to testdata/multi-workspace-matrix-merge_comment_golden.md index 4925859..aca7a06 100644 --- a/testdata/terragrunt_comment_golden.md +++ b/testdata/multi-workspace-matrix-merge_comment_golden.md @@ -9,13 +9,13 @@ - infracost/actions/examples/terragrunt/code/dev + infracost/actions/examples/plan...pace-matrix/code/dev-plan.json $0 $51.97 +$51.97 - infracost/actions/examples/terragrunt/code/prod + infracost/actions/examples/plan...ace-matrix/code/prod-plan.json $0 $748 +$748 @@ -33,7 +33,7 @@ Infracost output ``` -Project: infracost/actions/examples/terragrunt/code/dev +Project: infracost/actions/examples/plan-json/multi-workspace-matrix/code/dev-plan.json + aws_instance.web_app +$51.97 @@ -65,11 +65,11 @@ Project: infracost/actions/examples/terragrunt/code/dev Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/terragrunt/code/dev +Monthly cost change for infracost/actions/examples/plan-json/multi-workspace-matrix/code/dev-plan.json Amount: +$51.97 ($0.00 ā†’ $51.97) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ -Project: infracost/actions/examples/terragrunt/code/prod +Project: infracost/actions/examples/plan-json/multi-workspace-matrix/code/prod-plan.json + aws_instance.web_app +$748 @@ -101,7 +101,7 @@ Project: infracost/actions/examples/terragrunt/code/prod Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/terragrunt/code/prod +Monthly cost change for infracost/actions/examples/plan-json/multi-workspace-matrix/code/prod-plan.json Amount: +$748 ($0.00 ā†’ $748) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ diff --git a/testdata/private-terraform-module_comment_golden.md b/testdata/private-terraform-module_comment_golden.md index ea34386..d0d2ed3 100644 --- a/testdata/private-terraform-module_comment_golden.md +++ b/testdata/private-terraform-module_comment_golden.md @@ -1,5 +1,5 @@ -šŸ’° Infracost estimate: **monthly cost will increase by $11.37 šŸ“ˆ** +šŸ’° Infracost estimate: **monthly cost will increase by $25.40 (+223%) šŸ“ˆ** @@ -10,9 +10,9 @@ - - + +
Project
infracost/actions/examples/private-terraform-module/code$0 $11.37+$11.37$36.77+$25.40 (+223%)
@@ -23,22 +23,15 @@ ``` Project: infracost/actions/examples/private-terraform-module/code -+ module.ec2_cluster.aws_instance.this[0] - +$11.37 +~ module.ec2_cluster.aws_instance.this[0] + +$25.40 ($11.37 ā†’ $36.77) - + Instance usage (Linux/UNIX, on-demand, t2.micro) - +$8.47 - - + EC2 detailed monitoring - +$2.10 - - + root_block_device - - + Storage (general purpose SSD, gp2) - +$0.80 + ~ Instance usage (Linux/UNIX, on-demand, t2.micro ā†’ t2.medium) + +$25.40 ($8.47 ā†’ $33.87) Monthly cost change for infracost/actions/examples/private-terraform-module/code -Amount: +$11.37 ($0.00 ā†’ $11.37) +Amount: +$25.40 ($11.37 ā†’ $36.77) +Percent: +223% ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ Key: ~ changed, + added, - removed diff --git a/testdata/slack_comment_golden.md b/testdata/slack_comment_golden.md index 402ca4a..90a42d1 100644 --- a/testdata/slack_comment_golden.md +++ b/testdata/slack_comment_golden.md @@ -1,5 +1,5 @@ -šŸ’° Infracost estimate: **monthly cost will increase by $743 šŸ“ˆ** +šŸ’° Infracost estimate: **monthly cost will increase by $586 (+73%) šŸ“ˆ** @@ -9,10 +9,22 @@ - - - - + + + + + + + + + + + + + + + +
Project
infracost/actions/examples/slack/code/plan.json$0$743+$743infracost/actions/examples/terraform-project/code/dev$51.97$77.37+$25.40 (+49%)
infracost/actions/examples/terraform-project/code/prod$748$1,308+$561 (+75%)
All projects$800$1,386+$586 (+73%)
@@ -21,46 +33,36 @@ Infracost output ``` -Project: infracost/actions/examples/slack/code/plan.json - -+ aws_instance.web_app - +$743 +Project: infracost/actions/examples/terraform-project/code/dev - + Instance usage (Linux/UNIX, on-demand, m5.4xlarge) - +$561 +~ module.base.aws_instance.web_app + +$25.40 ($51.97 ā†’ $77.37) - + root_block_device - - + Storage (general purpose SSD, gp2) - +$5.00 + ~ Instance usage (Linux/UNIX, on-demand, t2.micro ā†’ t2.medium) + +$25.40 ($8.47 ā†’ $33.87) - + ebs_block_device[0] - - + Storage (provisioned IOPS SSD, io1) - +$125 - - + Provisioned IOPS - +$52.00 +Monthly cost change for infracost/actions/examples/terraform-project/code/dev +Amount: +$25.40 ($51.97 ā†’ $77.37) +Percent: +49% -+ aws_lambda_function.hello_world - Monthly cost depends on usage +ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ +Project: infracost/actions/examples/terraform-project/code/prod - + Requests - Monthly cost depends on usage - +$0.20 per 1M requests +~ module.base.aws_instance.web_app + +$561 ($748 ā†’ $1,308) - + Duration - Monthly cost depends on usage - +$0.0000166667 per GB-seconds + ~ Instance usage (Linux/UNIX, on-demand, m5.4xlarge ā†’ m5.8xlarge) + +$561 ($561 ā†’ $1,121) -Monthly cost change for infracost/actions/examples/slack/code/plan.json -Amount: +$743 ($0.00 ā†’ $743) +Monthly cost change for infracost/actions/examples/terraform-project/code/prod +Amount: +$561 ($748 ā†’ $1,308) +Percent: +75% ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ Key: ~ changed, + added, - removed -2 cloud resources were detected: -āˆ™ 2 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file +4 cloud resources were detected: +āˆ™ 4 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file ``` diff --git a/testdata/slack_slack_message_golden.json b/testdata/slack_slack_message_golden.json index 1b04a44..d0340e4 100644 --- a/testdata/slack_slack_message_golden.json +++ b/testdata/slack_slack_message_golden.json @@ -1,49 +1 @@ -{ - "attachments": [ - { - "blocks": [ - { - "text": { - "text": "*Infracost output*\n```Project: infracost/actions/examples/slack/code/plan.json\n\n+ aws_instance.web_app\n +$743\n\n + Instance usage (Linux/UNIX, on-demand, m5.4xlarge)\n +$561\n\n + root_block_device\n \n + Storage (general purpose SSD, gp2)\n +$5.00\n\n + ebs_block_device[0]\n \n + Storage (provisioned IOPS SSD, io1)\n +$125\n \n + Provisioned IOPS\n +$52.00\n\n+ aws_lambda_function.hello_world\n Monthly cost depends on usage\n\n + Requests\n Monthly cost depends on usage\n +$0.20 per 1M requests\n\n + Duration\n Monthly cost depends on usage\n +$0.0000166667 per GB-seconds\n\nMonthly cost change for infracost/actions/examples/slack/code/plan.json\nAmount: +$743 ($0.00 ā†’ $743)\n\nā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€\nKey: ~ changed, + added, - removed\n\n2 cloud resources were detected:\nāˆ™ 2 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file```", - "type": "mrkdwn" - }, - "type": "section" - } - ], - "color": "#dcd8e1" - } - ], - "blocks": [ - { - "text": { - "text": "šŸ’° Infracost estimate: *monthly cost will increase by $743 šŸ“ˆ*", - "type": "mrkdwn" - }, - "type": "section" - }, - { - "type": "divider" - }, - { - "fields": [ - { - "text": "Project", - "type": "plain_text" - }, - { - "text": "Diff", - "type": "plain_text" - }, - { - "text": "infracost/actions/ex...lack/code/plan.json", - "type": "plain_text" - }, - { - "text": "+$743 ($0.00 ā†’ $743)", - "type": "plain_text" - } - ], - "type": "section" - } - ] -} +{"attachments":[{"color":"#dcd8e1","blocks":[{"type":"section","text":{"type":"mrkdwn","text":"*Infracost output*\n```Project: infracost/actions/examples/terraform-project/code/dev\n\n~ module.base.aws_instance.web_app\n +$25.40 ($51.97 ā†’ $77.37)\n\n ~ Instance usage (Linux/UNIX, on-demand, t2.micro ā†’ t2.medium)\n +$25.40 ($8.47 ā†’ $33.87)\n\nMonthly cost change for infracost/actions/examples/terraform-project/code/dev\nAmount: +$25.40 ($51.97 ā†’ $77.37)\nPercent: +49%\n\nā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€\nProject: infracost/actions/examples/terraform-project/code/prod\n\n~ module.base.aws_instance.web_app\n +$561 ($748 ā†’ $1,308)\n\n ~ Instance usage (Linux/UNIX, on-demand, m5.4xlarge ā†’ m5.8xlarge)\n +$561 ($561 ā†’ $1,121)\n\nMonthly cost change for infracost/actions/examples/terraform-project/code/prod\nAmount: +$561 ($748 ā†’ $1,308)\nPercent: +75%\n\nā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€\nKey: ~ changed, + added, - removed\n\n4 cloud resources were detected:\nāˆ™ 4 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file```"}}]}],"blocks":[{"type":"section","text":{"type":"mrkdwn","text":"šŸ’° Infracost estimate: *monthly cost will increase by $586 (+73%) šŸ“ˆ*"}},{"type":"divider"},{"type":"section","fields":[{"type":"plain_text","text":"Project"},{"type":"plain_text","text":"Diff"},{"type":"plain_text","text":"infracost/actions/ex...rm-project/code/dev"},{"type":"plain_text","text":"+$25.40 ($51.97 ā†’ $77.37)"},{"type":"plain_text","text":"infracost/actions/ex...m-project/code/prod"},{"type":"plain_text","text":"+$561 ($748 ā†’ $1,308)"},{"type":"plain_text","text":"All projects"},{"type":"plain_text","text":"+$586 ($800 ā†’ $1,386)"}]}]} diff --git a/testdata/terraform-cloud-enterprise_comment_golden.md b/testdata/terraform-cloud-enterprise_comment_golden.md index 79e8fd0..5c41031 100644 --- a/testdata/terraform-cloud-enterprise_comment_golden.md +++ b/testdata/terraform-cloud-enterprise_comment_golden.md @@ -9,7 +9,7 @@ - infracost/actions/examples/terraform-cloud-enterprise/code + infracost/actions/examples/plan...loud-enterprise/code/plan.json $0 $743 +$743 @@ -21,7 +21,7 @@ Infracost output ``` -Project: infracost/actions/examples/terraform-cloud-enterprise/code +Project: infracost/actions/examples/plan-json/terraform-cloud-enterprise/code/plan.json + aws_instance.web_app +$743 @@ -53,7 +53,7 @@ Project: infracost/actions/examples/terraform-cloud-enterprise/code Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/terraform-cloud-enterprise/code +Monthly cost change for infracost/actions/examples/plan-json/terraform-cloud-enterprise/code/plan.json Amount: +$743 ($0.00 ā†’ $743) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ diff --git a/testdata/terraform-directory_comment_golden.md b/testdata/terraform-directory_comment_golden.md deleted file mode 100644 index 69cd58d..0000000 --- a/testdata/terraform-directory_comment_golden.md +++ /dev/null @@ -1,73 +0,0 @@ - -šŸ’° Infracost estimate: **monthly cost will increase by $743 šŸ“ˆ** - - - - - - - - - - - - - - - -
ProjectPreviousNewDiff
infracost/actions/examples/terraform-directory/code$0$743+$743
- -
-Infracost output - -``` -Project: infracost/actions/examples/terraform-directory/code - -+ aws_instance.web_app - +$743 - - + Instance usage (Linux/UNIX, on-demand, m5.4xlarge) - +$561 - - + root_block_device - - + Storage (general purpose SSD, gp2) - +$5.00 - - + ebs_block_device[0] - - + Storage (provisioned IOPS SSD, io1) - +$125 - - + Provisioned IOPS - +$52.00 - -+ aws_lambda_function.hello_world - Monthly cost depends on usage - - + Requests - Monthly cost depends on usage - +$0.20 per 1M requests - - + Duration - Monthly cost depends on usage - +$0.0000166667 per GB-seconds - -Monthly cost change for infracost/actions/examples/terraform-directory/code -Amount: +$743 ($0.00 ā†’ $743) - -ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ -Key: ~ changed, + added, - removed - -2 cloud resources were detected: -āˆ™ 2 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file -``` -
- -This comment will be updated when the cost estimate changes. - - - Is this comment useful? Yes, No - - -Comment not posted to GitHub (--dry-run was specified) diff --git a/testdata/terraform-plan-json_comment_golden.md b/testdata/terraform-plan-json_comment_golden.md deleted file mode 100644 index 2a3afb6..0000000 --- a/testdata/terraform-plan-json_comment_golden.md +++ /dev/null @@ -1,73 +0,0 @@ - -šŸ’° Infracost estimate: **monthly cost will increase by $743 šŸ“ˆ** - - - - - - - - - - - - - - - -
ProjectPreviousNewDiff
infracost/actions/examples/terraform-plan-json/code/plan.json$0$743+$743
- -
-Infracost output - -``` -Project: infracost/actions/examples/terraform-plan-json/code/plan.json - -+ aws_instance.web_app - +$743 - - + Instance usage (Linux/UNIX, on-demand, m5.4xlarge) - +$561 - - + root_block_device - - + Storage (general purpose SSD, gp2) - +$5.00 - - + ebs_block_device[0] - - + Storage (provisioned IOPS SSD, io1) - +$125 - - + Provisioned IOPS - +$52.00 - -+ aws_lambda_function.hello_world - Monthly cost depends on usage - - + Requests - Monthly cost depends on usage - +$0.20 per 1M requests - - + Duration - Monthly cost depends on usage - +$0.0000166667 per GB-seconds - -Monthly cost change for infracost/actions/examples/terraform-plan-json/code/plan.json -Amount: +$743 ($0.00 ā†’ $743) - -ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ -Key: ~ changed, + added, - removed - -2 cloud resources were detected: -āˆ™ 2 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file -``` -
- -This comment will be updated when the cost estimate changes. - - - Is this comment useful? Yes, No - - -Comment not posted to GitHub (--dry-run was specified) diff --git a/testdata/terraform-project_comment_golden.md b/testdata/terraform-project_comment_golden.md new file mode 100644 index 0000000..90a42d1 --- /dev/null +++ b/testdata/terraform-project_comment_golden.md @@ -0,0 +1,75 @@ + +šŸ’° Infracost estimate: **monthly cost will increase by $586 (+73%) šŸ“ˆ** + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProjectPreviousNewDiff
infracost/actions/examples/terraform-project/code/dev$51.97$77.37+$25.40 (+49%)
infracost/actions/examples/terraform-project/code/prod$748$1,308+$561 (+75%)
All projects$800$1,386+$586 (+73%)
+ +
+Infracost output + +``` +Project: infracost/actions/examples/terraform-project/code/dev + +~ module.base.aws_instance.web_app + +$25.40 ($51.97 ā†’ $77.37) + + ~ Instance usage (Linux/UNIX, on-demand, t2.micro ā†’ t2.medium) + +$25.40 ($8.47 ā†’ $33.87) + +Monthly cost change for infracost/actions/examples/terraform-project/code/dev +Amount: +$25.40 ($51.97 ā†’ $77.37) +Percent: +49% + +ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ +Project: infracost/actions/examples/terraform-project/code/prod + +~ module.base.aws_instance.web_app + +$561 ($748 ā†’ $1,308) + + ~ Instance usage (Linux/UNIX, on-demand, m5.4xlarge ā†’ m5.8xlarge) + +$561 ($561 ā†’ $1,121) + +Monthly cost change for infracost/actions/examples/terraform-project/code/prod +Amount: +$561 ($748 ā†’ $1,308) +Percent: +75% + +ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ +Key: ~ changed, + added, - removed + +4 cloud resources were detected: +āˆ™ 4 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file +``` +
+ +This comment will be updated when the cost estimate changes. + + + Is this comment useful? Yes, No + + +Comment not posted to GitHub (--dry-run was specified) diff --git a/testdata/multi-terraform-workspace-config-file_comment_golden.md b/testdata/terragrunt-project_comment_golden.md similarity index 84% rename from testdata/multi-terraform-workspace-config-file_comment_golden.md rename to testdata/terragrunt-project_comment_golden.md index c665ce0..2965776 100644 --- a/testdata/multi-terraform-workspace-config-file_comment_golden.md +++ b/testdata/terragrunt-project_comment_golden.md @@ -9,13 +9,13 @@ - infracost/actions/examples/multi-terraform-workspace/code (dev) + infracost/actions/examples/plan.../terragrunt/code/dev/plan.json $0 $51.97 +$51.97 - infracost/actions/examples/multi-terraform-workspace/code (prod) + infracost/actions/examples/plan...terragrunt/code/prod/plan.json $0 $748 +$748 @@ -33,7 +33,7 @@ Infracost output ``` -Project: infracost/actions/examples/multi-terraform-workspace/code (dev) +Project: infracost/actions/examples/plan-json/terragrunt/code/dev/plan.json + aws_instance.web_app +$51.97 @@ -65,11 +65,11 @@ Project: infracost/actions/examples/multi-terraform-workspace/code (dev) Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/multi-terraform-workspace/code (dev) +Monthly cost change for infracost/actions/examples/plan-json/terragrunt/code/dev/plan.json Amount: +$51.97 ($0.00 ā†’ $51.97) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ -Project: infracost/actions/examples/multi-terraform-workspace/code (prod) +Project: infracost/actions/examples/plan-json/terragrunt/code/prod/plan.json + aws_instance.web_app +$748 @@ -101,7 +101,7 @@ Project: infracost/actions/examples/multi-terraform-workspace/code (prod) Monthly cost depends on usage +$0.0000166667 per GB-seconds -Monthly cost change for infracost/actions/examples/multi-terraform-workspace/code (prod) +Monthly cost change for infracost/actions/examples/plan-json/terragrunt/code/prod/plan.json Amount: +$748 ($0.00 ā†’ $748) ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€