diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 7a1b9bbe..5520e0a1 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -25,22 +25,19 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml < ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_md_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_summary_md_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: "${{ fromJSON(steps.metadata.outputs.file_md) }}" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.files_json_count }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(steps.metadata.outputs.file_json) }}" expected: | { "stack": "plat-ue2-sandbox", "component": "foobar/changes", "componentPath": "tests/components/terraform/foobar", "drifted": true, "error": false } - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: | @@ -163,7 +162,7 @@ jobs: --- ### Create ```diff - + random_id.foo + + random_id.foo[0] ``` @@ -173,7 +172,7 @@ jobs: ```hcl - # random_id.foo will be created + # random_id.foo[0] will be created + resource "random_id" "foo" { + b64_std = (known after apply) + b64_url = (known after apply) diff --git a/.github/workflows/test-changes-exists.yml b/.github/workflows/test-changes-exists.yml index ec9ba0f9..ae260fce 100644 --- a/.github/workflows/test-changes-exists.yml +++ b/.github/workflows/test-changes-exists.yml @@ -30,18 +30,15 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: | @@ -105,7 +103,7 @@ jobs: --- ### Create ```diff - + random_id.foo + + random_id.foo[0] ``` @@ -114,7 +112,7 @@ jobs: ```hcl - # random_id.foo will be created + # random_id.foo[0] will be created + resource "random_id" "foo" { + b64_std = (known after apply) + b64_url = (known after apply) diff --git a/.github/workflows/test-failed-plan-drift.yml b/.github/workflows/test-failed-plan-drift.yml index bdd32ccf..461949da 100644 --- a/.github/workflows/test-failed-plan-drift.yml +++ b/.github/workflows/test-failed-plan-drift.yml @@ -30,18 +30,16 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_md_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: "${{ fromJSON(steps.metadata.outputs.file_md) }}" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(steps.metadata.outputs.file_json) }}" expected: | { "stack": "plat-ue2-sandbox", "component": "foobar-fail", "componentPath": "tests/components/terraform/foobar", "drifted": false, "error": true } - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: | @@ -147,8 +146,8 @@ jobs: ```hcl Error: Invalid function argument - on main.tf line 16, in locals: - 16: failure = var.enable_failure ? file("Failed because failure mode is enabled") : null + on main.tf line 17, in locals: + 17: failure = var.enabled && var.enable_failure ? file("Failed because failure mode is enabled") : null ├──────────────── │ while calling file(path) diff --git a/.github/workflows/test-failed-plan.yml b/.github/workflows/test-failed-plan.yml index 8d39542a..ca2656fa 100644 --- a/.github/workflows/test-failed-plan.yml +++ b/.github/workflows/test-failed-plan.yml @@ -30,18 +30,16 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: | @@ -105,8 +104,8 @@ jobs: ```hcl Error: Invalid function argument - on main.tf line 16, in locals: - 16: failure = var.enable_failure ? file("Failed because failure mode is enabled") : null + on main.tf line 17, in locals: + 17: failure = var.enabled && var.enable_failure ? file("Failed because failure mode is enabled") : null ├──────────────── │ while calling file(path) diff --git a/.github/workflows/test-infra-cost.yml b/.github/workflows/test-infra-cost.yml index c38501f2..df250330 100644 --- a/.github/workflows/test-infra-cost.yml +++ b/.github/workflows/test-infra-cost.yml @@ -30,19 +30,16 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: | @@ -109,7 +107,7 @@ jobs: --- ### Create ```diff - + random_id.foo + + random_id.foo[0] ``` @@ -118,7 +116,7 @@ jobs: ```hcl - # random_id.foo will be created + # random_id.foo[0] will be created + resource "random_id" "foo" { + b64_std = (known after apply) + b64_url = (known after apply) diff --git a/.github/workflows/test-no-changes-drift-more.yml b/.github/workflows/test-no-changes-drift-more.yml index 26552815..945ea2ea 100644 --- a/.github/workflows/test-no-changes-drift-more.yml +++ b/.github/workflows/test-no-changes-drift-more.yml @@ -30,19 +30,15 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_exists }}" expected: "0" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.file_md_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(steps.metadata.outputs.file_json) }}" expected: | { "stack": "plat-ue2-sandbox", "component": "foobar", "componentPath": "tests/components/terraform/foobar", "drifted": false, "error": false } - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: "" diff --git a/.github/workflows/test-no-changes.yml b/.github/workflows/test-no-changes.yml index fa13cd08..74c9c0bd 100644 --- a/.github/workflows/test-no-changes.yml +++ b/.github/workflows/test-no-changes.yml @@ -30,19 +30,15 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" - expected: "" + expected: | + ## Changes Found for `foobar` in `plat-ue2-sandbox` + + + [![no changes](https://shields.io/badge/-NO_CHANGE-inactive?style=for-the-badge)](#user-content-plat-ue2-sandbox-foobar) + + + +
No changes. Your infrastructure matches the configuration. + +
+ To reproduce this locally, run:

+ + ```shell + atmos terraform plan foobar -s plat-ue2-sandbox + ``` + + + + + --- + +
teardown: runs-on: ubuntu-latest diff --git a/.github/workflows/test-settings-action-disabled-drift.yml b/.github/workflows/test-settings-action-disabled-drift.yml index 77d59545..9613aca3 100644 --- a/.github/workflows/test-settings-action-disabled-drift.yml +++ b/.github/workflows/test-settings-action-disabled-drift.yml @@ -30,19 +30,15 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: "" diff --git a/.github/workflows/test-settings-action-disabled.yml b/.github/workflows/test-settings-action-disabled.yml index 3d8ccb58..80aae2bd 100644 --- a/.github/workflows/test-settings-action-disabled.yml +++ b/.github/workflows/test-settings-action-disabled.yml @@ -30,19 +30,15 @@ jobs: - shell: bash run: | mkdir -p ${{ runner.temp }} - cat > ${{ runner.temp }}/atmos-gitops.yaml <> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ steps.metadata.outputs.dir_exists }}" expected: "1" - - uses: nick-fields/assert-action@v1 + - uses: nick-fields/assert-action@v2 with: actual: "${{ fromJSON(needs.test.outputs.summary) }}" expected: "" diff --git a/README.md b/README.md index 353833bf..6689a65e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,8 @@ - -# github-action-atmos-terraform-plan [![Latest Release](https://img.shields.io/github/release/cloudposse/github-action-atmos-terraform-plan.svg)](https://github.com/cloudposse/github-action-atmos-terraform-plan/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) +# github-action-atmos-terraform-plan +Latest ReleaseSlack Community -[![README Header][readme_header_img]][readme_header_link] - -[![Cloud Posse][logo]](https://cpco.io/homepage) - - [logo]: https://cloudposse.com/logo-300x69.svg - [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=docs - [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=website - [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=github - [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=jobs - [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=hire - [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=slack - [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=twitter - [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=office_hours - [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=newsletter - [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=email - [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=commercial_support - [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=we_love_open_source - [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=terraform_modules - [readme_header_img]: https://cloudposse.com/readme/header/img - [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=readme_header_link - [readme_footer_img]: https://cloudposse.com/readme/footer/img - [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=readme_footer_link - [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img - [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/github-action-atmos-terraform-plan&utm_content=readme_commercial_support_link - [beacon]: https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/github-action-atmos-terraform-plan?pixel&cs=github&cm=readme&an=github-action-atmos-terraform-plan - +Copyright © 2017-2024 [Cloud Posse, LLC](https://cpco.io/copyright) + + +README footer + +Beacon diff --git a/README.yaml b/README.yaml index dd8a3ad4..f6cd8cb3 100644 --- a/README.yaml +++ b/README.yaml @@ -55,26 +55,30 @@ usage: |- ### Config - The action expects the atmos gitops configuration file to be present in the repository in `./.github/config/atmos-gitops.yaml`. + The action expects the atmos configuration file `atmos.yaml` to be present in the repository. The config should have the following structure: ```yaml - atmos-version: 1.45.3 - atmos-config-path: ./rootfs/usr/local/etc/atmos/ - terraform-state-bucket: cptest-core-ue2-auto-gitops - terraform-state-table: cptest-core-ue2-auto-gitops - terraform-state-role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha - terraform-plan-role: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops - terraform-apply-role: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops - terraform-version: 1.5.2 - aws-region: us-east-2 - enable-infracost: false - sort-by: .stack_slug - group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-") + integrations: + github: + gitops: + terraform-version: 1.5.2 + infracost-enabled: false + artifact-storage: + region: us-east-2 + bucket: cptest-core-ue2-auto-gitops + table: cptest-core-ue2-auto-gitops-plan-storage + role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha + role: + plan: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops + apply: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops + matrix: + sort-by: .stack_slug + group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-") ``` - + > [!IMPORTANT] - > **Please note!** the `terraform-state-*` parameters refer to the S3 Bucket and corresponding meta storage DynamoDB table used to store the Terraform Plan files, and not the "Terraform State". These parameters will be renamed in a subsequent release. + > **Please note!** This GitHub Action only works with `atmos >= 1.63.0`. If you are using `atmos < 1.63.0` please use `v1` version of this action. ### Workflow example @@ -102,19 +106,111 @@ usage: |- runs-on: ubuntu-latest steps: - name: Plan Atmos Component - uses: cloudposse/github-action-atmos-terraform-plan@v1 + uses: cloudposse/github-action-atmos-terraform-plan@v2 with: component: "foobar" stack: "plat-ue2-sandbox" - component-path: "components/terraform/s3-bucket" - terraform-plan-role: "arn:aws:iam::111111111111:role/acme-core-gbl-identity-gitops" - terraform-state-bucket: "acme-core-ue2-auto-gitops" - terraform-state-role: "arn:aws:iam::999999999999:role/acme-core-ue2-auto-gitops-gha" - terraform-state-table: "acme-core-ue2-auto-gitops" - aws-region: "us-east-2" + atmos-config-path: ./rootfs/usr/local/etc/atmos/ + atmos-version: 1.63.0 + ``` + + ### Migrating from `v1` to `v2` + + The notable changes in `v2` are: + - `v2` works only with `atmos >= 1.63.0` + - `v2` drops `install-terraform` input because terraform is not required for affected stacks call + - `v2` drops `atmos-gitops-config-path` input and the `./.github/config/atmos-gitops.yaml` config file. Now you have to use GitHub Actions environment variables to specify the location of the `atmos.yaml`. + + The following configuration fields now moved to GitHub action inputs with the same names + + | name | + |-------------------------| + | `atmos-version` | + | `atmos-config-path` | + + + The following configuration fields moved to the `atmos.yaml` configuration file. + + | name | YAML path in `atmos.yaml` | + |--------------------------|-------------------------------------------------| + | `aws-region` | `integrations.github.gitops.artifact-storage.region` | + | `terraform-state-bucket` | `integrations.github.gitops.artifact-storage.bucket` | + | `terraform-state-table` | `integrations.github.gitops.artifact-storage.table` | + | `terraform-state-role` | `integrations.github.gitops.artifact-storage.role` | + | `terraform-plan-role` | `integrations.github.gitops.role.plan` | + | `terraform-apply-role` | `integrations.github.gitops.role.apply` | + | `terraform-version` | `integrations.github.gitops.terraform-version` | + | `enable-infracost` | `integrations.github.gitops.infracost-enabled` | + | `sort-by` | `integrations.github.gitops.matrix.sort-by` | + | `group-by` | `integrations.github.gitops.matrix.group-by` | + + + For example, to migrate from `v1` to `v2`, you should have something similar to the following in your `atmos.yaml`: + + `./.github/config/atmos.yaml` + ```yaml + # ... your existing configuration + + integrations: + github: + gitops: + terraform-version: 1.5.2 + infracost-enabled: false + artifact-storage: + region: us-east-2 + bucket: cptest-core-ue2-auto-gitops + table: cptest-core-ue2-auto-gitops-plan-storage + role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha + role: + plan: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops + apply: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops + matrix: + sort-by: .stack_slug + group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-") ``` + `.github/workflows/main.yaml` + ```yaml + - name: Plan Atmos Component + uses: cloudposse/github-action-atmos-terraform-plan@v2 + with: + component: "foobar" + stack: "plat-ue2-sandbox" + atmos-config-path: ./rootfs/usr/local/etc/atmos/ + atmos-version: 1.63.0 + ``` + + This corresponds to the `v1` configuration (deprecated) below. + + The `v1` configuration file `./.github/config/atmos-gitops.yaml` looked like this: + ```yaml + atmos-version: 1.45.3 + atmos-config-path: ./rootfs/usr/local/etc/atmos/ + terraform-state-bucket: cptest-core-ue2-auto-gitops + terraform-state-table: cptest-core-ue2-auto-gitops + terraform-state-role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha + terraform-plan-role: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops + terraform-apply-role: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops + terraform-version: 1.5.2 + aws-region: us-east-2 + enable-infracost: false + sort-by: .stack_slug + group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-") + ``` + + And the `v1` GitHub Action Workflow looked like this. + + `.github/workflows/main.yaml` + ```yaml + - name: Plan Atmos Component + uses: cloudposse/github-action-atmos-terraform-plan@v1 + with: + component: "foobar" + stack: "plat-ue2-sandbox" + atmos-gitops-config-path: ./.github/config/atmos-gitops.yaml + ``` + ### Migrating from `v1` to `v2` 1. `v2` drops the `component-path` variable and instead fetches if directly from the [`atmos.yaml` file](https://atmos.tools/cli/configuration/) automatically. Simply remove the `component-path` argument from your invocations of the `cloudposse/github-action-atmos-terraform-plan` action. diff --git a/action.yml b/action.yml index c973d601..b7cb8e0c 100644 --- a/action.yml +++ b/action.yml @@ -19,10 +19,13 @@ inputs: description: "Indicate whether this action is used in drift detection workflow." required: true default: 'false' - atmos-gitops-config-path: - description: The path to the atmos-gitops.yaml file + atmos-version: + description: The version of atmos to install required: false - default: ./.github/config/atmos-gitops.yaml + default: ">= 1.63.0" + atmos-config-path: + description: The path to the atmos.yaml file + required: true infracost-api-key: description: "Infracost API key" required: false @@ -59,18 +62,29 @@ runs: - name: Checkout uses: actions/checkout@v4 - - name: config - uses: cloudposse/github-action-config-levels@nodejs20 - id: config + - name: Set atmos cli config path vars + shell: bash + run: |- + echo "ATMOS_CLI_CONFIG_PATH=$(realpath ${{ inputs.atmos-config-path }})" >> $GITHUB_ENV + + - name: Install Atmos + uses: cloudposse/github-action-setup-atmos@v2 with: - output_properties: true - patterns: | - - ${{ inputs.atmos-gitops-config-path }} + atmos-version: ${{ inputs.atmos-version }} + token: ${{ inputs.token }} + install-wrapper: false - - name: Set atmos cli config path vars + - name: config shell: bash + id: config run: |- - echo "ATMOS_CLI_CONFIG_PATH=$(realpath ${{ steps.config.outputs.atmos-config-path }})" >> $GITHUB_ENV + echo "terraform-version=$(atmos describe config -f json | jq -r '.integrations.github.gitops["terraform-version"]')" >> $GITHUB_OUTPUT + echo "enable-infracost=$(atmos describe config -f json | jq -r '.integrations.github.gitops["infracost-enabled"]')" >> $GITHUB_OUTPUT + echo "aws-region=$(atmos describe config -f json | jq -r '.integrations.github.gitops["artifact-storage"].region')" >> $GITHUB_OUTPUT + echo "terraform-state-role=$(atmos describe config -f json | jq -r '.integrations.github.gitops["artifact-storage"].role')" >> $GITHUB_OUTPUT + echo "terraform-state-table=$(atmos describe config -f json | jq -r '.integrations.github.gitops["artifact-storage"].table')" >> $GITHUB_OUTPUT + echo "terraform-state-bucket=$(atmos describe config -f json | jq -r '.integrations.github.gitops["artifact-storage"].bucket')" >> $GITHUB_OUTPUT + echo "terraform-plan-role=$(atmos describe config -f json | jq -r '.integrations.github.gitops.role.plan')" >> $GITHUB_OUTPUT - name: Cache Dependencies id: cache-dependencies @@ -99,7 +113,7 @@ runs: - name: Install Terraform if: ${{ steps.cache-dependencies.outputs.cache-hit != 'true' }} - uses: hashicorp/setup-terraform@v2 + uses: hashicorp/setup-terraform@v3 with: terraform_version: ${{ steps.config.outputs.terraform-version }} terraform_wrapper: false @@ -166,6 +180,14 @@ runs: ATMOS_BASE_PATH="${{ steps.base-path.outputs.value }}" echo "ATMOS_BASE_PATH=$(realpath ${ATMOS_BASE_PATH:-./})" >> $GITHUB_ENV + + - name: Install tfcmt + if: ${{ steps.atmos-github-actions-enabled.outputs.value == 'true' }} + uses: jaxxstorm/action-install-gh-release@v1.11.0 + with: + repo: suzuki-shunsuke/tfcmt + tag: v4.6.0 + - name: Prepare Artifacts Directory if: ${{ steps.atmos-github-actions-enabled.outputs.value == 'true' }} shell: bash @@ -201,7 +223,7 @@ runs: - name: Configure Plan AWS Credentials if: ${{ steps.atmos-github-actions-enabled.outputs.value == 'true' }} - uses: aws-actions/configure-aws-credentials@v4.0.1 + uses: aws-actions/configure-aws-credentials@v4.0.2 with: aws-region: ${{ steps.config.outputs.aws-region }} role-to-assume: ${{ steps.config.outputs.terraform-plan-role }} @@ -215,31 +237,33 @@ runs: run: | set +e - TERRAFORM_OUTPUT=$( \ - tfcmt \ - --config ${{ github.action_path }}/config/summary.yaml \ - -owner "${{ github.repository_owner }}" \ - -repo "${{ github.event.repository.name }}" \ - -var "target:${{ steps.vars.outputs.component_slug }}" \ - -var "component:${{ inputs.component }}" \ - -var "componentPath:${{ steps.vars.outputs.component_path }}" \ - -var "commitSHA:${{ inputs.sha }}" \ - -var "stack:${{ inputs.stack }}" \ - -var "job:${{ github.job }}" \ - -var "logoImage:${{ inputs.branding-logo-image }}" \ - -var "logoUrl:${{ inputs.branding-logo-url }}" \ - -var "infracost_enabled:${{ steps.config.outputs.enable-infracost }}" \ - -var "driftModeEnabled:${{ inputs.drift-detection-mode-enabled }}" \ - --output ${{ steps.vars.outputs.summary_file }} \ - --log-level $([[ "${{ inputs.debug }}" == "true" ]] && echo "DEBUG" || echo "INFO") \ - plan -- \ - $(which atmos) terraform plan ${{ inputs.component }} \ - --stack ${{ inputs.stack }} \ - -out="${{ steps.vars.outputs.plan_file }}" \ - -lock=false \ - -input=false \ - -no-color - ) + TERRAFORM_OUTPUT_FILE="./terraform-${GITHUB_RUN_ID}-output.txt" + + tfcmt \ + --config ${{ github.action_path }}/config/summary.yaml \ + -owner "${{ github.repository_owner }}" \ + -repo "${{ github.event.repository.name }}" \ + -var "target:${{ steps.vars.outputs.component_slug }}" \ + -var "component:${{ inputs.component }}" \ + -var "componentPath:${{ steps.vars.outputs.component_path }}" \ + -var "commitSHA:${{ inputs.sha }}" \ + -var "stack:${{ inputs.stack }}" \ + -var "job:${{ github.job }}" \ + -var "logoImage:${{ inputs.branding-logo-image }}" \ + -var "logoUrl:${{ inputs.branding-logo-url }}" \ + -var "infracost_enabled:${{ steps.config.outputs.enable-infracost }}" \ + -var "driftModeEnabled:${{ inputs.drift-detection-mode-enabled }}" \ + --output ${{ steps.vars.outputs.summary_file }} \ + --log-level $([[ "${{ inputs.debug }}" == "true" ]] && echo "DEBUG" || echo "INFO") \ + plan -- \ + atmos terraform plan ${{ inputs.component }} \ + --stack ${{ inputs.stack }} \ + -out="${{ steps.vars.outputs.plan_file }}" \ + -lock=false \ + -input=false \ + -no-color \ + &> ${TERRAFORM_OUTPUT_FILE} + TERRAFORM_RESULT=$? set -e @@ -255,14 +279,14 @@ runs: fi echo "::group::Terraform Plan" - echo -ne "${TERRAFORM_OUTPUT}" + cat "${TERRAFORM_OUTPUT_FILE}" echo "::endgroup::" - + HAS_CHANGES=false HAS_NO_CHANGES=false HAS_ERROR=false if [[ "${TERRAFORM_RESULT}" == "0" ]]; then - if echo "$TERRAFORM_OUTPUT" | grep -q '^No changes. Your infrastructure matches the configuration.'; then + if grep -q '^No changes. Your infrastructure matches the configuration.' ${TERRAFORM_OUTPUT_FILE} ; then echo "No changes found" HAS_NO_CHANGES=true else @@ -280,17 +304,12 @@ runs: echo "error=${HAS_ERROR}" >> $GITHUB_OUTPUT echo "result=${TERRAFORM_RESULT}" >> $GITHUB_OUTPUT - - - name: Convert PLANFILE to JSON - if: ${{ steps.atmos-plan.outputs.changes == 'true' }} - shell: bash - working-directory: ./${{ steps.vars.outputs.component_path }} - run: | - terraform show -json "${{ steps.vars.outputs.plan_file }}" > "${{ steps.vars.outputs.plan_file }}.json" + + rm -f ${TERRAFORM_OUTPUT_FILE} - name: Configure State AWS Credentials - if: ${{ steps.atmos-plan.outputs.changes == 'true' }} - uses: aws-actions/configure-aws-credentials@v4.0.1 + if: ${{ steps.atmos-plan.outputs.error == 'false' }} + uses: aws-actions/configure-aws-credentials@v4.0.2 with: aws-region: ${{ steps.config.outputs.aws-region }} role-to-assume: ${{ steps.config.outputs.terraform-state-role }} @@ -356,7 +375,7 @@ runs: echo "found=${NEW_PLAN_FOUND}" >> $GITHUB_OUTPUT - name: Store New Plan - if: ${{ steps.new-plan.outputs.found == 'true' }} + if: ${{ steps.atmos-plan.outputs.error == 'false' }} uses: cloudposse/github-action-terraform-plan-storage@v1 id: store-plan with: @@ -369,7 +388,7 @@ runs: bucketName: ${{ steps.config.outputs.terraform-state-bucket }} - name: Store Lockfile for New Plan - if: ${{ steps.new-plan.outputs.found == 'true' }} + if: ${{ steps.atmos-plan.outputs.error == 'false' }} uses: cloudposse/github-action-terraform-plan-storage@v1 with: action: storePlan @@ -382,10 +401,17 @@ runs: - name: Setup Infracost if: ${{ steps.config.outputs.enable-infracost == 'true' && steps.atmos-plan.outputs.changes == 'true' }} - uses: infracost/actions/setup@v2 + uses: infracost/actions/setup@v3 with: api-key: ${{ inputs.infracost-api-key }} + - name: Convert PLANFILE to JSON + if: ${{ steps.config.outputs.enable-infracost == 'true' && steps.atmos-plan.outputs.changes == 'true' }} + shell: bash + working-directory: ./${{ steps.vars.outputs.component_path }} + run: | + terraform show -json "${{ steps.vars.outputs.plan_file }}" > "${{ steps.vars.outputs.plan_file }}.json" + - name: Generate Infracost Diff if: ${{ steps.config.outputs.enable-infracost == 'true' && steps.atmos-plan.outputs.changes == 'true' }} id: infracost @@ -445,6 +471,11 @@ runs: run: | if [[ "${{ inputs.drift-detection-mode-enabled }}" == "true" ]]; then STEP_SUMMARY_FILE="${{ steps.vars.outputs.issue_file }}" + + if [[ "${{ steps.atmos-plan.outputs.no-changes }}" == "true" ]]; then + rm -f ${STEP_SUMMARY_FILE} + fi + else STEP_SUMMARY_FILE="${{ steps.vars.outputs.step_summary_file }}" fi diff --git a/docs/github-action.md b/docs/github-action.md index 77158bc0..26c44b7d 100644 --- a/docs/github-action.md +++ b/docs/github-action.md @@ -4,7 +4,8 @@ | Name | Description | Default | Required | |------|-------------|---------|----------| -| atmos-gitops-config-path | The path to the atmos-gitops.yaml file | ./.github/config/atmos-gitops.yaml | false | +| atmos-config-path | The path to the atmos.yaml file | N/A | true | +| atmos-version | The version of atmos to install | >= 1.63.0 | false | | branding-logo-image | Branding logo image url | https://cloudposse.com/logo-300x69.svg | false | | branding-logo-url | Branding logo url | https://cloudposse.com/ | false | | component | The name of the component to plan. | N/A | true | diff --git a/tests/atmos.yaml b/tests/atmos.yaml index 8ee70cfe..489143dc 100644 --- a/tests/atmos.yaml +++ b/tests/atmos.yaml @@ -64,6 +64,23 @@ workflows: # Supports both absolute and relative paths base_path: "stacks/workflows" +integrations: + github: + gitops: + terraform-version: 1.5.2 + infracost-enabled: __INFRACOST_ENABLED__ + artifact-storage: + region: __STORAGE_REGION__ + bucket: __STORAGE_BUCKET__ + table: __STORAGE_TABLE__ + role: __STORAGE_ROLE__ + role: + plan: __PLAN_ROLE__ + apply: __APPLY_ROLE__ + matrix: + sort-by: .stack_slug + group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-") + logs: verbose: false colors: true diff --git a/tests/components/terraform/foobar/main.tf b/tests/components/terraform/foobar/main.tf index e2fd1c2c..23c2e521 100644 --- a/tests/components/terraform/foobar/main.tf +++ b/tests/components/terraform/foobar/main.tf @@ -1,4 +1,5 @@ resource "random_id" "foo" { + count = var.enabled ? 1 : 0 keepers = { # Generate a new id each time we switch to a new seed seed = "${module.this.id}-${var.example}" @@ -13,5 +14,5 @@ resource "random_id" "foo" { } locals { - failure = var.enable_failure ? file("Failed because failure mode is enabled") : null + failure = var.enabled && var.enable_failure ? file("Failed because failure mode is enabled") : null } diff --git a/tests/stacks/catalog/foobar-changes.yaml b/tests/stacks/catalog/foobar-changes.yaml index 9b8f322b..48bebbdc 100644 --- a/tests/stacks/catalog/foobar-changes.yaml +++ b/tests/stacks/catalog/foobar-changes.yaml @@ -7,4 +7,5 @@ components: actions_enabled: true vars: example: blue + enabled: true enable_failure: false diff --git a/tests/stacks/catalog/foobar-disabled.yaml b/tests/stacks/catalog/foobar-disabled.yaml index 335d2b9b..dea88ba5 100644 --- a/tests/stacks/catalog/foobar-disabled.yaml +++ b/tests/stacks/catalog/foobar-disabled.yaml @@ -6,3 +6,4 @@ components: actions_enabled: false vars: example: blue + enabled: true diff --git a/tests/stacks/catalog/foobar-fail.yaml b/tests/stacks/catalog/foobar-fail.yaml index 173225df..adf35279 100644 --- a/tests/stacks/catalog/foobar-fail.yaml +++ b/tests/stacks/catalog/foobar-fail.yaml @@ -7,4 +7,5 @@ components: actions_enabled: true vars: example: blue + enabled: true enable_failure: true diff --git a/tests/stacks/catalog/foobar.yaml b/tests/stacks/catalog/foobar.yaml index 991c4742..53ba98fa 100644 --- a/tests/stacks/catalog/foobar.yaml +++ b/tests/stacks/catalog/foobar.yaml @@ -6,3 +6,4 @@ components: actions_enabled: true vars: example: blue + enabled: false diff --git a/tests/stacks/orgs/foo/plat/sandbox/plat-ue2-sandbox.yaml b/tests/stacks/orgs/foo/plat/sandbox/plat-ue2-sandbox.yaml index 3ddda93f..89cf3d19 100644 --- a/tests/stacks/orgs/foo/plat/sandbox/plat-ue2-sandbox.yaml +++ b/tests/stacks/orgs/foo/plat/sandbox/plat-ue2-sandbox.yaml @@ -5,17 +5,11 @@ import: - catalog/foobar-disabled terraform: - backend_type: s3 + backend_type: local backend: - s3: - bucket: cptest-core-ue2-root-tfstate-plat - dynamodb_table: cptest-core-ue2-root-tfstate-plat-lock - role_arn: arn:aws:iam::822777368227:role/cptest-core-gbl-root-tfstate-plat - encrypt: true - key: terraform.tfstate - acl: bucket-owner-full-control - region: us-east-2 - + local: + path: "terraform.tfstate" + vars: environment: ue2 namespace: foo