From 3e2af522a18007e7604518c5139b2557ab5fbe64 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Mon, 6 Apr 2026 18:55:41 -0500 Subject: [PATCH 01/44] feat: add consolidated TF module check workflow --- .../workflows/reusable-terraform-check.yml | 169 ++++++++++++++++++ docs/reusable-terraform-check.md | 160 +++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 .github/workflows/reusable-terraform-check.yml create mode 100644 docs/reusable-terraform-check.md diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml new file mode 100644 index 0000000..147630d --- /dev/null +++ b/.github/workflows/reusable-terraform-check.yml @@ -0,0 +1,169 @@ +name: Check Terraform Code + +on: + workflow_call: + inputs: + auth_method: + description: 'Authentication method to use for Terraform checks. Valid values are "none", "aws", and "azure".' + required: true + type: string + assume_role_arn: + description: "ARN of the role to assume when running tests and creating test resources. Required if auth_method is 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN variable." + required: false + type: string + default: "${{ vars.TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN }}" + region: + description: "AWS region to deploy when running tests and creating resources. Required if auth_method is 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_REGION variable." + default: "${{ vars.TERRAFORM_CHECK_AWS_REGION }}" + required: false + type: string + secrets: + # If using Azure authentication, these secrets must be provided. They are not required for the workflow itself to allow reuse in non-Azure contexts. + TERRAFORM_CHECK_AZURE_CLIENT_ID: + required: false + TERRAFORM_CHECK_AZURE_TENANT_ID: + required: false + TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID: + required: false + +permissions: + contents: read + id-token: write # Required for various OIDC auth flows. + +jobs: + validate-inputs: + name: "Validate Inputs" + runs-on: ubuntu-latest + outputs: + auth_method: ${{ steps.validate.outputs.auth_method }} + steps: + - name: Validate inputs and secrets + id: validate + shell: bash + run: | + if [[ "${{ inputs.auth_method }}" != "none" && "${{ inputs.auth_method }}" != "aws" && "${{ inputs.auth_method }}" != "azure" ]]; then + echo "Error: Invalid auth_method input '${{ inputs.auth_method }}'. Valid values are 'none', 'aws', and 'azure'." + exit 1 + fi + + if [[ "${{ inputs.auth_method }}" == "aws" ]]; then + if [[ -z "${{ inputs.assume_role_arn }}" ]]; then + echo "Error: assume_role_arn input is required when auth_method is 'aws'." + exit 1 + fi + if [[ -z "${{ inputs.region }}" ]]; then + echo "Error: region input is required when auth_method is 'aws'." + exit 1 + fi + fi + + if [[ "${{ inputs.auth_method }}" == "azure" ]]; then + if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }}" ]]; then + echo "Error: TERRAFORM_CHECK_AZURE_CLIENT_ID secret is required when auth_method is 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }}" ]]; then + echo "Error: TERRAFORM_CHECK_AZURE_TENANT_ID secret is required when auth_method is 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }}" ]]; then + echo "Error: TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID secret is required when auth_method is 'azure'." + exit 1 + fi + fi + + echo "auth_method=${{ inputs.auth_method }}" >> $GITHUB_OUTPUT + check: + name: "Run Tests" + runs-on: ubuntu-latest + needs: validate-inputs + steps: + - id: checkout + name: Checkout + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 + + - id: dependencies + name: Setup asdf + # We use the 'setup' variant of this action, because we have some custom behavior in + # our .tool-versions file and Makefile to install plugins from outside the default registry. + uses: asdf-vm/actions/setup@b7bcd026f18772e44fe1026d729e1611cc435d47 + + - id: cache-restore + uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 + # If we've cached the asdf tools, restore them based on the hash of the .tool-versions file. + name: Restore cached asdf tools + with: + path: ~/.asdf + key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + + - id: configure + name: Setup Repository for Checks + # Ensure the 'repo' tool is installed, set up git to make the Makefile happy, and then configure to clone LCAF. + shell: bash + run: | + mkdir -p ~/.local/bin + curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo + chmod +x ~/.local/bin/repo + echo "$HOME/.local/bin" >> $GITHUB_PATH + set -x + git config user.name "GitHub Actions" + git config user.email "noreply@launch.nttdata.com" + if [[ "${{ needs.validate-inputs.outputs.auth_method }}" == "aws" ]]; then + export AWS_REGION=${{ inputs.region }} + elif [[ "${{ needs.validate-inputs.outputs.auth_method }}" == "azure" ]]; then + export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + fi + make configure + + - id: save-cache + uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 + name: Cache asdf tools + # If we didn't restore the asdf tools, save them based on the hash of the .tool-versions file. + if: steps.cache-restore.outputs.cache-hit != 'true' + with: + path: ~/.asdf + key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + + - id: lint + name: "make lint" + run: | + make lint + + - id: configure-aws-credentials + name: Configure AWS credentials + if: needs.validate-inputs.outputs.auth_method == 'aws' + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 + with: + role-to-assume: ${{ inputs.assume_role_arn }} + role-session-name: ${{ github.run_id }} + aws-region: ${{ inputs.region }} + + - id: create-aws-profile + name: "Create AWS Profile" + if: needs.validate-inputs.outputs.auth_method == 'aws' + # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. + # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need + # to remove line setting the profile in our examples, or we see failures to initialize the provider. + run: | + set -x + mkdir -p ~/.aws + echo "[default]" > ~/.aws/credentials + echo "aws_access_key_id=${{ secrets.AWS_ACCESS_KEY_ID }}" >> ~/.aws/credentials + echo "aws_secret_access_key=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> ~/.aws/credentials + echo "aws_session_token=${{ secrets.AWS_SESSION_TOKEN }}" >> ~/.aws/credentials + # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. + find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; + + - id: azure-login + name: Azure login + if: needs.validate-inputs.outputs.auth_method == 'azure' + uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 + with: + client-id: ${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }} + subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + + - id: test + name: "make test" + run: | + make test diff --git a/docs/reusable-terraform-check.md b/docs/reusable-terraform-check.md new file mode 100644 index 0000000..e2dc7b9 --- /dev/null +++ b/docs/reusable-terraform-check.md @@ -0,0 +1,160 @@ +# Check a Terraform Module + +Performs a series of checks of a Terraform module, including linting the Terraform code via `make lint`, and deploying the example modules to a cloud provider (or no provider at all) and running the golang tests via the `make test` target. This workflow unifies the previously separate `reusable-terraform-check-aws.yml` and `reusable-terraform-check-azure.yml` workflows into a single, provider-agnostic workflow controlled by the `auth_method` input. + +This workflow wraps both the `make lint` and `make test` targets in the Makefile. + +## Usage + +### No cloud authentication (`auth_method: none`) + +Use this when your module does not require cloud credentials to run tests (e.g., pure Terraform logic tests, mocked providers): + +```yaml +name: Check Terraform Code + +on: + pull_request: + types: [ opened, reopened, synchronize, ready_for_review ] + branches: [ main ] + +permissions: + id-token: write + contents: read + +jobs: + check: + name: "Check Terraform Code" + permissions: + contents: read + id-token: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check.yml@ref + with: + auth_method: "none" +``` + +### AWS authentication (`auth_method: aws`) + +Use this when your module deploys example resources to AWS. Authentication is performed via OIDC using a role you provide: + +```yaml +name: Check AWS Terraform Code + +on: + pull_request: + types: [ opened, reopened, synchronize, ready_for_review ] + branches: [ main ] + +permissions: + id-token: write + contents: read + +jobs: + check: + name: "Check AWS Terraform Code" + permissions: + contents: read + id-token: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check.yml@ref + with: + auth_method: "aws" + assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" # optional, falls back to TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN variable + region: "us-east-2" # optional, falls back to TERRAFORM_CHECK_AWS_REGION variable +``` + +Replace `ref` with an appropriate ref to this repository, and replace `assume_role_arn` and `region` with values of your choosing. If either is not provided, they fall back to the `TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN` and `TERRAFORM_CHECK_AWS_REGION` variables set at the repository, organization, or enterprise level. + +### Azure authentication (`auth_method: azure`) + +Use this when your module deploys example resources to Azure. Authentication is performed via OIDC using Azure credentials passed as secrets: + +```yaml +name: Check Azure Terraform Code + +on: + pull_request: + types: [ opened, reopened, synchronize, ready_for_review ] + branches: [ main ] + +permissions: + id-token: write + contents: read + +jobs: + check: + name: "Check Azure Terraform Code" + permissions: + contents: read + id-token: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check.yml@ref + with: + auth_method: "azure" + secrets: inherit # pragma: allowlist secret + + # For usage outside the launchbynttdata organization, pass the secrets explicitly: + # secrets: + # TERRAFORM_CHECK_AZURE_CLIENT_ID: ${{ secrets.your_azure_client_id_secret }} + # TERRAFORM_CHECK_AZURE_TENANT_ID: ${{ secrets.your_azure_tenant_id_secret }} + # TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID: ${{ secrets.your_azure_subscription_id_secret }} +``` + +Replace `ref` with an appropriate ref to this repository. For more information on OIDC setup for Azure, see the [azure/login action documentation](https://github.com/Azure/login?tab=readme-ov-file#login-with-openid-connect-oidc-recommended). + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `auth_method` | Authentication method to use. Valid values are `none`, `aws`, and `azure`. | Yes | β€” | +| `assume_role_arn` | ARN of the IAM role to assume. Required when `auth_method` is `aws`. | No | `${{ vars.TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN }}` | +| `region` | AWS region to use when deploying test resources. Only used when `auth_method` is `aws`. | No | `${{ vars.TERRAFORM_CHECK_AWS_REGION }}` | + +## Secrets + +| Name | Description | Required | +|------|-------------|----------| +| `TERRAFORM_CHECK_AZURE_CLIENT_ID` | Azure client ID for OIDC authentication. Required when `auth_method` is `azure`. | No* | +| `TERRAFORM_CHECK_AZURE_TENANT_ID` | Azure tenant ID for OIDC authentication. Required when `auth_method` is `azure`. | No* | +| `TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID` | Azure subscription ID for OIDC authentication. Required when `auth_method` is `azure`. | No* | + +*These secrets are declared as optional at the workflow level to allow reuse in non-Azure contexts, but the workflow will fail at the `validate-inputs` job if any of them are missing when `auth_method` is `azure`. + +## Migrating from the provider-specific workflows + +If you are currently using `reusable-terraform-check-aws.yml`, replace the `uses` reference and add `auth_method: "aws"`: + +```yaml +# Before +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check-aws.yml@ref +with: + assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" + +# After +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check.yml@ref +with: + auth_method: "aws" + assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" +``` + +If you are currently using `reusable-terraform-check-azure.yml`, replace the `uses` reference and add `auth_method: "azure"`: + +```yaml +# Before +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check-azure.yml@ref +secrets: inherit # pragma: allowlist secret + +# After +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check.yml@ref +with: + auth_method: "azure" +secrets: inherit # pragma: allowlist secret +``` + +For our Terraform modules, the `auth_method` can be derived automatically from the repository name: repositories prefixed with `tf-aws` use AWS authentication, those prefixed with `tf-az` use Azure authentication, and all others use no authentication: + +```yaml +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terraform-check.yml@ref +with: + auth_method: ${{ startsWith(github.event.repository.name, 'tf-aws') && 'aws' || startsWith(github.event.repository.name, 'tf-az') && 'azure' || 'none' }} +secrets: inherit # pragma: allowlist secret +``` + From 0ae0413d261e1f94b91fa3a22a5240fb2fc53534 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 7 Apr 2026 09:37:20 -0500 Subject: [PATCH 02/44] feat: add action to update status checks, unify status checks across workflows, add deprecation notice --- .github/actions/update-status-check/README.md | 111 ++++++++++++++++++ .../actions/update-status-check/action.yml | 65 ++++++++++ .../reusable-terraform-check-aws.yml | 45 ++++++- .../reusable-terraform-check-azure.yml | 37 +++++- .../workflows/reusable-terraform-check.yml | 35 ++++++ docs/reusable-terraform-check-aws.md | 5 + docs/reusable-terraform-check-azure.md | 5 + 7 files changed, 295 insertions(+), 8 deletions(-) create mode 100644 .github/actions/update-status-check/README.md create mode 100644 .github/actions/update-status-check/action.yml diff --git a/.github/actions/update-status-check/README.md b/.github/actions/update-status-check/README.md new file mode 100644 index 0000000..be26cc7 --- /dev/null +++ b/.github/actions/update-status-check/README.md @@ -0,0 +1,111 @@ +# Update Status Check Action + +GitHub's [Commit Status API](https://docs.github.com/en/rest/commits/statuses) allows workflows to report the state of a check back to a specific commit SHA. This is useful for surfacing the outcome of external processes, gating merges, or providing richer context in pull requests beyond what a workflow run alone provides. + +This action wraps the Commit Status API with a simple interface: provide a check name and a status, and we handle the API call. + +## Behavior + +This action will: +1. Validate that the provided `status` is one of the accepted values (`error`, `failure`, `pending`, `success`) +2. Call the GitHub Commit Status API to create or update the named status check on the specified commit SHA +3. Optionally attach a human-readable description and a target URL to the status + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `check_name` | The name (context) of the status check to create or update | Yes | β€” | +| `status` | The state to set. One of: `error`, `failure`, `pending`, `success` | Yes | β€” | +| `sha` | The commit SHA to attach the status check to | No | `${{ github.sha }}` | +| `description` | A short human-readable description of the status | No | `""` | +| `target_url` | A URL to associate with the status (e.g. a link to a build log) | No | `""` | +| `github_token` | GitHub token for API access | No | `${{ github.token }}` | + +## Usage + +### Basic Usage + +Mark a status check as successful on the current commit: + +```yaml +jobs: + your-job: + runs-on: ubuntu-latest + permissions: + statuses: write + steps: + - name: Set status check to success + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + with: + check_name: "my-check" + status: "success" +``` + +### With Description and Target URL + +Provide additional context visible in the GitHub UI: + +```yaml +- name: Set status check to failure + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + with: + check_name: "security-scan" + status: "failure" + description: "Vulnerabilities were detected." + target_url: "https://example.com/scan-results/123" +``` + +### Marking a Check as Pending Before a Long-Running Step + +Use `pending` to signal that a check is in progress, then update it on completion: + +```yaml +- name: Mark check as pending + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + with: + check_name: "integration-tests" + status: "pending" + description: "Integration tests are running..." + +- name: Run integration tests + run: make test-integration + +- name: Mark check as success + if: success() + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + with: + check_name: "integration-tests" + status: "success" + description: "All integration tests passed." + +- name: Mark check as failure + if: failure() + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + with: + check_name: "integration-tests" + status: "failure" + description: "One or more integration tests failed." +``` + +### Targeting a Specific Commit SHA + +Override the default SHA to set a status on a commit other than the one that triggered the workflow: + +```yaml +- name: Set status on a specific commit + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + with: + check_name: "my-check" + status: "success" + sha: "abc1234def5678" +``` + +## Required Permissions + +This action requires the following permission on the workflow job: + +```yaml +permissions: + statuses: write +``` diff --git a/.github/actions/update-status-check/action.yml b/.github/actions/update-status-check/action.yml new file mode 100644 index 0000000..7a58b35 --- /dev/null +++ b/.github/actions/update-status-check/action.yml @@ -0,0 +1,65 @@ +name: "Update Status Check" +description: "Use the GitHub Commit Status API to create or update a status check on a commit." +inputs: + check_name: + description: "The name (context) of the status check to create or update." + required: true + status: + description: "The state to set on the status check. Must be one of: error, failure, pending, success." + required: true + sha: + description: "The commit SHA to attach the status check to. Defaults to the SHA that triggered the workflow." + required: false + default: ${{ github.sha }} + description: + description: "A short human-readable description of the status check." + required: false + default: "" + target_url: + description: "A URL to associate with the status check, typically a link to relevant build or run output." + required: false + default: "" + github_token: + description: "GitHub token for API access. Defaults to the automatic GITHUB_TOKEN." + required: false + default: ${{ github.token }} +runs: + using: "composite" + steps: + - name: Update Status Check + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + CHECK_NAME: ${{ inputs.check_name }} + STATUS: ${{ inputs.status }} + SHA: ${{ inputs.sha }} + DESCRIPTION: ${{ inputs.description }} + TARGET_URL: ${{ inputs.target_url }} + run: | + VALID_STATES=("error" "failure" "pending" "success") + VALID=false + for state in "${VALID_STATES[@]}"; do + if [[ "$STATUS" == "$state" ]]; then + VALID=true + break + fi + done + + if [[ "$VALID" != "true" ]]; then + echo "Error: Invalid status '${STATUS}'. Must be one of: error, failure, pending, success." + exit 1 + fi + + echo "Setting status check '${CHECK_NAME}' to '${STATUS}' on commit ${SHA}..." + + PAYLOAD=$(jq -n \ + --arg state "$STATUS" \ + --arg context "$CHECK_NAME" \ + --arg description "$DESCRIPTION" \ + --arg target_url "$TARGET_URL" \ + '{state: $state, context: $context, description: $description, target_url: $target_url}') + + gh api -X POST "repos/${{ github.repository }}/statuses/${SHA}" \ + --input - <<< "$PAYLOAD" + + echo "Status check '${CHECK_NAME}' successfully set to '${STATUS}'." diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index 4197090..d473dc8 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -4,18 +4,19 @@ on: workflow_call: inputs: assume_role_arn: - description: 'ARN of the role to assume prior to Terragrunt invocation. Terragrunt may use this role to assume other roles if configured to do so.' + description: "ARN of the role to assume prior to Terragrunt invocation. Terragrunt may use this role to assume other roles if configured to do so." required: true type: string region: - description: 'Region within the environment (e.g. us-east-1) to deploy' - default: 'us-east-2' + description: "Region within the environment (e.g. us-east-1) to deploy" + default: "us-east-2" required: true type: string permissions: id-token: write contents: read + statuses: write jobs: check: @@ -26,7 +27,7 @@ jobs: uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 - name: Setup asdf - # We use the 'setup' variant of this action, because we have some custom behavior in + # We use the 'setup' variant of this action, because we have some custom behavior in # our .tool-versions file and Makefile to install plugins from outside the default registry. uses: asdf-vm/actions/setup@b7bcd026f18772e44fe1026d729e1611cc435d47 @@ -61,10 +62,26 @@ jobs: path: ~/.asdf key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - - name: "make lint" + - name: "Set Terraform Lint status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Lint" + status: "pending" + description: "Terraform lint check is running..." + + - id: lint + name: "make lint" run: | make lint + - name: "Update Terraform Lint status" + if: always() && steps.lint.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Lint" + status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform lint ${{ steps.lint.outcome }}" + - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 with: @@ -86,6 +103,22 @@ jobs: # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - - name: "make test" + - name: "Set Terraform Tests status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Tests" + status: "pending" + description: "Terraform tests are running..." + + - id: test + name: "make test" run: | make test + + - name: "Update Terraform Tests status" + if: always() && steps.test.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Tests" + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform tests ${{ steps.test.outcome }}" diff --git a/.github/workflows/reusable-terraform-check-azure.yml b/.github/workflows/reusable-terraform-check-azure.yml index 785dbc7..1efa462 100644 --- a/.github/workflows/reusable-terraform-check-azure.yml +++ b/.github/workflows/reusable-terraform-check-azure.yml @@ -13,6 +13,7 @@ on: permissions: id-token: write contents: read + statuses: write jobs: check: @@ -58,10 +59,26 @@ jobs: path: ~/.asdf key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - - name: "make lint" + - name: "Set Terraform Lint status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Lint" + status: "pending" + description: "Terraform lint check is running..." + + - id: lint + name: "make lint" run: | make lint + - name: "Update Terraform Lint status" + if: always() && steps.lint.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Lint" + status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform lint ${{ steps.lint.outcome }}" + - name: Azure login uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 with: @@ -69,6 +86,22 @@ jobs: tenant-id: ${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }} subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} - - name: "make test" + - name: "Set Terraform Tests status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Tests" + status: "pending" + description: "Terraform tests are running..." + + - id: test + name: "make test" run: | make test + + - name: "Update Terraform Tests status" + if: always() && steps.test.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Tests" + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform tests ${{ steps.test.outcome }}" diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 147630d..b7785ee 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -29,6 +29,7 @@ on: permissions: contents: read id-token: write # Required for various OIDC auth flows. + statuses: write jobs: validate-inputs: @@ -124,11 +125,28 @@ jobs: path: ~/.asdf key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + - id: set-lint-pending + name: "Set Terraform Lint status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Lint" + status: "pending" + description: "Terraform lint check is running..." + - id: lint name: "make lint" run: | make lint + - id: update-lint-status + name: "Update Terraform Lint status" + if: always() && steps.lint.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Lint" + status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform lint ${{ steps.lint.outcome }}" + - id: configure-aws-credentials name: Configure AWS credentials if: needs.validate-inputs.outputs.auth_method == 'aws' @@ -163,7 +181,24 @@ jobs: tenant-id: ${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }} subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + - id: set-tests-pending + name: "Set Terraform Tests status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Tests" + status: "pending" + description: "Terraform tests are running..." + - id: test name: "make test" run: | make test + + - id: update-tests-status + name: "Update Terraform Tests status" + if: always() && steps.test.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terraform Tests" + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform tests ${{ steps.test.outcome }}" diff --git a/docs/reusable-terraform-check-aws.md b/docs/reusable-terraform-check-aws.md index 2986de0..86bdc60 100644 --- a/docs/reusable-terraform-check-aws.md +++ b/docs/reusable-terraform-check-aws.md @@ -1,3 +1,8 @@ +> [!CAUTION] +> Deprecation Notice +> +> This workflow will be deprecated with the 1.0.0 release of launch-workflows. + # Check a Terraform Module in AWS Performs a series of checks of a Terraform module, including deploying the example modules to AWS. diff --git a/docs/reusable-terraform-check-azure.md b/docs/reusable-terraform-check-azure.md index 74c172c..a056a8f 100644 --- a/docs/reusable-terraform-check-azure.md +++ b/docs/reusable-terraform-check-azure.md @@ -1,3 +1,8 @@ +> [!CAUTION] +> Deprecation Notice +> +> This workflow will be deprecated with the 1.0.0 release of launch-workflows. + # Check a Terraform Module in Azure Performs a series of checks of a Terraform module, including deploying the example modules to Azure. From cb5acb85f4d84b5a99d91e54e9964a10c80e1fe7 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 7 Apr 2026 12:48:48 -0500 Subject: [PATCH 03/44] feat: create consolidated terragrunt workflows with composable auth --- .../workflows/reusable-terragrunt-deploy.yml | 342 ++++++++++++++++++ .../reusable-terragrunt-plan-only.yml | 239 ++++++++++++ docs/reusable-terragrunt-deploy.md | 266 ++++++++++++++ docs/reusable-terragrunt-plan-only.md | 284 +++++++++++++++ 4 files changed, 1131 insertions(+) create mode 100644 .github/workflows/reusable-terragrunt-deploy.yml create mode 100644 .github/workflows/reusable-terragrunt-plan-only.yml create mode 100644 docs/reusable-terragrunt-deploy.md create mode 100644 docs/reusable-terragrunt-plan-only.md diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml new file mode 100644 index 0000000..0dbf5e6 --- /dev/null +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -0,0 +1,342 @@ +name: Deploy Terragrunt Environment + +on: + workflow_call: + inputs: + auth_method: + description: 'Comma-delimited list of authentication methods to use. Valid values are "aws", "azure", and "github" (e.g. "aws", "aws,github", "aws,azure"). Pass an empty string or omit to run Terragrunt without any authentication.' + required: false + default: "" + type: string + # --- AWS authentication inputs --- + aws_auth_region: + description: "The AWS region to use for authentication. Required if auth_method includes 'aws', ignored otherwise." + required: false + type: string + aws_assume_role_arn: + description: "ARN of the role to assume prior to Terragrunt invocation, defaulting to the DEPLOY_ROLE_ARN variable. Required if auth_method includes 'aws', ignored otherwise." + required: false + default: "${{ vars.DEPLOY_ROLE_ARN }}" + type: string + # --- GitHub App authentication inputs --- + github_app_id: + description: "The GitHub App ID to use for authentication, defaulting to the TERRAGRUNT_DEPLOY_GITHUB_APP_ID variable. Required if auth_method includes 'github', ignored otherwise." + required: false + default: "${{ vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID }}" + type: string + # --- General workflow configuration --- + git_branch: + description: "Branch triggering this deployment." + required: true + type: string + tf_version: + description: "Version of Terraform to utilize" + required: true + default: "1.5.5" + type: string + tg_version: + description: "Version of Terragrunt to utilize" + required: true + type: string + gh_environment: + description: "GitHub Environment to deploy to (e.g. test, production)." + required: false + type: string + tg_dir: + description: "Folder containing the Terragrunt configuration to deploy (relative to the repository root, e.g. platform/test/us-east-1/000)" + required: true + type: string + before_plan_commands: + description: "Commands to run prior to executing Terragrunt plan." + required: false + type: string + default: "" + before_deploy_commands: + description: "Commands to run prior to executing Terragrunt apply." + required: false + type: string + default: "" + before_shared_commands: + description: "Commands to run prior to both Terragrunt plan and apply. These are applied after before_plan_commands and before_deploy_commands." + required: false + type: string + default: "" + after_plan_commands: + description: "Commands to run after executing Terragrunt plan." + required: false + type: string + default: "" + after_deploy_commands: + description: "Commands to run after executing Terragrunt apply." + required: false + type: string + default: "" + after_shared_commands: + description: "Commands to run after both Terragrunt plan and apply. These are applied after after_plan_commands and after_deploy_commands." + required: false + type: string + default: "" + outputs: + terraform_outputs: + description: "JSON string containing all Terraform outputs from the deployment (base64 encoded)" + value: ${{ jobs.deploy.outputs.terraform_outputs }} + secrets: + # --- Azure authentication secrets (required if auth_method includes 'azure') --- + TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: + required: false + TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: + required: false + TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: + required: false + # --- GitHub App authentication secrets (required if auth_method includes 'github') --- + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: + required: false + +permissions: + id-token: write + contents: read + statuses: write + +jobs: + validate-inputs: + name: "Validate Inputs" + runs-on: ubuntu-latest + environment: ${{ inputs.gh_environment }} + outputs: + auth_aws: ${{ steps.validate.outputs.auth_aws }} + auth_azure: ${{ steps.validate.outputs.auth_azure }} + auth_github: ${{ steps.validate.outputs.auth_github }} + steps: + - name: Validate inputs and secrets + id: validate + shell: bash + run: | + auth_aws=false + auth_azure=false + auth_github=false + + IFS=',' read -ra AUTH_METHODS <<< "${{ inputs.auth_method }}" + for method in "${AUTH_METHODS[@]}"; do + method=$(echo "$method" | xargs) + [[ -z "$method" ]] && continue + case "$method" in + # --- AWS authentication validation --- + aws) + auth_aws=true + if [[ -z "${{ inputs.aws_auth_region }}" ]]; then + echo "Error: aws_auth_region input is required when auth_method includes 'aws'." + exit 1 + fi + if [[ -z "${{ inputs.aws_assume_role_arn }}" ]]; then + echo "Error: aws_assume_role_arn input is required when auth_method includes 'aws'." + exit 1 + fi + ;; + # --- Azure authentication validation --- + azure) + auth_azure=true + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_AZURE_TENANT_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + ;; + # --- GitHub App authentication validation --- + github) + auth_github=true + if [[ -z "${{ inputs.github_app_id }}" ]]; then + echo "Error: github_app_id input is required when auth_method includes 'github'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET secret is required when auth_method includes 'github'." + exit 1 + fi + ;; + *) + echo "Error: Invalid auth_method '$method'. Valid values are 'aws', 'azure', and 'github'." + exit 1 + ;; + esac + done + + echo "auth_aws=$auth_aws" >> $GITHUB_OUTPUT + echo "auth_azure=$auth_azure" >> $GITHUB_OUTPUT + echo "auth_github=$auth_github" >> $GITHUB_OUTPUT + + deploy: + name: "Plan & Deploy ${{ inputs.tg_dir }}" + runs-on: ubuntu-latest + needs: validate-inputs + environment: ${{ inputs.gh_environment }} + outputs: + terraform_outputs: ${{ steps.set-outputs.outputs.terraform_outputs }} + steps: + - name: Checkout + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 + + - name: Configure AWS credentials + if: needs.validate-inputs.outputs.auth_aws == 'true' + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 + with: + role-to-assume: ${{ inputs.aws_assume_role_arn }} + role-session-name: ${{ github.run_id }} + aws-region: ${{ inputs.aws_auth_region }} + + - name: Azure Login + if: needs.validate-inputs.outputs.auth_azure == 'true' + uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 + with: + client-id: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + subscription-id: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + + - name: "Set default Terraform Tags (AWS)" + if: needs.validate-inputs.outputs.auth_aws == 'true' + id: set-tags-aws + run: | + set -x + echo "TF_VAR_organization_tag=${{ github.repository_owner }}" >> "$GITHUB_OUTPUT" + echo "TF_VAR_repository_tag=$(echo "${{ github.repository }}" | cut -d "/" -f 2)" >> "$GITHUB_OUTPUT" + echo "TF_VAR_commit_hash_tag=${{ github.sha }}" >> "$GITHUB_OUTPUT" + echo "TF_VAR_branch_tag=${{ inputs.git_branch }}" >> "$GITHUB_OUTPUT" + + - name: "Set default Terraform Tags (Azure)" + if: needs.validate-inputs.outputs.auth_azure == 'true' + id: set-tags-azure + run: | + set -x + repo=$(echo "${{ github.repository }}" | cut -d "/" -f 2) + echo "SYSTEM_TAGS={\"Organization\":\"${{ github.repository_owner }}\",\"Repository\":\"$repo\",\"Branch\":\"${{ inputs.git_branch }}\",\"CommitHash\":\"${{ github.sha }}\"}" >> "$GITHUB_OUTPUT" + + - name: Create GitHub App Token + id: github-app-token + if: needs.validate-inputs.outputs.auth_github == 'true' + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ inputs.github_app_id }} + private-key: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} + + - name: Configure Mise + id: configure-mise + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + with: + tf_version: ${{ inputs.tf_version }} + tg_version: ${{ inputs.tg_version }} + + - name: "Set Terragrunt Plan status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" + status: "pending" + description: "Terragrunt plan is running..." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - name: Plan + id: plan + uses: gruntwork-io/terragrunt-action@5e86476ca61eaf74adb9c0525745f29f921f2199 + env: + INPUT_PRE_EXEC_0: | + ${{ inputs.before_plan_commands }} + INPUT_PRE_EXEC_1: | + ${{ inputs.before_shared_commands }} + INPUT_POST_EXEC_0: | + ${{ inputs.after_plan_commands }} + INPUT_POST_EXEC_1: | + ${{ inputs.after_shared_commands }} + TF_VAR_organization_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_organization_tag }} + TF_VAR_repository_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_repository_tag }} + TF_VAR_commit_hash_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_commit_hash_tag }} + TF_VAR_branch_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_branch_tag }} + ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + TF_VAR_system_tags: ${{ steps.set-tags-azure.outputs.SYSTEM_TAGS }} + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} + with: + tf_path: "terraform" + tg_version: ${{ inputs.tg_version }} + tg_dir: "${{ inputs.tg_dir }}" + tg_command: "plan -out=${{ github.sha }}.tfplan" + + - name: "Update Terragrunt Plan status" + if: always() && steps.plan.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" + status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome == 'failure' && 'failure' || 'error' }} + description: "Terragrunt plan ${{ steps.plan.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - name: "Set Terragrunt Deploy status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" + status: "pending" + description: "Terragrunt deploy is running..." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - name: Deploy + id: deploy + uses: gruntwork-io/terragrunt-action@5e86476ca61eaf74adb9c0525745f29f921f2199 + env: + INPUT_PRE_EXEC_0: | + ${{ inputs.before_deploy_commands }} + INPUT_PRE_EXEC_1: | + ${{ inputs.before_shared_commands }} + INPUT_POST_EXEC_0: | + ${{ inputs.after_deploy_commands }} + INPUT_POST_EXEC_1: | + ${{ inputs.after_shared_commands }} + TF_VAR_organization_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_organization_tag }} + TF_VAR_repository_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_repository_tag }} + TF_VAR_commit_hash_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_commit_hash_tag }} + TF_VAR_branch_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_branch_tag }} + ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + TF_VAR_system_tags: ${{ steps.set-tags-azure.outputs.SYSTEM_TAGS }} + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} + with: + tf_path: "terraform" + tg_version: ${{ inputs.tg_version }} + tg_dir: "${{ inputs.tg_dir }}" + tg_command: "apply ${{ github.sha }}.tfplan" + + - name: "Update Terragrunt Deploy status" + if: always() && steps.deploy.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" + status: ${{ steps.deploy.outcome == 'success' && 'success' || steps.deploy.outcome == 'failure' && 'failure' || 'error' }} + description: "Terragrunt deploy ${{ steps.deploy.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - name: Get Terraform Outputs + id: set-outputs + working-directory: "${{ inputs.tg_dir }}" + env: + ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} + run: | + echo "=== Getting Terraform outputs ===" + TF_OUTPUTS=$(terragrunt output -json 2>/dev/null | jq 'with_entries(select(.value.sensitive != true))' || echo '{}') + echo "Raw outputs:" + echo "$TF_OUTPUTS" | jq '.' + + # Base64 encode for safe transfer + ENCODED_OUTPUTS=$(echo "$TF_OUTPUTS" | base64 -w 0) + echo "terraform_outputs=$ENCODED_OUTPUTS" >> "$GITHUB_OUTPUT" + echo "=== Outputs captured and encoded ===" diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml new file mode 100644 index 0000000..27ab8a8 --- /dev/null +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -0,0 +1,239 @@ +name: Plan Terragrunt Environment + +on: + workflow_call: + inputs: + auth_method: + description: 'Comma-delimited list of authentication methods to use. Valid values are "aws", "azure", and "github" (e.g. "aws", "aws,github", "aws,azure"). Pass an empty string or omit to run Terragrunt without any authentication.' + required: false + default: "" + type: string + # --- AWS authentication inputs --- + aws_auth_region: + description: "The AWS region to use for authentication. Required if auth_method includes 'aws', ignored otherwise." + required: false + type: string + aws_assume_role_arn: + description: "ARN of the role to assume prior to Terragrunt invocation. Required if auth_method includes 'aws', ignored otherwise." + required: false + type: string + # --- GitHub App authentication inputs --- + github_app_id: + description: "The GitHub App ID to use for authentication, defaulting to the TERRAGRUNT_DEPLOY_GITHUB_APP_ID variable. Required if auth_method includes 'github', ignored otherwise." + required: false + default: "${{ vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID }}" + type: string + # --- General workflow configuration --- + git_branch: + description: "Branch triggering this plan" + required: true + type: string + tf_version: + description: "Version of Terraform to utilize" + required: true + default: "1.5.5" + type: string + tg_version: + description: "Version of Terragrunt to utilize" + required: true + type: string + tg_dir: + description: "Folder containing the Terragrunt configuration to plan (relative to the repository root, e.g. platform/test/us-east-1/000)" + required: true + type: string + before_plan_commands: + description: "Commands to run prior to executing Terragrunt plan." + required: false + type: string + default: "" + after_plan_commands: + description: "Commands to run after executing Terragrunt plan." + required: false + type: string + default: "" + secrets: + # --- Azure authentication secrets (required if auth_method includes 'azure') --- + TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: + required: false + TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: + required: false + TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: + required: false + # --- GitHub App authentication secrets (required if auth_method includes 'github') --- + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: + required: false + +permissions: + id-token: write + contents: read + statuses: write + +jobs: + validate-inputs: + name: "Validate Inputs" + runs-on: ubuntu-latest + outputs: + auth_aws: ${{ steps.validate.outputs.auth_aws }} + auth_azure: ${{ steps.validate.outputs.auth_azure }} + auth_github: ${{ steps.validate.outputs.auth_github }} + steps: + - name: Validate inputs and secrets + id: validate + shell: bash + run: | + auth_aws=false + auth_azure=false + auth_github=false + + IFS=',' read -ra AUTH_METHODS <<< "${{ inputs.auth_method }}" + for method in "${AUTH_METHODS[@]}"; do + method=$(echo "$method" | xargs) + [[ -z "$method" ]] && continue + case "$method" in + # --- AWS authentication validation --- + aws) + auth_aws=true + if [[ -z "${{ inputs.aws_auth_region }}" ]]; then + echo "Error: aws_auth_region input is required when auth_method includes 'aws'." + exit 1 + fi + if [[ -z "${{ inputs.aws_assume_role_arn }}" ]]; then + echo "Error: aws_assume_role_arn input is required when auth_method includes 'aws'." + exit 1 + fi + ;; + # --- Azure authentication validation --- + azure) + auth_azure=true + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_AZURE_TENANT_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + ;; + # --- GitHub App authentication validation --- + github) + auth_github=true + if [[ -z "${{ inputs.github_app_id }}" ]]; then + echo "Error: github_app_id input is required when auth_method includes 'github'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }}" ]]; then + echo "Error: TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET secret is required when auth_method includes 'github'." + exit 1 + fi + ;; + *) + echo "Error: Invalid auth_method '$method'. Valid values are 'aws', 'azure', and 'github'." + exit 1 + ;; + esac + done + + echo "auth_aws=$auth_aws" >> $GITHUB_OUTPUT + echo "auth_azure=$auth_azure" >> $GITHUB_OUTPUT + echo "auth_github=$auth_github" >> $GITHUB_OUTPUT + + plan: + name: "Plan ${{ inputs.tg_dir }}" + runs-on: ubuntu-latest + needs: validate-inputs + steps: + - name: Checkout + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 + - name: Configure AWS credentials + if: needs.validate-inputs.outputs.auth_aws == 'true' + uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 + with: + role-to-assume: ${{ inputs.aws_assume_role_arn }} + role-session-name: ${{ github.run_id }} + aws-region: ${{ inputs.aws_auth_region }} + + - name: Azure Login + if: needs.validate-inputs.outputs.auth_azure == 'true' + uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 + with: + client-id: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + subscription-id: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + + - name: "Set default Terraform Tags (AWS)" + if: needs.validate-inputs.outputs.auth_aws == 'true' + id: set-tags-aws + run: | + set -x + echo "TF_VAR_organization_tag=${{ github.repository_owner }}" >> "$GITHUB_OUTPUT" + echo "TF_VAR_repository_tag=$(echo "${{ github.repository }}" | cut -d "/" -f 2)" >> "$GITHUB_OUTPUT" + echo "TF_VAR_commit_hash_tag=${{ github.sha }}" >> "$GITHUB_OUTPUT" + echo "TF_VAR_branch_tag=${{ inputs.git_branch }}" >> "$GITHUB_OUTPUT" + + - name: "Set default Terraform Tags (Azure)" + if: needs.validate-inputs.outputs.auth_azure == 'true' + id: set-tags-azure + run: | + set -x + repo=$(echo "${{ github.repository }}" | cut -d "/" -f 2) + echo "SYSTEM_TAGS={\"Organization\":\"${{ github.repository_owner }}\",\"Repository\":\"$repo\",\"Branch\":\"${{ inputs.git_branch }}\",\"CommitHash\":\"${{ github.sha }}\"}" >> "$GITHUB_OUTPUT" + + - name: Create GitHub App Token + id: github-app-token + if: needs.validate-inputs.outputs.auth_github == 'true' + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ inputs.github_app_id }} + private-key: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} + + - name: Configure Mise + id: configure-mise + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + with: + tf_version: ${{ inputs.tf_version }} + tg_version: ${{ inputs.tg_version }} + + - name: "Set Terragrunt Plan status to pending" + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" + status: "pending" + description: "Terragrunt plan is running..." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - name: Plan + id: plan + uses: gruntwork-io/terragrunt-action@5e86476ca61eaf74adb9c0525745f29f921f2199 + env: + INPUT_PRE_EXEC_0: | + ${{ inputs.before_plan_commands }} + INPUT_POST_EXEC_0: | + ${{ inputs.after_plan_commands }} + TF_VAR_organization_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_organization_tag }} + TF_VAR_repository_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_repository_tag }} + TF_VAR_commit_hash_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_commit_hash_tag }} + TF_VAR_branch_tag: ${{ steps.set-tags-aws.outputs.TF_VAR_branch_tag }} + ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + TF_VAR_system_tags: ${{ steps.set-tags-azure.outputs.SYSTEM_TAGS }} + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} + with: + tf_path: "terraform" + tg_version: ${{ inputs.tg_version }} + tg_dir: "${{ inputs.tg_dir }}" + tg_command: "plan" + + - name: "Update Terragrunt Plan status" + if: always() && steps.plan.outcome != 'skipped' + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" + status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome == 'failure' && 'failure' || 'error' }} + description: "Terragrunt plan ${{ steps.plan.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/docs/reusable-terragrunt-deploy.md b/docs/reusable-terragrunt-deploy.md new file mode 100644 index 0000000..c5b1497 --- /dev/null +++ b/docs/reusable-terragrunt-deploy.md @@ -0,0 +1,266 @@ +# Terragrunt Environment Deployment + +Plans and deploys a single Terragrunt environment. This workflow unifies the previously separate `reusable-terragrunt-deploy-aws.yml` and `reusable-terragrunt-deploy-azure.yml` workflows into a single, provider-agnostic workflow controlled by the `auth_method` input. + +`auth_method` accepts a comma-delimited list of authentication methods, enabling multiple providers to be authenticated simultaneously (e.g. `"aws,github"` to authenticate with AWS via OIDC while also generating a GitHub App token for private module access). It can also be omitted or set to an empty string to run Terragrunt without any authentication. + +## Usage + +### AWS authentication (`auth_method: aws`) + +Use this when your environment is deployed to AWS. Authentication is performed via OIDC using a role you provide (or set the `DEPLOY_ROLE_ARN` variable on your environment or repository). + +Let's say we have a repository with the structure shown below: + +> ./ +> platform/ +> sandbox/ +> us-east-2/ +> 000/ +> test/ +> us-east-2/ +> 000/ +> production/ +> us-east-2/ +> 000/ + +If we wanted to deploy our production environment when a release was published, we might create a workflow like so: + +```yaml +name: Release to Production + +on: + release: + types: + - published + +jobs: + deploy-production: + permissions: + contents: read + id-token: write + statuses: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy.yml@ref + with: + auth_method: "aws" + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.54.11' + gh_environment: 'production' + tg_dir: 'platform/production/us-east-2/000' + aws_auth_region: 'us-east-2' + aws_assume_role_arn: 'arn:aws:iam::123456789012:role/my-assumed-role' +``` + +If you wanted to deploy all regions and instances within a given environment -- say you had production resources that were in us-east-1 and us-east-2 -- then you can utilize GitHub's matrix functionality and our [workflow to create a matrix for Terragrunt](./reusable-github-matrix-tg.md). + +### Azure authentication (`auth_method: azure`) + +Use this when your environment is deployed to Azure. Authentication is performed via OIDC using Azure credentials passed as secrets. + +Let's say we have a repository with the structure shown below: + +> ./ +> platform/ +> sandbox/ +> eastus2/ +> 000/ +> test/ +> eastus2/ +> 000/ +> production/ +> eastus2/ +> 000/ + +If we wanted to deploy our production environment when a release was published, we might create a workflow like so: + +```yaml +name: Release to Production + +on: + release: + types: + - published + +jobs: + deploy-production: + permissions: + contents: read + id-token: write + statuses: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy.yml@ref + with: + auth_method: "azure" + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.77.22' + gh_environment: 'production' + tg_dir: 'platform/production/eastus2/000' + secrets: inherit # pragma: allowlist secret + + # For usage outside the launchbynttdata organization, pass the secrets explicitly: + # secrets: + # TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: ${{ secrets.your_azure_client_id_secret }} + # TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: ${{ secrets.your_azure_tenant_id_secret }} + # TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: ${{ secrets.your_azure_subscription_id_secret }} +``` + +If you wanted to deploy all regions and instances within a given environment -- say you had production resources that were in eastus and eastus2 -- then you can utilize GitHub's matrix functionality and our [workflow to create a matrix for Terragrunt](./reusable-github-matrix-tg.md). For more information on OIDC setup for Azure, see the [azure/login action documentation](https://github.com/Azure/login?tab=readme-ov-file#login-with-openid-connect-oidc-recommended). + +### GitHub App authentication (`auth_method: github`) + +Use this when your Terragrunt configuration needs to apply changes via the GitHub Terraform Provider. Authentication is performed using a GitHub App, which generates a short-lived token: + +```yaml +name: Release to Production + +on: + release: + types: + - published + +jobs: + deploy-production: + permissions: + contents: read + id-token: write + statuses: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy.yml@ref + with: + auth_method: "github" + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.54.11' + gh_environment: 'production' + tg_dir: 'platform/production/us-east-2/000' + github_app_id: "123456" + secrets: + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: ${{ secrets.MY_GITHUB_APP_PRIVATE_KEY }} +``` + +Replace `ref` with an appropriate ref to this repository, and replace the `TERRAGRUNT_DEPLOY_GITHUB_APP_ID` input and `TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET` secret with values for your GitHub App. + +Note that this does not perform the checkout with the obtained GitHub token, it is only used in the context of applying GitHub resources with Terragrunt! + +### Combined authentication (e.g. `auth_method: "aws,github"`) + +Use this when your infrastructure is deployed across multiple Terraform providers. The example below might deploy a new GitHub repository (authenticating as a GitHub App to use the GitHub API) and then stand up some additional resources for that repository in AWS. Both AWS OIDC and a GitHub App token will be configured: + +```yaml +name: Release to Production + +on: + release: + types: + - published + +jobs: + deploy-production: + permissions: + contents: read + id-token: write + statuses: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy.yml@ref + with: + auth_method: "aws,github" + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.54.11' + gh_environment: 'production' + tg_dir: 'platform/production/us-east-2/000' + aws_auth_region: 'us-east-2' + aws_assume_role_arn: 'arn:aws:iam::123456789012:role/my-assumed-role' + github_app_id: "123456" + secrets: + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: ${{ secrets.MY_GITHUB_APP_PRIVATE_KEY }} +``` + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `auth_method` | Comma-delimited list of authentication methods to use. Valid values are `aws`, `azure`, and `github` (e.g. `"aws"`, `"aws,github"`, `"aws,azure"`). Omit or pass an empty string to run without authentication. | No | `""` | +| `git_branch` | Branch triggering this deployment. | Yes | β€” | +| `tf_version` | Version of Terraform to utilize. | Yes | `1.5.5` | +| `tg_version` | Version of Terragrunt to utilize. | Yes | β€” | +| `gh_environment` | GitHub Environment to deploy to (e.g. test, production). | No | β€” | +| `tg_dir` | Folder containing the Terragrunt configuration to deploy (relative to the repository root). | Yes | β€” | +| `aws_auth_region` | AWS region to use for authentication. Required when `auth_method` includes `aws`. | No | β€” | +| `aws_assume_role_arn` | ARN of the role to assume prior to Terragrunt invocation. Required when `auth_method` includes `aws`. Defaults to `vars.DEPLOY_ROLE_ARN`. | No | `${{ vars.DEPLOY_ROLE_ARN }}` | +| `github_app_id` | GitHub App ID for authentication. Required when `auth_method` includes `github`. Defaults to `vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID`. | No | `${{ vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID }}` | +| `before_plan_commands` | Commands to run prior to executing Terragrunt plan. | No | `""` | +| `before_deploy_commands` | Commands to run prior to executing Terragrunt apply. | No | `""` | +| `before_shared_commands` | Commands to run prior to both Terragrunt plan and apply (after the specific before commands). | No | `""` | +| `after_plan_commands` | Commands to run after executing Terragrunt plan. | No | `""` | +| `after_deploy_commands` | Commands to run after executing Terragrunt apply. | No | `""` | +| `after_shared_commands` | Commands to run after both Terragrunt plan and apply (after the specific after commands). | No | `""` | + +## Outputs + +| Name | Description | +|------|-------------| +| `terraform_outputs` | JSON string containing all Terraform outputs from the deployment (base64 encoded). | + +## Secrets + +| Name | Description | Required | +|------|-------------|----------| +| `TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID` | Azure client ID for OIDC authentication. Required when `auth_method` includes `azure`. | No* | +| `TERRAGRUNT_DEPLOY_AZURE_TENANT_ID` | Azure tenant ID for OIDC authentication. Required when `auth_method` includes `azure`. | No* | +| `TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID` | Azure subscription ID for OIDC authentication. Required when `auth_method` includes `azure`. | No* | +| `TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET` | GitHub App private key for authentication. Required when `auth_method` includes `github`. | No* | + +*These secrets are declared as optional at the workflow level to allow reuse across different auth methods, but the workflow will fail at the `validate-inputs` job if the required secrets for the selected `auth_method` are missing. + +## Migrating from the provider-specific workflows + +If you are currently using `reusable-terragrunt-deploy-aws.yml`, replace the `uses` reference and add `auth_method: "aws"`. Several other inputs have been consolidated down to a `tg_dir` input: + +```yaml +# Before +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy-aws.yml@ref +with: + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.54.11' + environment: 'production' + region: 'us-east-2' + env_id: '000' + +# After +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy.yml@ref +with: + auth_method: "aws" + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.54.11' + gh_environment: 'production' + tg_dir: 'platform/production/us-east-2/000' + aws_auth_region: 'us-east-2' +``` + +If you are currently using `reusable-terragrunt-deploy-azure.yml`, replace the `uses` reference and add `auth_method: "azure"`. Several other inputs have been consolidated down to a `tg_dir` input: + +```yaml +# Before +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy-azure.yml@ref +with: + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.77.22' + environment: 'production' + region: 'eastus2' + env_id: '000' +secrets: inherit # pragma: allowlist secret + +# After +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-deploy.yml@ref +with: + auth_method: "azure" + git_branch: ${{ github.head_ref }} + tf_version: '1.5.5' + tg_version: '0.77.22' + gh_environment: 'production' + tg_dir: 'platform/production/eastus2/000' +secrets: inherit # pragma: allowlist secret +``` diff --git a/docs/reusable-terragrunt-plan-only.md b/docs/reusable-terragrunt-plan-only.md new file mode 100644 index 0000000..49ff342 --- /dev/null +++ b/docs/reusable-terragrunt-plan-only.md @@ -0,0 +1,284 @@ +# Plan a Terragrunt Environment + +Plans a single Terragrunt environment. This workflow unifies the previously separate `reusable-terragrunt-plan-only-aws.yml` and `reusable-terragrunt-plan-only-azure.yml` workflows into a single, provider-agnostic workflow controlled by the `auth_method` input. + +`auth_method` accepts a comma-delimited list of authentication methods, enabling multiple providers to be authenticated simultaneously (e.g. `"aws,github"` to authenticate with AWS via OIDC while also generating a GitHub App token for private module access). It can also be omitted or set to an empty string to run Terragrunt without any authentication. + +Rather than utilizing a GitHub Environment (which may require approval for this plan-only scenario), this workflow takes authentication credentials directly. The typical use case for this workflow is to perform a plan against an upper environment, e.g. production, when the code is being PRed. + +## Usage + +### AWS authentication (`auth_method: aws`) + +Use this when your environment is deployed to AWS. Authentication is performed via OIDC using a role you provide: + +```yaml +name: Plan Production Environment + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: [ "**" ] + +jobs: + get-tg-versions: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-versions.yml@ref + + build-matrix: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-github-matrix-tg.yml@ref + with: + platform_environment: production + + call-terragrunt-plan: + needs: [get-tg-versions, build-matrix] + permissions: + contents: read + id-token: write + statuses: write + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only.yml@ref + with: + auth_method: "aws" + git_branch: ${{ github.head_ref }} + tf_version: ${{ needs.get-tg-versions.outputs.tf_version }} + tg_version: ${{ needs.get-tg-versions.outputs.tg_version }} + tg_dir: "platform/${{ matrix.terragrunt_environment.environment }}/${{ matrix.terragrunt_environment.region }}/${{ matrix.terragrunt_environment.instance }}" + aws_auth_region: "us-east-2" + aws_assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" +``` + +Replace `ref` with an appropriate ref to this repository, and replace the `assume_role_arn` and `auth_region` inputs with values of your choosing. + +### Azure authentication (`auth_method: azure`) + +Use this when your environment is deployed to Azure. Authentication is performed via OIDC using Azure credentials passed as secrets: + +```yaml +name: Plan Production Environment + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: [ "**" ] + +jobs: + get-tg-versions: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-versions.yml@ref + + build-matrix: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-github-matrix-tg.yml@ref + with: + platform_environment: production + + call-terragrunt-plan: + needs: [get-tg-versions, build-matrix] + permissions: + contents: read + id-token: write + statuses: write + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only.yml@ref + with: + auth_method: "azure" + git_branch: ${{ github.head_ref }} + tf_version: ${{ needs.get-tg-versions.outputs.tf_version }} + tg_version: ${{ needs.get-tg-versions.outputs.tg_version }} + tg_dir: "platform/${{ matrix.terragrunt_environment.environment }}/${{ matrix.terragrunt_environment.region }}/${{ matrix.terragrunt_environment.instance }}" + secrets: inherit # pragma: allowlist secret + + # For usage outside the launchbynttdata organization, pass the secrets explicitly: + # secrets: + # TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: ${{ secrets.your_azure_client_id_secret }} + # TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: ${{ secrets.your_azure_tenant_id_secret }} + # TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: ${{ secrets.your_azure_subscription_id_secret }} +``` + +Replace `ref` with an appropriate ref to this repository. For more information on OIDC setup for Azure, see the [azure/login action documentation](https://github.com/Azure/login?tab=readme-ov-file#login-with-openid-connect-oidc-recommended). + +### GitHub App authentication (`auth_method: github`) + +Use this when your Terragrunt configuration needs to plan changes via the GitHub Terraform Provider. Authentication is performed using a GitHub App, which generates a short-lived token: + +```yaml +name: Plan Production Environment + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: [ "**" ] + +jobs: + get-tg-versions: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-versions.yml@ref + + build-matrix: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-github-matrix-tg.yml@ref + with: + platform_environment: production + + call-terragrunt-plan: + needs: [get-tg-versions, build-matrix] + permissions: + contents: read + id-token: write + statuses: write + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only.yml@ref + with: + auth_method: "github" + git_branch: ${{ github.head_ref }} + tf_version: ${{ needs.get-tg-versions.outputs.tf_version }} + tg_version: ${{ needs.get-tg-versions.outputs.tg_version }} + tg_dir: "platform/${{ matrix.terragrunt_environment.environment }}/${{ matrix.terragrunt_environment.region }}/${{ matrix.terragrunt_environment.instance }}" + github_app_id: "123456" + secrets: + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: ${{ secrets.MY_GITHUB_APP_PRIVATE_KEY }} +``` + +Replace `ref` with an appropriate ref to this repository, and replace the `github_app_id` input and `TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET` secret with values for your GitHub App. + +Note that this does not perform the checkout with the obtained GitHub token, it is only used in the context of planning GitHub resources managed with Terragrunt! + +### Combined authentication (e.g. `auth_method: "aws,azure"`) + +Use this when your infrastructure is deployed across AWS and Azure within a single Terragrunt environment: + +```yaml +name: Plan Production Environment + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: [ "**" ] + +jobs: + get-tg-versions: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-versions.yml@ref + + build-matrix: + permissions: + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-github-matrix-tg.yml@ref + with: + platform_environment: production + + call-terragrunt-plan: + needs: [get-tg-versions, build-matrix] + permissions: + contents: read + id-token: write + statuses: write + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only.yml@ref + with: + auth_method: "aws,azure" + git_branch: ${{ github.head_ref }} + tf_version: ${{ needs.get-tg-versions.outputs.tf_version }} + tg_version: ${{ needs.get-tg-versions.outputs.tg_version }} + tg_dir: "platform/${{ matrix.terragrunt_environment.environment }}/${{ matrix.terragrunt_environment.region }}/${{ matrix.terragrunt_environment.instance }}" + aws_auth_region: "us-east-2" + aws_assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" + secrets: + TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: ${{ secrets.your_azure_client_id_secret }} + TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: ${{ secrets.your_azure_tenant_id_secret }} + TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: ${{ secrets.your_azure_subscription_id_secret }} +``` + +Replace `ref` with an appropriate ref to this repository, and replace the `aws_assume_role_arn`, `aws_auth_region`, and `TERRAGRUNT_DEPLOY_AZURE_*` secrets with your own. + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `auth_method` | Comma-delimited list of authentication methods to use. Valid values are `aws`, `azure`, and `github` (e.g. `"aws"`, `"aws,github"`, `"aws,azure"`). Omit or pass an empty string to run without authentication. | No | `""` | +| `git_branch` | Branch triggering this plan. | Yes | β€” | +| `tf_version` | Version of Terraform to utilize. | Yes | `1.5.5` | +| `tg_version` | Version of Terragrunt to utilize. | Yes | β€” | +| `tg_dir` | Folder containing the Terragrunt configuration to plan (relative to the repository root). | Yes | β€” | +| `aws_auth_region` | AWS region to use for authentication. Required when `auth_method` includes `aws`. | No | β€” | +| `aws_assume_role_arn` | ARN of the role to assume prior to Terragrunt invocation. Required when `auth_method` includes `aws`. | No | β€” | +| `github_app_id` | GitHub App ID for authentication. Required when `auth_method` includes `github`. Defaults to `vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID`. | No | `${{ vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID }}` | +| `before_plan_commands` | Commands to run prior to executing Terragrunt plan. | No | `""` | +| `after_plan_commands` | Commands to run after executing Terragrunt plan. | No | `""` | + +## Secrets + +| Name | Description | Required | +|------|-------------|----------| +| `TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID` | Azure client ID for OIDC authentication. Required when `auth_method` includes `azure`. | No* | +| `TERRAGRUNT_DEPLOY_AZURE_TENANT_ID` | Azure tenant ID for OIDC authentication. Required when `auth_method` includes `azure`. | No* | +| `TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID` | Azure subscription ID for OIDC authentication. Required when `auth_method` includes `azure`. | No* | +| `TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET` | GitHub App private key for authentication. Required when `auth_method` includes `github`. | No* | + +*These secrets are declared as optional at the workflow level to allow reuse across different auth methods, but the workflow will fail at the `validate-inputs` job if the required secrets for the selected `auth_method` are missing. + +## Migrating from the provider-specific workflows + +If you are currently using `reusable-terragrunt-plan-only-aws.yml`, replace the `uses` reference and add `auth_method: "aws"`. Several other inputs have been consolidated down to a `tg_dir` input: + +```yaml +# Before +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only-aws.yml@ref +with: + git_branch: ${{ github.head_ref }} + assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" + environment: production + region: us-east-2 + env_id: "000" + +# After +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only.yml@ref +with: + auth_method: "aws" + git_branch: ${{ github.head_ref }} + tg_dir: "platform/production/us-east-2/000" + aws_auth_region: "us-east-2" + aws_assume_role_arn: "arn:aws:iam::123456789012:role/my-assumed-role" +``` + +If you are currently using `reusable-terragrunt-plan-only-azure.yml`, replace the `uses` reference and add `auth_method: "azure"`. Several other inputs have been consolidated down to a `tg_dir` input: + +```yaml +# Before +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only-azure.yml@ref +with: + git_branch: ${{ github.head_ref }} + environment: production + region: eastus2 + env_id: "000" +secrets: inherit # pragma: allowlist secret + +# After +uses: launchbynttdata/launch-workflows/.github/workflows/reusable-terragrunt-plan-only.yml@ref +with: + auth_method: "azure" + git_branch: ${{ github.head_ref }} + tg_dir: "platform/production/eastus2/000" +secrets: inherit # pragma: allowlist secret +``` From 21a4365fa5a19b65c05035027d1f1f46d0b2986c Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 7 Apr 2026 15:32:37 -0500 Subject: [PATCH 04/44] fix: tweak reusable terraform with improvements from terragrunt --- .../workflows/reusable-terraform-check.yml | 148 ++++++++++++------ 1 file changed, 102 insertions(+), 46 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index b7785ee..fad1803 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -4,27 +4,38 @@ on: workflow_call: inputs: auth_method: - description: 'Authentication method to use for Terraform checks. Valid values are "none", "aws", and "azure".' - required: true + description: 'Comma-delimited list of authentication methods to use. Valid values are "aws", "azure", and "github" (e.g. "aws", "aws,github", "aws,azure"). Pass an empty string or omit to run Terraform checks without any authentication.' + required: false + default: "" type: string - assume_role_arn: - description: "ARN of the role to assume when running tests and creating test resources. Required if auth_method is 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN variable." + # --- AWS authentication inputs --- + aws_assume_role_arn: + description: "ARN of the role to assume when running tests and creating test resources. Required if auth_method includes 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN variable." required: false type: string default: "${{ vars.TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN }}" - region: - description: "AWS region to deploy when running tests and creating resources. Required if auth_method is 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_REGION variable." + aws_auth_region: + description: "AWS region to use for authentication. Required if auth_method includes 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_REGION variable." default: "${{ vars.TERRAFORM_CHECK_AWS_REGION }}" required: false type: string + # --- GitHub App authentication inputs --- + github_app_id: + description: "The GitHub App ID to use for authentication, defaulting to the TERRAFORM_CHECK_GITHUB_APP_ID variable. Required if auth_method includes 'github', ignored otherwise." + required: false + default: "${{ vars.TERRAFORM_CHECK_GITHUB_APP_ID }}" + type: string secrets: - # If using Azure authentication, these secrets must be provided. They are not required for the workflow itself to allow reuse in non-Azure contexts. + # --- Azure authentication secrets (required if auth_method includes 'azure') --- TERRAFORM_CHECK_AZURE_CLIENT_ID: required: false TERRAFORM_CHECK_AZURE_TENANT_ID: required: false TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID: required: false + # --- GitHub App authentication secrets (required if auth_method includes 'github') --- + TERRAFORM_CHECK_GITHUB_APP_SECRET: + required: false permissions: contents: read @@ -36,49 +47,86 @@ jobs: name: "Validate Inputs" runs-on: ubuntu-latest outputs: - auth_method: ${{ steps.validate.outputs.auth_method }} + auth_aws: ${{ steps.validate.outputs.auth_aws }} + auth_azure: ${{ steps.validate.outputs.auth_azure }} + auth_github: ${{ steps.validate.outputs.auth_github }} steps: - name: Validate inputs and secrets id: validate shell: bash run: | - if [[ "${{ inputs.auth_method }}" != "none" && "${{ inputs.auth_method }}" != "aws" && "${{ inputs.auth_method }}" != "azure" ]]; then - echo "Error: Invalid auth_method input '${{ inputs.auth_method }}'. Valid values are 'none', 'aws', and 'azure'." - exit 1 - fi + auth_aws=false + auth_azure=false + auth_github=false - if [[ "${{ inputs.auth_method }}" == "aws" ]]; then - if [[ -z "${{ inputs.assume_role_arn }}" ]]; then - echo "Error: assume_role_arn input is required when auth_method is 'aws'." - exit 1 - fi - if [[ -z "${{ inputs.region }}" ]]; then - echo "Error: region input is required when auth_method is 'aws'." - exit 1 - fi - fi - - if [[ "${{ inputs.auth_method }}" == "azure" ]]; then - if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }}" ]]; then - echo "Error: TERRAFORM_CHECK_AZURE_CLIENT_ID secret is required when auth_method is 'azure'." - exit 1 - fi - if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }}" ]]; then - echo "Error: TERRAFORM_CHECK_AZURE_TENANT_ID secret is required when auth_method is 'azure'." - exit 1 - fi - if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }}" ]]; then - echo "Error: TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID secret is required when auth_method is 'azure'." - exit 1 - fi - fi + IFS=',' read -ra AUTH_METHODS <<< "${{ inputs.auth_method }}" + for method in "${AUTH_METHODS[@]}"; do + method=$(echo "$method" | xargs) + [[ -z "$method" ]] && continue + case "$method" in + # --- AWS authentication validation --- + aws) + auth_aws=true + if [[ -z "${{ inputs.aws_assume_role_arn }}" ]]; then + echo "Error: aws_assume_role_arn input is required when auth_method includes 'aws'." + exit 1 + fi + if [[ -z "${{ inputs.aws_auth_region }}" ]]; then + echo "Error: aws_auth_region input is required when auth_method includes 'aws'." + exit 1 + fi + ;; + # --- Azure authentication validation --- + azure) + auth_azure=true + if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }}" ]]; then + echo "Error: TERRAFORM_CHECK_AZURE_CLIENT_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }}" ]]; then + echo "Error: TERRAFORM_CHECK_AZURE_TENANT_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }}" ]]; then + echo "Error: TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID secret is required when auth_method includes 'azure'." + exit 1 + fi + ;; + # --- GitHub App authentication validation --- + github) + auth_github=true + if [[ -z "${{ inputs.github_app_id }}" ]]; then + echo "Error: github_app_id input is required when auth_method includes 'github'." + exit 1 + fi + if [[ -z "${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }}" ]]; then + echo "Error: TERRAFORM_CHECK_GITHUB_APP_SECRET secret is required when auth_method includes 'github'." + exit 1 + fi + ;; + *) + echo "Error: Invalid auth_method '$method'. Valid values are 'aws', 'azure', and 'github'." + exit 1 + ;; + esac + done - echo "auth_method=${{ inputs.auth_method }}" >> $GITHUB_OUTPUT + echo "auth_aws=$auth_aws" >> $GITHUB_OUTPUT + echo "auth_azure=$auth_azure" >> $GITHUB_OUTPUT + echo "auth_github=$auth_github" >> $GITHUB_OUTPUT check: name: "Run Tests" runs-on: ubuntu-latest needs: validate-inputs steps: + - id: github-app-token + name: Create GitHub App Token + if: needs.validate-inputs.outputs.auth_github == 'true' + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ inputs.github_app_id }} + private-key: ${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }} + - id: checkout name: Checkout uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 @@ -109,12 +157,14 @@ jobs: set -x git config user.name "GitHub Actions" git config user.email "noreply@launch.nttdata.com" - if [[ "${{ needs.validate-inputs.outputs.auth_method }}" == "aws" ]]; then - export AWS_REGION=${{ inputs.region }} - elif [[ "${{ needs.validate-inputs.outputs.auth_method }}" == "azure" ]]; then + if [[ "${{ needs.validate-inputs.outputs.auth_aws }}" == "true" ]]; then + export AWS_REGION=${{ inputs.aws_auth_region }} + elif [[ "${{ needs.validate-inputs.outputs.auth_azure }}" == "true" ]]; then export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} fi make configure + env: + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} - id: save-cache uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 @@ -132,6 +182,7 @@ jobs: check_name: "Terraform Lint" status: "pending" description: "Terraform lint check is running..." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - id: lint name: "make lint" @@ -146,19 +197,20 @@ jobs: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} description: "Terraform lint ${{ steps.lint.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - id: configure-aws-credentials name: Configure AWS credentials - if: needs.validate-inputs.outputs.auth_method == 'aws' + if: needs.validate-inputs.outputs.auth_aws == 'true' uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 with: - role-to-assume: ${{ inputs.assume_role_arn }} + role-to-assume: ${{ inputs.aws_assume_role_arn }} role-session-name: ${{ github.run_id }} - aws-region: ${{ inputs.region }} + aws-region: ${{ inputs.aws_auth_region }} - id: create-aws-profile name: "Create AWS Profile" - if: needs.validate-inputs.outputs.auth_method == 'aws' + if: needs.validate-inputs.outputs.auth_aws == 'true' # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need # to remove line setting the profile in our examples, or we see failures to initialize the provider. @@ -174,7 +226,7 @@ jobs: - id: azure-login name: Azure login - if: needs.validate-inputs.outputs.auth_method == 'azure' + if: needs.validate-inputs.outputs.auth_azure == 'true' uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 with: client-id: ${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }} @@ -188,9 +240,12 @@ jobs: check_name: "Terraform Tests" status: "pending" description: "Terraform tests are running..." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - id: test name: "make test" + env: + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} run: | make test @@ -202,3 +257,4 @@ jobs: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} description: "Terraform tests ${{ steps.test.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" From b13ecdf6af7a6b6a1c5f02585ef340a24fd5b75e Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 7 Apr 2026 18:15:13 -0500 Subject: [PATCH 05/44] fix: pass owner to create-github-app-token --- .github/workflows/reusable-terraform-check.yml | 17 +++++++++-------- .../workflows/reusable-terragrunt-deploy.yml | 1 + .../workflows/reusable-terragrunt-plan-only.yml | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index fad1803..34b496b 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -119,14 +119,6 @@ jobs: runs-on: ubuntu-latest needs: validate-inputs steps: - - id: github-app-token - name: Create GitHub App Token - if: needs.validate-inputs.outputs.auth_github == 'true' - uses: actions/create-github-app-token@v3 - with: - app-id: ${{ inputs.github_app_id }} - private-key: ${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }} - - id: checkout name: Checkout uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 @@ -233,6 +225,15 @@ jobs: tenant-id: ${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }} subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + - id: github-app-token + name: Create GitHub App Token + if: needs.validate-inputs.outputs.auth_github == 'true' + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ inputs.github_app_id }} + private-key: ${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }} + owner: ${{ github.repository_owner }} + - id: set-tests-pending name: "Set Terraform Tests status to pending" uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index 0dbf5e6..13b168a 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -223,6 +223,7 @@ jobs: with: app-id: ${{ inputs.github_app_id }} private-key: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} + owner: ${{ github.repository_owner }} - name: Configure Mise id: configure-mise diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index 27ab8a8..e6e5128 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -189,6 +189,7 @@ jobs: with: app-id: ${{ inputs.github_app_id }} private-key: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} + owner: ${{ github.repository_owner }} - name: Configure Mise id: configure-mise From 7b0fe7b3ab4db155c7f2652b908512c295dad794 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 17:51:28 -0500 Subject: [PATCH 06/44] fix: write legacy status checks --- .../workflows/reusable-terraform-check.yml | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 34b496b..bb6f576 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -39,7 +39,7 @@ on: permissions: contents: read - id-token: write # Required for various OIDC auth flows. + id-token: write statuses: write jobs: @@ -236,6 +236,7 @@ jobs: - id: set-tests-pending name: "Set Terraform Tests status to pending" + continue-on-error: true uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: check_name: "Terraform Tests" @@ -253,9 +254,32 @@ jobs: - id: update-tests-status name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' + continue-on-error: true uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} description: "Terraform tests ${{ steps.test.outcome }}" target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # Once we're fully on the new workflows, we can remove these steps: + + - id: update-legacy-status-checks-aws + name: "Add AWS Legacy Status Check" + if: always() && startsWith(github.repository, 'tf-aws-') + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Check AWS Terraform Code / Check AWS Terraform Code" + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform tests ${{ steps.test.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - id: update-legacy-status-checks-azure + name: "Add Azure Legacy Status Check" + if: always() && startsWith(github.repository, 'tf-az') + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Check Azure Terraform Code / Check Azure Terraform Code" + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + description: "Terraform tests ${{ steps.test.outcome }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" From 91872160437c9245372069fb94d43e6fa3fe4294 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 17:59:57 -0500 Subject: [PATCH 07/44] fix: repo name detection --- .github/workflows/reusable-terraform-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index bb6f576..9d3ac80 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -266,7 +266,7 @@ jobs: - id: update-legacy-status-checks-aws name: "Add AWS Legacy Status Check" - if: always() && startsWith(github.repository, 'tf-aws-') + if: always() && startsWith(github.event.repository.name, 'tf-aws-') uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: check_name: "Check AWS Terraform Code / Check AWS Terraform Code" @@ -276,7 +276,7 @@ jobs: - id: update-legacy-status-checks-azure name: "Add Azure Legacy Status Check" - if: always() && startsWith(github.repository, 'tf-az') + if: always() && startsWith(github.event.repository.name, 'tf-az') uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: check_name: "Check Azure Terraform Code / Check Azure Terraform Code" From 12517d7f988763bb8f66c846dedd903186102cdc Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 18:11:24 -0500 Subject: [PATCH 08/44] feat: parallelize lint and tests --- .../workflows/reusable-terraform-check.yml | 85 ++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 9d3ac80..4aa9e7f 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -114,8 +114,8 @@ jobs: echo "auth_aws=$auth_aws" >> $GITHUB_OUTPUT echo "auth_azure=$auth_azure" >> $GITHUB_OUTPUT echo "auth_github=$auth_github" >> $GITHUB_OUTPUT - check: - name: "Run Tests" + lint: + name: "Lint Module" runs-on: ubuntu-latest needs: validate-inputs steps: @@ -191,6 +191,59 @@ jobs: description: "Terraform lint ${{ steps.lint.outcome }}" target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + tests: + name: "Run Tests" + runs-on: ubuntu-latest + needs: validate-inputs + steps: + - id: checkout + name: Checkout + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 + + - id: dependencies + name: Setup asdf + # We use the 'setup' variant of this action, because we have some custom behavior in + # our .tool-versions file and Makefile to install plugins from outside the default registry. + uses: asdf-vm/actions/setup@b7bcd026f18772e44fe1026d729e1611cc435d47 + + - id: cache-restore + uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 + # If we've cached the asdf tools, restore them based on the hash of the .tool-versions file. + name: Restore cached asdf tools + with: + path: ~/.asdf + key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + + - id: configure + name: Setup Repository for Checks + # Ensure the 'repo' tool is installed, set up git to make the Makefile happy, and then configure to clone LCAF. + shell: bash + run: | + mkdir -p ~/.local/bin + curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo + chmod +x ~/.local/bin/repo + echo "$HOME/.local/bin" >> $GITHUB_PATH + set -x + git config user.name "GitHub Actions" + git config user.email "noreply@launch.nttdata.com" + if [[ "${{ needs.validate-inputs.outputs.auth_aws }}" == "true" ]]; then + export AWS_REGION=${{ inputs.aws_auth_region }} + elif [[ "${{ needs.validate-inputs.outputs.auth_azure }}" == "true" ]]; then + export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + fi + make configure + env: + GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} + + - id: save-cache + uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 + name: Cache asdf tools + # If we didn't restore the asdf tools, save them based on the hash of the .tool-versions file. + if: steps.cache-restore.outputs.cache-hit != 'true' + with: + path: ~/.asdf + key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + - id: configure-aws-credentials name: Configure AWS credentials if: needs.validate-inputs.outputs.auth_aws == 'true' @@ -283,3 +336,31 @@ jobs: status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} description: "Terraform tests ${{ steps.test.outcome }}" target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # These legacy status checks will write the necessary success for the existing launch workflows, so that we can transition + # between models without breaking merge capabilities on existing repositories. Once all repositories have transitioned to + # the new checks, we can remove this entire job. + legacy: + name: "Legacy Status Checks" + runs-on: ubuntu-latest + needs: [validate-inputs, lint, tests] + steps: + - id: update-legacy-status-checks-aws + name: "Add AWS Legacy Status Check" + if: startsWith(github.event.repository.name, 'tf-aws-') + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Check AWS Terraform Code / Check AWS Terraform Code" + status: "pending" + description: "This check is being deprecated. Please refer to the new 'Terraform Tests' check for test results." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + - id: update-legacy-status-checks-azure + name: "Add Azure Legacy Status Check" + if: startsWith(github.event.repository.name, 'tf-az') + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Check Azure Terraform Code / Check Azure Terraform Code" + status: "pending" + description: "This check is being deprecated. Please refer to the new 'Terraform Tests' check for test results." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" From 4601aa944248186d2342ab57b436789e482daf77 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 18:28:49 -0500 Subject: [PATCH 09/44] fix: aws auth, cleanup --- .../workflows/reusable-terraform-check.yml | 28 ++----------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 4aa9e7f..39e5b05 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -263,9 +263,9 @@ jobs: set -x mkdir -p ~/.aws echo "[default]" > ~/.aws/credentials - echo "aws_access_key_id=${{ secrets.AWS_ACCESS_KEY_ID }}" >> ~/.aws/credentials - echo "aws_secret_access_key=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> ~/.aws/credentials - echo "aws_session_token=${{ secrets.AWS_SESSION_TOKEN }}" >> ~/.aws/credentials + echo "aws_access_key_id=${{ steps.configure-aws-credentials.outputs.aws-access-key-id }}" >> ~/.aws/credentials + echo "aws_secret_access_key=${{ steps.configure-aws-credentials.outputs.aws-secret-access-key }}" >> ~/.aws/credentials + echo "aws_session_token=${{ steps.configure-aws-credentials.outputs.aws-session-token }}" >> ~/.aws/credentials # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; @@ -315,28 +315,6 @@ jobs: description: "Terraform tests ${{ steps.test.outcome }}" target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - # Once we're fully on the new workflows, we can remove these steps: - - - id: update-legacy-status-checks-aws - name: "Add AWS Legacy Status Check" - if: always() && startsWith(github.event.repository.name, 'tf-aws-') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows - with: - check_name: "Check AWS Terraform Code / Check AWS Terraform Code" - status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} - description: "Terraform tests ${{ steps.test.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - - id: update-legacy-status-checks-azure - name: "Add Azure Legacy Status Check" - if: always() && startsWith(github.event.repository.name, 'tf-az') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows - with: - check_name: "Check Azure Terraform Code / Check Azure Terraform Code" - status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} - description: "Terraform tests ${{ steps.test.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - # These legacy status checks will write the necessary success for the existing launch workflows, so that we can transition # between models without breaking merge capabilities on existing repositories. Once all repositories have transitioned to # the new checks, we can remove this entire job. From fe3af0a71081d54b0af11e7f53bbe6fd59c759eb Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 18:46:13 -0500 Subject: [PATCH 10/44] test: no profile handling --- .../workflows/reusable-terraform-check.yml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 39e5b05..f85cfb8 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -253,21 +253,21 @@ jobs: role-session-name: ${{ github.run_id }} aws-region: ${{ inputs.aws_auth_region }} - - id: create-aws-profile - name: "Create AWS Profile" - if: needs.validate-inputs.outputs.auth_aws == 'true' - # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. - # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need - # to remove line setting the profile in our examples, or we see failures to initialize the provider. - run: | - set -x - mkdir -p ~/.aws - echo "[default]" > ~/.aws/credentials - echo "aws_access_key_id=${{ steps.configure-aws-credentials.outputs.aws-access-key-id }}" >> ~/.aws/credentials - echo "aws_secret_access_key=${{ steps.configure-aws-credentials.outputs.aws-secret-access-key }}" >> ~/.aws/credentials - echo "aws_session_token=${{ steps.configure-aws-credentials.outputs.aws-session-token }}" >> ~/.aws/credentials - # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. - find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; + # - id: create-aws-profile + # name: "Create AWS Profile" + # if: needs.validate-inputs.outputs.auth_aws == 'true' + # # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. + # # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need + # # to remove line setting the profile in our examples, or we see failures to initialize the provider. + # run: | + # set -x + # mkdir -p ~/.aws + # echo "[default]" > ~/.aws/credentials + # echo "aws_access_key_id=${{ steps.configure-aws-credentials.outputs.aws-access-key-id }}" >> ~/.aws/credentials + # echo "aws_secret_access_key=${{ steps.configure-aws-credentials.outputs.aws-secret-access-key }}" >> ~/.aws/credentials + # echo "aws_session_token=${{ steps.configure-aws-credentials.outputs.aws-session-token }}" >> ~/.aws/credentials + # # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. + # find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - id: azure-login name: Azure login From 10d9bcb538eb9625286bf9a0898075261d163b1b Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 18:53:53 -0500 Subject: [PATCH 11/44] test: env vars instead --- .../workflows/reusable-terraform-check.yml | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index f85cfb8..86e7947 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -155,8 +155,6 @@ jobs: export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} fi make configure - env: - GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} - id: save-cache uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 @@ -253,21 +251,21 @@ jobs: role-session-name: ${{ github.run_id }} aws-region: ${{ inputs.aws_auth_region }} - # - id: create-aws-profile - # name: "Create AWS Profile" - # if: needs.validate-inputs.outputs.auth_aws == 'true' - # # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. - # # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need - # # to remove line setting the profile in our examples, or we see failures to initialize the provider. - # run: | - # set -x - # mkdir -p ~/.aws - # echo "[default]" > ~/.aws/credentials - # echo "aws_access_key_id=${{ steps.configure-aws-credentials.outputs.aws-access-key-id }}" >> ~/.aws/credentials - # echo "aws_secret_access_key=${{ steps.configure-aws-credentials.outputs.aws-secret-access-key }}" >> ~/.aws/credentials - # echo "aws_session_token=${{ steps.configure-aws-credentials.outputs.aws-session-token }}" >> ~/.aws/credentials - # # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. - # find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; + - id: create-aws-profile + name: "Create AWS Profile" + if: needs.validate-inputs.outputs.auth_aws == 'true' + # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. + # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need + # to remove line setting the profile in our examples, or we see failures to initialize the provider. + run: | + set -x + mkdir -p ~/.aws + echo "[default]" > ~/.aws/credentials + echo "aws_access_key_id=$AWS_ACCESS_KEY_ID" >> ~/.aws/credentials + echo "aws_secret_access_key=$AWS_SECRET_ACCESS_KEY" >> ~/.aws/credentials + echo "aws_session_token=$AWS_SESSION_TOKEN" >> ~/.aws/credentials + # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. + find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - id: azure-login name: Azure login From 2a7237aa3d153dba74b2187a8403cedd012ec28c Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 8 Apr 2026 19:09:58 -0500 Subject: [PATCH 12/44] fix: provider version, status --- .github/workflows/reusable-terraform-check.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 86e7947..09f5b49 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -254,7 +254,7 @@ jobs: - id: create-aws-profile name: "Create AWS Profile" if: needs.validate-inputs.outputs.auth_aws == 'true' - # Works around the interactions of aws-actions/configure-aws-credentials with 4.x.x AWS TF provider. + # Works around the interactions of aws-actions/configure-aws-credentials with 5.x.x AWS TF provider. # In short, we need to create the profile in ~/.aws/credentials for the provider to use, but also need # to remove line setting the profile in our examples, or we see failures to initialize the provider. run: | @@ -327,7 +327,7 @@ jobs: uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: check_name: "Check AWS Terraform Code / Check AWS Terraform Code" - status: "pending" + status: "success" description: "This check is being deprecated. Please refer to the new 'Terraform Tests' check for test results." target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" @@ -337,6 +337,6 @@ jobs: uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: check_name: "Check Azure Terraform Code / Check Azure Terraform Code" - status: "pending" + status: "success" description: "This check is being deprecated. Please refer to the new 'Terraform Tests' check for test results." target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" From d2a1550df727cf0a49d2cb4fce34d12937957294 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Thu, 9 Apr 2026 16:33:32 -0500 Subject: [PATCH 13/44] test: dump provider details to debug azure --- .github/workflows/reusable-terraform-check.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 09f5b49..254af2f 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -149,11 +149,6 @@ jobs: set -x git config user.name "GitHub Actions" git config user.email "noreply@launch.nttdata.com" - if [[ "${{ needs.validate-inputs.outputs.auth_aws }}" == "true" ]]; then - export AWS_REGION=${{ inputs.aws_auth_region }} - elif [[ "${{ needs.validate-inputs.outputs.auth_azure }}" == "true" ]]; then - export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} - fi make configure - id: save-cache @@ -300,6 +295,7 @@ jobs: env: GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} run: | + find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c "echo {}; cat {}" \; make test - id: update-tests-status From c0f428d136c70a62cb51ae6b407ba1c304885992 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Thu, 9 Apr 2026 16:35:48 -0500 Subject: [PATCH 14/44] test: create providers first --- .github/workflows/reusable-terraform-check.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 254af2f..4d99e3a 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -295,6 +295,7 @@ jobs: env: GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} run: | + make tfmodule/create_example_providers find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c "echo {}; cat {}" \; make test From a892e40431bb8855cf336f826624c964c5b7519c Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Thu, 9 Apr 2026 16:40:24 -0500 Subject: [PATCH 15/44] fix: creating providers ahead of time fixes it, bug in makefile somewhere? --- .github/workflows/reusable-terraform-check.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 4d99e3a..2adda25 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -295,8 +295,9 @@ jobs: env: GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} run: | + # Hack for Azure, reevaluate when we have another look at the Make targets make tfmodule/create_example_providers - find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c "echo {}; cat {}" \; + make test - id: update-tests-status From 875422569104a17431c82a94085a84b81ae58b97 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 10 Apr 2026 15:59:37 -0500 Subject: [PATCH 16/44] fix: drop wip from conventional commit defaults; we don't want work in progress on main --- .github/configs/release-drafter-conventional-commits.yml | 4 ---- .github/workflows/reusable-pr-conventional-commit-title.yml | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/configs/release-drafter-conventional-commits.yml b/.github/configs/release-drafter-conventional-commits.yml index ec7406d..98ba60f 100644 --- a/.github/configs/release-drafter-conventional-commits.yml +++ b/.github/configs/release-drafter-conventional-commits.yml @@ -49,10 +49,6 @@ categories: collapse-after: 3 labels: - "revert" - - title: "🚧 WIP" - collapse-after: 3 - labels: - - "WIP" change-template: "- $TITLE @$AUTHOR (#$NUMBER)" diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index d8a29c1..0b6dcea 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -28,9 +28,9 @@ on: default: true custom_labels: type: string - description: 'A JSON object mapping task types to custom label names. Default: {"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert", "wip": "WIP"}' + description: 'A JSON object mapping task types to custom label names. Default: {"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert"}' required: false - default: '{"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert", "wip": "WIP"}' + default: '{"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert"}' comment_on_failure: type: boolean description: "Whether to comment on the pull request if the title validation fails. Default: true" From 1da984ea486c903715b16d1c8d784754bd8d6cfa Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 10 Apr 2026 18:05:24 -0500 Subject: [PATCH 17/44] fix: support legacy PR validation with conventional commit workflow --- .../reusable-pr-conventional-commit-title.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 0b6dcea..15b205a 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -162,3 +162,21 @@ jobs: if [ "${{ steps.find-comment.outputs.comment-id }}" != "" ]; then gh api -X DELETE repos/${{ github.repository }}/issues/comments/${{ steps.find-comment.outputs.comment-id }} --silent fi + + - id: set-status-check + name: Set Legacy Check + if: ${{ inputs.comment_on_failure }} + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Conventional Commit PR Title" + status: ${{ steps.pr-validation.outcome == 'success' && 'success' || steps.pr-validation.outcome == 'failure' && 'failure' || 'error' }} + description: ${{ steps.pr-validation.outcome == 'success' && 'PR title is valid.' || steps.pr-validation.outcome == 'failure' && 'PR title is invalid.' || 'Error validating PR title.' }} + + - id: set-status-check-legacy + name: Set Legacy Check + if: ${{ inputs.comment_on_failure }} + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + with: + check_name: "Label Pull Request / Label Pull Request" + status: ${{ steps.pr-validation.outcome == 'success' && 'success' || steps.pr-validation.outcome == 'failure' && 'failure' || 'error' }} + description: ${{ steps.pr-validation.outcome == 'success' && 'PR title is valid.' || steps.pr-validation.outcome == 'failure' && 'PR title is invalid.' || 'Error validating PR title.' }} From a6ae1cc011f7db49a51c587b9b6f41eff6fc7c03 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 10 Apr 2026 18:09:09 -0500 Subject: [PATCH 18/44] fix: status permissions --- .github/workflows/reusable-pr-conventional-commit-title.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 15b205a..481c553 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -45,6 +45,7 @@ on: permissions: contents: read pull-requests: write + statuses: write jobs: validate-title: From 8047d78462b400b4d2b023b72890f4706f4b90a3 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Mon, 13 Apr 2026 11:21:23 -0500 Subject: [PATCH 19/44] fix: one status check is not legacy --- .../workflows/reusable-pr-conventional-commit-title.yml | 2 +- docs/reusable-pr-conventional-commit-title.md | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 481c553..9cc3a58 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -165,7 +165,7 @@ jobs: fi - id: set-status-check - name: Set Legacy Check + name: Set Status Check if: ${{ inputs.comment_on_failure }} uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows with: diff --git a/docs/reusable-pr-conventional-commit-title.md b/docs/reusable-pr-conventional-commit-title.md index c2eabee..3cdee30 100644 --- a/docs/reusable-pr-conventional-commit-title.md +++ b/docs/reusable-pr-conventional-commit-title.md @@ -42,15 +42,18 @@ jobs: permissions: contents: read pull-requests: write + statuses: write uses: launchbynttdata/launch-workflows/.github/workflows/reusable-pr-conventional-commit-title.yml@ref ``` Be sure you replace `ref` with an appropriate ref to this repository. > [!CAUTION] -> By default, your repository likely does not require this workflow to succeed before a change is merged. By making this workflow required, you ensure that a successful run must be achieved prior to merge, which ensures your commit messages are consistent! +> By default, your repository may not require this workflow to succeed before a change is merged. By making this workflow required, you ensure that a successful run must be achieved prior to merge, which ensures your commit messages are consistent! > -> To make this workflow required, visit your repository's settings and create a new Ruleset with a required status check, as shown below: +> Repositories within `launchbynttdata` are already configured with a required status check, and no further action needs to be taken. + +To make this workflow required, visit your repository's settings and create a new Ruleset with a required status check, as shown below: ![Required status check in the GitHub settings page](images/required-status-check.png) From bd797f89230deb8687b5f8a254dfc293933d113b Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 14 Apr 2026 16:29:21 -0500 Subject: [PATCH 20/44] feat: workflows from nttdtest poc --- .../reusable-pr-automated-approvals.yml | 123 ++++++++++ .../reusable-pr-dependabot-automerge.yml | 26 +++ .../reusable-update-from-skeleton.yml | 211 ++++++++++++++++++ docs/reusable-pr-automated-approvals.md | 53 +++++ docs/reusable-pr-dependabot-automerge.md | 43 ++++ docs/reusable-update-from-skeleton.md | 73 ++++++ 6 files changed, 529 insertions(+) create mode 100644 .github/workflows/reusable-pr-automated-approvals.yml create mode 100644 .github/workflows/reusable-pr-dependabot-automerge.yml create mode 100644 .github/workflows/reusable-update-from-skeleton.yml create mode 100644 docs/reusable-pr-automated-approvals.md create mode 100644 docs/reusable-pr-dependabot-automerge.md create mode 100644 docs/reusable-update-from-skeleton.md diff --git a/.github/workflows/reusable-pr-automated-approvals.yml b/.github/workflows/reusable-pr-automated-approvals.yml new file mode 100644 index 0000000..7af30c3 --- /dev/null +++ b/.github/workflows/reusable-pr-automated-approvals.yml @@ -0,0 +1,123 @@ +name: Automated Approvals + +on: + workflow_call: + inputs: + # No inputs needed for this workflow, but we need to define at least one to make it callable. + placeholder: + type: string + required: false + default: "" + description: "This input is not used, but is required to make this workflow callable." + +permissions: + pull-requests: read + contents: read + +jobs: + approvals: + name: Update Automated Approvals + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'launch-skeleton-auto-updater[bot]' }} + steps: + - name: Check Pull Request + id: check-pull-request + run: | + ALLOWED_AUTHORS="dependabot[bot] launch-skeleton-auto-updater[bot]" + + # Get all commit authors on this PR + AUTHORS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits" \ + --jq '.[].author.login' | sort -u) + + echo "Commit authors on this PR:" + echo "$AUTHORS" + + SHOULD_APPROVE=true + for author in $AUTHORS; do + if [[ ! " $ALLOWED_AUTHORS " =~ " $author " ]]; then + echo "Found non-automated author: $author" + SHOULD_APPROVE=false + break + fi + done + + if [ "$SHOULD_APPROVE" == "true" ] && [ "${{ github.actor }}" == "launch-skeleton-auto-updater[bot]" ]; then + PR_TITLE="${{ github.event.pull_request.title }}" + if [[ "$PR_TITLE" != chore* ]]; then + echo "Skeleton updater PR title does not start with 'chore': $PR_TITLE" + SHOULD_APPROVE=false + fi + fi + + echo "should_approve=$SHOULD_APPROVE" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ github.token }} + + - name: Get Approver Alpha Token + id: approver-alpha-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ vars.LAUNCH_APPROVER_ALPHA_ID }} + private-key: ${{ secrets.LAUNCH_APPROVER_ALPHA_KEY }} + + - name: Get Approver Bravo Token + id: approver-bravo-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ vars.LAUNCH_APPROVER_BRAVO_ID }} + private-key: ${{ secrets.LAUNCH_APPROVER_BRAVO_KEY }} + + - name: Approve PR + if: steps.check-pull-request.outputs.should_approve == 'true' + run: | + echo "All commits are from automated users. Approving PR..." + + GH_TOKEN="${{ steps.approver-alpha-token.outputs.token }}" \ + gh pr review "${{ github.event.pull_request.number }}" \ + --repo "${{ github.repository }}" \ + --approve \ + --body "Automated approval: all commits from trusted automation accounts." + + GH_TOKEN="${{ steps.approver-bravo-token.outputs.token }}" \ + gh pr review "${{ github.event.pull_request.number }}" \ + --repo "${{ github.repository }}" \ + --approve \ + --body "Automated approval: all commits from trusted automation accounts." + env: + GH_TOKEN: ${{ steps.approver-alpha-token.outputs.token }} + + - name: Revoke Approvals + if: steps.check-pull-request.outputs.should_approve == 'false' + run: | + echo "Non-automated commits detected. Revoking any existing automated approvals..." + + # Get approver app slugs + ALPHA_SLUG="${{ steps.approver-alpha-token.outputs.app-slug }}" + BRAVO_SLUG="${{ steps.approver-bravo-token.outputs.app-slug }}" + ALPHA_TOKEN="${{ steps.approver-alpha-token.outputs.token }}" + BRAVO_TOKEN="${{ steps.approver-bravo-token.outputs.token }}" + + # Get all reviews on this PR + REVIEWS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews") + + # Dismiss Alpha's approval if present + ALPHA_REVIEW_ID=$(echo "$REVIEWS" | jq -r ".[] | select(.user.login == \"${ALPHA_SLUG}[bot]\" and .state == \"APPROVED\") | .id" | head -1) + if [ -n "$ALPHA_REVIEW_ID" ] && [ "$ALPHA_REVIEW_ID" != "null" ]; then + echo "Dismissing review $ALPHA_REVIEW_ID from ${ALPHA_SLUG}[bot]" + GH_TOKEN="$ALPHA_TOKEN" gh api \ + --method PUT \ + "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews/$ALPHA_REVIEW_ID/dismissals" \ + -f message="Automated approval revoked: non-automated commits detected on this PR." + fi + + # Dismiss Bravo's approval if present + BRAVO_REVIEW_ID=$(echo "$REVIEWS" | jq -r ".[] | select(.user.login == \"${BRAVO_SLUG}[bot]\" and .state == \"APPROVED\") | .id" | head -1) + if [ -n "$BRAVO_REVIEW_ID" ] && [ "$BRAVO_REVIEW_ID" != "null" ]; then + echo "Dismissing review $BRAVO_REVIEW_ID from ${BRAVO_SLUG}[bot]" + GH_TOKEN="$BRAVO_TOKEN" gh api \ + --method PUT \ + "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews/$BRAVO_REVIEW_ID/dismissals" \ + -f message="Automated approval revoked: non-automated commits detected on this PR." + fi + env: + GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/reusable-pr-dependabot-automerge.yml b/.github/workflows/reusable-pr-dependabot-automerge.yml new file mode 100644 index 0000000..1d546a1 --- /dev/null +++ b/.github/workflows/reusable-pr-dependabot-automerge.yml @@ -0,0 +1,26 @@ +name: Dependabot Auto-Merge + +on: + workflow_call: + inputs: + # No inputs needed for this workflow, but we need to define at least one to make it callable. + placeholder: + type: string + required: false + default: "" + description: "This input is not used, but is required to make this workflow callable." + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot-automerge: + name: Dependabot Auto-Merge + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Enable auto-merge + run: gh pr merge --auto --squash "${{ github.event.pull_request.html_url }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml new file mode 100644 index 0000000..522a8a8 --- /dev/null +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -0,0 +1,211 @@ +name: Update Repository from Skeleton + +on: + workflow_call: + inputs: + recopy: + description: "Perform a full recopy instead of an incremental update (overwrites all templated files), and re-runs any tasks defined in copier.yml. The resulting PR will require manual review and merging." + type: boolean + default: false + skeleton_update_app_id: + description: "The GitHub App ID of the app to use for authentication when pushing updates. The app must be installed on the repository and have permissions to read and write code, as well as create pull requests." + required: false + type: string + default: ${{ vars.LAUNCH_SKELETON_UPDATE_APP_ID }} + secrets: + LAUNCH_SKELETON_UPDATE_KEY: + description: "The private key for the GitHub App used for authentication when pushing updates. The app must be installed on the repository and have permissions to read and write code, as well as create pull requests." + required: true + +permissions: + contents: write + pull-requests: write + +jobs: + update-from-skeleton: + name: Update from Skeleton + runs-on: ubuntu-latest + steps: + - id: get-app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ inputs.skeleton_update_app_id }} + private-key: ${{ secrets.LAUNCH_SKELETON_UPDATE_KEY }} + + - id: checkout + name: Checkout Repository + uses: actions/checkout@v6 + with: + token: ${{ steps.get-app-token.outputs.token }} + + - id: setup-python + name: Set up Python 3.14 + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 + with: + python-version: 3.14 + + - id: install-tools + name: Install Tools with uv + run: | + uv tool install copier + uv tool install pre-commit --with pre-commit-uv + + - id: get-repo-custom-properties + name: Get Repository Custom Properties + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@feat/prerelease-on-merge + + - id: run-updates + name: Run Updates from Skeleton + run: | + PRERELEASE=$(echo '${{ steps.get-repo-custom-properties.outputs.properties }}' | jq -r '.[] | select(.property_name == "prerelease") | .value') + + COPIER_CMD="update" + COPIER_FLAGS="--defaults --trust" + if [ "${{ inputs.recopy }}" == "true" ]; then + COPIER_CMD="recopy" + COPIER_FLAGS="$COPIER_FLAGS --overwrite" + fi + + if [ "$PRERELEASE" == "true" ]; then + echo "Using prerelease versions of skeleton workflows ($COPIER_CMD)" + uv run copier $COPIER_CMD $COPIER_FLAGS --prerelease + else + echo "Using stable versions of skeleton workflows ($COPIER_CMD)" + uv run copier $COPIER_CMD $COPIER_FLAGS + fi + + if git diff --quiet; then + echo "No changes detected" + echo "has_changes=false" >> "$GITHUB_OUTPUT" + else + echo "Changes detected" + echo "has_changes=true" >> "$GITHUB_OUTPUT" + if [ ! -f .pre-commit-config.yaml ]; then + echo "No .pre-commit-config.yaml found, skipping pre-commit validation" + echo "pre_commit_passed=false" >> "$GITHUB_OUTPUT" + { + echo "PRE_COMMIT_OUTPUT<<__PRECOMMIT_EOF__" + echo "No .pre-commit-config.yaml found in repository. Pre-commit validation was skipped." + echo "__PRECOMMIT_EOF__" + } >> "$GITHUB_ENV" + else + PRE_COMMIT_LOG=$(mktemp) + set -o pipefail + if ! pre-commit run check-merge-conflict --all-files 2>&1 | tee "$PRE_COMMIT_LOG"; then + PRE_COMMIT_OUTPUT=$(cat "$PRE_COMMIT_LOG") + rm -f "$PRE_COMMIT_LOG" + + echo "Pre-commit checks failed" + echo "pre_commit_passed=false" >> "$GITHUB_OUTPUT" + + CONFLICT_FILES=$(echo "$PRE_COMMIT_OUTPUT" | grep ': Merge conflict' | sed 's/:[0-9]*: Merge conflict.*//' | sort -u) || true + + { + echo "PRE_COMMIT_OUTPUT<<__PRECOMMIT_EOF__" + echo "$PRE_COMMIT_OUTPUT" + echo "__PRECOMMIT_EOF__" + } >> "$GITHUB_ENV" + + if [ -n "$CONFLICT_FILES" ]; then + { + echo "CONFLICT_FILES<<__CONFLICTS_EOF__" + echo "$CONFLICT_FILES" + echo "__CONFLICTS_EOF__" + } >> "$GITHUB_ENV" + fi + else + rm -f "$PRE_COMMIT_LOG" + echo "Pre-commit checks passed" + echo "pre_commit_passed=true" >> "$GITHUB_OUTPUT" + fi + fi + fi + + - name: Commit and Push Changes + id: commit-and-push + if: steps.run-updates.outputs.has_changes == 'true' + run: | + USER_ID=$(gh api "/users/${{ steps.get-app-token.outputs.app-slug }}[bot]" --jq .id) + + git config --global user.name '${{ steps.get-app-token.outputs.app-slug }}[bot]' + git config --global user.email "$USER_ID+${{ steps.get-app-token.outputs.app-slug }}[bot]@users.noreply.github.com" + + BRANCH_NAME="patch/skeleton-update-$(date +%Y%m%d-%H%M%S)" + echo "branch_name=$BRANCH_NAME" >> "$GITHUB_OUTPUT" + git checkout -b "$BRANCH_NAME" + git add . + + if [ "${{ steps.run-updates.outputs.pre_commit_passed }}" == "true" ] && [ "${{ inputs.recopy }}" != "true" ]; then + git commit -m "chore: update from skeleton" + else + git commit -m "fix: update from skeleton" + fi + + git push origin "$BRANCH_NAME" + env: + GH_TOKEN: ${{ steps.get-app-token.outputs.token }} + + - name: Create Pull Request + if: steps.run-updates.outputs.has_changes == 'true' && steps.run-updates.outputs.pre_commit_passed == 'true' && inputs.recopy != true + run: | + PR_BODY=$(cat <<'EOF' + Automated update from skeleton template. + + No conflicting changes were detected from the base repository. + EOF + ) + PR_URL=$(gh pr create \ + --base main \ + --head "${{ steps.commit-and-push.outputs.branch_name }}" \ + --title "chore: update from skeleton" \ + --body "$PR_BODY") + gh pr merge "${{ steps.commit-and-push.outputs.branch_name }}" --auto --squash + echo "### βœ… Pull Request Created" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "$PR_URL" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Auto-merge has been enabled." >> "$GITHUB_STEP_SUMMARY" + env: + GH_TOKEN: ${{ steps.get-app-token.outputs.token }} + + - name: Create Pull Request (requires review) + if: steps.run-updates.outputs.has_changes == 'true' && (steps.run-updates.outputs.pre_commit_passed == 'false' || inputs.recopy == true) + run: | + if [ "${{ inputs.recopy }}" == "true" ] && [ "${{ steps.run-updates.outputs.pre_commit_passed }}" == "true" ]; then + PR_BODY=$(cat <<'EOF' + Automated recopy from skeleton template. + + All templated files have been overwritten. Please review the changes carefully before merging. + EOF + ) + else + PR_BODY=$(cat < /') + EOF + ) + + if [ -n "$CONFLICT_FILES" ]; then + CONFLICT_LIST=$(echo "$CONFLICT_FILES" | sed 's/^/- `/' | sed 's/$/`/') + PR_BODY="${PR_BODY} + + The following files contain merge conflict markers: + ${CONFLICT_LIST}" + fi + fi + PR_URL=$(gh pr create \ + --base main \ + --head "${{ steps.commit-and-push.outputs.branch_name }}" \ + --title "fix: update from skeleton" \ + --body "$PR_BODY") + echo "### ⚠️ Pull Request Created (requires review)" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "$PR_URL" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "This PR requires manual review before merging." >> "$GITHUB_STEP_SUMMARY" + env: + GH_TOKEN: ${{ steps.get-app-token.outputs.token }} diff --git a/docs/reusable-pr-automated-approvals.md b/docs/reusable-pr-automated-approvals.md new file mode 100644 index 0000000..3f915d0 --- /dev/null +++ b/docs/reusable-pr-automated-approvals.md @@ -0,0 +1,53 @@ +# Automated Approvals for Pull Requests + +Automatically approves pull requests authored entirely by trusted automation accounts (`dependabot[bot]` and `launch-skeleton-auto-updater[bot]`). If any non-automated commits are detected on the PR, existing automated approvals are revoked instead. + +This workflow uses two separate GitHub App identities to provide the two approvals typically required by branch protection rules. + +## Behavior + +1. **Approve** β€” If all commits on the PR are from allowed automation authors, both approver apps submit an approval review. +2. **Revoke** β€” If any commit is from a non-automated author, any existing approvals from the approver apps are dismissed. This prevents a human from pushing commits onto an automated PR to bypass review requirements. +3. **Skeleton updater title check** β€” For PRs authored by `launch-skeleton-auto-updater[bot]`, the PR title must start with `chore`. If it does not, approval is withheld. + +## Usage + +Add the following workflow to your repository (suggested name: `.github/workflows/pr-automated-approvals.yml`): + +```yaml +name: Automated Approvals + +on: + pull_request: + types: [opened, reopened, synchronize] + +permissions: + pull-requests: read + contents: read + +jobs: + automated-approvals: + name: Automated Approvals + permissions: + pull-requests: read + contents: read + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-pr-automated-approvals.yml@ref + secrets: inherit +``` + +Be sure you replace `ref` with an appropriate ref to this repository. + +## Inputs + +This workflow has no configurable inputs. + +## Required Secrets and Variables + +| Name | Type | Description | +|------|------|-------------| +| `LAUNCH_APPROVER_ALPHA_ID` | Variable | The GitHub App ID for the first approver app. | +| `LAUNCH_APPROVER_ALPHA_KEY` | Secret | The private key for the first approver app. | +| `LAUNCH_APPROVER_BRAVO_ID` | Variable | The GitHub App ID for the second approver app. | +| `LAUNCH_APPROVER_BRAVO_KEY` | Secret | The private key for the second approver app. | + +Both approver apps must be installed on the repository with permission to submit pull request reviews. diff --git a/docs/reusable-pr-dependabot-automerge.md b/docs/reusable-pr-dependabot-automerge.md new file mode 100644 index 0000000..5c97129 --- /dev/null +++ b/docs/reusable-pr-dependabot-automerge.md @@ -0,0 +1,43 @@ +# Dependabot Auto-Merge + +Automatically enables GitHub's auto-merge (squash strategy) on pull requests created by Dependabot. Once all required status checks pass and any required approvals are in place, the PR will be merged automatically. + +This workflow only runs when the PR actor is `dependabot[bot]`. For all other actors, the job is skipped. + +## Usage + +Add the following workflow to your repository (suggested name: `.github/workflows/pr-dependabot-automerge.yml`): + +```yaml +name: Dependabot Auto-Merge + +on: + pull_request: + types: [opened, reopened, synchronize] + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot-automerge: + name: Dependabot Auto-Merge + permissions: + contents: write + pull-requests: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-pr-dependabot-automerge.yml@ref + secrets: inherit +``` + +Be sure you replace `ref` with an appropriate ref to this repository. + +> [!TIP] +> This workflow pairs well with the [Automated Approvals](reusable-pr-automated-approvals.md) workflow. When both are active, Dependabot PRs receive automated approvals and are then auto-merged once all status checks pass. + +## Inputs + +This workflow has no configurable inputs. + +## Required Permissions + +The calling workflow must grant `contents: write` and `pull-requests: write` permissions so that the `GITHUB_TOKEN` can enable auto-merge on the pull request. diff --git a/docs/reusable-update-from-skeleton.md b/docs/reusable-update-from-skeleton.md new file mode 100644 index 0000000..4b04a49 --- /dev/null +++ b/docs/reusable-update-from-skeleton.md @@ -0,0 +1,73 @@ +# Update Repository from Skeleton + +Keeps a repository in sync with its upstream [Copier](https://copier.readthedocs.io/) skeleton template. When triggered, the workflow runs `copier update` (or `copier recopy`) against the repository, detects changes, validates them with pre-commit, and opens a pull request with the result. + +```mermaid +flowchart TD + A[Workflow Triggered] --> B[Run copier update/recopy] + B --> C{Changes detected?} + C -- No --> D[Done] + C -- Yes --> E{Pre-commit passes?} + E -- Yes --> F[Create PR with auto-merge] + E -- No --> G[Create PR requiring manual review] +``` + +## Behavior + +1. **Copier update** β€” Runs `copier update --defaults --trust` to pull the latest changes from the skeleton template. If the repository's `prerelease` custom property is `true`, the `--prerelease` flag is added to pick up prerelease skeleton versions. +2. **Recopy mode** β€” When `recopy` is set to `true`, runs `copier recopy --defaults --trust --overwrite` instead, which overwrites all templated files. Recopy PRs always require manual review. +3. **Pre-commit validation** β€” If a `.pre-commit-config.yaml` exists, runs `check-merge-conflict` against all files to detect merge conflict markers. +4. **Pull request creation**: + - If pre-commit passes and recopy is not enabled, a PR titled `chore: update from skeleton` is created with auto-merge enabled. + - If pre-commit fails or recopy is enabled, a PR titled `fix: update from skeleton` is created and flagged for manual review. Any files with merge conflict markers are listed in the PR body. + +## Usage + +Add the following workflow to your repository (suggested name: `.github/workflows/update-from-skeleton.yml`): + +```yaml +name: Update from Skeleton + +on: + schedule: + - cron: "0 6 * * 1" # Weekly on Monday at 6:00 UTC + workflow_dispatch: + inputs: + recopy: + description: "Perform a full recopy instead of an incremental update" + type: boolean + default: false + +permissions: + contents: write + pull-requests: write + +jobs: + update-from-skeleton: + name: Update from Skeleton + permissions: + contents: write + pull-requests: write + uses: launchbynttdata/launch-workflows/.github/workflows/reusable-update-from-skeleton.yml@ref + with: + recopy: ${{ github.event.inputs.recopy == 'true' }} + secrets: inherit +``` + +Be sure you replace `ref` with an appropriate ref to this repository. + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `recopy` | Perform a full recopy instead of an incremental update. Overwrites all templated files and re-runs tasks defined in `copier.yml`. The resulting PR will require manual review. | No | `false` | +| `skeleton_update_app_id` | The GitHub App ID of the app used for authentication when pushing updates. | No | `${{ vars.LAUNCH_SKELETON_UPDATE_APP_ID }}` | + +## Required Secrets and Variables + +| Name | Type | Description | +|------|------|-------------| +| `LAUNCH_SKELETON_UPDATE_APP_ID` | Variable | The GitHub App ID for the skeleton update app. | +| `LAUNCH_SKELETON_UPDATE_KEY` | Secret | The private key for the skeleton update app. | + +The GitHub App must be installed on the repository with permissions to read and write code and create pull requests. From c744e07a733bd2816ee735f8aea2c2c4518640ec Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 14 Apr 2026 16:44:14 -0500 Subject: [PATCH 21/44] fix: prereleases --- .github/workflows/reusable-update-from-skeleton.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index 522a8a8..38e2d93 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -68,7 +68,7 @@ jobs: if [ "$PRERELEASE" == "true" ]; then echo "Using prerelease versions of skeleton workflows ($COPIER_CMD)" - uv run copier $COPIER_CMD $COPIER_FLAGS --prerelease + uv run copier $COPIER_CMD $COPIER_FLAGS --prereleases else echo "Using stable versions of skeleton workflows ($COPIER_CMD)" uv run copier $COPIER_CMD $COPIER_FLAGS From f1420da1593a947240fbefb44b3f722ec19ce751 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 22 Apr 2026 17:28:20 -0500 Subject: [PATCH 22/44] fix: grab PR head SHA if available before falling back to event SHA --- .github/actions/update-status-check/action.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/actions/update-status-check/action.yml b/.github/actions/update-status-check/action.yml index 7a58b35..f441fe6 100644 --- a/.github/actions/update-status-check/action.yml +++ b/.github/actions/update-status-check/action.yml @@ -1,22 +1,26 @@ name: "Update Status Check" -description: "Use the GitHub Commit Status API to create or update a status check on a commit." +description: "Use the GitHub Commit Status API to create or update a status + check on a commit." inputs: check_name: description: "The name (context) of the status check to create or update." required: true status: - description: "The state to set on the status check. Must be one of: error, failure, pending, success." + description: "The state to set on the status check. Must be one of: error, + failure, pending, success." required: true sha: - description: "The commit SHA to attach the status check to. Defaults to the SHA that triggered the workflow." + description: "The commit SHA to attach the status check to. Defaults to the PR + head SHA if available, otherwise the SHA that triggered the workflow." required: false - default: ${{ github.sha }} + default: ${{ github.event.pull_request.head.sha || github.sha }} description: description: "A short human-readable description of the status check." required: false default: "" target_url: - description: "A URL to associate with the status check, typically a link to relevant build or run output." + description: "A URL to associate with the status check, typically a link to + relevant build or run output." required: false default: "" github_token: From 6b62168e5c381c3bde7f90cbe2101bdab1d00583 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 22 Apr 2026 17:51:59 -0500 Subject: [PATCH 23/44] fix: SHA detection through API for PRs --- .github/actions/update-status-check/action.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/actions/update-status-check/action.yml b/.github/actions/update-status-check/action.yml index f441fe6..3f832a7 100644 --- a/.github/actions/update-status-check/action.yml +++ b/.github/actions/update-status-check/action.yml @@ -39,7 +39,19 @@ runs: SHA: ${{ inputs.sha }} DESCRIPTION: ${{ inputs.description }} TARGET_URL: ${{ inputs.target_url }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: | + # For pull request events, resolve the actual head SHA via the API. + # github.sha on PR events points to a temporary merge commit that + # doesn't appear on the PR, so status checks set on it are invisible. + if [[ -n "$PR_NUMBER" ]]; then + PR_HEAD_SHA=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}" --jq '.head.sha' 2>/dev/null || true) + if [[ -n "$PR_HEAD_SHA" ]]; then + echo "Resolved PR #${PR_NUMBER} head SHA: ${PR_HEAD_SHA} (input was: ${SHA})" + SHA="$PR_HEAD_SHA" + fi + fi + VALID_STATES=("error" "failure" "pending" "success") VALID=false for state in "${VALID_STATES[@]}"; do From 950d45cd364322d642c9a167b050a2545f1a75a8 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 22 Apr 2026 18:19:55 -0500 Subject: [PATCH 24/44] fix: all status check calls on this branch --- .../reusable-pr-conventional-commit-title.yml | 61 +++++++++++++----- .../reusable-terraform-check-aws.yml | 27 ++++---- .../reusable-terraform-check-azure.yml | 14 +++-- .../workflows/reusable-terraform-check.yml | 62 +++++++++++------- .../workflows/reusable-terragrunt-deploy.yml | 63 ++++++++++++------- .../reusable-terragrunt-plan-only.yml | 34 ++++++---- 6 files changed, 174 insertions(+), 87 deletions(-) diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 9cc3a58..b889476 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -3,17 +3,24 @@ on: inputs: task_types: type: string - description: 'A JSON array of task types that are allowed. Default: ["feat","fix","docs","test","ci","refactor","perf","chore","revert"]' + description: "A JSON array of task types that are allowed. Default: + [\"feat\",\"fix\",\"docs\",\"test\",\"ci\",\"refactor\",\"perf\",\"ch\ + ore\",\"revert\"]" required: false - default: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]' + default: "[\"feat\",\"fix\",\"docs\",\"test\",\"ci\",\"refactor\",\"perf\",\"ch\ + ore\",\"revert\"]" scope_types: type: string - description: 'A JSON array of valid scope types. If omitted, any scope is allowed. If given, include the empty scope with "". Example: ["login","signup","checkout","payment", ""]' + description: "A JSON array of valid scope types. If omitted, any scope is + allowed. If given, include the empty scope with \"\". Example: + [\"login\",\"signup\",\"checkout\",\"payment\", \"\"]" required: false default: "" title_regex: type: string - description: 'Regular expression for custom title validation; disabled by default. Example: ''PROJECT-\d{2,5}$'' for trailing issue ticket, ''"^[^:]+: [A-Z]"'' for capitalized title' + description: "Regular expression for custom title validation; disabled by + default. Example: 'PROJECT-\\d{2,5}$' for trailing issue ticket, + '\"^[^:]+: [A-Z]\"' for capitalized title" required: false default: "" add_label: @@ -23,22 +30,34 @@ on: default: true add_scope_label: type: boolean - description: 'Whether to add labels to your pull request. Example: the ''login'' scope will be added for this PR title: "fix(login): fix message in login page". Default: true' + description: "Whether to add labels to your pull request. Example: the 'login' + scope will be added for this PR title: \"fix(login): fix message in + login page\". Default: true" required: false default: true custom_labels: type: string - description: 'A JSON object mapping task types to custom label names. Default: {"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert"}' + description: "A JSON object mapping task types to custom label names. Default: + {\"feat\": \"feature\", \"fix\": \"fix\", \"docs\": \"documentation\", + \"test\": \"test\", \"ci\": \"CI/CD\", \"refactor\": \"refactor\", + \"perf\": \"performance\", \"chore\": \"chore\", \"revert\": + \"revert\"}" required: false - default: '{"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert"}' + default: "{\"feat\": \"feature\", \"fix\": \"fix\", \"docs\": \"documentation\", + \"test\": \"test\", \"ci\": \"CI/CD\", \"refactor\": \"refactor\", + \"perf\": \"performance\", \"chore\": \"chore\", \"revert\": + \"revert\"}" comment_on_failure: type: boolean - description: "Whether to comment on the pull request if the title validation fails. Default: true" + description: "Whether to comment on the pull request if the title validation + fails. Default: true" required: false default: true clear_labels: type: boolean - description: "Whether to clear existing labels when the workflow is run. This helps clean up scope labels added by this action when the scope changes. Default: true" + description: "Whether to clear existing labels when the workflow is run. This + helps clean up scope labels added by this action when the scope + changes. Default: true" required: false default: true @@ -147,7 +166,8 @@ jobs: body-includes: "Pull Request Title Validation Failed" - name: Comment on Failure - if: ${{ failure() && steps.pr-validation.outcome == 'failure' && inputs.comment_on_failure }} + if: ${{ failure() && steps.pr-validation.outcome == 'failure' && + inputs.comment_on_failure }} uses: peter-evans/create-or-update-comment@v5 with: issue-number: ${{ github.event.pull_request.number }} @@ -156,7 +176,8 @@ jobs: edit-mode: replace - name: Cleanup Failure Comment on Success - if: ${{ success() && steps.find-comment.outcome == 'success' && inputs.comment_on_failure }} + if: ${{ success() && steps.find-comment.outcome == 'success' && + inputs.comment_on_failure }} env: GH_TOKEN: ${{ github.token }} run: | @@ -167,17 +188,23 @@ jobs: - id: set-status-check name: Set Status Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Conventional Commit PR Title" - status: ${{ steps.pr-validation.outcome == 'success' && 'success' || steps.pr-validation.outcome == 'failure' && 'failure' || 'error' }} - description: ${{ steps.pr-validation.outcome == 'success' && 'PR title is valid.' || steps.pr-validation.outcome == 'failure' && 'PR title is invalid.' || 'Error validating PR title.' }} + status: ${{ steps.pr-validation.outcome == 'success' && 'success' || + steps.pr-validation.outcome == 'failure' && 'failure' || 'error' }} + description: ${{ steps.pr-validation.outcome == 'success' && 'PR title is + valid.' || steps.pr-validation.outcome == 'failure' && 'PR title is + invalid.' || 'Error validating PR title.' }} - id: set-status-check-legacy name: Set Legacy Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Label Pull Request / Label Pull Request" - status: ${{ steps.pr-validation.outcome == 'success' && 'success' || steps.pr-validation.outcome == 'failure' && 'failure' || 'error' }} - description: ${{ steps.pr-validation.outcome == 'success' && 'PR title is valid.' || steps.pr-validation.outcome == 'failure' && 'PR title is invalid.' || 'Error validating PR title.' }} + status: ${{ steps.pr-validation.outcome == 'success' && 'success' || + steps.pr-validation.outcome == 'failure' && 'failure' || 'error' }} + description: ${{ steps.pr-validation.outcome == 'success' && 'PR title is + valid.' || steps.pr-validation.outcome == 'failure' && 'PR title is + invalid.' || 'Error validating PR title.' }} diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index d473dc8..d740769 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -4,7 +4,9 @@ on: workflow_call: inputs: assume_role_arn: - description: "ARN of the role to assume prior to Terragrunt invocation. Terragrunt may use this role to assume other roles if configured to do so." + description: "ARN of the role to assume prior to Terragrunt invocation. + Terragrunt may use this role to assume other roles if configured to do + so." required: true type: string region: @@ -63,7 +65,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: "pending" @@ -76,13 +78,15 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" - status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome + == 'failure' && 'failure' || 'error' }} description: "Terraform lint ${{ steps.lint.outcome }}" - - name: Configure AWS credentials + - id: aws-login + name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 with: role-to-assume: ${{ inputs.assume_role_arn }} @@ -97,14 +101,14 @@ jobs: set -x mkdir -p ~/.aws echo "[default]" > ~/.aws/credentials - echo "aws_access_key_id=${{ secrets.AWS_ACCESS_KEY_ID }}" >> ~/.aws/credentials - echo "aws_secret_access_key=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> ~/.aws/credentials - echo "aws_session_token=${{ secrets.AWS_SESSION_TOKEN }}" >> ~/.aws/credentials + echo "aws_access_key_id=${{ steps.aws-login.outputs.aws-access-key-id }}" >> ~/.aws/credentials + echo "aws_secret_access_key=${{ steps.aws-login.outputs.aws-secret-access-key }}" >> ~/.aws/credentials + echo "aws_session_token=${{ steps.aws-login.outputs.aws-session-token }}" >> ~/.aws/credentials # Fixup examples' provider.tf by dropping references to the profile, so that we can use the default profile. find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: "pending" @@ -117,8 +121,9 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" - status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome + == 'failure' && 'failure' || 'error' }} description: "Terraform tests ${{ steps.test.outcome }}" diff --git a/.github/workflows/reusable-terraform-check-azure.yml b/.github/workflows/reusable-terraform-check-azure.yml index 1efa462..46517a1 100644 --- a/.github/workflows/reusable-terraform-check-azure.yml +++ b/.github/workflows/reusable-terraform-check-azure.yml @@ -60,7 +60,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: "pending" @@ -73,10 +73,11 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" - status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome + == 'failure' && 'failure' || 'error' }} description: "Terraform lint ${{ steps.lint.outcome }}" - name: Azure login @@ -87,7 +88,7 @@ jobs: subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: "pending" @@ -100,8 +101,9 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" - status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome + == 'failure' && 'failure' || 'error' }} description: "Terraform tests ${{ steps.test.outcome }}" diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 2adda25..0b8f210 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -4,24 +4,34 @@ on: workflow_call: inputs: auth_method: - description: 'Comma-delimited list of authentication methods to use. Valid values are "aws", "azure", and "github" (e.g. "aws", "aws,github", "aws,azure"). Pass an empty string or omit to run Terraform checks without any authentication.' + description: "Comma-delimited list of authentication methods to use. Valid + values are \"aws\", \"azure\", and \"github\" (e.g. \"aws\", + \"aws,github\", \"aws,azure\"). Pass an empty string or omit to run + Terraform checks without any authentication." required: false default: "" type: string # --- AWS authentication inputs --- aws_assume_role_arn: - description: "ARN of the role to assume when running tests and creating test resources. Required if auth_method includes 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN variable." + description: "ARN of the role to assume when running tests and creating test + resources. Required if auth_method includes 'aws', ignored otherwise. + Defaults to the value of the TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN + variable." required: false type: string default: "${{ vars.TERRAFORM_CHECK_AWS_ASSUME_ROLE_ARN }}" aws_auth_region: - description: "AWS region to use for authentication. Required if auth_method includes 'aws', ignored otherwise. Defaults to the value of the TERRAFORM_CHECK_AWS_REGION variable." + description: "AWS region to use for authentication. Required if auth_method + includes 'aws', ignored otherwise. Defaults to the value of the + TERRAFORM_CHECK_AWS_REGION variable." default: "${{ vars.TERRAFORM_CHECK_AWS_REGION }}" required: false type: string # --- GitHub App authentication inputs --- github_app_id: - description: "The GitHub App ID to use for authentication, defaulting to the TERRAFORM_CHECK_GITHUB_APP_ID variable. Required if auth_method includes 'github', ignored otherwise." + description: "The GitHub App ID to use for authentication, defaulting to the + TERRAFORM_CHECK_GITHUB_APP_ID variable. Required if auth_method + includes 'github', ignored otherwise." required: false default: "${{ vars.TERRAFORM_CHECK_GITHUB_APP_ID }}" type: string @@ -162,12 +172,13 @@ jobs: - id: set-lint-pending name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: "pending" description: "Terraform lint check is running..." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - id: lint name: "make lint" @@ -177,12 +188,14 @@ jobs: - id: update-lint-status name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" - status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome + == 'failure' && 'failure' || 'error' }} description: "Terraform lint ${{ steps.lint.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" tests: name: "Run Tests" @@ -283,12 +296,13 @@ jobs: - id: set-tests-pending name: "Set Terraform Tests status to pending" continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: "pending" description: "Terraform tests are running..." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - id: test name: "make test" @@ -304,12 +318,14 @@ jobs: name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" - status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome + == 'failure' && 'failure' || 'error' }} description: "Terraform tests ${{ steps.test.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" # These legacy status checks will write the necessary success for the existing launch workflows, so that we can transition # between models without breaking merge capabilities on existing repositories. Once all repositories have transitioned to @@ -317,24 +333,28 @@ jobs: legacy: name: "Legacy Status Checks" runs-on: ubuntu-latest - needs: [validate-inputs, lint, tests] + needs: [ validate-inputs, lint, tests ] steps: - id: update-legacy-status-checks-aws name: "Add AWS Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-aws-') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Check AWS Terraform Code / Check AWS Terraform Code" status: "success" - description: "This check is being deprecated. Please refer to the new 'Terraform Tests' check for test results." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + description: "This check is being deprecated. Please refer to the new 'Terraform + Tests' check for test results." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - id: update-legacy-status-checks-azure name: "Add Azure Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-az') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Check Azure Terraform Code / Check Azure Terraform Code" status: "success" - description: "This check is being deprecated. Please refer to the new 'Terraform Tests' check for test results." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + description: "This check is being deprecated. Please refer to the new 'Terraform + Tests' check for test results." + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index 13b168a..2dfe22c 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -4,23 +4,31 @@ on: workflow_call: inputs: auth_method: - description: 'Comma-delimited list of authentication methods to use. Valid values are "aws", "azure", and "github" (e.g. "aws", "aws,github", "aws,azure"). Pass an empty string or omit to run Terragrunt without any authentication.' + description: "Comma-delimited list of authentication methods to use. Valid + values are \"aws\", \"azure\", and \"github\" (e.g. \"aws\", + \"aws,github\", \"aws,azure\"). Pass an empty string or omit to run + Terragrunt without any authentication." required: false default: "" type: string # --- AWS authentication inputs --- aws_auth_region: - description: "The AWS region to use for authentication. Required if auth_method includes 'aws', ignored otherwise." + description: "The AWS region to use for authentication. Required if auth_method + includes 'aws', ignored otherwise." required: false type: string aws_assume_role_arn: - description: "ARN of the role to assume prior to Terragrunt invocation, defaulting to the DEPLOY_ROLE_ARN variable. Required if auth_method includes 'aws', ignored otherwise." + description: "ARN of the role to assume prior to Terragrunt invocation, + defaulting to the DEPLOY_ROLE_ARN variable. Required if auth_method + includes 'aws', ignored otherwise." required: false default: "${{ vars.DEPLOY_ROLE_ARN }}" type: string # --- GitHub App authentication inputs --- github_app_id: - description: "The GitHub App ID to use for authentication, defaulting to the TERRAGRUNT_DEPLOY_GITHUB_APP_ID variable. Required if auth_method includes 'github', ignored otherwise." + description: "The GitHub App ID to use for authentication, defaulting to the + TERRAGRUNT_DEPLOY_GITHUB_APP_ID variable. Required if auth_method + includes 'github', ignored otherwise." required: false default: "${{ vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID }}" type: string @@ -43,7 +51,8 @@ on: required: false type: string tg_dir: - description: "Folder containing the Terragrunt configuration to deploy (relative to the repository root, e.g. platform/test/us-east-1/000)" + description: "Folder containing the Terragrunt configuration to deploy (relative + to the repository root, e.g. platform/test/us-east-1/000)" required: true type: string before_plan_commands: @@ -57,7 +66,8 @@ on: type: string default: "" before_shared_commands: - description: "Commands to run prior to both Terragrunt plan and apply. These are applied after before_plan_commands and before_deploy_commands." + description: "Commands to run prior to both Terragrunt plan and apply. These are + applied after before_plan_commands and before_deploy_commands." required: false type: string default: "" @@ -72,13 +82,15 @@ on: type: string default: "" after_shared_commands: - description: "Commands to run after both Terragrunt plan and apply. These are applied after after_plan_commands and after_deploy_commands." + description: "Commands to run after both Terragrunt plan and apply. These are + applied after after_plan_commands and after_deploy_commands." required: false type: string default: "" outputs: terraform_outputs: - description: "JSON string containing all Terraform outputs from the deployment (base64 encoded)" + description: "JSON string containing all Terraform outputs from the deployment + (base64 encoded)" value: ${{ jobs.deploy.outputs.terraform_outputs }} secrets: # --- Azure authentication secrets (required if auth_method includes 'azure') --- @@ -233,12 +245,13 @@ jobs: tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" description: "Terragrunt plan is running..." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - name: Plan id: plan @@ -259,7 +272,8 @@ jobs: ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} - ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' + || '' }} TF_VAR_system_tags: ${{ steps.set-tags-azure.outputs.SYSTEM_TAGS }} GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} with: @@ -270,20 +284,23 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" - status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome + == 'failure' && 'failure' || 'error' }} description: "Terragrunt plan ${{ steps.plan.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - name: "Set Terragrunt Deploy status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: "pending" description: "Terragrunt deploy is running..." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - name: Deploy id: deploy @@ -304,7 +321,8 @@ jobs: ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} - ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' + || '' }} TF_VAR_system_tags: ${{ steps.set-tags-azure.outputs.SYSTEM_TAGS }} GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} with: @@ -315,12 +333,14 @@ jobs: - name: "Update Terragrunt Deploy status" if: always() && steps.deploy.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" - status: ${{ steps.deploy.outcome == 'success' && 'success' || steps.deploy.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.deploy.outcome == 'success' && 'success' || + steps.deploy.outcome == 'failure' && 'failure' || 'error' }} description: "Terragrunt deploy ${{ steps.deploy.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - name: Get Terraform Outputs id: set-outputs @@ -329,7 +349,8 @@ jobs: ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} - ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' + || '' }} GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} run: | echo "=== Getting Terraform outputs ===" diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index e6e5128..c3ff9ae 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -4,22 +4,29 @@ on: workflow_call: inputs: auth_method: - description: 'Comma-delimited list of authentication methods to use. Valid values are "aws", "azure", and "github" (e.g. "aws", "aws,github", "aws,azure"). Pass an empty string or omit to run Terragrunt without any authentication.' + description: "Comma-delimited list of authentication methods to use. Valid + values are \"aws\", \"azure\", and \"github\" (e.g. \"aws\", + \"aws,github\", \"aws,azure\"). Pass an empty string or omit to run + Terragrunt without any authentication." required: false default: "" type: string # --- AWS authentication inputs --- aws_auth_region: - description: "The AWS region to use for authentication. Required if auth_method includes 'aws', ignored otherwise." + description: "The AWS region to use for authentication. Required if auth_method + includes 'aws', ignored otherwise." required: false type: string aws_assume_role_arn: - description: "ARN of the role to assume prior to Terragrunt invocation. Required if auth_method includes 'aws', ignored otherwise." + description: "ARN of the role to assume prior to Terragrunt invocation. Required + if auth_method includes 'aws', ignored otherwise." required: false type: string # --- GitHub App authentication inputs --- github_app_id: - description: "The GitHub App ID to use for authentication, defaulting to the TERRAGRUNT_DEPLOY_GITHUB_APP_ID variable. Required if auth_method includes 'github', ignored otherwise." + description: "The GitHub App ID to use for authentication, defaulting to the + TERRAGRUNT_DEPLOY_GITHUB_APP_ID variable. Required if auth_method + includes 'github', ignored otherwise." required: false default: "${{ vars.TERRAGRUNT_DEPLOY_GITHUB_APP_ID }}" type: string @@ -38,7 +45,8 @@ on: required: true type: string tg_dir: - description: "Folder containing the Terragrunt configuration to plan (relative to the repository root, e.g. platform/test/us-east-1/000)" + description: "Folder containing the Terragrunt configuration to plan (relative + to the repository root, e.g. platform/test/us-east-1/000)" required: true type: string before_plan_commands: @@ -199,12 +207,13 @@ jobs: tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" description: "Terragrunt plan is running..." - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" - name: Plan id: plan @@ -221,7 +230,8 @@ jobs: ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} ARM_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} - ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' || '' }} + ARM_USE_OIDC: ${{ needs.validate-inputs.outputs.auth_azure == 'true' && 'true' + || '' }} TF_VAR_system_tags: ${{ steps.set-tags-azure.outputs.SYSTEM_TAGS }} GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || '' }} with: @@ -232,9 +242,11 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-terraform-check-workflows + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" - status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome == 'failure' && 'failure' || 'error' }} + status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome + == 'failure' && 'failure' || 'error' }} description: "Terragrunt plan ${{ steps.plan.outcome }}" - target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + target_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ + github.run_id }}" From 7d1e332718c6c7ff367dd0a8a20a8e34b37399aa Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 22 Apr 2026 18:25:43 -0500 Subject: [PATCH 25/44] fix: needs to be able to read the PR --- .github/workflows/reusable-terraform-check.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 0b8f210..5ea06ff 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -49,6 +49,7 @@ on: permissions: contents: read + pull-requests: read id-token: write statuses: write From ca4220b48b129ae9923f27212b1c9e65f86c0064 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Thu, 23 Apr 2026 10:26:24 -0500 Subject: [PATCH 26/44] fix: toml command --- .github/actions/terragrunt-configure-mise/action.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/actions/terragrunt-configure-mise/action.yml b/.github/actions/terragrunt-configure-mise/action.yml index e8dc4a9..2c257ad 100644 --- a/.github/actions/terragrunt-configure-mise/action.yml +++ b/.github/actions/terragrunt-configure-mise/action.yml @@ -1,5 +1,6 @@ name: "Configure Mise for Terragrunt" -description: "Configure Mise to install specific versions of Terraform and Terragrunt for use with terragrunt-action" +description: "Configure Mise to install specific versions of Terraform and + Terragrunt for use with terragrunt-action" inputs: tf_version: description: "Version of Terraform to install" @@ -34,8 +35,8 @@ runs: # https://github.com/mrijken/toml-cli # `toml set` will add if necessary or update if the entry already exists - toml set mise.toml tools.terragrunt "${{ inputs.tg_version }}" - toml set mise.toml tools.terraform "${{ inputs.tf_version }}" + toml set --toml-path mise.toml tools.terragrunt "${{ inputs.tg_version }}" + toml set --toml-path mise.toml tools.terraform "${{ inputs.tf_version }}" fi echo "Final mise.toml configuration:" cat mise.toml From e5bb7fe818c503872f678c94fb68f6db032cafea Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Thu, 23 Apr 2026 10:31:29 -0500 Subject: [PATCH 27/44] fix: repoint to current tag --- .../terragrunt-configure-mise/README.md | 2 +- .../reusable-terragrunt-deploy-aws.yml | 32 ++++++++++++------- .../reusable-terragrunt-deploy-azure.yml | 29 +++++++++++------ ...usable-terragrunt-deploy-ephemeral-aws.yml | 24 +++++++++----- .../workflows/reusable-terragrunt-deploy.yml | 2 +- ...sable-terragrunt-destroy-ephemeral-aws.yml | 9 ++++-- .../reusable-terragrunt-plan-only-aws.yml | 9 ++++-- .../reusable-terragrunt-plan-only-azure.yml | 5 +-- .../reusable-terragrunt-plan-only.yml | 2 +- 9 files changed, 74 insertions(+), 40 deletions(-) diff --git a/.github/actions/terragrunt-configure-mise/README.md b/.github/actions/terragrunt-configure-mise/README.md index c451af8..3ac935e 100644 --- a/.github/actions/terragrunt-configure-mise/README.md +++ b/.github/actions/terragrunt-configure-mise/README.md @@ -29,7 +29,7 @@ jobs: # Ensure mise.toml contains terraform and terragrunt at our desired versions - name: Configure Mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.0 # or later + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: '1.5.5' tg_version: '0.54.11' diff --git a/.github/workflows/reusable-terragrunt-deploy-aws.yml b/.github/workflows/reusable-terragrunt-deploy-aws.yml index b1ec8d3..1c257ea 100644 --- a/.github/workflows/reusable-terragrunt-deploy-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-aws.yml @@ -18,7 +18,8 @@ on: default: "0.54.11" type: string gh_environment: - description: "GitHub Environment to deploy to (e.g. test, production). If not supplied, will be set from the environment input." + description: "GitHub Environment to deploy to (e.g. test, production). If not + supplied, will be set from the environment input." required: false type: string environments_root: @@ -49,7 +50,8 @@ on: type: string default: "" before_shared_commands: - description: "Commands to run prior to both Terragrunt plan and apply. These are applied after before_plan_commands and before_deploy_commands." + description: "Commands to run prior to both Terragrunt plan and apply. These are + applied after before_plan_commands and before_deploy_commands." required: false type: string default: "" @@ -64,13 +66,15 @@ on: type: string default: "" after_shared_commands: - description: "Commands to run after both Terragrunt plan and apply. These are applied after after_plan_commands and after_deploy_commands." + description: "Commands to run after both Terragrunt plan and apply. These are + applied after after_plan_commands and after_deploy_commands." required: false type: string default: "" outputs: terraform_outputs: - description: "JSON string containing all Terraform outputs from the deployment (base64 encoded)" + description: "JSON string containing all Terraform outputs from the deployment + (base64 encoded)" value: ${{ jobs.deploy.outputs.terraform_outputs }} permissions: @@ -79,7 +83,8 @@ permissions: jobs: deploy: - name: "Plan & Deploy ${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" + name: "Plan & Deploy ${{ inputs.environment }}/${{ inputs.region }}/${{ + inputs.env_id }}" runs-on: ubuntu-latest environment: ${{ inputs.gh_environment || inputs.environment }} outputs: @@ -112,7 +117,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} @@ -137,8 +142,10 @@ jobs: with: tf_path: "terraform" tg_version: ${{ inputs.tg_version }} - tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" - tg_command: "plan -out=${{ inputs.environment }}-${{ inputs.region }}-${{ inputs.env_id }}.tfplan" + tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ + inputs.region }}/${{ inputs.env_id }}" + tg_command: "plan -out=${{ inputs.environment }}-${{ inputs.region }}-${{ + inputs.env_id }}.tfplan" - name: Deploy uses: gruntwork-io/terragrunt-action@5e86476ca61eaf74adb9c0525745f29f921f2199 @@ -159,12 +166,15 @@ jobs: with: tf_path: "terraform" tg_version: ${{ inputs.tg_version }} - tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" - tg_command: "apply ${{ inputs.environment }}-${{ inputs.region }}-${{ inputs.env_id }}.tfplan" + tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ + inputs.region }}/${{ inputs.env_id }}" + tg_command: "apply ${{ inputs.environment }}-${{ inputs.region }}-${{ + inputs.env_id }}.tfplan" - name: Get Terraform Outputs id: set-outputs - working-directory: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" + working-directory: "${{ inputs.environments_root }}/${{ inputs.environment + }}/${{ inputs.region }}/${{ inputs.env_id }}" env: AWS_REGION: ${{ inputs.region }} run: | diff --git a/.github/workflows/reusable-terragrunt-deploy-azure.yml b/.github/workflows/reusable-terragrunt-deploy-azure.yml index ad1d8e7..892c09f 100644 --- a/.github/workflows/reusable-terragrunt-deploy-azure.yml +++ b/.github/workflows/reusable-terragrunt-deploy-azure.yml @@ -45,7 +45,8 @@ on: type: string default: "" before_shared_commands: - description: "Commands to run prior to both Terragrunt plan and apply. These are applied after before_plan_commands and before_deploy_commands." + description: "Commands to run prior to both Terragrunt plan and apply. These are + applied after before_plan_commands and before_deploy_commands." required: false type: string default: "" @@ -60,13 +61,15 @@ on: type: string default: "" after_shared_commands: - description: "Commands to run after both Terragrunt plan and apply. These are applied after after_plan_commands and after_deploy_commands." + description: "Commands to run after both Terragrunt plan and apply. These are + applied after after_plan_commands and after_deploy_commands." required: false type: string default: "" outputs: terraform_outputs: - description: "JSON string containing all Terraform outputs from the deployment (base64 encoded)" + description: "JSON string containing all Terraform outputs from the deployment + (base64 encoded)" value: ${{ jobs.deploy.outputs.terraform_outputs }} secrets: TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: @@ -82,7 +85,8 @@ permissions: jobs: deploy: - name: "Plan & Deploy ${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" + name: "Plan & Deploy ${{ inputs.environment }}/${{ inputs.region }}/${{ + inputs.env_id }}" runs-on: ubuntu-latest outputs: terraform_outputs: ${{ steps.set-outputs.outputs.terraform_outputs }} @@ -106,7 +110,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} @@ -129,8 +133,10 @@ jobs: ARM_USE_OIDC: true TF_VAR_system_tags: ${{ steps.set-tags.outputs.SYSTEM_TAGS }} with: - tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" - tg_command: "plan -out=${{ inputs.environment }}-${{ inputs.region }}-${{ inputs.env_id }}.tfplan" + tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ + inputs.region }}/${{ inputs.env_id }}" + tg_command: "plan -out=${{ inputs.environment }}-${{ inputs.region }}-${{ + inputs.env_id }}.tfplan" - name: Deploy uses: gruntwork-io/terragrunt-action@5e86476ca61eaf74adb9c0525745f29f921f2199 @@ -149,12 +155,15 @@ jobs: ARM_USE_OIDC: true TF_VAR_system_tags: ${{ steps.set-tags.outputs.SYSTEM_TAGS }} with: - tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" - tg_command: "apply ${{ inputs.environment }}-${{ inputs.region }}-${{ inputs.env_id }}.tfplan" + tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ + inputs.region }}/${{ inputs.env_id }}" + tg_command: "apply ${{ inputs.environment }}-${{ inputs.region }}-${{ + inputs.env_id }}.tfplan" - name: Get Terraform Outputs id: set-outputs - working-directory: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" + working-directory: "${{ inputs.environments_root }}/${{ inputs.environment + }}/${{ inputs.region }}/${{ inputs.env_id }}" env: ARM_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} diff --git a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml index 57e9c21..ca1993c 100644 --- a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml @@ -17,7 +17,9 @@ on: default: "0.54.11" type: string assume_role_arn: - description: "ARN of the role to assume prior to Terragrunt invocation. Terragrunt may use this role to assume other roles if configured to do so." + description: "ARN of the role to assume prior to Terragrunt invocation. + Terragrunt may use this role to assume other roles if configured to do + so." required: true type: string region: @@ -44,7 +46,8 @@ on: type: string default: "" before_shared_commands: - description: "Commands to run prior to both Terragrunt plan and apply. These are applied after before_plan_commands and before_deploy_commands." + description: "Commands to run prior to both Terragrunt plan and apply. These are + applied after before_plan_commands and before_deploy_commands." required: false type: string default: "" @@ -59,13 +62,15 @@ on: type: string default: "" after_shared_commands: - description: "Commands to run after both Terragrunt plan and apply. These are applied after after_plan_commands and after_deploy_commands." + description: "Commands to run after both Terragrunt plan and apply. These are + applied after after_plan_commands and after_deploy_commands." required: false type: string default: "" outputs: terraform_outputs_json: - description: "Base64-encoded JSON string containing all non-sensitive Terraform outputs from the apply" + description: "Base64-encoded JSON string containing all non-sensitive Terraform + outputs from the apply" value: ${{ jobs.deploy.outputs.terraform_outputs_json }} permissions: @@ -100,7 +105,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} @@ -126,8 +131,10 @@ jobs: with: tf_path: "terraform" tg_version: ${{ inputs.tg_version }} - tg_dir: "${{ inputs.environments_root }}/sandbox/${{ inputs.region }}/${{ inputs.env_id }}" - tg_command: "plan -out=ephemeral-${{ inputs.region }}-${{ inputs.env_id }}.tfplan" + tg_dir: "${{ inputs.environments_root }}/sandbox/${{ inputs.region }}/${{ + inputs.env_id }}" + tg_command: "plan -out=ephemeral-${{ inputs.region }}-${{ inputs.env_id + }}.tfplan" - name: Deploy id: deploy @@ -153,7 +160,8 @@ jobs: with: tf_path: "terraform" tg_version: ${{ inputs.tg_version }} - tg_dir: "${{ inputs.environments_root }}/sandbox/${{ inputs.region }}/${{ inputs.env_id }}" + tg_dir: "${{ inputs.environments_root }}/sandbox/${{ inputs.region }}/${{ + inputs.env_id }}" tg_command: "apply ephemeral-${{ inputs.region }}-${{ inputs.env_id }}.tfplan" - name: Set Terraform Outputs diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index 2dfe22c..895168f 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -239,7 +239,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml index 736a1d8..b50ffda 100644 --- a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml @@ -17,7 +17,9 @@ on: default: "0.54.11" type: string assume_role_arn: - description: "ARN of the role to assume prior to Terragrunt invocation. Terragrunt may use this role to assume other roles if configured to do so." + description: "ARN of the role to assume prior to Terragrunt invocation. + Terragrunt may use this role to assume other roles if configured to do + so." required: true type: string region: @@ -74,7 +76,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} @@ -95,5 +97,6 @@ jobs: with: tf_path: "terraform" tg_version: ${{ inputs.tg_version }} - tg_dir: "${{ inputs.environments_root }}/sandbox/${{ inputs.region }}/${{ inputs.env_id }}" + tg_dir: "${{ inputs.environments_root }}/sandbox/${{ inputs.region }}/${{ + inputs.env_id }}" tg_command: "destroy" diff --git a/.github/workflows/reusable-terragrunt-plan-only-aws.yml b/.github/workflows/reusable-terragrunt-plan-only-aws.yml index 10bd42c..6c8a56d 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-aws.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-aws.yml @@ -18,7 +18,9 @@ on: default: "0.54.11" type: string assume_role_arn: - description: "ARN of the role to assume prior to Terragrunt invocation. Terragrunt may use this role to assume other roles if configured to do so." + description: "ARN of the role to assume prior to Terragrunt invocation. + Terragrunt may use this role to assume other roles if configured to do + so." required: true type: string environments_root: @@ -79,7 +81,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} @@ -100,5 +102,6 @@ jobs: with: tf_path: "terraform" tg_version: ${{ inputs.tg_version }} - tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" + tg_dir: "${{ inputs.environments_root }}/${{ inputs.environment }}/${{ + inputs.region }}/${{ inputs.env_id }}" tg_command: "plan" diff --git a/.github/workflows/reusable-terragrunt-plan-only-azure.yml b/.github/workflows/reusable-terragrunt-plan-only-azure.yml index 4b12a0f..d2d1100 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-azure.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-azure.yml @@ -80,7 +80,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} @@ -99,5 +99,6 @@ jobs: ARM_USE_OIDC: true TF_VAR_system_tags: ${{ steps.set-tags.outputs.SYSTEM_TAGS }} with: - tg_dir: "${{inputs.environments_root}}/${{ inputs.environment }}/${{ inputs.region }}/${{ inputs.env_id }}" + tg_dir: "${{inputs.environments_root}}/${{ inputs.environment }}/${{ + inputs.region }}/${{ inputs.env_id }}" tg_command: "plan" diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index c3ff9ae..4ca1b38 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -201,7 +201,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.14.2 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} From 0330f9cf31bb6f80e40ea45703a7995e48e679bb Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 24 Apr 2026 11:12:45 -0500 Subject: [PATCH 28/44] fix: only clear labels on certain event types --- .github/workflows/reusable-pr-conventional-commit-title.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index b889476..f3f3a7a 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -57,7 +57,8 @@ on: type: boolean description: "Whether to clear existing labels when the workflow is run. This helps clean up scope labels added by this action when the scope - changes. Default: true" + changes. Labels will only be cleared for ready_for_review or edited + actions. Default: true" required: false default: true @@ -121,7 +122,8 @@ jobs: - name: Clear labels id: clear-labels - if: ${{ inputs.clear_labels }} + if: ${{ inputs.clear_labels && (github.event.action == 'ready_for_review' || + (github.event.action == 'edited' && github.event.changes.title)) }} env: GH_TOKEN: ${{ github.token }} run: | From 266540b60ed40691800ca0371cc2c353ec06d592 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 24 Apr 2026 12:27:19 -0500 Subject: [PATCH 29/44] fix: add PR read permissions to plan-only TG workflow --- .github/workflows/reusable-terragrunt-plan-only.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index 4ca1b38..fae3ec8 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -73,6 +73,7 @@ on: permissions: id-token: write + pull-requests: read contents: read statuses: write From 9f5ad036e4ed144d5d36239f62fb44f8719cb477 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 24 Apr 2026 15:14:06 -0500 Subject: [PATCH 30/44] fix: newline for better output --- .../actions/update-status-check/action.yml | 2 +- scripts/clone_to_test_organization.sh | 106 ++++++++++ scripts/copier_conversion.sh | 108 ++++++++++ scripts/dependabot_config_audition.sh | 126 ++++++++++++ scripts/full_migration.sh | 15 ++ scripts/migrate.sh | 188 ++++++++++++++++++ 6 files changed, 544 insertions(+), 1 deletion(-) create mode 100755 scripts/clone_to_test_organization.sh create mode 100755 scripts/copier_conversion.sh create mode 100755 scripts/dependabot_config_audition.sh create mode 100755 scripts/full_migration.sh create mode 100755 scripts/migrate.sh diff --git a/.github/actions/update-status-check/action.yml b/.github/actions/update-status-check/action.yml index 3f832a7..f68d48d 100644 --- a/.github/actions/update-status-check/action.yml +++ b/.github/actions/update-status-check/action.yml @@ -78,4 +78,4 @@ runs: gh api -X POST "repos/${{ github.repository }}/statuses/${SHA}" \ --input - <<< "$PAYLOAD" - echo "Status check '${CHECK_NAME}' successfully set to '${STATUS}'." + echo "\nStatus check '${CHECK_NAME}' successfully set to '${STATUS}'." diff --git a/scripts/clone_to_test_organization.sh b/scripts/clone_to_test_organization.sh new file mode 100755 index 0000000..ffeb147 --- /dev/null +++ b/scripts/clone_to_test_organization.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# Clone the current repo to a test organization for testing in a clean environment. +# Usage: bash scripts/clone_to_test_organization.sh REPOSITORY_NAME + +# https://github.com/nttdtest/tf-azurerm-module_primitive-storage_account.git + +PRIMARY_ORG="launchbynttdata" +TEST_ORG="nttdtest" + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 REPOSITORY_NAME" + exit 1 +fi + +REPOSITORY_NAME="$1" + +PRIMARY_REPO_URL="https://github.com/$PRIMARY_ORG/$REPOSITORY_NAME.git" +TEST_REPO_URL="https://github.com/$TEST_ORG/$REPOSITORY_NAME.git" + +echo "Cloning $PRIMARY_ORG/$REPOSITORY_NAME to $TEST_ORG/$REPOSITORY_NAME..." + +# Delete the test repo if it already exists, then create a fresh empty one. +if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$REPOSITORY_NAME" &>/dev/null; then + echo "Deleting existing repo $TEST_ORG/$REPOSITORY_NAME..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$REPOSITORY_NAME" --yes +fi + +echo "Creating fresh repo $TEST_ORG/$REPOSITORY_NAME..." +GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$REPOSITORY_NAME" --private + +echo "Configuring repo settings for $TEST_ORG/$REPOSITORY_NAME..." +GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$REPOSITORY_NAME" \ + --enable-rebase-merge=false \ + --enable-merge-commit=false \ + --enable-squash-merge \ + --enable-auto-merge \ + --delete-branch-on-merge + +TEMP_PATH=$(mktemp -d) +git clone "$PRIMARY_REPO_URL" "$TEMP_PATH" + +cd "$TEMP_PATH" +git fetch --tags origin + +# Remove .github/ from the initial push so workflows don't fire during release setup. +git rm -r --quiet .github/ 2>/dev/null || true +git commit -m "chore: temporarily remove .github/ for clean clone" --allow-empty + +git remote remove origin +git remote add origin "$TEST_REPO_URL" +git push -u origin main -f || git push -u origin main -f + +# Sort tags by their commit date (oldest first) so releases are created in order. +SORTED_TAGS=() +while IFS= read -r t; do + SORTED_TAGS+=("$t") +done < <(git tag --sort=creatordate) + +if [[ ${#SORTED_TAGS[@]} -eq 0 ]]; then + echo "No tags found β€” skipping release copy." +else + # Copy all releases except the last one; the final release will be handled by workflows. + LAST_INDEX=$(( ${#SORTED_TAGS[@]} - 1 )) + + # Push all tags except the last one to the test repo before creating releases. + echo "Pushing tags to $TEST_ORG/$REPOSITORY_NAME..." + for i in "${!SORTED_TAGS[@]}"; do + if [[ "$i" -lt "$LAST_INDEX" ]]; then + git push origin "refs/tags/${SORTED_TAGS[$i]}" + fi + done + + for i in "${!SORTED_TAGS[@]}"; do + tag="${SORTED_TAGS[$i]}" + TAG_COMMIT=$(git rev-list -n 1 "$tag") + + # Fetch the release title and body from the primary repo. + RELEASE_TITLE=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json name --jq '.name' 2>/dev/null || echo "$tag") + RELEASE_BODY=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json body --jq '.body' 2>/dev/null || echo "") + + if [[ "$i" -lt "$LAST_INDEX" ]]; then + echo "Creating release $tag (${i+1}/${#SORTED_TAGS[@]})..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh release create "$tag" \ + --repo "$TEST_ORG/$REPOSITORY_NAME" \ + --target "$TAG_COMMIT" \ + --title "$RELEASE_TITLE" \ + --notes "$RELEASE_BODY" \ + --verify-tag + else + echo "Skipping final release $tag β€” will be handled by workflows after .github/ is restored." + fi + done + + # Restore .github/ and force-push to main so workflows can create the final release. + echo "Restoring .github/ folder..." + git checkout HEAD~1 -- .github/ + rm -fr .github/dependabot.yml # Remove dependabot config, will be overlaid by copier + git add .github/ + git commit -m "chore: restore .github/ for workflow-managed releases" + git push origin main -f || git push origin main -f +fi + +echo "Repository cloned to $TEST_ORG/$REPOSITORY_NAME. Cleaning up local temp files..." +cd / +rm -rf "$TEMP_PATH" +echo "Done!" diff --git a/scripts/copier_conversion.sh b/scripts/copier_conversion.sh new file mode 100755 index 0000000..76ef27b --- /dev/null +++ b/scripts/copier_conversion.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# Convert an existing Launch Terraform module repo to the copier-managed +# skeleton layout. +# +# Usage: +# bash scripts/copier_conversion.sh REPOSITORY_NAME + +set -euo pipefail + +ORG="nttdtest" + +info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } +warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } +error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } +die() { error "$@"; exit 1; } + +if [[ $# -ne 1 ]]; then + die "Usage: $0 REPOSITORY_NAME" +fi + +REPOSITORY_NAME="$1" +REPO_URL="https://github.com/$ORG/$REPOSITORY_NAME.git" + +if ! command -v uv &>/dev/null; then + die "uv is not installed. Install it with: + + curl -LsSf https://astral.sh/uv/install.sh | sh + +See the installation docs: https://docs.astral.sh/uv/getting-started/installation/" +fi + +info "uv found: $(uv --version)" + +if ! uv tool list 2>/dev/null | grep -q '^copier '; then + info "copier not found in uv tools β€” installing…" + uv tool install copier +fi + +info "copier is available" + +TEMP_PATH=$(mktemp -d) +info "Cloning $ORG/$REPOSITORY_NAME to $TEMP_PATH..." +git clone "$REPO_URL" "$TEMP_PATH" || git clone "$REPO_URL" "$TEMP_PATH" + +cd "$TEMP_PATH" + +missing=() +[[ -d .git ]] || missing+=(".git/") +[[ -d examples ]] || missing+=("examples/") +[[ -d tests ]] || missing+=("tests/") +[[ -f main.tf ]] || missing+=("main.tf") + +if [[ ${#missing[@]} -gt 0 ]]; then + die "$REPOSITORY_NAME does not look like a Launch Terraform module. +Missing: ${missing[*]}" +fi + +info "Running copier copy (--trust --force) from $ORG/poc-skeleton..." +uv tool run copier copy --trust --force gh:$ORG/poc-skeleton . + +info "copier copy complete" + +# info "Checking changed files for deletion-only diffs..." + +# # Get the list of modified (tracked) files that have a diff vs HEAD. +# # Untracked (new) files are additions-only by definition, so skip them. +# while IFS= read -r file; do +# [[ -z "$file" ]] && continue + +# additions=$(git diff HEAD -- "$file" | grep -c '^+[^+]' || true) +# deletions=$(git diff HEAD -- "$file" | grep -c '^-[^-]' || true) + +# if [[ "$deletions" -gt 0 && "$additions" -eq 0 ]]; then +# info "Restoring $file (deletion-only change)" +# git restore "$file" +# fi +# done < <(git diff --name-only HEAD) + +# info "Deletion-only files restored" + +BRANCH="feat!/copier-conversion" + +git checkout -b "$BRANCH" +git add -A +git commit -m "feat!: convert to copier-managed skeleton" +git push -u origin "$BRANCH" || git push -u origin "$BRANCH" # Retry once to kick secrets-helper over in case of an auth failure. + +if ! command -v gh &>/dev/null; then + warn "gh CLI not found β€” skipping pull request creation. Push complete." + exit 0 +fi + +info "Opening pull request..." +GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh pr create \ + --repo "$ORG/$REPOSITORY_NAME" \ + --title "feat!: convert to copier-managed skeleton" \ + --body "Automated copier conversion via \`copier_conversion.sh\`." \ + --base main \ + --head "$BRANCH" + +info "Pull request opened for branch $BRANCH." + +info "Cleaning up temp files..." +cd / +rm -rf "$TEMP_PATH" +info "Done!" + + diff --git a/scripts/dependabot_config_audition.sh b/scripts/dependabot_config_audition.sh new file mode 100755 index 0000000..89c8ebd --- /dev/null +++ b/scripts/dependabot_config_audition.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# Audition Dependabot configurations by creating a test-org copy of a source +# repo for each config file in dependabot-configs/. +# +# For every YAML file in dependabot-configs/ the script: +# 1. Creates a fresh private repo in the test organization. +# 2. Pushes the main branch of the source repo (without .github/). +# 3. Populates .github/dependabot.yml from the config file. +# 4. Sets the repo description to the test-case description (line 2 of the config). +# +# Usage: +# bash scripts/dependabot_config_audition.sh + +set -euo pipefail + +PRIMARY_ORG="launchbynttdata" +TEST_ORG="nttdtest" +SOURCE_REPOS=( + "tf-azurerm-module_primitive-dns_zone" + "tf-aws-module_primitive-iam_role" +) + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIGS_DIR="$SCRIPT_DIR/dependabot-configs" + +info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } +warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } +error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } +die() { error "$@"; exit 1; } + +# ── Prerequisites ─────────────────────────────────────────────────────────── + +if ! command -v gh &>/dev/null; then + die "gh CLI is not installed." +fi + +# Verify config directory has YAML files. +shopt -s nullglob +CONFIG_FILES=("$CONFIGS_DIR"/*.yaml "$CONFIGS_DIR"/*.yml) +shopt -u nullglob + +if [[ ${#CONFIG_FILES[@]} -eq 0 ]]; then + die "No YAML config files found in $CONFIGS_DIR" +fi + +info "Found ${#CONFIG_FILES[@]} config file(s) to audition across ${#SOURCE_REPOS[@]} source repo(s)." + +# ── Clone source repos once ───────────────────────────────────────────────── + +TEMP_PATH=$(mktemp -d) +for SOURCE_REPO in "${SOURCE_REPOS[@]}"; do + info "Cloning source repo $PRIMARY_ORG/$SOURCE_REPO..." + git clone "https://github.com/$PRIMARY_ORG/$SOURCE_REPO.git" "$TEMP_PATH/$SOURCE_REPO" +done + +# ── Process each source repo Γ— config combination ─────────────────────────── + +for SOURCE_REPO in "${SOURCE_REPOS[@]}"; do +for CONFIG_FILE in "${CONFIG_FILES[@]}"; do + CONFIG_NAME="$(basename "$CONFIG_FILE" .yaml)" + CONFIG_NAME="$(basename "$CONFIG_NAME" .yml)" + + TEST_REPO_NAME="${SOURCE_REPO}-dependabot-${CONFIG_NAME}" + TEST_REPO_URL="https://github.com/$TEST_ORG/$TEST_REPO_NAME.git" + + # Extract the description from the second line of the config file. + DESCRIPTION="$(sed -n '2p' "$CONFIG_FILE" | sed 's/^#\s*//')" + + info "──────────────────────────────────────────────────────────────" + info "Config: $(basename "$CONFIG_FILE") β†’ $TEST_ORG/$TEST_REPO_NAME" + info "Description: $DESCRIPTION" + + # ── Create test repo ──────────────────────────────────────────────────── + + if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$TEST_REPO_NAME" &>/dev/null; then + info "Deleting existing repo $TEST_ORG/$TEST_REPO_NAME..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$TEST_REPO_NAME" --yes + fi + + info "Creating fresh repo $TEST_ORG/$TEST_REPO_NAME..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$TEST_REPO_NAME" --private + + sleep 2 # Wait a moment for GitHub to be ready to accept pushes to the new repo. + + info "Configuring repo settings..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$TEST_REPO_NAME" \ + --description "$DESCRIPTION" \ + --enable-rebase-merge=false \ + --enable-merge-commit=false \ + --enable-squash-merge \ + --enable-auto-merge \ + --delete-branch-on-merge + + # ── Prepare and push main branch ─────────────────────────────────────── + + WORK_PATH=$(mktemp -d) + cp -a "$TEMP_PATH/$SOURCE_REPO" "$WORK_PATH/repo" + cd "$WORK_PATH/repo" + + # Wipe .github/ entirely. + git rm -r --quiet .github/ 2>/dev/null || true + + # Populate .github/dependabot.yml from the config file. + mkdir -p .github + cp "$CONFIG_FILE" .github/dependabot.yml + git add .github/dependabot.yml + + git commit -m "chore: set up dependabot audition ($CONFIG_NAME)" + + git remote remove origin + git remote add origin "https://x-access-token:${GITHUB_TOKEN_nttdtest}@github.com/$TEST_ORG/$TEST_REPO_NAME.git" + git push -u origin main -f || git push -u origin main -f + + info "Test repo ready: $TEST_ORG/$TEST_REPO_NAME" + + # ── Clean up working copy ────────────────────────────────────────────── + + cd / + rm -rf "$WORK_PATH" +done +done + +# ── Final cleanup ──────────────────────────────────────────────────────────── + +rm -rf "$TEMP_PATH" +info "All dependabot audition repos created. Done!" \ No newline at end of file diff --git a/scripts/full_migration.sh b/scripts/full_migration.sh new file mode 100755 index 0000000..2efbe95 --- /dev/null +++ b/scripts/full_migration.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +./scripts/migrate.sh tf-aws-module_primitive-api_gateway_v2_api +./scripts/migrate.sh tf-aws-module_primitive-iam_role +./scripts/migrate.sh tf-aws-module_primitive-lambda_layer +./scripts/migrate.sh tf-aws-module_primitive-route53_record +./scripts/migrate.sh tf-aws-module_primitive-route53_zone +./scripts/migrate.sh tf-aws-module_primitive-sqs_queue +./scripts/migrate.sh tf-azurerm-module_primitive-container_registry +./scripts/migrate.sh tf-azurerm-module_primitive-dns_zone +# ./scripts/migrate.sh tf-azurerm-module_primitive-iothub +./scripts/migrate.sh tf-azurerm-module_primitive-key_vault +./scripts/migrate.sh tf-azurerm-module_primitive-route_table +./scripts/migrate.sh tf-azurerm-module_primitive-resource_group +./scripts/migrate.sh tf-azurerm-module_primitive-storage_account diff --git a/scripts/migrate.sh b/scripts/migrate.sh new file mode 100755 index 0000000..4c3fdd5 --- /dev/null +++ b/scripts/migrate.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +# Migrate a Launch Terraform module repo to the copier-managed skeleton layout. +# +# This script consolidates clone_to_test_organization.sh and copier_conversion.sh +# into a single workflow: +# 1. Copies the repo to the test organization (deleting it if it exists). +# 2. Configures merge settings (squash-only, auto-merge, delete branch on merge). +# 3. Copies tags and releases (oldest-first), leaving the final release for workflows. +# 4. Restores .github/ (minus dependabot) and pushes main. +# 5. Runs copier conversion, pushes the branch, and opens a PR. +# +# Usage: +# bash scripts/migrate.sh REPOSITORY_NAME + +set -euo pipefail + +PRIMARY_ORG="launchbynttdata" +TEST_ORG="nttdtest" + +info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } +warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } +error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } +die() { error "$@"; exit 1; } + +if [[ $# -ne 1 ]]; then + die "Usage: $0 REPOSITORY_NAME" +fi + +REPOSITORY_NAME="$1" +PRIMARY_REPO_URL="https://github.com/$PRIMARY_ORG/$REPOSITORY_NAME.git" +TEST_REPO_URL="https://x-access-token:${GITHUB_TOKEN_nttdtest}@github.com/$TEST_ORG/$REPOSITORY_NAME.git" + +# ── Prerequisites ─────────────────────────────────────────────────────────── + +if ! command -v gh &>/dev/null; then + die "gh CLI is not installed." +fi + +if ! command -v uv &>/dev/null; then + die "uv is not installed. Install it with: + + curl -LsSf https://astral.sh/uv/install.sh | sh + +See the installation docs: https://docs.astral.sh/uv/getting-started/installation/" +fi + +info "uv found: $(uv --version)" + +if ! uv tool list 2>/dev/null | grep -q '^copier '; then + info "copier not found in uv tools β€” installing…" + uv tool install copier +fi + +info "copier is available" + +# ── Phase 1: Clone to test organization ───────────────────────────────────── + +info "Cloning $PRIMARY_ORG/$REPOSITORY_NAME to $TEST_ORG/$REPOSITORY_NAME..." + +# Delete the test repo if it already exists, then create a fresh empty one. +if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$REPOSITORY_NAME" &>/dev/null; then + info "Deleting existing repo $TEST_ORG/$REPOSITORY_NAME..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$REPOSITORY_NAME" --yes +fi + +info "Creating fresh repo $TEST_ORG/$REPOSITORY_NAME..." +GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$REPOSITORY_NAME" --private + +info "Configuring repo settings for $TEST_ORG/$REPOSITORY_NAME..." +GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$REPOSITORY_NAME" \ + --enable-rebase-merge=false \ + --enable-merge-commit=false \ + --enable-squash-merge \ + --enable-auto-merge \ + --delete-branch-on-merge + +TEMP_PATH=$(mktemp -d) +git clone "$PRIMARY_REPO_URL" "$TEMP_PATH" + +cd "$TEMP_PATH" +git fetch --tags origin + +# Remove .github/ from the initial push so workflows don't fire during release setup. +git rm -r --quiet .github/ 2>/dev/null || true +git commit -m "chore: temporarily remove .github/ for clean clone" --allow-empty + +git remote remove origin +git remote add origin "$TEST_REPO_URL" +git push -u origin main -f || git push -u origin main -f + +# ── Phase 2: Copy tags and releases ───────────────────────────────────────── + +# Sort tags by their commit date (oldest first) so releases are created in order. +SORTED_TAGS=() +while IFS= read -r t; do + SORTED_TAGS+=("$t") +done < <(git tag --sort=creatordate) + +if [[ ${#SORTED_TAGS[@]} -eq 0 ]]; then + info "No tags found β€” skipping release copy." +else + # Copy all releases except the last one; the final release will be handled by workflows. + LAST_INDEX=$(( ${#SORTED_TAGS[@]} - 1 )) + + # Push all tags except the last one to the test repo before creating releases. + info "Pushing tags to $TEST_ORG/$REPOSITORY_NAME..." + for i in "${!SORTED_TAGS[@]}"; do + if [[ "$i" -lt "$LAST_INDEX" ]]; then + git push origin "refs/tags/${SORTED_TAGS[$i]}" + fi + done + + for i in "${!SORTED_TAGS[@]}"; do + tag="${SORTED_TAGS[$i]}" + TAG_COMMIT=$(git rev-list -n 1 "$tag") + + # Fetch the release title and body from the primary repo. + RELEASE_TITLE=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json name --jq '.name' 2>/dev/null || echo "$tag") + RELEASE_BODY=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json body --jq '.body' 2>/dev/null || echo "") + + if [[ "$i" -lt "$LAST_INDEX" ]]; then + info "Creating release $tag ($((i + 1))/${#SORTED_TAGS[@]})..." + GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh release create "$tag" \ + --repo "$TEST_ORG/$REPOSITORY_NAME" \ + --target "$TAG_COMMIT" \ + --title "$RELEASE_TITLE" \ + --notes "$RELEASE_BODY" \ + --verify-tag + else + info "Skipping final release $tag β€” will be handled by workflows after .github/ is restored." + fi + done + + # Restore .github/ and force-push to main so workflows can create the final release. + info "Restoring .github/ folder..." + git checkout HEAD~1 -- .github/ + rm -fr .github/dependabot.yml # Remove dependabot config, will be overlaid by copier + git add .github/ + git commit -m "chore: restore .github/ for workflow-managed releases" + git push origin main -f || git push origin main -f +fi + +info "Test repository ready at $TEST_ORG/$REPOSITORY_NAME." + +# ── Phase 3: Copier conversion ────────────────────────────────────────────── + +# We already have the repo checked out in TEMP_PATH with origin pointing at the +# test org, so we can run copier directly without re-cloning. + +missing=() +[[ -d .git ]] || missing+=(".git/") +[[ -d examples ]] || missing+=("examples/") +[[ -d tests ]] || missing+=("tests/") +[[ -f main.tf ]] || missing+=("main.tf") + +if [[ ${#missing[@]} -gt 0 ]]; then + die "$REPOSITORY_NAME does not look like a Launch Terraform module. +Missing: ${missing[*]}" +fi + +info "Running copier copy (--trust --force) from $TEST_ORG/poc-skeleton..." +uv tool run copier copy --trust --force "gh:$TEST_ORG/poc-skeleton" . + +info "copier copy complete" + +BRANCH="feat!/copier-conversion" + +git checkout -b "$BRANCH" +git add -A +git commit -m "feat!: convert to copier-managed skeleton" +git push -u origin "$BRANCH" || git push -u origin "$BRANCH" + +info "Opening pull request..." +GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh pr create \ + --repo "$TEST_ORG/$REPOSITORY_NAME" \ + --title "feat!: convert to copier-managed skeleton" \ + --body "Automated copier conversion via \`migrate.sh\`." \ + --base main \ + --head "$BRANCH" + +info "Pull request opened for branch $BRANCH." + +# ── Cleanup ────────────────────────────────────────────────────────────────── + +info "Cleaning up temp files..." +cd / +rm -rf "$TEMP_PATH" +info "Done!" From 24478cb735d45cb2e84b111c9a4b63c65b13eae2 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Mon, 27 Apr 2026 09:56:16 -0500 Subject: [PATCH 31/44] feat: auto-update writes summary info --- .../reusable-update-from-skeleton.yml | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index 38e2d93..ba100b1 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -4,17 +4,23 @@ on: workflow_call: inputs: recopy: - description: "Perform a full recopy instead of an incremental update (overwrites all templated files), and re-runs any tasks defined in copier.yml. The resulting PR will require manual review and merging." + description: "Perform a full recopy instead of an incremental update (overwrites + all templated files), and re-runs any tasks defined in copier.yml. The + resulting PR will require manual review and merging." type: boolean default: false skeleton_update_app_id: - description: "The GitHub App ID of the app to use for authentication when pushing updates. The app must be installed on the repository and have permissions to read and write code, as well as create pull requests." + description: "The GitHub App ID of the app to use for authentication when + pushing updates. The app must be installed on the repository and have + permissions to read and write code, as well as create pull requests." required: false type: string default: ${{ vars.LAUNCH_SKELETON_UPDATE_APP_ID }} secrets: LAUNCH_SKELETON_UPDATE_KEY: - description: "The private key for the GitHub App used for authentication when pushing updates. The app must be installed on the repository and have permissions to read and write code, as well as create pull requests." + description: "The private key for the GitHub App used for authentication when + pushing updates. The app must be installed on the repository and have + permissions to read and write code, as well as create pull requests." required: true permissions: @@ -77,9 +83,15 @@ jobs: if git diff --quiet; then echo "No changes detected" echo "has_changes=false" >> "$GITHUB_OUTPUT" + echo "### βœ… No Updates Available" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "The repository is already up to date with the skeleton template." >> "$GITHUB_STEP_SUMMARY" else echo "Changes detected" echo "has_changes=true" >> "$GITHUB_OUTPUT" + echo "### πŸ”„ Updates Available" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Changes were detected from the skeleton template. A pull request will be created." >> "$GITHUB_STEP_SUMMARY" if [ ! -f .pre-commit-config.yaml ]; then echo "No .pre-commit-config.yaml found, skipping pre-commit validation" echo "pre_commit_passed=false" >> "$GITHUB_OUTPUT" @@ -146,7 +158,9 @@ jobs: GH_TOKEN: ${{ steps.get-app-token.outputs.token }} - name: Create Pull Request - if: steps.run-updates.outputs.has_changes == 'true' && steps.run-updates.outputs.pre_commit_passed == 'true' && inputs.recopy != true + if: steps.run-updates.outputs.has_changes == 'true' && + steps.run-updates.outputs.pre_commit_passed == 'true' && inputs.recopy + != true run: | PR_BODY=$(cat <<'EOF' Automated update from skeleton template. @@ -169,7 +183,9 @@ jobs: GH_TOKEN: ${{ steps.get-app-token.outputs.token }} - name: Create Pull Request (requires review) - if: steps.run-updates.outputs.has_changes == 'true' && (steps.run-updates.outputs.pre_commit_passed == 'false' || inputs.recopy == true) + if: steps.run-updates.outputs.has_changes == 'true' && + (steps.run-updates.outputs.pre_commit_passed == 'false' || + inputs.recopy == true) run: | if [ "${{ inputs.recopy }}" == "true" ] && [ "${{ steps.run-updates.outputs.pre_commit_passed }}" == "true" ]; then PR_BODY=$(cat <<'EOF' From 6e29f18ce8665df565839aa2d48d9db10cd7e757 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 13:16:05 -0500 Subject: [PATCH 32/44] fix: no need for GH token, drop script --- .github/workflows/reusable-terraform-check.yml | 2 -- scripts/full_migration.sh | 15 --------------- 2 files changed, 17 deletions(-) delete mode 100755 scripts/full_migration.sh diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 5ea06ff..8df5fe1 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -239,8 +239,6 @@ jobs: export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} fi make configure - env: - GITHUB_TOKEN: ${{ steps.github-app-token.outputs.token || github.token }} - id: save-cache uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 diff --git a/scripts/full_migration.sh b/scripts/full_migration.sh deleted file mode 100755 index 2efbe95..0000000 --- a/scripts/full_migration.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -./scripts/migrate.sh tf-aws-module_primitive-api_gateway_v2_api -./scripts/migrate.sh tf-aws-module_primitive-iam_role -./scripts/migrate.sh tf-aws-module_primitive-lambda_layer -./scripts/migrate.sh tf-aws-module_primitive-route53_record -./scripts/migrate.sh tf-aws-module_primitive-route53_zone -./scripts/migrate.sh tf-aws-module_primitive-sqs_queue -./scripts/migrate.sh tf-azurerm-module_primitive-container_registry -./scripts/migrate.sh tf-azurerm-module_primitive-dns_zone -# ./scripts/migrate.sh tf-azurerm-module_primitive-iothub -./scripts/migrate.sh tf-azurerm-module_primitive-key_vault -./scripts/migrate.sh tf-azurerm-module_primitive-route_table -./scripts/migrate.sh tf-azurerm-module_primitive-resource_group -./scripts/migrate.sh tf-azurerm-module_primitive-storage_account From ac559e0bfde280e370e464cb40da18bafdecd7c0 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 13:21:21 -0500 Subject: [PATCH 33/44] fix: normalize versions, tags --- .../actions/terragrunt-configure-mise/README.md | 2 +- .../workflows/reusable-pr-automated-approvals.yml | 10 ++++++---- .../reusable-pr-conventional-commit-title.yml | 10 +++++----- .github/workflows/reusable-terraform-check-aws.yml | 8 ++++---- .../workflows/reusable-terraform-check-azure.yml | 10 +++++----- .github/workflows/reusable-terraform-check.yml | 14 +++++++------- .../workflows/reusable-terragrunt-deploy-aws.yml | 2 +- .../workflows/reusable-terragrunt-deploy-azure.yml | 2 +- .../reusable-terragrunt-deploy-ephemeral-aws.yml | 4 ++-- .github/workflows/reusable-terragrunt-deploy.yml | 12 ++++++------ .../reusable-terragrunt-destroy-ephemeral-aws.yml | 2 +- .../reusable-terragrunt-plan-only-aws.yml | 2 +- .../reusable-terragrunt-plan-only-azure.yml | 2 +- .../workflows/reusable-terragrunt-plan-only.yml | 8 ++++---- .../workflows/reusable-update-from-skeleton.yml | 6 +++--- 15 files changed, 48 insertions(+), 46 deletions(-) diff --git a/.github/actions/terragrunt-configure-mise/README.md b/.github/actions/terragrunt-configure-mise/README.md index 3ac935e..72538d3 100644 --- a/.github/actions/terragrunt-configure-mise/README.md +++ b/.github/actions/terragrunt-configure-mise/README.md @@ -29,7 +29,7 @@ jobs: # Ensure mise.toml contains terraform and terragrunt at our desired versions - name: Configure Mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: '1.5.5' tg_version: '0.54.11' diff --git a/.github/workflows/reusable-pr-automated-approvals.yml b/.github/workflows/reusable-pr-automated-approvals.yml index 7af30c3..0c7d8cc 100644 --- a/.github/workflows/reusable-pr-automated-approvals.yml +++ b/.github/workflows/reusable-pr-automated-approvals.yml @@ -8,7 +8,8 @@ on: type: string required: false default: "" - description: "This input is not used, but is required to make this workflow callable." + description: "This input is not used, but is required to make this workflow + callable." permissions: pull-requests: read @@ -18,7 +19,8 @@ jobs: approvals: name: Update Automated Approvals runs-on: ubuntu-latest - if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'launch-skeleton-auto-updater[bot]' }} + if: ${{ github.actor == 'dependabot[bot]' || github.actor == + 'launch-skeleton-auto-updater[bot]' }} steps: - name: Check Pull Request id: check-pull-request @@ -55,14 +57,14 @@ jobs: - name: Get Approver Alpha Token id: approver-alpha-token - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: app-id: ${{ vars.LAUNCH_APPROVER_ALPHA_ID }} private-key: ${{ secrets.LAUNCH_APPROVER_ALPHA_KEY }} - name: Get Approver Bravo Token id: approver-bravo-token - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: app-id: ${{ vars.LAUNCH_APPROVER_BRAVO_ID }} private-key: ${{ secrets.LAUNCH_APPROVER_BRAVO_KEY }} diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index f3f3a7a..ba3a593 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Validate inputs - uses: actions/github-script@v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 with: script: | const taskTypes = `${{ inputs.task_types }}`; @@ -161,7 +161,7 @@ jobs: - name: Find previous failure comment id: find-comment if: ${{ always() && inputs.comment_on_failure }} - uses: peter-evans/find-comment@v4 + uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad with: issue-number: ${{ github.event.pull_request.number }} comment-author: github-actions[bot] @@ -170,7 +170,7 @@ jobs: - name: Comment on Failure if: ${{ failure() && steps.pr-validation.outcome == 'failure' && inputs.comment_on_failure }} - uses: peter-evans/create-or-update-comment@v5 + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 with: issue-number: ${{ github.event.pull_request.number }} comment-id: ${{ steps.find-comment.outputs.comment-id }} @@ -190,7 +190,7 @@ jobs: - id: set-status-check name: Set Status Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Conventional Commit PR Title" status: ${{ steps.pr-validation.outcome == 'success' && 'success' || @@ -202,7 +202,7 @@ jobs: - id: set-status-check-legacy name: Set Legacy Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Label Pull Request / Label Pull Request" status: ${{ steps.pr-validation.outcome == 'success' && 'success' || diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index d740769..06f9b3e 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -65,7 +65,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: "pending" @@ -78,7 +78,7 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -108,7 +108,7 @@ jobs: find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: "pending" @@ -121,7 +121,7 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome diff --git a/.github/workflows/reusable-terraform-check-azure.yml b/.github/workflows/reusable-terraform-check-azure.yml index 46517a1..12cd7c5 100644 --- a/.github/workflows/reusable-terraform-check-azure.yml +++ b/.github/workflows/reusable-terraform-check-azure.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 - name: Setup asdf # We use the 'setup' variant of this action, because we have some custom behavior in @@ -60,7 +60,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: "pending" @@ -73,7 +73,7 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -88,7 +88,7 @@ jobs: subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: "pending" @@ -101,7 +101,7 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 8df5fe1..b6ec5cb 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -173,7 +173,7 @@ jobs: - id: set-lint-pending name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: "pending" @@ -189,7 +189,7 @@ jobs: - id: update-lint-status name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -286,7 +286,7 @@ jobs: - id: github-app-token name: Create GitHub App Token if: needs.validate-inputs.outputs.auth_github == 'true' - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: app-id: ${{ inputs.github_app_id }} private-key: ${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }} @@ -295,7 +295,7 @@ jobs: - id: set-tests-pending name: "Set Terraform Tests status to pending" continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: "pending" @@ -317,7 +317,7 @@ jobs: name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome @@ -337,7 +337,7 @@ jobs: - id: update-legacy-status-checks-aws name: "Add AWS Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-aws-') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Check AWS Terraform Code / Check AWS Terraform Code" status: "success" @@ -349,7 +349,7 @@ jobs: - id: update-legacy-status-checks-azure name: "Add Azure Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-az') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Check Azure Terraform Code / Check Azure Terraform Code" status: "success" diff --git a/.github/workflows/reusable-terragrunt-deploy-aws.yml b/.github/workflows/reusable-terragrunt-deploy-aws.yml index 1c257ea..f97f7d6 100644 --- a/.github/workflows/reusable-terragrunt-deploy-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-aws.yml @@ -117,7 +117,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy-azure.yml b/.github/workflows/reusable-terragrunt-deploy-azure.yml index 892c09f..f5d880a 100644 --- a/.github/workflows/reusable-terragrunt-deploy-azure.yml +++ b/.github/workflows/reusable-terragrunt-deploy-azure.yml @@ -110,7 +110,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml index ca1993c..416b464 100644 --- a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml @@ -85,7 +85,7 @@ jobs: terraform_outputs_json: ${{ steps.set-outputs.outputs.terraform_outputs_json }} steps: - name: Checkout - uses: actions/checkout@8edcb1bdb4e267140fa742c62e395cd74f332709 + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 @@ -105,7 +105,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index 895168f..02cb9fa 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -231,7 +231,7 @@ jobs: - name: Create GitHub App Token id: github-app-token if: needs.validate-inputs.outputs.auth_github == 'true' - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: app-id: ${{ inputs.github_app_id }} private-key: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} @@ -239,13 +239,13 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" @@ -284,7 +284,7 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome @@ -294,7 +294,7 @@ jobs: github.run_id }}" - name: "Set Terragrunt Deploy status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: "pending" @@ -333,7 +333,7 @@ jobs: - name: "Update Terragrunt Deploy status" if: always() && steps.deploy.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: ${{ steps.deploy.outcome == 'success' && 'success' || diff --git a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml index b50ffda..5e03276 100644 --- a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml @@ -76,7 +76,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only-aws.yml b/.github/workflows/reusable-terragrunt-plan-only-aws.yml index 6c8a56d..ce47d86 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-aws.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-aws.yml @@ -81,7 +81,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only-azure.yml b/.github/workflows/reusable-terragrunt-plan-only-azure.yml index d2d1100..5843c1c 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-azure.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-azure.yml @@ -80,7 +80,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index fae3ec8..be36fbc 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -194,7 +194,7 @@ jobs: - name: Create GitHub App Token id: github-app-token if: needs.validate-inputs.outputs.auth_github == 'true' - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: app-id: ${{ inputs.github_app_id }} private-key: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} @@ -202,13 +202,13 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" @@ -243,7 +243,7 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index ba100b1..70472ed 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -33,14 +33,14 @@ jobs: runs-on: ubuntu-latest steps: - id: get-app-token - uses: actions/create-github-app-token@v3 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: app-id: ${{ inputs.skeleton_update_app_id }} private-key: ${{ secrets.LAUNCH_SKELETON_UPDATE_KEY }} - id: checkout name: Checkout Repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: token: ${{ steps.get-app-token.outputs.token }} @@ -58,7 +58,7 @@ jobs: - id: get-repo-custom-properties name: Get Repository Custom Properties - uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@feat/prerelease-on-merge + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@0.15.0 - id: run-updates name: Run Updates from Skeleton From e4bdd1de43ceca51a2f408f66c9699b401ad23fa Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 13:31:07 -0500 Subject: [PATCH 34/44] fix: shell expansion issues --- .../workflows/reusable-python-uv-pytest.yml | 122 +++++++++--------- .../reusable-terraform-check-aws.yml | 4 +- .../reusable-terraform-check-azure.yml | 4 +- .../workflows/reusable-terraform-check.yml | 38 ++++-- .../workflows/reusable-terragrunt-deploy.yml | 25 ++-- .../reusable-terragrunt-plan-only.yml | 25 ++-- 6 files changed, 129 insertions(+), 89 deletions(-) diff --git a/.github/workflows/reusable-python-uv-pytest.yml b/.github/workflows/reusable-python-uv-pytest.yml index 0bc8652..a7f3b3e 100644 --- a/.github/workflows/reusable-python-uv-pytest.yml +++ b/.github/workflows/reusable-python-uv-pytest.yml @@ -4,32 +4,34 @@ on: workflow_call: inputs: python-version: - description: 'Python version to test against. Currently, this only supports one version per workflow run.' + description: "Python version to test against. Currently, this only supports one + version per workflow run." required: false type: string - default: '3.11' + default: "3.11" asdf-install: - description: 'Whether to install supplementary tools from .tool-versions' + description: "Whether to install supplementary tools from .tool-versions" required: false type: boolean default: true lcaf-makefile-setup: - description: 'Whether to set the environment up for the LCAF Makefile' + description: "Whether to set the environment up for the LCAF Makefile" required: false type: boolean default: false lcaf-aws-region: - description: 'AWS region to use for LCAF Makefile setup. Ignored if lcaf-makefile-setup is false.' + description: "AWS region to use for LCAF Makefile setup. Ignored if + lcaf-makefile-setup is false." required: false type: string - default: 'us-east-2' + default: "us-east-2" run-ruff: - description: 'Run Ruff for linting and formatting checks' + description: "Run Ruff for linting and formatting checks" required: false type: boolean default: true report-coverage: - description: 'Report on code coverage with a comment on the PR' + description: "Report on code coverage with a comment on the PR" required: false type: boolean default: true @@ -47,62 +49,64 @@ jobs: matrix: python-version: [ "${{ inputs.python-version }}" ] steps: - - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 + - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 - - name: Restore cached asdf tools - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 - if: ${{ inputs.asdf-install }} - id: cache - with: - path: ~/.asdf - key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + - name: Restore cached asdf tools + uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 + if: ${{ inputs.asdf-install }} + id: cache + with: + path: ~/.asdf + key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - - name: asdf install - if: ${{ inputs.asdf-install }} - uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 + - name: asdf install + if: ${{ inputs.asdf-install }} + uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 - - name: Cache asdf tools - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 - id: save-cache - if: ${{ inputs.asdf-install && steps.cache.outputs.cache-hit != 'true' }} - with: - path: ~/.asdf - key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} + - name: Cache asdf tools + uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 + id: save-cache + if: ${{ inputs.asdf-install && steps.cache.outputs.cache-hit != 'true' }} + with: + path: ~/.asdf + key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - - name: Set up Python ${{ matrix.python-version }} - uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 - with: - python-version: ${{ matrix.python-version }} + - name: Set up Python ${{ matrix.python-version }} + uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 + with: + python-version: ${{ matrix.python-version }} - - name: Setup Repository for Makefile - if: ${{ inputs.lcaf-makefile-setup }} - # Ensure the 'repo' tool is installed, set up git to make the Makefile happy - shell: bash - run: | - mkdir -p ~/.local/bin - curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo - chmod +x ~/.local/bin/repo - echo "$HOME/.local/bin" >> $GITHUB_PATH - set -x - git config --global user.name "GitHub Actions" - git config --global user.email "noreply@launch.nttdata.com" - export AWS_REGION=${{ inputs.lcaf-aws-region }} + - name: Setup Repository for Makefile + if: ${{ inputs.lcaf-makefile-setup }} + # Ensure the 'repo' tool is installed, set up git to make the Makefile happy + shell: bash + env: + AWS_REGION: ${{ inputs.lcaf-aws-region }} + run: | + mkdir -p ~/.local/bin + curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo + chmod +x ~/.local/bin/repo + echo "$HOME/.local/bin" >> $GITHUB_PATH + set -x + git config --global user.name "GitHub Actions" + git config --global user.email "noreply@launch.nttdata.com" + export AWS_REGION="$AWS_REGION" - - name: Ruff check - if: ${{ inputs.run-ruff }} - run: | - uvx ruff check + - name: Ruff check + if: ${{ inputs.run-ruff }} + run: | + uvx ruff check - - name: Test with pytest - run: | - uv run pytest + - name: Test with pytest + run: | + uv run pytest - - name: Report coverage - if: ${{ inputs.report-coverage }} - uses: MishaKav/pytest-coverage-comment@26f986d2599c288bb62f623d29c2da98609e9cd4 - with: - pytest-xml-coverage-path: ./htmlcov/coverage.xml - title: Coverage report for Python ${{ matrix.python-version }} - remove-link-from-badge: true - unique-id-for-comment: ${{ matrix.python-version }} - coverage-path-prefix: src/ + - name: Report coverage + if: ${{ inputs.report-coverage }} + uses: MishaKav/pytest-coverage-comment@26f986d2599c288bb62f623d29c2da98609e9cd4 + with: + pytest-xml-coverage-path: ./htmlcov/coverage.xml + title: Coverage report for Python ${{ matrix.python-version }} + remove-link-from-badge: true + unique-id-for-comment: ${{ matrix.python-version }} + coverage-path-prefix: src/ diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index 06f9b3e..1664619 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -44,6 +44,8 @@ jobs: - name: Setup Repository for Checks # Ensure the 'repo' tool is installed, set up git to make the Makefile happy, and then configure to clone LCAF. shell: bash + env: + AWS_REGION: ${{ inputs.region }} run: | mkdir -p ~/.local/bin curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo @@ -52,7 +54,7 @@ jobs: set -x git config user.name "GitHub Actions" git config user.email "noreply@launch.nttdata.com" - export AWS_REGION=${{ inputs.region }} + export AWS_REGION="$AWS_REGION" make configure - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 diff --git a/.github/workflows/reusable-terraform-check-azure.yml b/.github/workflows/reusable-terraform-check-azure.yml index 12cd7c5..ecee790 100644 --- a/.github/workflows/reusable-terraform-check-azure.yml +++ b/.github/workflows/reusable-terraform-check-azure.yml @@ -39,6 +39,8 @@ jobs: - name: Setup Repository for Checks # Ensure the 'repo' tool is installed, set up git to make the Makefile happy, and then configure to clone LCAF. shell: bash + env: + TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} run: | mkdir -p ~/.local/bin curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo @@ -47,7 +49,7 @@ jobs: set -x git config user.name "GitHub Actions" git config user.email "noreply@launch.nttdata.com" - export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + export ARM_SUBSCRIPTION_ID="$TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID" make configure - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index b6ec5cb..bc5692f 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -65,12 +65,21 @@ jobs: - name: Validate inputs and secrets id: validate shell: bash + env: + AUTH_METHOD: ${{ inputs.auth_method }} + AWS_ASSUME_ROLE_ARN: ${{ inputs.aws_assume_role_arn }} + AWS_AUTH_REGION: ${{ inputs.aws_auth_region }} + TERRAFORM_CHECK_AZURE_CLIENT_ID: ${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }} + TERRAFORM_CHECK_AZURE_TENANT_ID: ${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }} + TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + GITHUB_APP_ID: ${{ inputs.github_app_id }} + TERRAFORM_CHECK_GITHUB_APP_SECRET: ${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }} run: | auth_aws=false auth_azure=false auth_github=false - IFS=',' read -ra AUTH_METHODS <<< "${{ inputs.auth_method }}" + IFS=',' read -ra AUTH_METHODS <<< "$AUTH_METHOD" for method in "${AUTH_METHODS[@]}"; do method=$(echo "$method" | xargs) [[ -z "$method" ]] && continue @@ -78,11 +87,11 @@ jobs: # --- AWS authentication validation --- aws) auth_aws=true - if [[ -z "${{ inputs.aws_assume_role_arn }}" ]]; then + if [[ -z "$AWS_ASSUME_ROLE_ARN" ]]; then echo "Error: aws_assume_role_arn input is required when auth_method includes 'aws'." exit 1 fi - if [[ -z "${{ inputs.aws_auth_region }}" ]]; then + if [[ -z "$AWS_AUTH_REGION" ]]; then echo "Error: aws_auth_region input is required when auth_method includes 'aws'." exit 1 fi @@ -90,15 +99,15 @@ jobs: # --- Azure authentication validation --- azure) auth_azure=true - if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_CLIENT_ID }}" ]]; then + if [[ -z "$TERRAFORM_CHECK_AZURE_CLIENT_ID" ]]; then echo "Error: TERRAFORM_CHECK_AZURE_CLIENT_ID secret is required when auth_method includes 'azure'." exit 1 fi - if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_TENANT_ID }}" ]]; then + if [[ -z "$TERRAFORM_CHECK_AZURE_TENANT_ID" ]]; then echo "Error: TERRAFORM_CHECK_AZURE_TENANT_ID secret is required when auth_method includes 'azure'." exit 1 fi - if [[ -z "${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }}" ]]; then + if [[ -z "$TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID" ]]; then echo "Error: TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID secret is required when auth_method includes 'azure'." exit 1 fi @@ -106,11 +115,11 @@ jobs: # --- GitHub App authentication validation --- github) auth_github=true - if [[ -z "${{ inputs.github_app_id }}" ]]; then + if [[ -z "$GITHUB_APP_ID" ]]; then echo "Error: github_app_id input is required when auth_method includes 'github'." exit 1 fi - if [[ -z "${{ secrets.TERRAFORM_CHECK_GITHUB_APP_SECRET }}" ]]; then + if [[ -z "$TERRAFORM_CHECK_GITHUB_APP_SECRET" ]]; then echo "Error: TERRAFORM_CHECK_GITHUB_APP_SECRET secret is required when auth_method includes 'github'." exit 1 fi @@ -225,6 +234,11 @@ jobs: name: Setup Repository for Checks # Ensure the 'repo' tool is installed, set up git to make the Makefile happy, and then configure to clone LCAF. shell: bash + env: + AUTH_AWS: ${{ needs.validate-inputs.outputs.auth_aws }} + AUTH_AZURE: ${{ needs.validate-inputs.outputs.auth_azure }} + AWS_AUTH_REGION: ${{ inputs.aws_auth_region }} + TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} run: | mkdir -p ~/.local/bin curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.local/bin/repo @@ -233,10 +247,10 @@ jobs: set -x git config user.name "GitHub Actions" git config user.email "noreply@launch.nttdata.com" - if [[ "${{ needs.validate-inputs.outputs.auth_aws }}" == "true" ]]; then - export AWS_REGION=${{ inputs.aws_auth_region }} - elif [[ "${{ needs.validate-inputs.outputs.auth_azure }}" == "true" ]]; then - export ARM_SUBSCRIPTION_ID=${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} + if [[ "$AUTH_AWS" == "true" ]]; then + export AWS_REGION="$AWS_AUTH_REGION" + elif [[ "$AUTH_AZURE" == "true" ]]; then + export ARM_SUBSCRIPTION_ID="$TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID" fi make configure diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index 02cb9fa..8c42af2 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -122,12 +122,21 @@ jobs: - name: Validate inputs and secrets id: validate shell: bash + env: + AUTH_METHOD: ${{ inputs.auth_method }} + AWS_AUTH_REGION: ${{ inputs.aws_auth_region }} + AWS_ASSUME_ROLE_ARN: ${{ inputs.aws_assume_role_arn }} + TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + GITHUB_APP_ID: ${{ inputs.github_app_id }} + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} run: | auth_aws=false auth_azure=false auth_github=false - IFS=',' read -ra AUTH_METHODS <<< "${{ inputs.auth_method }}" + IFS=',' read -ra AUTH_METHODS <<< "$AUTH_METHOD" for method in "${AUTH_METHODS[@]}"; do method=$(echo "$method" | xargs) [[ -z "$method" ]] && continue @@ -135,11 +144,11 @@ jobs: # --- AWS authentication validation --- aws) auth_aws=true - if [[ -z "${{ inputs.aws_auth_region }}" ]]; then + if [[ -z "$AWS_AUTH_REGION" ]]; then echo "Error: aws_auth_region input is required when auth_method includes 'aws'." exit 1 fi - if [[ -z "${{ inputs.aws_assume_role_arn }}" ]]; then + if [[ -z "$AWS_ASSUME_ROLE_ARN" ]]; then echo "Error: aws_assume_role_arn input is required when auth_method includes 'aws'." exit 1 fi @@ -147,15 +156,15 @@ jobs: # --- Azure authentication validation --- azure) auth_azure=true - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID" ]]; then echo "Error: TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID secret is required when auth_method includes 'azure'." exit 1 fi - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_AZURE_TENANT_ID" ]]; then echo "Error: TERRAGRUNT_DEPLOY_AZURE_TENANT_ID secret is required when auth_method includes 'azure'." exit 1 fi - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID" ]]; then echo "Error: TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID secret is required when auth_method includes 'azure'." exit 1 fi @@ -163,11 +172,11 @@ jobs: # --- GitHub App authentication validation --- github) auth_github=true - if [[ -z "${{ inputs.github_app_id }}" ]]; then + if [[ -z "$GITHUB_APP_ID" ]]; then echo "Error: github_app_id input is required when auth_method includes 'github'." exit 1 fi - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET" ]]; then echo "Error: TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET secret is required when auth_method includes 'github'." exit 1 fi diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index be36fbc..4cf914a 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -89,12 +89,21 @@ jobs: - name: Validate inputs and secrets id: validate shell: bash + env: + AUTH_METHOD: ${{ inputs.auth_method }} + AWS_AUTH_REGION: ${{ inputs.aws_auth_region }} + AWS_ASSUME_ROLE_ARN: ${{ inputs.aws_assume_role_arn }} + TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }} + TERRAGRUNT_DEPLOY_AZURE_TENANT_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }} + TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID: ${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }} + GITHUB_APP_ID: ${{ inputs.github_app_id }} + TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET: ${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }} run: | auth_aws=false auth_azure=false auth_github=false - IFS=',' read -ra AUTH_METHODS <<< "${{ inputs.auth_method }}" + IFS=',' read -ra AUTH_METHODS <<< "$AUTH_METHOD" for method in "${AUTH_METHODS[@]}"; do method=$(echo "$method" | xargs) [[ -z "$method" ]] && continue @@ -102,11 +111,11 @@ jobs: # --- AWS authentication validation --- aws) auth_aws=true - if [[ -z "${{ inputs.aws_auth_region }}" ]]; then + if [[ -z "$AWS_AUTH_REGION" ]]; then echo "Error: aws_auth_region input is required when auth_method includes 'aws'." exit 1 fi - if [[ -z "${{ inputs.aws_assume_role_arn }}" ]]; then + if [[ -z "$AWS_ASSUME_ROLE_ARN" ]]; then echo "Error: aws_assume_role_arn input is required when auth_method includes 'aws'." exit 1 fi @@ -114,15 +123,15 @@ jobs: # --- Azure authentication validation --- azure) auth_azure=true - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID" ]]; then echo "Error: TERRAGRUNT_DEPLOY_AZURE_CLIENT_ID secret is required when auth_method includes 'azure'." exit 1 fi - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_TENANT_ID }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_AZURE_TENANT_ID" ]]; then echo "Error: TERRAGRUNT_DEPLOY_AZURE_TENANT_ID secret is required when auth_method includes 'azure'." exit 1 fi - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID" ]]; then echo "Error: TERRAGRUNT_DEPLOY_AZURE_SUBSCRIPTION_ID secret is required when auth_method includes 'azure'." exit 1 fi @@ -130,11 +139,11 @@ jobs: # --- GitHub App authentication validation --- github) auth_github=true - if [[ -z "${{ inputs.github_app_id }}" ]]; then + if [[ -z "$GITHUB_APP_ID" ]]; then echo "Error: github_app_id input is required when auth_method includes 'github'." exit 1 fi - if [[ -z "${{ secrets.TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET }}" ]]; then + if [[ -z "$TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET" ]]; then echo "Error: TERRAGRUNT_DEPLOY_GITHUB_APP_SECRET secret is required when auth_method includes 'github'." exit 1 fi From 90e54a5486b03de267841bb1144e36a18f45e451 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 13:37:08 -0500 Subject: [PATCH 35/44] fix: input validation, secrets refs for caller --- .../reusable-pr-automated-approvals.yml | 73 ++++++++++++++++--- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/.github/workflows/reusable-pr-automated-approvals.yml b/.github/workflows/reusable-pr-automated-approvals.yml index 0c7d8cc..1f8c149 100644 --- a/.github/workflows/reusable-pr-automated-approvals.yml +++ b/.github/workflows/reusable-pr-automated-approvals.yml @@ -3,24 +3,79 @@ name: Automated Approvals on: workflow_call: inputs: - # No inputs needed for this workflow, but we need to define at least one to make it callable. - placeholder: + approver_alpha_app_id: + description: "The GitHub App ID for the first approver bot. Defaults to the + value of the LAUNCH_APPROVER_ALPHA_ID variable." + required: false + type: string + default: "${{ vars.LAUNCH_APPROVER_ALPHA_ID }}" + approver_bravo_app_id: + description: "The GitHub App ID for the second approver bot. Defaults to the + value of the LAUNCH_APPROVER_BRAVO_ID variable." + required: false type: string + default: "${{ vars.LAUNCH_APPROVER_BRAVO_ID }}" + secrets: + LAUNCH_APPROVER_ALPHA_KEY: required: false - default: "" - description: "This input is not used, but is required to make this workflow - callable." + description: "The private key for the first approver GitHub App." + LAUNCH_APPROVER_BRAVO_KEY: + required: false + description: "The private key for the second approver GitHub App." permissions: pull-requests: read contents: read jobs: - approvals: - name: Update Automated Approvals + validate-inputs: + name: "Validate Inputs" runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'launch-skeleton-auto-updater[bot]' }} + steps: + - name: Validate required secrets and variables + id: validate + shell: bash + env: + APPROVER_ALPHA_APP_ID: ${{ inputs.approver_alpha_app_id }} + APPROVER_BRAVO_APP_ID: ${{ inputs.approver_bravo_app_id }} + LAUNCH_APPROVER_ALPHA_KEY: ${{ secrets.LAUNCH_APPROVER_ALPHA_KEY }} + LAUNCH_APPROVER_BRAVO_KEY: ${{ secrets.LAUNCH_APPROVER_BRAVO_KEY }} + run: | + ERRORS=0 + + if [[ -z "$APPROVER_ALPHA_APP_ID" ]]; then + echo "Error: approver_alpha_app_id input (or LAUNCH_APPROVER_ALPHA_ID variable) is required." + ERRORS=$((ERRORS + 1)) + fi + + if [[ -z "$LAUNCH_APPROVER_ALPHA_KEY" ]]; then + echo "Error: LAUNCH_APPROVER_ALPHA_KEY secret is required." + ERRORS=$((ERRORS + 1)) + fi + + if [[ -z "$APPROVER_BRAVO_APP_ID" ]]; then + echo "Error: approver_bravo_app_id input (or LAUNCH_APPROVER_BRAVO_ID variable) is required." + ERRORS=$((ERRORS + 1)) + fi + + if [[ -z "$LAUNCH_APPROVER_BRAVO_KEY" ]]; then + echo "Error: LAUNCH_APPROVER_BRAVO_KEY secret is required." + ERRORS=$((ERRORS + 1)) + fi + + if [[ $ERRORS -gt 0 ]]; then + echo "Validation failed with $ERRORS error(s)." + exit 1 + fi + + echo "All required inputs and secrets are present." + + approvals: + name: Update Automated Approvals + runs-on: ubuntu-latest + needs: validate-inputs steps: - name: Check Pull Request id: check-pull-request @@ -59,14 +114,14 @@ jobs: id: approver-alpha-token uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: - app-id: ${{ vars.LAUNCH_APPROVER_ALPHA_ID }} + app-id: ${{ inputs.approver_alpha_app_id }} private-key: ${{ secrets.LAUNCH_APPROVER_ALPHA_KEY }} - name: Get Approver Bravo Token id: approver-bravo-token uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 with: - app-id: ${{ vars.LAUNCH_APPROVER_BRAVO_ID }} + app-id: ${{ inputs.approver_bravo_app_id }} private-key: ${{ secrets.LAUNCH_APPROVER_BRAVO_KEY }} - name: Approve PR From 10fa46fc105afb2f5a06fee05a4b93473b9007ef Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 13:48:39 -0500 Subject: [PATCH 36/44] fix: add-only detection, sha --- .github/workflows/reusable-update-from-skeleton.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index 70472ed..a04f38b 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -40,7 +40,7 @@ jobs: - id: checkout name: Checkout Repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 with: token: ${{ steps.get-app-token.outputs.token }} @@ -80,7 +80,7 @@ jobs: uv run copier $COPIER_CMD $COPIER_FLAGS fi - if git diff --quiet; then + if [[ -z "$(git status --porcelain)" ]]; then echo "No changes detected" echo "has_changes=false" >> "$GITHUB_OUTPUT" echo "### βœ… No Updates Available" >> "$GITHUB_STEP_SUMMARY" From f0cd43c1cc07e9b68e92ed40035db94a94cfda8c Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 13:55:01 -0500 Subject: [PATCH 37/44] fix: branch refs, heredocs, folding --- .github/actions/update-status-check/README.md | 14 +++++++------- .../reusable-pr-conventional-commit-title.yml | 8 ++++---- .github/workflows/reusable-python-uv-pytest.yml | 1 - .../workflows/reusable-update-from-skeleton.yml | 6 +++--- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/actions/update-status-check/README.md b/.github/actions/update-status-check/README.md index be26cc7..da986f9 100644 --- a/.github/actions/update-status-check/README.md +++ b/.github/actions/update-status-check/README.md @@ -26,7 +26,7 @@ This action will: ### Basic Usage -Mark a status check as successful on the current commit: +Mark a status check as successful on the current commit (replacing `ref` with a tag or commit SHA from this repository): ```yaml jobs: @@ -36,7 +36,7 @@ jobs: statuses: write steps: - name: Set status check to success - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@ref with: check_name: "my-check" status: "success" @@ -48,7 +48,7 @@ Provide additional context visible in the GitHub UI: ```yaml - name: Set status check to failure - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@ref with: check_name: "security-scan" status: "failure" @@ -62,7 +62,7 @@ Use `pending` to signal that a check is in progress, then update it on completio ```yaml - name: Mark check as pending - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@ref with: check_name: "integration-tests" status: "pending" @@ -73,7 +73,7 @@ Use `pending` to signal that a check is in progress, then update it on completio - name: Mark check as success if: success() - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@ref with: check_name: "integration-tests" status: "success" @@ -81,7 +81,7 @@ Use `pending` to signal that a check is in progress, then update it on completio - name: Mark check as failure if: failure() - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@ref with: check_name: "integration-tests" status: "failure" @@ -94,7 +94,7 @@ Override the default SHA to set a status on a commit other than the one that tri ```yaml - name: Set status on a specific commit - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@main + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@ref with: check_name: "my-check" status: "success" diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index ba3a593..7a0cfdf 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -4,11 +4,11 @@ on: task_types: type: string description: "A JSON array of task types that are allowed. Default: - [\"feat\",\"fix\",\"docs\",\"test\",\"ci\",\"refactor\",\"perf\",\"ch\ - ore\",\"revert\"]" + [\"feat\",\"fix\",\"docs\",\"test\",\"ci\",\"refactor\",\"perf\", + \"chore\",\"revert\"]" required: false - default: "[\"feat\",\"fix\",\"docs\",\"test\",\"ci\",\"refactor\",\"perf\",\"ch\ - ore\",\"revert\"]" + default: "[\"feat\",\"fix\",\"docs\",\"test\",\"ci\",\"refactor\",\"perf\", + \"chore\",\"revert\"]" scope_types: type: string description: "A JSON array of valid scope types. If omitted, any scope is diff --git a/.github/workflows/reusable-python-uv-pytest.yml b/.github/workflows/reusable-python-uv-pytest.yml index a7f3b3e..ec2f674 100644 --- a/.github/workflows/reusable-python-uv-pytest.yml +++ b/.github/workflows/reusable-python-uv-pytest.yml @@ -90,7 +90,6 @@ jobs: set -x git config --global user.name "GitHub Actions" git config --global user.email "noreply@launch.nttdata.com" - export AWS_REGION="$AWS_REGION" - name: Ruff check if: ${{ inputs.run-ruff }} diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index a04f38b..7a09525 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -162,7 +162,7 @@ jobs: steps.run-updates.outputs.pre_commit_passed == 'true' && inputs.recopy != true run: | - PR_BODY=$(cat <<'EOF' + PR_BODY=$(cat <<-'EOF' Automated update from skeleton template. No conflicting changes were detected from the base repository. @@ -188,14 +188,14 @@ jobs: inputs.recopy == true) run: | if [ "${{ inputs.recopy }}" == "true" ] && [ "${{ steps.run-updates.outputs.pre_commit_passed }}" == "true" ]; then - PR_BODY=$(cat <<'EOF' + PR_BODY=$(cat <<-'EOF' Automated recopy from skeleton template. All templated files have been overwritten. Please review the changes carefully before merging. EOF ) else - PR_BODY=$(cat < Date: Tue, 28 Apr 2026 13:56:44 -0500 Subject: [PATCH 38/44] fix: redundant --- .../reusable-pr-automated-approvals.yml | 2 -- .../reusable-terraform-check-aws.yml | 1 - scripts/full_migration.sh | 24 +++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100755 scripts/full_migration.sh diff --git a/.github/workflows/reusable-pr-automated-approvals.yml b/.github/workflows/reusable-pr-automated-approvals.yml index 1f8c149..7dfbbca 100644 --- a/.github/workflows/reusable-pr-automated-approvals.yml +++ b/.github/workflows/reusable-pr-automated-approvals.yml @@ -140,8 +140,6 @@ jobs: --repo "${{ github.repository }}" \ --approve \ --body "Automated approval: all commits from trusted automation accounts." - env: - GH_TOKEN: ${{ steps.approver-alpha-token.outputs.token }} - name: Revoke Approvals if: steps.check-pull-request.outputs.should_approve == 'false' diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index 1664619..b71727e 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -54,7 +54,6 @@ jobs: set -x git config user.name "GitHub Actions" git config user.email "noreply@launch.nttdata.com" - export AWS_REGION="$AWS_REGION" make configure - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 diff --git a/scripts/full_migration.sh b/scripts/full_migration.sh new file mode 100755 index 0000000..7f36bc1 --- /dev/null +++ b/scripts/full_migration.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +./scripts/migrate.sh tf-aws-module_primitive-lambda_layer +./scripts/migrate.sh tf-aws-module_primitive-route53_record +./scripts/migrate.sh tf-aws-module_primitive-route53_zone +./scripts/migrate.sh tf-aws-module_primitive-sqs_queue +./scripts/migrate.sh tf-azurerm-module_primitive-container_registry +./scripts/migrate.sh tf-azurerm-module_primitive-dns_zone +# ./scripts/migrate.sh tf-azurerm-module_primitive-iothub +./scripts/migrate.sh tf-azurerm-module_primitive-key_vault +./scripts/migrate.sh tf-azurerm-module_primitive-route_table +./scripts/migrate.sh tf-azurerm-module_primitive-resource_group +./scripts/migrate.sh tf-azurerm-module_primitive-storage_account + + + +./scripts/migrate.sh tf-aws-module_primitive-route53_record +./scripts/migrate.sh tf-aws-module_primitive-route53_zone +./scripts/migrate.sh tf-aws-module_primitive-sqs_queue +./scripts/migrate.sh tf-azurerm-module_primitive-container_registry +./scripts/migrate.sh tf-azurerm-module_primitive-key_vault +./scripts/migrate.sh tf-azurerm-module_primitive-route_table +./scripts/migrate.sh tf-azurerm-module_primitive-resource_group +./scripts/migrate.sh tf-azurerm-module_primitive-storage_account \ No newline at end of file From 1a852f78b9e42942809677dc066541de4d708569 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 14:24:35 -0500 Subject: [PATCH 39/44] fix: unstage scripts --- scripts/clone_to_test_organization.sh | 106 --------------- scripts/copier_conversion.sh | 108 --------------- scripts/dependabot_config_audition.sh | 126 ----------------- scripts/full_migration.sh | 24 ---- scripts/migrate.sh | 188 -------------------------- 5 files changed, 552 deletions(-) delete mode 100755 scripts/clone_to_test_organization.sh delete mode 100755 scripts/copier_conversion.sh delete mode 100755 scripts/dependabot_config_audition.sh delete mode 100755 scripts/full_migration.sh delete mode 100755 scripts/migrate.sh diff --git a/scripts/clone_to_test_organization.sh b/scripts/clone_to_test_organization.sh deleted file mode 100755 index ffeb147..0000000 --- a/scripts/clone_to_test_organization.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash -# Clone the current repo to a test organization for testing in a clean environment. -# Usage: bash scripts/clone_to_test_organization.sh REPOSITORY_NAME - -# https://github.com/nttdtest/tf-azurerm-module_primitive-storage_account.git - -PRIMARY_ORG="launchbynttdata" -TEST_ORG="nttdtest" - -if [[ $# -ne 1 ]]; then - echo "Usage: $0 REPOSITORY_NAME" - exit 1 -fi - -REPOSITORY_NAME="$1" - -PRIMARY_REPO_URL="https://github.com/$PRIMARY_ORG/$REPOSITORY_NAME.git" -TEST_REPO_URL="https://github.com/$TEST_ORG/$REPOSITORY_NAME.git" - -echo "Cloning $PRIMARY_ORG/$REPOSITORY_NAME to $TEST_ORG/$REPOSITORY_NAME..." - -# Delete the test repo if it already exists, then create a fresh empty one. -if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$REPOSITORY_NAME" &>/dev/null; then - echo "Deleting existing repo $TEST_ORG/$REPOSITORY_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$REPOSITORY_NAME" --yes -fi - -echo "Creating fresh repo $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$REPOSITORY_NAME" --private - -echo "Configuring repo settings for $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$REPOSITORY_NAME" \ - --enable-rebase-merge=false \ - --enable-merge-commit=false \ - --enable-squash-merge \ - --enable-auto-merge \ - --delete-branch-on-merge - -TEMP_PATH=$(mktemp -d) -git clone "$PRIMARY_REPO_URL" "$TEMP_PATH" - -cd "$TEMP_PATH" -git fetch --tags origin - -# Remove .github/ from the initial push so workflows don't fire during release setup. -git rm -r --quiet .github/ 2>/dev/null || true -git commit -m "chore: temporarily remove .github/ for clean clone" --allow-empty - -git remote remove origin -git remote add origin "$TEST_REPO_URL" -git push -u origin main -f || git push -u origin main -f - -# Sort tags by their commit date (oldest first) so releases are created in order. -SORTED_TAGS=() -while IFS= read -r t; do - SORTED_TAGS+=("$t") -done < <(git tag --sort=creatordate) - -if [[ ${#SORTED_TAGS[@]} -eq 0 ]]; then - echo "No tags found β€” skipping release copy." -else - # Copy all releases except the last one; the final release will be handled by workflows. - LAST_INDEX=$(( ${#SORTED_TAGS[@]} - 1 )) - - # Push all tags except the last one to the test repo before creating releases. - echo "Pushing tags to $TEST_ORG/$REPOSITORY_NAME..." - for i in "${!SORTED_TAGS[@]}"; do - if [[ "$i" -lt "$LAST_INDEX" ]]; then - git push origin "refs/tags/${SORTED_TAGS[$i]}" - fi - done - - for i in "${!SORTED_TAGS[@]}"; do - tag="${SORTED_TAGS[$i]}" - TAG_COMMIT=$(git rev-list -n 1 "$tag") - - # Fetch the release title and body from the primary repo. - RELEASE_TITLE=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json name --jq '.name' 2>/dev/null || echo "$tag") - RELEASE_BODY=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json body --jq '.body' 2>/dev/null || echo "") - - if [[ "$i" -lt "$LAST_INDEX" ]]; then - echo "Creating release $tag (${i+1}/${#SORTED_TAGS[@]})..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh release create "$tag" \ - --repo "$TEST_ORG/$REPOSITORY_NAME" \ - --target "$TAG_COMMIT" \ - --title "$RELEASE_TITLE" \ - --notes "$RELEASE_BODY" \ - --verify-tag - else - echo "Skipping final release $tag β€” will be handled by workflows after .github/ is restored." - fi - done - - # Restore .github/ and force-push to main so workflows can create the final release. - echo "Restoring .github/ folder..." - git checkout HEAD~1 -- .github/ - rm -fr .github/dependabot.yml # Remove dependabot config, will be overlaid by copier - git add .github/ - git commit -m "chore: restore .github/ for workflow-managed releases" - git push origin main -f || git push origin main -f -fi - -echo "Repository cloned to $TEST_ORG/$REPOSITORY_NAME. Cleaning up local temp files..." -cd / -rm -rf "$TEMP_PATH" -echo "Done!" diff --git a/scripts/copier_conversion.sh b/scripts/copier_conversion.sh deleted file mode 100755 index 76ef27b..0000000 --- a/scripts/copier_conversion.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash -# Convert an existing Launch Terraform module repo to the copier-managed -# skeleton layout. -# -# Usage: -# bash scripts/copier_conversion.sh REPOSITORY_NAME - -set -euo pipefail - -ORG="nttdtest" - -info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } -warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } -error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } -die() { error "$@"; exit 1; } - -if [[ $# -ne 1 ]]; then - die "Usage: $0 REPOSITORY_NAME" -fi - -REPOSITORY_NAME="$1" -REPO_URL="https://github.com/$ORG/$REPOSITORY_NAME.git" - -if ! command -v uv &>/dev/null; then - die "uv is not installed. Install it with: - - curl -LsSf https://astral.sh/uv/install.sh | sh - -See the installation docs: https://docs.astral.sh/uv/getting-started/installation/" -fi - -info "uv found: $(uv --version)" - -if ! uv tool list 2>/dev/null | grep -q '^copier '; then - info "copier not found in uv tools β€” installing…" - uv tool install copier -fi - -info "copier is available" - -TEMP_PATH=$(mktemp -d) -info "Cloning $ORG/$REPOSITORY_NAME to $TEMP_PATH..." -git clone "$REPO_URL" "$TEMP_PATH" || git clone "$REPO_URL" "$TEMP_PATH" - -cd "$TEMP_PATH" - -missing=() -[[ -d .git ]] || missing+=(".git/") -[[ -d examples ]] || missing+=("examples/") -[[ -d tests ]] || missing+=("tests/") -[[ -f main.tf ]] || missing+=("main.tf") - -if [[ ${#missing[@]} -gt 0 ]]; then - die "$REPOSITORY_NAME does not look like a Launch Terraform module. -Missing: ${missing[*]}" -fi - -info "Running copier copy (--trust --force) from $ORG/poc-skeleton..." -uv tool run copier copy --trust --force gh:$ORG/poc-skeleton . - -info "copier copy complete" - -# info "Checking changed files for deletion-only diffs..." - -# # Get the list of modified (tracked) files that have a diff vs HEAD. -# # Untracked (new) files are additions-only by definition, so skip them. -# while IFS= read -r file; do -# [[ -z "$file" ]] && continue - -# additions=$(git diff HEAD -- "$file" | grep -c '^+[^+]' || true) -# deletions=$(git diff HEAD -- "$file" | grep -c '^-[^-]' || true) - -# if [[ "$deletions" -gt 0 && "$additions" -eq 0 ]]; then -# info "Restoring $file (deletion-only change)" -# git restore "$file" -# fi -# done < <(git diff --name-only HEAD) - -# info "Deletion-only files restored" - -BRANCH="feat!/copier-conversion" - -git checkout -b "$BRANCH" -git add -A -git commit -m "feat!: convert to copier-managed skeleton" -git push -u origin "$BRANCH" || git push -u origin "$BRANCH" # Retry once to kick secrets-helper over in case of an auth failure. - -if ! command -v gh &>/dev/null; then - warn "gh CLI not found β€” skipping pull request creation. Push complete." - exit 0 -fi - -info "Opening pull request..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh pr create \ - --repo "$ORG/$REPOSITORY_NAME" \ - --title "feat!: convert to copier-managed skeleton" \ - --body "Automated copier conversion via \`copier_conversion.sh\`." \ - --base main \ - --head "$BRANCH" - -info "Pull request opened for branch $BRANCH." - -info "Cleaning up temp files..." -cd / -rm -rf "$TEMP_PATH" -info "Done!" - - diff --git a/scripts/dependabot_config_audition.sh b/scripts/dependabot_config_audition.sh deleted file mode 100755 index 89c8ebd..0000000 --- a/scripts/dependabot_config_audition.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash -# Audition Dependabot configurations by creating a test-org copy of a source -# repo for each config file in dependabot-configs/. -# -# For every YAML file in dependabot-configs/ the script: -# 1. Creates a fresh private repo in the test organization. -# 2. Pushes the main branch of the source repo (without .github/). -# 3. Populates .github/dependabot.yml from the config file. -# 4. Sets the repo description to the test-case description (line 2 of the config). -# -# Usage: -# bash scripts/dependabot_config_audition.sh - -set -euo pipefail - -PRIMARY_ORG="launchbynttdata" -TEST_ORG="nttdtest" -SOURCE_REPOS=( - "tf-azurerm-module_primitive-dns_zone" - "tf-aws-module_primitive-iam_role" -) - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONFIGS_DIR="$SCRIPT_DIR/dependabot-configs" - -info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } -warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } -error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } -die() { error "$@"; exit 1; } - -# ── Prerequisites ─────────────────────────────────────────────────────────── - -if ! command -v gh &>/dev/null; then - die "gh CLI is not installed." -fi - -# Verify config directory has YAML files. -shopt -s nullglob -CONFIG_FILES=("$CONFIGS_DIR"/*.yaml "$CONFIGS_DIR"/*.yml) -shopt -u nullglob - -if [[ ${#CONFIG_FILES[@]} -eq 0 ]]; then - die "No YAML config files found in $CONFIGS_DIR" -fi - -info "Found ${#CONFIG_FILES[@]} config file(s) to audition across ${#SOURCE_REPOS[@]} source repo(s)." - -# ── Clone source repos once ───────────────────────────────────────────────── - -TEMP_PATH=$(mktemp -d) -for SOURCE_REPO in "${SOURCE_REPOS[@]}"; do - info "Cloning source repo $PRIMARY_ORG/$SOURCE_REPO..." - git clone "https://github.com/$PRIMARY_ORG/$SOURCE_REPO.git" "$TEMP_PATH/$SOURCE_REPO" -done - -# ── Process each source repo Γ— config combination ─────────────────────────── - -for SOURCE_REPO in "${SOURCE_REPOS[@]}"; do -for CONFIG_FILE in "${CONFIG_FILES[@]}"; do - CONFIG_NAME="$(basename "$CONFIG_FILE" .yaml)" - CONFIG_NAME="$(basename "$CONFIG_NAME" .yml)" - - TEST_REPO_NAME="${SOURCE_REPO}-dependabot-${CONFIG_NAME}" - TEST_REPO_URL="https://github.com/$TEST_ORG/$TEST_REPO_NAME.git" - - # Extract the description from the second line of the config file. - DESCRIPTION="$(sed -n '2p' "$CONFIG_FILE" | sed 's/^#\s*//')" - - info "──────────────────────────────────────────────────────────────" - info "Config: $(basename "$CONFIG_FILE") β†’ $TEST_ORG/$TEST_REPO_NAME" - info "Description: $DESCRIPTION" - - # ── Create test repo ──────────────────────────────────────────────────── - - if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$TEST_REPO_NAME" &>/dev/null; then - info "Deleting existing repo $TEST_ORG/$TEST_REPO_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$TEST_REPO_NAME" --yes - fi - - info "Creating fresh repo $TEST_ORG/$TEST_REPO_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$TEST_REPO_NAME" --private - - sleep 2 # Wait a moment for GitHub to be ready to accept pushes to the new repo. - - info "Configuring repo settings..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$TEST_REPO_NAME" \ - --description "$DESCRIPTION" \ - --enable-rebase-merge=false \ - --enable-merge-commit=false \ - --enable-squash-merge \ - --enable-auto-merge \ - --delete-branch-on-merge - - # ── Prepare and push main branch ─────────────────────────────────────── - - WORK_PATH=$(mktemp -d) - cp -a "$TEMP_PATH/$SOURCE_REPO" "$WORK_PATH/repo" - cd "$WORK_PATH/repo" - - # Wipe .github/ entirely. - git rm -r --quiet .github/ 2>/dev/null || true - - # Populate .github/dependabot.yml from the config file. - mkdir -p .github - cp "$CONFIG_FILE" .github/dependabot.yml - git add .github/dependabot.yml - - git commit -m "chore: set up dependabot audition ($CONFIG_NAME)" - - git remote remove origin - git remote add origin "https://x-access-token:${GITHUB_TOKEN_nttdtest}@github.com/$TEST_ORG/$TEST_REPO_NAME.git" - git push -u origin main -f || git push -u origin main -f - - info "Test repo ready: $TEST_ORG/$TEST_REPO_NAME" - - # ── Clean up working copy ────────────────────────────────────────────── - - cd / - rm -rf "$WORK_PATH" -done -done - -# ── Final cleanup ──────────────────────────────────────────────────────────── - -rm -rf "$TEMP_PATH" -info "All dependabot audition repos created. Done!" \ No newline at end of file diff --git a/scripts/full_migration.sh b/scripts/full_migration.sh deleted file mode 100755 index 7f36bc1..0000000 --- a/scripts/full_migration.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -./scripts/migrate.sh tf-aws-module_primitive-lambda_layer -./scripts/migrate.sh tf-aws-module_primitive-route53_record -./scripts/migrate.sh tf-aws-module_primitive-route53_zone -./scripts/migrate.sh tf-aws-module_primitive-sqs_queue -./scripts/migrate.sh tf-azurerm-module_primitive-container_registry -./scripts/migrate.sh tf-azurerm-module_primitive-dns_zone -# ./scripts/migrate.sh tf-azurerm-module_primitive-iothub -./scripts/migrate.sh tf-azurerm-module_primitive-key_vault -./scripts/migrate.sh tf-azurerm-module_primitive-route_table -./scripts/migrate.sh tf-azurerm-module_primitive-resource_group -./scripts/migrate.sh tf-azurerm-module_primitive-storage_account - - - -./scripts/migrate.sh tf-aws-module_primitive-route53_record -./scripts/migrate.sh tf-aws-module_primitive-route53_zone -./scripts/migrate.sh tf-aws-module_primitive-sqs_queue -./scripts/migrate.sh tf-azurerm-module_primitive-container_registry -./scripts/migrate.sh tf-azurerm-module_primitive-key_vault -./scripts/migrate.sh tf-azurerm-module_primitive-route_table -./scripts/migrate.sh tf-azurerm-module_primitive-resource_group -./scripts/migrate.sh tf-azurerm-module_primitive-storage_account \ No newline at end of file diff --git a/scripts/migrate.sh b/scripts/migrate.sh deleted file mode 100755 index 4c3fdd5..0000000 --- a/scripts/migrate.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env bash -# Migrate a Launch Terraform module repo to the copier-managed skeleton layout. -# -# This script consolidates clone_to_test_organization.sh and copier_conversion.sh -# into a single workflow: -# 1. Copies the repo to the test organization (deleting it if it exists). -# 2. Configures merge settings (squash-only, auto-merge, delete branch on merge). -# 3. Copies tags and releases (oldest-first), leaving the final release for workflows. -# 4. Restores .github/ (minus dependabot) and pushes main. -# 5. Runs copier conversion, pushes the branch, and opens a PR. -# -# Usage: -# bash scripts/migrate.sh REPOSITORY_NAME - -set -euo pipefail - -PRIMARY_ORG="launchbynttdata" -TEST_ORG="nttdtest" - -info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } -warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } -error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } -die() { error "$@"; exit 1; } - -if [[ $# -ne 1 ]]; then - die "Usage: $0 REPOSITORY_NAME" -fi - -REPOSITORY_NAME="$1" -PRIMARY_REPO_URL="https://github.com/$PRIMARY_ORG/$REPOSITORY_NAME.git" -TEST_REPO_URL="https://x-access-token:${GITHUB_TOKEN_nttdtest}@github.com/$TEST_ORG/$REPOSITORY_NAME.git" - -# ── Prerequisites ─────────────────────────────────────────────────────────── - -if ! command -v gh &>/dev/null; then - die "gh CLI is not installed." -fi - -if ! command -v uv &>/dev/null; then - die "uv is not installed. Install it with: - - curl -LsSf https://astral.sh/uv/install.sh | sh - -See the installation docs: https://docs.astral.sh/uv/getting-started/installation/" -fi - -info "uv found: $(uv --version)" - -if ! uv tool list 2>/dev/null | grep -q '^copier '; then - info "copier not found in uv tools β€” installing…" - uv tool install copier -fi - -info "copier is available" - -# ── Phase 1: Clone to test organization ───────────────────────────────────── - -info "Cloning $PRIMARY_ORG/$REPOSITORY_NAME to $TEST_ORG/$REPOSITORY_NAME..." - -# Delete the test repo if it already exists, then create a fresh empty one. -if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$REPOSITORY_NAME" &>/dev/null; then - info "Deleting existing repo $TEST_ORG/$REPOSITORY_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$REPOSITORY_NAME" --yes -fi - -info "Creating fresh repo $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$REPOSITORY_NAME" --private - -info "Configuring repo settings for $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$REPOSITORY_NAME" \ - --enable-rebase-merge=false \ - --enable-merge-commit=false \ - --enable-squash-merge \ - --enable-auto-merge \ - --delete-branch-on-merge - -TEMP_PATH=$(mktemp -d) -git clone "$PRIMARY_REPO_URL" "$TEMP_PATH" - -cd "$TEMP_PATH" -git fetch --tags origin - -# Remove .github/ from the initial push so workflows don't fire during release setup. -git rm -r --quiet .github/ 2>/dev/null || true -git commit -m "chore: temporarily remove .github/ for clean clone" --allow-empty - -git remote remove origin -git remote add origin "$TEST_REPO_URL" -git push -u origin main -f || git push -u origin main -f - -# ── Phase 2: Copy tags and releases ───────────────────────────────────────── - -# Sort tags by their commit date (oldest first) so releases are created in order. -SORTED_TAGS=() -while IFS= read -r t; do - SORTED_TAGS+=("$t") -done < <(git tag --sort=creatordate) - -if [[ ${#SORTED_TAGS[@]} -eq 0 ]]; then - info "No tags found β€” skipping release copy." -else - # Copy all releases except the last one; the final release will be handled by workflows. - LAST_INDEX=$(( ${#SORTED_TAGS[@]} - 1 )) - - # Push all tags except the last one to the test repo before creating releases. - info "Pushing tags to $TEST_ORG/$REPOSITORY_NAME..." - for i in "${!SORTED_TAGS[@]}"; do - if [[ "$i" -lt "$LAST_INDEX" ]]; then - git push origin "refs/tags/${SORTED_TAGS[$i]}" - fi - done - - for i in "${!SORTED_TAGS[@]}"; do - tag="${SORTED_TAGS[$i]}" - TAG_COMMIT=$(git rev-list -n 1 "$tag") - - # Fetch the release title and body from the primary repo. - RELEASE_TITLE=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json name --jq '.name' 2>/dev/null || echo "$tag") - RELEASE_BODY=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json body --jq '.body' 2>/dev/null || echo "") - - if [[ "$i" -lt "$LAST_INDEX" ]]; then - info "Creating release $tag ($((i + 1))/${#SORTED_TAGS[@]})..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh release create "$tag" \ - --repo "$TEST_ORG/$REPOSITORY_NAME" \ - --target "$TAG_COMMIT" \ - --title "$RELEASE_TITLE" \ - --notes "$RELEASE_BODY" \ - --verify-tag - else - info "Skipping final release $tag β€” will be handled by workflows after .github/ is restored." - fi - done - - # Restore .github/ and force-push to main so workflows can create the final release. - info "Restoring .github/ folder..." - git checkout HEAD~1 -- .github/ - rm -fr .github/dependabot.yml # Remove dependabot config, will be overlaid by copier - git add .github/ - git commit -m "chore: restore .github/ for workflow-managed releases" - git push origin main -f || git push origin main -f -fi - -info "Test repository ready at $TEST_ORG/$REPOSITORY_NAME." - -# ── Phase 3: Copier conversion ────────────────────────────────────────────── - -# We already have the repo checked out in TEMP_PATH with origin pointing at the -# test org, so we can run copier directly without re-cloning. - -missing=() -[[ -d .git ]] || missing+=(".git/") -[[ -d examples ]] || missing+=("examples/") -[[ -d tests ]] || missing+=("tests/") -[[ -f main.tf ]] || missing+=("main.tf") - -if [[ ${#missing[@]} -gt 0 ]]; then - die "$REPOSITORY_NAME does not look like a Launch Terraform module. -Missing: ${missing[*]}" -fi - -info "Running copier copy (--trust --force) from $TEST_ORG/poc-skeleton..." -uv tool run copier copy --trust --force "gh:$TEST_ORG/poc-skeleton" . - -info "copier copy complete" - -BRANCH="feat!/copier-conversion" - -git checkout -b "$BRANCH" -git add -A -git commit -m "feat!: convert to copier-managed skeleton" -git push -u origin "$BRANCH" || git push -u origin "$BRANCH" - -info "Opening pull request..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh pr create \ - --repo "$TEST_ORG/$REPOSITORY_NAME" \ - --title "feat!: convert to copier-managed skeleton" \ - --body "Automated copier conversion via \`migrate.sh\`." \ - --base main \ - --head "$BRANCH" - -info "Pull request opened for branch $BRANCH." - -# ── Cleanup ────────────────────────────────────────────────────────────────── - -info "Cleaning up temp files..." -cd / -rm -rf "$TEMP_PATH" -info "Done!" From be5282bf15a9e746577aa2717049c9380560b6cd Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 14:24:35 -0500 Subject: [PATCH 40/44] fix: unstage scripts --- .../terragrunt-configure-mise/README.md | 2 +- .../reusable-pr-conventional-commit-title.yml | 4 +- .../reusable-terraform-check-aws.yml | 8 +- .../reusable-terraform-check-azure.yml | 8 +- .../workflows/reusable-terraform-check.yml | 12 +- .../reusable-terragrunt-deploy-aws.yml | 2 +- .../reusable-terragrunt-deploy-azure.yml | 2 +- ...usable-terragrunt-deploy-ephemeral-aws.yml | 2 +- .../workflows/reusable-terragrunt-deploy.yml | 10 +- ...sable-terragrunt-destroy-ephemeral-aws.yml | 2 +- .../reusable-terragrunt-plan-only-aws.yml | 2 +- .../reusable-terragrunt-plan-only-azure.yml | 2 +- .../reusable-terragrunt-plan-only.yml | 6 +- .../reusable-update-from-skeleton.yml | 2 +- scripts/clone_to_test_organization.sh | 106 ---------- scripts/copier_conversion.sh | 108 ---------- scripts/dependabot_config_audition.sh | 126 ------------ scripts/full_migration.sh | 24 --- scripts/migrate.sh | 188 ------------------ 19 files changed, 32 insertions(+), 584 deletions(-) delete mode 100755 scripts/clone_to_test_organization.sh delete mode 100755 scripts/copier_conversion.sh delete mode 100755 scripts/dependabot_config_audition.sh delete mode 100755 scripts/full_migration.sh delete mode 100755 scripts/migrate.sh diff --git a/.github/actions/terragrunt-configure-mise/README.md b/.github/actions/terragrunt-configure-mise/README.md index 72538d3..3ac935e 100644 --- a/.github/actions/terragrunt-configure-mise/README.md +++ b/.github/actions/terragrunt-configure-mise/README.md @@ -29,7 +29,7 @@ jobs: # Ensure mise.toml contains terraform and terragrunt at our desired versions - name: Configure Mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: '1.5.5' tg_version: '0.54.11' diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 7a0cfdf..8156e35 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -190,7 +190,7 @@ jobs: - id: set-status-check name: Set Status Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Conventional Commit PR Title" status: ${{ steps.pr-validation.outcome == 'success' && 'success' || @@ -202,7 +202,7 @@ jobs: - id: set-status-check-legacy name: Set Legacy Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Label Pull Request / Label Pull Request" status: ${{ steps.pr-validation.outcome == 'success' && 'success' || diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index b71727e..5bba4e5 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -66,7 +66,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: "pending" @@ -79,7 +79,7 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -109,7 +109,7 @@ jobs: find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: "pending" @@ -122,7 +122,7 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome diff --git a/.github/workflows/reusable-terraform-check-azure.yml b/.github/workflows/reusable-terraform-check-azure.yml index ecee790..0b74d17 100644 --- a/.github/workflows/reusable-terraform-check-azure.yml +++ b/.github/workflows/reusable-terraform-check-azure.yml @@ -62,7 +62,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: "pending" @@ -75,7 +75,7 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -90,7 +90,7 @@ jobs: subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: "pending" @@ -103,7 +103,7 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index bc5692f..0fa1c5d 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -182,7 +182,7 @@ jobs: - id: set-lint-pending name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: "pending" @@ -198,7 +198,7 @@ jobs: - id: update-lint-status name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -309,7 +309,7 @@ jobs: - id: set-tests-pending name: "Set Terraform Tests status to pending" continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: "pending" @@ -331,7 +331,7 @@ jobs: name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome @@ -351,7 +351,7 @@ jobs: - id: update-legacy-status-checks-aws name: "Add AWS Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-aws-') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Check AWS Terraform Code / Check AWS Terraform Code" status: "success" @@ -363,7 +363,7 @@ jobs: - id: update-legacy-status-checks-azure name: "Add Azure Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-az') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Check Azure Terraform Code / Check Azure Terraform Code" status: "success" diff --git a/.github/workflows/reusable-terragrunt-deploy-aws.yml b/.github/workflows/reusable-terragrunt-deploy-aws.yml index f97f7d6..1c257ea 100644 --- a/.github/workflows/reusable-terragrunt-deploy-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-aws.yml @@ -117,7 +117,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy-azure.yml b/.github/workflows/reusable-terragrunt-deploy-azure.yml index f5d880a..892c09f 100644 --- a/.github/workflows/reusable-terragrunt-deploy-azure.yml +++ b/.github/workflows/reusable-terragrunt-deploy-azure.yml @@ -110,7 +110,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml index 416b464..6192901 100644 --- a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml @@ -105,7 +105,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index 8c42af2..b9762b9 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -248,13 +248,13 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" @@ -293,7 +293,7 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome @@ -303,7 +303,7 @@ jobs: github.run_id }}" - name: "Set Terragrunt Deploy status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: "pending" @@ -342,7 +342,7 @@ jobs: - name: "Update Terragrunt Deploy status" if: always() && steps.deploy.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: ${{ steps.deploy.outcome == 'success' && 'success' || diff --git a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml index 5e03276..b50ffda 100644 --- a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml @@ -76,7 +76,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only-aws.yml b/.github/workflows/reusable-terragrunt-plan-only-aws.yml index ce47d86..6c8a56d 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-aws.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-aws.yml @@ -81,7 +81,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only-azure.yml b/.github/workflows/reusable-terragrunt-plan-only-azure.yml index 5843c1c..d2d1100 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-azure.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-azure.yml @@ -80,7 +80,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index 4cf914a..91baf22 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -211,13 +211,13 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" @@ -252,7 +252,7 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index 7a09525..7608ac7 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -58,7 +58,7 @@ jobs: - id: get-repo-custom-properties name: Get Repository Custom Properties - uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@0.15.0 + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@feat/unify-provider-auth - id: run-updates name: Run Updates from Skeleton diff --git a/scripts/clone_to_test_organization.sh b/scripts/clone_to_test_organization.sh deleted file mode 100755 index ffeb147..0000000 --- a/scripts/clone_to_test_organization.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash -# Clone the current repo to a test organization for testing in a clean environment. -# Usage: bash scripts/clone_to_test_organization.sh REPOSITORY_NAME - -# https://github.com/nttdtest/tf-azurerm-module_primitive-storage_account.git - -PRIMARY_ORG="launchbynttdata" -TEST_ORG="nttdtest" - -if [[ $# -ne 1 ]]; then - echo "Usage: $0 REPOSITORY_NAME" - exit 1 -fi - -REPOSITORY_NAME="$1" - -PRIMARY_REPO_URL="https://github.com/$PRIMARY_ORG/$REPOSITORY_NAME.git" -TEST_REPO_URL="https://github.com/$TEST_ORG/$REPOSITORY_NAME.git" - -echo "Cloning $PRIMARY_ORG/$REPOSITORY_NAME to $TEST_ORG/$REPOSITORY_NAME..." - -# Delete the test repo if it already exists, then create a fresh empty one. -if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$REPOSITORY_NAME" &>/dev/null; then - echo "Deleting existing repo $TEST_ORG/$REPOSITORY_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$REPOSITORY_NAME" --yes -fi - -echo "Creating fresh repo $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$REPOSITORY_NAME" --private - -echo "Configuring repo settings for $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$REPOSITORY_NAME" \ - --enable-rebase-merge=false \ - --enable-merge-commit=false \ - --enable-squash-merge \ - --enable-auto-merge \ - --delete-branch-on-merge - -TEMP_PATH=$(mktemp -d) -git clone "$PRIMARY_REPO_URL" "$TEMP_PATH" - -cd "$TEMP_PATH" -git fetch --tags origin - -# Remove .github/ from the initial push so workflows don't fire during release setup. -git rm -r --quiet .github/ 2>/dev/null || true -git commit -m "chore: temporarily remove .github/ for clean clone" --allow-empty - -git remote remove origin -git remote add origin "$TEST_REPO_URL" -git push -u origin main -f || git push -u origin main -f - -# Sort tags by their commit date (oldest first) so releases are created in order. -SORTED_TAGS=() -while IFS= read -r t; do - SORTED_TAGS+=("$t") -done < <(git tag --sort=creatordate) - -if [[ ${#SORTED_TAGS[@]} -eq 0 ]]; then - echo "No tags found β€” skipping release copy." -else - # Copy all releases except the last one; the final release will be handled by workflows. - LAST_INDEX=$(( ${#SORTED_TAGS[@]} - 1 )) - - # Push all tags except the last one to the test repo before creating releases. - echo "Pushing tags to $TEST_ORG/$REPOSITORY_NAME..." - for i in "${!SORTED_TAGS[@]}"; do - if [[ "$i" -lt "$LAST_INDEX" ]]; then - git push origin "refs/tags/${SORTED_TAGS[$i]}" - fi - done - - for i in "${!SORTED_TAGS[@]}"; do - tag="${SORTED_TAGS[$i]}" - TAG_COMMIT=$(git rev-list -n 1 "$tag") - - # Fetch the release title and body from the primary repo. - RELEASE_TITLE=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json name --jq '.name' 2>/dev/null || echo "$tag") - RELEASE_BODY=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json body --jq '.body' 2>/dev/null || echo "") - - if [[ "$i" -lt "$LAST_INDEX" ]]; then - echo "Creating release $tag (${i+1}/${#SORTED_TAGS[@]})..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh release create "$tag" \ - --repo "$TEST_ORG/$REPOSITORY_NAME" \ - --target "$TAG_COMMIT" \ - --title "$RELEASE_TITLE" \ - --notes "$RELEASE_BODY" \ - --verify-tag - else - echo "Skipping final release $tag β€” will be handled by workflows after .github/ is restored." - fi - done - - # Restore .github/ and force-push to main so workflows can create the final release. - echo "Restoring .github/ folder..." - git checkout HEAD~1 -- .github/ - rm -fr .github/dependabot.yml # Remove dependabot config, will be overlaid by copier - git add .github/ - git commit -m "chore: restore .github/ for workflow-managed releases" - git push origin main -f || git push origin main -f -fi - -echo "Repository cloned to $TEST_ORG/$REPOSITORY_NAME. Cleaning up local temp files..." -cd / -rm -rf "$TEMP_PATH" -echo "Done!" diff --git a/scripts/copier_conversion.sh b/scripts/copier_conversion.sh deleted file mode 100755 index 76ef27b..0000000 --- a/scripts/copier_conversion.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash -# Convert an existing Launch Terraform module repo to the copier-managed -# skeleton layout. -# -# Usage: -# bash scripts/copier_conversion.sh REPOSITORY_NAME - -set -euo pipefail - -ORG="nttdtest" - -info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } -warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } -error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } -die() { error "$@"; exit 1; } - -if [[ $# -ne 1 ]]; then - die "Usage: $0 REPOSITORY_NAME" -fi - -REPOSITORY_NAME="$1" -REPO_URL="https://github.com/$ORG/$REPOSITORY_NAME.git" - -if ! command -v uv &>/dev/null; then - die "uv is not installed. Install it with: - - curl -LsSf https://astral.sh/uv/install.sh | sh - -See the installation docs: https://docs.astral.sh/uv/getting-started/installation/" -fi - -info "uv found: $(uv --version)" - -if ! uv tool list 2>/dev/null | grep -q '^copier '; then - info "copier not found in uv tools β€” installing…" - uv tool install copier -fi - -info "copier is available" - -TEMP_PATH=$(mktemp -d) -info "Cloning $ORG/$REPOSITORY_NAME to $TEMP_PATH..." -git clone "$REPO_URL" "$TEMP_PATH" || git clone "$REPO_URL" "$TEMP_PATH" - -cd "$TEMP_PATH" - -missing=() -[[ -d .git ]] || missing+=(".git/") -[[ -d examples ]] || missing+=("examples/") -[[ -d tests ]] || missing+=("tests/") -[[ -f main.tf ]] || missing+=("main.tf") - -if [[ ${#missing[@]} -gt 0 ]]; then - die "$REPOSITORY_NAME does not look like a Launch Terraform module. -Missing: ${missing[*]}" -fi - -info "Running copier copy (--trust --force) from $ORG/poc-skeleton..." -uv tool run copier copy --trust --force gh:$ORG/poc-skeleton . - -info "copier copy complete" - -# info "Checking changed files for deletion-only diffs..." - -# # Get the list of modified (tracked) files that have a diff vs HEAD. -# # Untracked (new) files are additions-only by definition, so skip them. -# while IFS= read -r file; do -# [[ -z "$file" ]] && continue - -# additions=$(git diff HEAD -- "$file" | grep -c '^+[^+]' || true) -# deletions=$(git diff HEAD -- "$file" | grep -c '^-[^-]' || true) - -# if [[ "$deletions" -gt 0 && "$additions" -eq 0 ]]; then -# info "Restoring $file (deletion-only change)" -# git restore "$file" -# fi -# done < <(git diff --name-only HEAD) - -# info "Deletion-only files restored" - -BRANCH="feat!/copier-conversion" - -git checkout -b "$BRANCH" -git add -A -git commit -m "feat!: convert to copier-managed skeleton" -git push -u origin "$BRANCH" || git push -u origin "$BRANCH" # Retry once to kick secrets-helper over in case of an auth failure. - -if ! command -v gh &>/dev/null; then - warn "gh CLI not found β€” skipping pull request creation. Push complete." - exit 0 -fi - -info "Opening pull request..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh pr create \ - --repo "$ORG/$REPOSITORY_NAME" \ - --title "feat!: convert to copier-managed skeleton" \ - --body "Automated copier conversion via \`copier_conversion.sh\`." \ - --base main \ - --head "$BRANCH" - -info "Pull request opened for branch $BRANCH." - -info "Cleaning up temp files..." -cd / -rm -rf "$TEMP_PATH" -info "Done!" - - diff --git a/scripts/dependabot_config_audition.sh b/scripts/dependabot_config_audition.sh deleted file mode 100755 index 89c8ebd..0000000 --- a/scripts/dependabot_config_audition.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash -# Audition Dependabot configurations by creating a test-org copy of a source -# repo for each config file in dependabot-configs/. -# -# For every YAML file in dependabot-configs/ the script: -# 1. Creates a fresh private repo in the test organization. -# 2. Pushes the main branch of the source repo (without .github/). -# 3. Populates .github/dependabot.yml from the config file. -# 4. Sets the repo description to the test-case description (line 2 of the config). -# -# Usage: -# bash scripts/dependabot_config_audition.sh - -set -euo pipefail - -PRIMARY_ORG="launchbynttdata" -TEST_ORG="nttdtest" -SOURCE_REPOS=( - "tf-azurerm-module_primitive-dns_zone" - "tf-aws-module_primitive-iam_role" -) - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONFIGS_DIR="$SCRIPT_DIR/dependabot-configs" - -info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } -warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } -error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } -die() { error "$@"; exit 1; } - -# ── Prerequisites ─────────────────────────────────────────────────────────── - -if ! command -v gh &>/dev/null; then - die "gh CLI is not installed." -fi - -# Verify config directory has YAML files. -shopt -s nullglob -CONFIG_FILES=("$CONFIGS_DIR"/*.yaml "$CONFIGS_DIR"/*.yml) -shopt -u nullglob - -if [[ ${#CONFIG_FILES[@]} -eq 0 ]]; then - die "No YAML config files found in $CONFIGS_DIR" -fi - -info "Found ${#CONFIG_FILES[@]} config file(s) to audition across ${#SOURCE_REPOS[@]} source repo(s)." - -# ── Clone source repos once ───────────────────────────────────────────────── - -TEMP_PATH=$(mktemp -d) -for SOURCE_REPO in "${SOURCE_REPOS[@]}"; do - info "Cloning source repo $PRIMARY_ORG/$SOURCE_REPO..." - git clone "https://github.com/$PRIMARY_ORG/$SOURCE_REPO.git" "$TEMP_PATH/$SOURCE_REPO" -done - -# ── Process each source repo Γ— config combination ─────────────────────────── - -for SOURCE_REPO in "${SOURCE_REPOS[@]}"; do -for CONFIG_FILE in "${CONFIG_FILES[@]}"; do - CONFIG_NAME="$(basename "$CONFIG_FILE" .yaml)" - CONFIG_NAME="$(basename "$CONFIG_NAME" .yml)" - - TEST_REPO_NAME="${SOURCE_REPO}-dependabot-${CONFIG_NAME}" - TEST_REPO_URL="https://github.com/$TEST_ORG/$TEST_REPO_NAME.git" - - # Extract the description from the second line of the config file. - DESCRIPTION="$(sed -n '2p' "$CONFIG_FILE" | sed 's/^#\s*//')" - - info "──────────────────────────────────────────────────────────────" - info "Config: $(basename "$CONFIG_FILE") β†’ $TEST_ORG/$TEST_REPO_NAME" - info "Description: $DESCRIPTION" - - # ── Create test repo ──────────────────────────────────────────────────── - - if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$TEST_REPO_NAME" &>/dev/null; then - info "Deleting existing repo $TEST_ORG/$TEST_REPO_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$TEST_REPO_NAME" --yes - fi - - info "Creating fresh repo $TEST_ORG/$TEST_REPO_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$TEST_REPO_NAME" --private - - sleep 2 # Wait a moment for GitHub to be ready to accept pushes to the new repo. - - info "Configuring repo settings..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$TEST_REPO_NAME" \ - --description "$DESCRIPTION" \ - --enable-rebase-merge=false \ - --enable-merge-commit=false \ - --enable-squash-merge \ - --enable-auto-merge \ - --delete-branch-on-merge - - # ── Prepare and push main branch ─────────────────────────────────────── - - WORK_PATH=$(mktemp -d) - cp -a "$TEMP_PATH/$SOURCE_REPO" "$WORK_PATH/repo" - cd "$WORK_PATH/repo" - - # Wipe .github/ entirely. - git rm -r --quiet .github/ 2>/dev/null || true - - # Populate .github/dependabot.yml from the config file. - mkdir -p .github - cp "$CONFIG_FILE" .github/dependabot.yml - git add .github/dependabot.yml - - git commit -m "chore: set up dependabot audition ($CONFIG_NAME)" - - git remote remove origin - git remote add origin "https://x-access-token:${GITHUB_TOKEN_nttdtest}@github.com/$TEST_ORG/$TEST_REPO_NAME.git" - git push -u origin main -f || git push -u origin main -f - - info "Test repo ready: $TEST_ORG/$TEST_REPO_NAME" - - # ── Clean up working copy ────────────────────────────────────────────── - - cd / - rm -rf "$WORK_PATH" -done -done - -# ── Final cleanup ──────────────────────────────────────────────────────────── - -rm -rf "$TEMP_PATH" -info "All dependabot audition repos created. Done!" \ No newline at end of file diff --git a/scripts/full_migration.sh b/scripts/full_migration.sh deleted file mode 100755 index 7f36bc1..0000000 --- a/scripts/full_migration.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -./scripts/migrate.sh tf-aws-module_primitive-lambda_layer -./scripts/migrate.sh tf-aws-module_primitive-route53_record -./scripts/migrate.sh tf-aws-module_primitive-route53_zone -./scripts/migrate.sh tf-aws-module_primitive-sqs_queue -./scripts/migrate.sh tf-azurerm-module_primitive-container_registry -./scripts/migrate.sh tf-azurerm-module_primitive-dns_zone -# ./scripts/migrate.sh tf-azurerm-module_primitive-iothub -./scripts/migrate.sh tf-azurerm-module_primitive-key_vault -./scripts/migrate.sh tf-azurerm-module_primitive-route_table -./scripts/migrate.sh tf-azurerm-module_primitive-resource_group -./scripts/migrate.sh tf-azurerm-module_primitive-storage_account - - - -./scripts/migrate.sh tf-aws-module_primitive-route53_record -./scripts/migrate.sh tf-aws-module_primitive-route53_zone -./scripts/migrate.sh tf-aws-module_primitive-sqs_queue -./scripts/migrate.sh tf-azurerm-module_primitive-container_registry -./scripts/migrate.sh tf-azurerm-module_primitive-key_vault -./scripts/migrate.sh tf-azurerm-module_primitive-route_table -./scripts/migrate.sh tf-azurerm-module_primitive-resource_group -./scripts/migrate.sh tf-azurerm-module_primitive-storage_account \ No newline at end of file diff --git a/scripts/migrate.sh b/scripts/migrate.sh deleted file mode 100755 index 4c3fdd5..0000000 --- a/scripts/migrate.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env bash -# Migrate a Launch Terraform module repo to the copier-managed skeleton layout. -# -# This script consolidates clone_to_test_organization.sh and copier_conversion.sh -# into a single workflow: -# 1. Copies the repo to the test organization (deleting it if it exists). -# 2. Configures merge settings (squash-only, auto-merge, delete branch on merge). -# 3. Copies tags and releases (oldest-first), leaving the final release for workflows. -# 4. Restores .github/ (minus dependabot) and pushes main. -# 5. Runs copier conversion, pushes the branch, and opens a PR. -# -# Usage: -# bash scripts/migrate.sh REPOSITORY_NAME - -set -euo pipefail - -PRIMARY_ORG="launchbynttdata" -TEST_ORG="nttdtest" - -info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; } -warn() { printf '\033[1;33m[WARN]\033[0m %s\n' "$*"; } -error() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; } -die() { error "$@"; exit 1; } - -if [[ $# -ne 1 ]]; then - die "Usage: $0 REPOSITORY_NAME" -fi - -REPOSITORY_NAME="$1" -PRIMARY_REPO_URL="https://github.com/$PRIMARY_ORG/$REPOSITORY_NAME.git" -TEST_REPO_URL="https://x-access-token:${GITHUB_TOKEN_nttdtest}@github.com/$TEST_ORG/$REPOSITORY_NAME.git" - -# ── Prerequisites ─────────────────────────────────────────────────────────── - -if ! command -v gh &>/dev/null; then - die "gh CLI is not installed." -fi - -if ! command -v uv &>/dev/null; then - die "uv is not installed. Install it with: - - curl -LsSf https://astral.sh/uv/install.sh | sh - -See the installation docs: https://docs.astral.sh/uv/getting-started/installation/" -fi - -info "uv found: $(uv --version)" - -if ! uv tool list 2>/dev/null | grep -q '^copier '; then - info "copier not found in uv tools β€” installing…" - uv tool install copier -fi - -info "copier is available" - -# ── Phase 1: Clone to test organization ───────────────────────────────────── - -info "Cloning $PRIMARY_ORG/$REPOSITORY_NAME to $TEST_ORG/$REPOSITORY_NAME..." - -# Delete the test repo if it already exists, then create a fresh empty one. -if GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo view "$TEST_ORG/$REPOSITORY_NAME" &>/dev/null; then - info "Deleting existing repo $TEST_ORG/$REPOSITORY_NAME..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo delete "$TEST_ORG/$REPOSITORY_NAME" --yes -fi - -info "Creating fresh repo $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo create "$TEST_ORG/$REPOSITORY_NAME" --private - -info "Configuring repo settings for $TEST_ORG/$REPOSITORY_NAME..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh repo edit "$TEST_ORG/$REPOSITORY_NAME" \ - --enable-rebase-merge=false \ - --enable-merge-commit=false \ - --enable-squash-merge \ - --enable-auto-merge \ - --delete-branch-on-merge - -TEMP_PATH=$(mktemp -d) -git clone "$PRIMARY_REPO_URL" "$TEMP_PATH" - -cd "$TEMP_PATH" -git fetch --tags origin - -# Remove .github/ from the initial push so workflows don't fire during release setup. -git rm -r --quiet .github/ 2>/dev/null || true -git commit -m "chore: temporarily remove .github/ for clean clone" --allow-empty - -git remote remove origin -git remote add origin "$TEST_REPO_URL" -git push -u origin main -f || git push -u origin main -f - -# ── Phase 2: Copy tags and releases ───────────────────────────────────────── - -# Sort tags by their commit date (oldest first) so releases are created in order. -SORTED_TAGS=() -while IFS= read -r t; do - SORTED_TAGS+=("$t") -done < <(git tag --sort=creatordate) - -if [[ ${#SORTED_TAGS[@]} -eq 0 ]]; then - info "No tags found β€” skipping release copy." -else - # Copy all releases except the last one; the final release will be handled by workflows. - LAST_INDEX=$(( ${#SORTED_TAGS[@]} - 1 )) - - # Push all tags except the last one to the test repo before creating releases. - info "Pushing tags to $TEST_ORG/$REPOSITORY_NAME..." - for i in "${!SORTED_TAGS[@]}"; do - if [[ "$i" -lt "$LAST_INDEX" ]]; then - git push origin "refs/tags/${SORTED_TAGS[$i]}" - fi - done - - for i in "${!SORTED_TAGS[@]}"; do - tag="${SORTED_TAGS[$i]}" - TAG_COMMIT=$(git rev-list -n 1 "$tag") - - # Fetch the release title and body from the primary repo. - RELEASE_TITLE=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json name --jq '.name' 2>/dev/null || echo "$tag") - RELEASE_BODY=$(gh release view "$tag" --repo "$PRIMARY_ORG/$REPOSITORY_NAME" --json body --jq '.body' 2>/dev/null || echo "") - - if [[ "$i" -lt "$LAST_INDEX" ]]; then - info "Creating release $tag ($((i + 1))/${#SORTED_TAGS[@]})..." - GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh release create "$tag" \ - --repo "$TEST_ORG/$REPOSITORY_NAME" \ - --target "$TAG_COMMIT" \ - --title "$RELEASE_TITLE" \ - --notes "$RELEASE_BODY" \ - --verify-tag - else - info "Skipping final release $tag β€” will be handled by workflows after .github/ is restored." - fi - done - - # Restore .github/ and force-push to main so workflows can create the final release. - info "Restoring .github/ folder..." - git checkout HEAD~1 -- .github/ - rm -fr .github/dependabot.yml # Remove dependabot config, will be overlaid by copier - git add .github/ - git commit -m "chore: restore .github/ for workflow-managed releases" - git push origin main -f || git push origin main -f -fi - -info "Test repository ready at $TEST_ORG/$REPOSITORY_NAME." - -# ── Phase 3: Copier conversion ────────────────────────────────────────────── - -# We already have the repo checked out in TEMP_PATH with origin pointing at the -# test org, so we can run copier directly without re-cloning. - -missing=() -[[ -d .git ]] || missing+=(".git/") -[[ -d examples ]] || missing+=("examples/") -[[ -d tests ]] || missing+=("tests/") -[[ -f main.tf ]] || missing+=("main.tf") - -if [[ ${#missing[@]} -gt 0 ]]; then - die "$REPOSITORY_NAME does not look like a Launch Terraform module. -Missing: ${missing[*]}" -fi - -info "Running copier copy (--trust --force) from $TEST_ORG/poc-skeleton..." -uv tool run copier copy --trust --force "gh:$TEST_ORG/poc-skeleton" . - -info "copier copy complete" - -BRANCH="feat!/copier-conversion" - -git checkout -b "$BRANCH" -git add -A -git commit -m "feat!: convert to copier-managed skeleton" -git push -u origin "$BRANCH" || git push -u origin "$BRANCH" - -info "Opening pull request..." -GITHUB_TOKEN=$GITHUB_TOKEN_nttdtest gh pr create \ - --repo "$TEST_ORG/$REPOSITORY_NAME" \ - --title "feat!: convert to copier-managed skeleton" \ - --body "Automated copier conversion via \`migrate.sh\`." \ - --base main \ - --head "$BRANCH" - -info "Pull request opened for branch $BRANCH." - -# ── Cleanup ────────────────────────────────────────────────────────────────── - -info "Cleaning up temp files..." -cd / -rm -rf "$TEMP_PATH" -info "Done!" From 2a322c6c38db784bdd59850132b4f7c7c7625372 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Thu, 26 Mar 2026 10:36:45 -0500 Subject: [PATCH 41/44] feat: action to retrieve repo custom properties --- .../actions/get-custom-properties/README.md | 92 +++++++++++++++++++ .../actions/get-custom-properties/action.yml | 61 ++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 .github/actions/get-custom-properties/README.md create mode 100644 .github/actions/get-custom-properties/action.yml diff --git a/.github/actions/get-custom-properties/README.md b/.github/actions/get-custom-properties/README.md new file mode 100644 index 0000000..e4369eb --- /dev/null +++ b/.github/actions/get-custom-properties/README.md @@ -0,0 +1,92 @@ +# Get Custom Properties Action + +This action retrieves custom properties from a GitHub repository using the GitHub API. Custom properties are organization-defined metadata that can be applied to repositories for classification, automation, and policy enforcement. + +## Behavior + +This action will: +1. Call the GitHub API to retrieve all custom properties applied to the specified repository +2. Return the properties as a JSON object that can be used in subsequent workflow steps + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `owner` | The owner (organization or user) of the repository | No | `${{ github.repository_owner }}` | +| `repo` | The name of the repository | No | `${{ github.event.repository.name }}` | +| `github_token` | GitHub token for API access | No | `${{ github.token }}` | + +## Outputs + +| Output | Description | +|--------|-------------| +| `properties` | JSON object containing all custom properties applied to the repository | + +## Usage + +### Basic Usage + +When used in a workflow, all inputs are optional. The action defaults to the current repository and automatic GITHUB_TOKEN: + +```yaml +jobs: + your-job: + runs-on: ubuntu-latest + steps: + - name: Get Custom Properties + id: props + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@main + + - name: Use Properties + run: | + echo "Properties: ${{ steps.props.outputs.properties }}" +``` + +### Query a Different Repository + +To retrieve properties from a different repository: + +```yaml +- name: Get Custom Properties + id: props + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@main + with: + owner: "my-org" + repo: "my-repo" +``` + +### Parse Properties in Workflow + +You can use `jq` to parse specific properties from the output: + +```yaml +- name: Get Custom Properties + id: props + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@main + +- name: Check Environment Property + run: | + ENVIRONMENT=$(echo '${{ steps.props.outputs.properties }}' | jq -r '.[] | select(.property_name == "environment") | .value') + echo "Environment: $ENVIRONMENT" +``` + +## Required Permissions + +The default `GITHUB_TOKEN` has sufficient permissions to read custom properties for the repository where the workflow runs. When querying a different repository, the token needs "Metadata" repository permission (read). + +## Response Format + +The API returns an array of property objects: + +```json +[ + { + "property_name": "environment", + "value": "production" + }, + { + "property_name": "team", + "value": "platform" + } +] +``` diff --git a/.github/actions/get-custom-properties/action.yml b/.github/actions/get-custom-properties/action.yml new file mode 100644 index 0000000..493bc1d --- /dev/null +++ b/.github/actions/get-custom-properties/action.yml @@ -0,0 +1,61 @@ +name: "Get Custom Properties" +description: "Retrieve custom properties from a GitHub repository" +inputs: + owner: + description: "The owner (organization or user) of the repository. Defaults to the current repository owner." + required: false + default: ${{ github.repository_owner }} + repo: + description: "The name of the repository. Defaults to the current repository name." + required: false + default: ${{ github.event.repository.name }} + github_token: + description: "GitHub token for API access. Defaults to the automatic GITHUB_TOKEN." + required: false + default: ${{ github.token }} +outputs: + properties: + description: "JSON object containing all custom properties applied to the repository" + value: ${{ steps.get-properties.outputs.properties }} +runs: + using: "composite" + steps: + - name: Get Custom Properties + id: get-properties + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + OWNER: ${{ inputs.owner }} + REPO: ${{ inputs.repo }} + run: | + if [[ -z "$OWNER" ]]; then + echo "Error: Repository owner not provided and not available in the event context." + exit 1 + fi + + if [[ -z "$REPO" ]]; then + echo "Error: Repository name not provided and not available in the event context." + exit 1 + fi + + echo "Fetching custom properties for ${OWNER}/${REPO}..." + + RESPONSE=$(curl -sL \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "X-GitHub-Api-Version: 2026-03-10" \ + "https://api.github.com/repos/${OWNER}/${REPO}/properties/values") + + # Check for API errors + if echo "$RESPONSE" | jq -e '.message' > /dev/null 2>&1; then + ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message') + echo "Error from GitHub API: $ERROR_MSG" + exit 1 + fi + + # Output the properties as JSON + echo "properties<> $GITHUB_OUTPUT + echo "$RESPONSE" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + echo "Successfully retrieved custom properties for ${OWNER}/${REPO}" From 28bd78708e33724e91083ce1f1805b51d98c940a Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Tue, 28 Apr 2026 16:55:58 -0500 Subject: [PATCH 42/44] fix: normalize tag references in actions docs --- .github/actions/get-custom-properties/README.md | 8 ++++---- .github/actions/remove-dependabot-labels/README.md | 8 ++++---- .github/actions/terragrunt-configure-mise/README.md | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/actions/get-custom-properties/README.md b/.github/actions/get-custom-properties/README.md index e4369eb..1aff8eb 100644 --- a/.github/actions/get-custom-properties/README.md +++ b/.github/actions/get-custom-properties/README.md @@ -26,7 +26,7 @@ This action will: ### Basic Usage -When used in a workflow, all inputs are optional. The action defaults to the current repository and automatic GITHUB_TOKEN: +When used in a workflow, all inputs are optional. The action defaults to the current repository and automatic GITHUB_TOKEN (replacing `ref` with a tag or commit SHA from this repository): ```yaml jobs: @@ -35,7 +35,7 @@ jobs: steps: - name: Get Custom Properties id: props - uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@main + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@ref - name: Use Properties run: | @@ -49,7 +49,7 @@ To retrieve properties from a different repository: ```yaml - name: Get Custom Properties id: props - uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@main + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@ref with: owner: "my-org" repo: "my-repo" @@ -62,7 +62,7 @@ You can use `jq` to parse specific properties from the output: ```yaml - name: Get Custom Properties id: props - uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@main + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@ref - name: Check Environment Property run: | diff --git a/.github/actions/remove-dependabot-labels/README.md b/.github/actions/remove-dependabot-labels/README.md index 70291af..27d332e 100644 --- a/.github/actions/remove-dependabot-labels/README.md +++ b/.github/actions/remove-dependabot-labels/README.md @@ -23,7 +23,7 @@ This action will: ### Basic Usage -When used in a `pull_request` event workflow, all inputs are optional: +When used in a `pull_request` event workflow, all inputs are optional (replacing `ref` with a tag or commit SHA from this repository): ```yaml jobs: @@ -36,7 +36,7 @@ jobs: - uses: actions/checkout@v4 - name: Remove Dependabot Labels - uses: launchbynttdata/launch-workflows/.github/actions/remove-dependabot-labels@main + uses: launchbynttdata/launch-workflows/.github/actions/remove-dependabot-labels@ref ``` ### Preserve Additional Labels @@ -45,7 +45,7 @@ To preserve additional Dependabot labels beyond `dependencies`: ```yaml - name: Remove Dependabot Labels - uses: launchbynttdata/launch-workflows/.github/actions/remove-dependabot-labels@main + uses: launchbynttdata/launch-workflows/.github/actions/remove-dependabot-labels@ref with: preserve_labels: "dependencies,security" ``` @@ -56,7 +56,7 @@ If running outside a `pull_request` event context, provide the PR number explici ```yaml - name: Remove Dependabot Labels - uses: launchbynttdata/launch-workflows/.github/actions/remove-dependabot-labels@main + uses: launchbynttdata/launch-workflows/.github/actions/remove-dependabot-labels@ref with: pr_number: "123" ``` diff --git a/.github/actions/terragrunt-configure-mise/README.md b/.github/actions/terragrunt-configure-mise/README.md index 3ac935e..f5e72dd 100644 --- a/.github/actions/terragrunt-configure-mise/README.md +++ b/.github/actions/terragrunt-configure-mise/README.md @@ -18,6 +18,8 @@ The configured `mise.toml` file will then be used by subsequent `gruntwork-io/te ## Usage +Replace `ref` with a tag or commit SHA from this repository: + ```yaml jobs: @@ -29,7 +31,7 @@ jobs: # Ensure mise.toml contains terraform and terragrunt at our desired versions - name: Configure Mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@ref with: tf_version: '1.5.5' tg_version: '0.54.11' From 81ca00c3d9a96e887752904be9ec697cbf779308 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Wed, 29 Apr 2026 13:35:33 -0500 Subject: [PATCH 43/44] fix: address feedback from PR review --- .../reusable-pr-automated-approvals.yml | 52 +++++++++++-------- .../reusable-pr-conventional-commit-title.yml | 46 ++++++++++------ .../reusable-pr-dependabot-automerge.yml | 3 +- .../workflows/reusable-pr-label-by-branch.yml | 8 +-- .../workflows/reusable-terraform-check.yml | 1 + .../workflows/reusable-terragrunt-deploy.yml | 29 ++++++++--- .../reusable-terragrunt-plan-only.yml | 29 ++++++++--- .../reusable-update-from-skeleton.yml | 47 +++++++++++------ 8 files changed, 145 insertions(+), 70 deletions(-) diff --git a/.github/workflows/reusable-pr-automated-approvals.yml b/.github/workflows/reusable-pr-automated-approvals.yml index 7dfbbca..67bd7ea 100644 --- a/.github/workflows/reusable-pr-automated-approvals.yml +++ b/.github/workflows/reusable-pr-automated-approvals.yml @@ -79,11 +79,17 @@ jobs: steps: - name: Check Pull Request id: check-pull-request + env: + GH_TOKEN: ${{ github.token }} + GITHUB_ACTOR: ${{ github.actor }} + PR_TITLE: ${{ github.event.pull_request.title }} + PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | ALLOWED_AUTHORS="dependabot[bot] launch-skeleton-auto-updater[bot]" # Get all commit authors on this PR - AUTHORS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits" \ + AUTHORS=$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/commits" \ --jq '.[].author.login' | sort -u) echo "Commit authors on this PR:" @@ -98,8 +104,7 @@ jobs: fi done - if [ "$SHOULD_APPROVE" == "true" ] && [ "${{ github.actor }}" == "launch-skeleton-auto-updater[bot]" ]; then - PR_TITLE="${{ github.event.pull_request.title }}" + if [ "$SHOULD_APPROVE" == "true" ] && [ "$GITHUB_ACTOR" == "launch-skeleton-auto-updater[bot]" ]; then if [[ "$PR_TITLE" != chore* ]]; then echo "Skeleton updater PR title does not start with 'chore': $PR_TITLE" SHOULD_APPROVE=false @@ -107,8 +112,6 @@ jobs: fi echo "should_approve=$SHOULD_APPROVE" >> "$GITHUB_OUTPUT" - env: - GH_TOKEN: ${{ github.token }} - name: Get Approver Alpha Token id: approver-alpha-token @@ -126,34 +129,41 @@ jobs: - name: Approve PR if: steps.check-pull-request.outputs.should_approve == 'true' + env: + APPROVER_ALPHA_TOKEN: ${{ steps.approver-alpha-token.outputs.token }} + APPROVER_BRAVO_TOKEN: ${{ steps.approver-bravo-token.outputs.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | echo "All commits are from automated users. Approving PR..." - GH_TOKEN="${{ steps.approver-alpha-token.outputs.token }}" \ - gh pr review "${{ github.event.pull_request.number }}" \ - --repo "${{ github.repository }}" \ + GH_TOKEN="$APPROVER_ALPHA_TOKEN" \ + gh pr review "$PR_NUMBER" \ + --repo "$GITHUB_REPOSITORY" \ --approve \ --body "Automated approval: all commits from trusted automation accounts." - GH_TOKEN="${{ steps.approver-bravo-token.outputs.token }}" \ - gh pr review "${{ github.event.pull_request.number }}" \ - --repo "${{ github.repository }}" \ + GH_TOKEN="$APPROVER_BRAVO_TOKEN" \ + gh pr review "$PR_NUMBER" \ + --repo "$GITHUB_REPOSITORY" \ --approve \ --body "Automated approval: all commits from trusted automation accounts." - name: Revoke Approvals if: steps.check-pull-request.outputs.should_approve == 'false' + env: + GH_TOKEN: ${{ github.token }} + ALPHA_SLUG: ${{ steps.approver-alpha-token.outputs.app-slug }} + BRAVO_SLUG: ${{ steps.approver-bravo-token.outputs.app-slug }} + ALPHA_TOKEN: ${{ steps.approver-alpha-token.outputs.token }} + BRAVO_TOKEN: ${{ steps.approver-bravo-token.outputs.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | echo "Non-automated commits detected. Revoking any existing automated approvals..." - # Get approver app slugs - ALPHA_SLUG="${{ steps.approver-alpha-token.outputs.app-slug }}" - BRAVO_SLUG="${{ steps.approver-bravo-token.outputs.app-slug }}" - ALPHA_TOKEN="${{ steps.approver-alpha-token.outputs.token }}" - BRAVO_TOKEN="${{ steps.approver-bravo-token.outputs.token }}" - # Get all reviews on this PR - REVIEWS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews") + REVIEWS=$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews") # Dismiss Alpha's approval if present ALPHA_REVIEW_ID=$(echo "$REVIEWS" | jq -r ".[] | select(.user.login == \"${ALPHA_SLUG}[bot]\" and .state == \"APPROVED\") | .id" | head -1) @@ -161,7 +171,7 @@ jobs: echo "Dismissing review $ALPHA_REVIEW_ID from ${ALPHA_SLUG}[bot]" GH_TOKEN="$ALPHA_TOKEN" gh api \ --method PUT \ - "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews/$ALPHA_REVIEW_ID/dismissals" \ + "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews/$ALPHA_REVIEW_ID/dismissals" \ -f message="Automated approval revoked: non-automated commits detected on this PR." fi @@ -171,8 +181,6 @@ jobs: echo "Dismissing review $BRAVO_REVIEW_ID from ${BRAVO_SLUG}[bot]" GH_TOKEN="$BRAVO_TOKEN" gh api \ --method PUT \ - "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews/$BRAVO_REVIEW_ID/dismissals" \ + "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews/$BRAVO_REVIEW_ID/dismissals" \ -f message="Automated approval revoked: non-automated commits detected on this PR." fi - env: - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 8156e35..07cd67b 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -126,8 +126,10 @@ jobs: (github.event.action == 'edited' && github.event.changes.title)) }} env: GH_TOKEN: ${{ github.token }} + GITHUB_REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: | - echo '{"labels":[]}' | gh api -X PUT repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels --input - + echo '{"labels":[]}' | gh api -X PUT "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --input - - name: PR Conventional Commit Validation id: pr-validation @@ -144,19 +146,31 @@ jobs: - name: Create failure comment based on inputs id: create-failure-comment if: ${{ failure() && inputs.comment_on_failure }} + env: + PR_TITLE: ${{ github.event.pull_request.title }} + TASK_TYPES: ${{ inputs.task_types }} + SCOPE_TYPES: ${{ inputs.scope_types }} + TITLE_REGEX: ${{ inputs.title_regex }} run: | - cat << EOC >> pr-title-failure-comment.md - ### ❌ Pull Request Title Validation Failed - Your pull request title (\`${{ github.event.pull_request.title }}\`) does not conform to the Conventional Commits specification. - - Please ensure your title follows the format: \`(): \`. - - **Type** must be one of the following: ${{ inputs.task_types }} - ${{ inputs.scope_types && format('- **Scope** must be one of the following: {0}', inputs.scope_types) || '- **Scope** is optional and can be any value or omitted entirely.' }} - - **Description** should be a brief summary of the changes. - - If you have a breaking change, ensure the exclamation mark (\`!\`) is placed immediately after the type or scope, e.g., \`feat!: ...\` or \`feat(scope)!: ...\`. - ${{ inputs.title_regex && format('- Additionally, your description must match the custom regex: `{0}`.\n', inputs.title_regex) || '' }} - If you have any questions, please refer to the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) documentation for more details. - EOC + { + echo "### ❌ Pull Request Title Validation Failed" + echo "Your pull request title (\`${PR_TITLE}\`) does not conform to the Conventional Commits specification." + echo "" + echo "Please ensure your title follows the format: \`(): \`." + echo "- **Type** must be one of the following: ${TASK_TYPES}" + if [[ -n "$SCOPE_TYPES" ]]; then + echo "- **Scope** must be one of the following: ${SCOPE_TYPES}" + else + echo "- **Scope** is optional and can be any value or omitted entirely." + fi + echo "- **Description** should be a brief summary of the changes." + echo "- If you have a breaking change, ensure the exclamation mark (\`!\`) is placed immediately after the type or scope, e.g., \`feat!: ...\` or \`feat(scope)!: ...\`." + if [[ -n "$TITLE_REGEX" ]]; then + echo "- Additionally, your description must match the custom regex: \`${TITLE_REGEX}\`." + echo "" + fi + echo "If you have any questions, please refer to the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) documentation for more details." + } >> pr-title-failure-comment.md - name: Find previous failure comment id: find-comment @@ -182,9 +196,11 @@ jobs: inputs.comment_on_failure }} env: GH_TOKEN: ${{ github.token }} + COMMENT_ID: ${{ steps.find-comment.outputs.comment-id }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | - if [ "${{ steps.find-comment.outputs.comment-id }}" != "" ]; then - gh api -X DELETE repos/${{ github.repository }}/issues/comments/${{ steps.find-comment.outputs.comment-id }} --silent + if [ -n "$COMMENT_ID" ]; then + gh api -X DELETE "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}" --silent fi - id: set-status-check diff --git a/.github/workflows/reusable-pr-dependabot-automerge.yml b/.github/workflows/reusable-pr-dependabot-automerge.yml index 1d546a1..7500368 100644 --- a/.github/workflows/reusable-pr-dependabot-automerge.yml +++ b/.github/workflows/reusable-pr-dependabot-automerge.yml @@ -21,6 +21,7 @@ jobs: if: ${{ github.actor == 'dependabot[bot]' }} steps: - name: Enable auto-merge - run: gh pr merge --auto --squash "${{ github.event.pull_request.html_url }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: gh pr merge --auto --squash "$PR_URL" diff --git a/.github/workflows/reusable-pr-label-by-branch.yml b/.github/workflows/reusable-pr-label-by-branch.yml index 4d544ff..14e46df 100644 --- a/.github/workflows/reusable-pr-label-by-branch.yml +++ b/.github/workflows/reusable-pr-label-by-branch.yml @@ -46,22 +46,24 @@ jobs: id: prerequisite-check env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BASE_REF: ${{ github.event.pull_request.base.ref }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} run: | cat < first-time-comment.md > [!TIP] > This is your first PR, and it will be labeled as a \`major\` release. - > + > > If you need to change this because you have existing tags, manually remove the label and apply the appropriate one (\`patch\`, \`minor\`). EOC PR_NUMBER=$(echo "${GITHUB_REF}" | cut -d'/' -f3) - if git diff --name-only HEAD origin/${{ github.event.pull_request.base.ref }} | grep -q "^\.github/release-drafter\.yml$"; then + if git diff --name-only HEAD "origin/${BASE_REF}" | grep -q "^\.github/release-drafter\.yml$"; then echo "updates_configuration=true" >> $GITHUB_OUTPUT else echo "updates_configuration=false" >> $GITHUB_OUTPUT fi if [[ $PR_NUMBER -eq "1" ]]; then - if git cat-file -e origin/${{ github.event.repository.default_branch }}:.github/release-drafter.yml 2>/dev/null; then + if git cat-file -e "origin/${DEFAULT_BRANCH}:.github/release-drafter.yml" 2>/dev/null; then # First PR, but we have a release-drafter.yml file on the main branch so we can let it proceed as normal. echo "auto_label=true" >> $GITHUB_OUTPUT else diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 0fa1c5d..4d49634 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -281,6 +281,7 @@ jobs: run: | set -x mkdir -p ~/.aws + install -m 600 /dev/null ~/.aws/credentials echo "[default]" > ~/.aws/credentials echo "aws_access_key_id=$AWS_ACCESS_KEY_ID" >> ~/.aws/credentials echo "aws_secret_access_key=$AWS_SECRET_ACCESS_KEY" >> ~/.aws/credentials diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index b9762b9..a9c15d1 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -222,20 +222,37 @@ jobs: - name: "Set default Terraform Tags (AWS)" if: needs.validate-inputs.outputs.auth_aws == 'true' id: set-tags-aws + env: + GIT_BRANCH: ${{ inputs.git_branch }} + REPO_OWNER: ${{ github.repository_owner }} + REPOSITORY: ${{ github.repository }} + COMMIT_SHA: ${{ github.sha }} run: | set -x - echo "TF_VAR_organization_tag=${{ github.repository_owner }}" >> "$GITHUB_OUTPUT" - echo "TF_VAR_repository_tag=$(echo "${{ github.repository }}" | cut -d "/" -f 2)" >> "$GITHUB_OUTPUT" - echo "TF_VAR_commit_hash_tag=${{ github.sha }}" >> "$GITHUB_OUTPUT" - echo "TF_VAR_branch_tag=${{ inputs.git_branch }}" >> "$GITHUB_OUTPUT" + repo=$(echo "$REPOSITORY" | cut -d "/" -f 2) + echo "TF_VAR_organization_tag=$REPO_OWNER" >> "$GITHUB_OUTPUT" + echo "TF_VAR_repository_tag=$repo" >> "$GITHUB_OUTPUT" + echo "TF_VAR_commit_hash_tag=$COMMIT_SHA" >> "$GITHUB_OUTPUT" + echo "TF_VAR_branch_tag=$GIT_BRANCH" >> "$GITHUB_OUTPUT" - name: "Set default Terraform Tags (Azure)" if: needs.validate-inputs.outputs.auth_azure == 'true' id: set-tags-azure + env: + GIT_BRANCH: ${{ inputs.git_branch }} + REPO_OWNER: ${{ github.repository_owner }} + REPOSITORY: ${{ github.repository }} + COMMIT_SHA: ${{ github.sha }} run: | set -x - repo=$(echo "${{ github.repository }}" | cut -d "/" -f 2) - echo "SYSTEM_TAGS={\"Organization\":\"${{ github.repository_owner }}\",\"Repository\":\"$repo\",\"Branch\":\"${{ inputs.git_branch }}\",\"CommitHash\":\"${{ github.sha }}\"}" >> "$GITHUB_OUTPUT" + repo=$(echo "$REPOSITORY" | cut -d "/" -f 2) + SYSTEM_TAGS=$(jq -nc \ + --arg org "$REPO_OWNER" \ + --arg repo "$repo" \ + --arg branch "$GIT_BRANCH" \ + --arg sha "$COMMIT_SHA" \ + '{"Organization":$org,"Repository":$repo,"Branch":$branch,"CommitHash":$sha}') + echo "SYSTEM_TAGS=$SYSTEM_TAGS" >> "$GITHUB_OUTPUT" - name: Create GitHub App Token id: github-app-token diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index 91baf22..438b35c 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -185,20 +185,37 @@ jobs: - name: "Set default Terraform Tags (AWS)" if: needs.validate-inputs.outputs.auth_aws == 'true' id: set-tags-aws + env: + GIT_BRANCH: ${{ inputs.git_branch }} + REPO_OWNER: ${{ github.repository_owner }} + REPOSITORY: ${{ github.repository }} + COMMIT_SHA: ${{ github.sha }} run: | set -x - echo "TF_VAR_organization_tag=${{ github.repository_owner }}" >> "$GITHUB_OUTPUT" - echo "TF_VAR_repository_tag=$(echo "${{ github.repository }}" | cut -d "/" -f 2)" >> "$GITHUB_OUTPUT" - echo "TF_VAR_commit_hash_tag=${{ github.sha }}" >> "$GITHUB_OUTPUT" - echo "TF_VAR_branch_tag=${{ inputs.git_branch }}" >> "$GITHUB_OUTPUT" + repo=$(echo "$REPOSITORY" | cut -d "/" -f 2) + echo "TF_VAR_organization_tag=$REPO_OWNER" >> "$GITHUB_OUTPUT" + echo "TF_VAR_repository_tag=$repo" >> "$GITHUB_OUTPUT" + echo "TF_VAR_commit_hash_tag=$COMMIT_SHA" >> "$GITHUB_OUTPUT" + echo "TF_VAR_branch_tag=$GIT_BRANCH" >> "$GITHUB_OUTPUT" - name: "Set default Terraform Tags (Azure)" if: needs.validate-inputs.outputs.auth_azure == 'true' id: set-tags-azure + env: + GIT_BRANCH: ${{ inputs.git_branch }} + REPO_OWNER: ${{ github.repository_owner }} + REPOSITORY: ${{ github.repository }} + COMMIT_SHA: ${{ github.sha }} run: | set -x - repo=$(echo "${{ github.repository }}" | cut -d "/" -f 2) - echo "SYSTEM_TAGS={\"Organization\":\"${{ github.repository_owner }}\",\"Repository\":\"$repo\",\"Branch\":\"${{ inputs.git_branch }}\",\"CommitHash\":\"${{ github.sha }}\"}" >> "$GITHUB_OUTPUT" + repo=$(echo "$REPOSITORY" | cut -d "/" -f 2) + SYSTEM_TAGS=$(jq -nc \ + --arg org "$REPO_OWNER" \ + --arg repo "$repo" \ + --arg branch "$GIT_BRANCH" \ + --arg sha "$COMMIT_SHA" \ + '{"Organization":$org,"Repository":$repo,"Branch":$branch,"CommitHash":$sha}') + echo "SYSTEM_TAGS=$SYSTEM_TAGS" >> "$GITHUB_OUTPUT" - name: Create GitHub App Token id: github-app-token diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index 7608ac7..d62d5ef 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -62,12 +62,15 @@ jobs: - id: run-updates name: Run Updates from Skeleton + env: + RECOPY: ${{ inputs.recopy }} + CUSTOM_PROPERTIES: ${{ steps.get-repo-custom-properties.outputs.properties }} run: | - PRERELEASE=$(echo '${{ steps.get-repo-custom-properties.outputs.properties }}' | jq -r '.[] | select(.property_name == "prerelease") | .value') + PRERELEASE=$(echo "$CUSTOM_PROPERTIES" | jq -r '.[] | select(.property_name == "prerelease") | .value') COPIER_CMD="update" COPIER_FLAGS="--defaults --trust" - if [ "${{ inputs.recopy }}" == "true" ]; then + if [ "$RECOPY" == "true" ]; then COPIER_CMD="recopy" COPIER_FLAGS="$COPIER_FLAGS --overwrite" fi @@ -136,31 +139,40 @@ jobs: - name: Commit and Push Changes id: commit-and-push if: steps.run-updates.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ steps.get-app-token.outputs.token }} + APP_SLUG: ${{ steps.get-app-token.outputs.app-slug }} + PRE_COMMIT_PASSED: ${{ steps.run-updates.outputs.pre_commit_passed }} + RECOPY: ${{ inputs.recopy }} run: | - USER_ID=$(gh api "/users/${{ steps.get-app-token.outputs.app-slug }}[bot]" --jq .id) + USER_ID=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) - git config --global user.name '${{ steps.get-app-token.outputs.app-slug }}[bot]' - git config --global user.email "$USER_ID+${{ steps.get-app-token.outputs.app-slug }}[bot]@users.noreply.github.com" + git config --global user.name "${APP_SLUG}[bot]" + git config --global user.email "${USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com" BRANCH_NAME="patch/skeleton-update-$(date +%Y%m%d-%H%M%S)" echo "branch_name=$BRANCH_NAME" >> "$GITHUB_OUTPUT" git checkout -b "$BRANCH_NAME" + + # Files coming from a release in the template repo are assumed to be trusted, + # as they've been through the PR review process in that repository. git add . - if [ "${{ steps.run-updates.outputs.pre_commit_passed }}" == "true" ] && [ "${{ inputs.recopy }}" != "true" ]; then + if [ "$PRE_COMMIT_PASSED" == "true" ] && [ "$RECOPY" != "true" ]; then git commit -m "chore: update from skeleton" else git commit -m "fix: update from skeleton" fi git push origin "$BRANCH_NAME" - env: - GH_TOKEN: ${{ steps.get-app-token.outputs.token }} - name: Create Pull Request if: steps.run-updates.outputs.has_changes == 'true' && steps.run-updates.outputs.pre_commit_passed == 'true' && inputs.recopy != true + env: + GH_TOKEN: ${{ steps.get-app-token.outputs.token }} + BRANCH_NAME: ${{ steps.commit-and-push.outputs.branch_name }} run: | PR_BODY=$(cat <<-'EOF' Automated update from skeleton template. @@ -170,24 +182,27 @@ jobs: ) PR_URL=$(gh pr create \ --base main \ - --head "${{ steps.commit-and-push.outputs.branch_name }}" \ + --head "$BRANCH_NAME" \ --title "chore: update from skeleton" \ --body "$PR_BODY") - gh pr merge "${{ steps.commit-and-push.outputs.branch_name }}" --auto --squash + gh pr merge "$BRANCH_NAME" --auto --squash echo "### βœ… Pull Request Created" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "$PR_URL" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "Auto-merge has been enabled." >> "$GITHUB_STEP_SUMMARY" - env: - GH_TOKEN: ${{ steps.get-app-token.outputs.token }} - name: Create Pull Request (requires review) if: steps.run-updates.outputs.has_changes == 'true' && (steps.run-updates.outputs.pre_commit_passed == 'false' || inputs.recopy == true) + env: + GH_TOKEN: ${{ steps.get-app-token.outputs.token }} + BRANCH_NAME: ${{ steps.commit-and-push.outputs.branch_name }} + RECOPY: ${{ inputs.recopy }} + PRE_COMMIT_PASSED: ${{ steps.run-updates.outputs.pre_commit_passed }} run: | - if [ "${{ inputs.recopy }}" == "true" ] && [ "${{ steps.run-updates.outputs.pre_commit_passed }}" == "true" ]; then + if [ "$RECOPY" == "true" ] && [ "$PRE_COMMIT_PASSED" == "true" ]; then PR_BODY=$(cat <<-'EOF' Automated recopy from skeleton template. @@ -195,7 +210,7 @@ jobs: EOF ) else - PR_BODY=$(cat <<-'EOF' + PR_BODY=$(cat <<-EOF Automated update from skeleton template. ⚠️ Problems occurred during pre-commit validation. Manual review and conflict resolution may be required before merging. @@ -215,7 +230,7 @@ jobs: fi PR_URL=$(gh pr create \ --base main \ - --head "${{ steps.commit-and-push.outputs.branch_name }}" \ + --head "$BRANCH_NAME" \ --title "fix: update from skeleton" \ --body "$PR_BODY") echo "### ⚠️ Pull Request Created (requires review)" >> "$GITHUB_STEP_SUMMARY" @@ -223,5 +238,3 @@ jobs: echo "$PR_URL" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "This PR requires manual review before merging." >> "$GITHUB_STEP_SUMMARY" - env: - GH_TOKEN: ${{ steps.get-app-token.outputs.token }} From b25cd8ba3cb404934e00f656df80f90f89106950 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Fri, 1 May 2026 16:18:10 -0500 Subject: [PATCH 44/44] fix: tags --- .../reusable-pr-conventional-commit-title.yml | 4 ++-- .github/workflows/reusable-terraform-check-aws.yml | 8 ++++---- .github/workflows/reusable-terraform-check-azure.yml | 8 ++++---- .github/workflows/reusable-terraform-check.yml | 12 ++++++------ .github/workflows/reusable-terragrunt-deploy-aws.yml | 2 +- .../workflows/reusable-terragrunt-deploy-azure.yml | 2 +- .../reusable-terragrunt-deploy-ephemeral-aws.yml | 2 +- .github/workflows/reusable-terragrunt-deploy.yml | 10 +++++----- .../reusable-terragrunt-destroy-ephemeral-aws.yml | 2 +- .../workflows/reusable-terragrunt-plan-only-aws.yml | 2 +- .../reusable-terragrunt-plan-only-azure.yml | 2 +- .github/workflows/reusable-terragrunt-plan-only.yml | 6 +++--- .github/workflows/reusable-update-from-skeleton.yml | 2 +- 13 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.github/workflows/reusable-pr-conventional-commit-title.yml b/.github/workflows/reusable-pr-conventional-commit-title.yml index 07cd67b..98bbf53 100644 --- a/.github/workflows/reusable-pr-conventional-commit-title.yml +++ b/.github/workflows/reusable-pr-conventional-commit-title.yml @@ -206,7 +206,7 @@ jobs: - id: set-status-check name: Set Status Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Conventional Commit PR Title" status: ${{ steps.pr-validation.outcome == 'success' && 'success' || @@ -218,7 +218,7 @@ jobs: - id: set-status-check-legacy name: Set Legacy Check if: ${{ inputs.comment_on_failure }} - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Label Pull Request / Label Pull Request" status: ${{ steps.pr-validation.outcome == 'success' && 'success' || diff --git a/.github/workflows/reusable-terraform-check-aws.yml b/.github/workflows/reusable-terraform-check-aws.yml index 5bba4e5..b71727e 100644 --- a/.github/workflows/reusable-terraform-check-aws.yml +++ b/.github/workflows/reusable-terraform-check-aws.yml @@ -66,7 +66,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: "pending" @@ -79,7 +79,7 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -109,7 +109,7 @@ jobs: find examples -type f -name "provider.tf" -mindepth 2 -maxdepth 2 -exec bash -c 'grep -vE "profile\s=" "$1" > $1.tmp && mv $1.tmp $1' bash {} \; - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: "pending" @@ -122,7 +122,7 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome diff --git a/.github/workflows/reusable-terraform-check-azure.yml b/.github/workflows/reusable-terraform-check-azure.yml index 0b74d17..ecee790 100644 --- a/.github/workflows/reusable-terraform-check-azure.yml +++ b/.github/workflows/reusable-terraform-check-azure.yml @@ -62,7 +62,7 @@ jobs: key: ${{ runner.os }}-tool-versions-${{ hashFiles('.tool-versions') }} - name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: "pending" @@ -75,7 +75,7 @@ jobs: - name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -90,7 +90,7 @@ jobs: subscription-id: ${{ secrets.TERRAFORM_CHECK_AZURE_SUBSCRIPTION_ID }} - name: "Set Terraform Tests status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: "pending" @@ -103,7 +103,7 @@ jobs: - name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome diff --git a/.github/workflows/reusable-terraform-check.yml b/.github/workflows/reusable-terraform-check.yml index 4d49634..86e6f20 100644 --- a/.github/workflows/reusable-terraform-check.yml +++ b/.github/workflows/reusable-terraform-check.yml @@ -182,7 +182,7 @@ jobs: - id: set-lint-pending name: "Set Terraform Lint status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: "pending" @@ -198,7 +198,7 @@ jobs: - id: update-lint-status name: "Update Terraform Lint status" if: always() && steps.lint.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Lint" status: ${{ steps.lint.outcome == 'success' && 'success' || steps.lint.outcome @@ -310,7 +310,7 @@ jobs: - id: set-tests-pending name: "Set Terraform Tests status to pending" continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: "pending" @@ -332,7 +332,7 @@ jobs: name: "Update Terraform Tests status" if: always() && steps.test.outcome != 'skipped' continue-on-error: true - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terraform Tests" status: ${{ steps.test.outcome == 'success' && 'success' || steps.test.outcome @@ -352,7 +352,7 @@ jobs: - id: update-legacy-status-checks-aws name: "Add AWS Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-aws-') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Check AWS Terraform Code / Check AWS Terraform Code" status: "success" @@ -364,7 +364,7 @@ jobs: - id: update-legacy-status-checks-azure name: "Add Azure Legacy Status Check" if: startsWith(github.event.repository.name, 'tf-az') - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Check Azure Terraform Code / Check Azure Terraform Code" status: "success" diff --git a/.github/workflows/reusable-terragrunt-deploy-aws.yml b/.github/workflows/reusable-terragrunt-deploy-aws.yml index 1c257ea..f97f7d6 100644 --- a/.github/workflows/reusable-terragrunt-deploy-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-aws.yml @@ -117,7 +117,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy-azure.yml b/.github/workflows/reusable-terragrunt-deploy-azure.yml index 892c09f..f5d880a 100644 --- a/.github/workflows/reusable-terragrunt-deploy-azure.yml +++ b/.github/workflows/reusable-terragrunt-deploy-azure.yml @@ -110,7 +110,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml index 6192901..416b464 100644 --- a/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-deploy-ephemeral-aws.yml @@ -105,7 +105,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-deploy.yml b/.github/workflows/reusable-terragrunt-deploy.yml index a9c15d1..5dc2b4b 100644 --- a/.github/workflows/reusable-terragrunt-deploy.yml +++ b/.github/workflows/reusable-terragrunt-deploy.yml @@ -265,13 +265,13 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" @@ -310,7 +310,7 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome @@ -320,7 +320,7 @@ jobs: github.run_id }}" - name: "Set Terragrunt Deploy status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: "pending" @@ -359,7 +359,7 @@ jobs: - name: "Update Terragrunt Deploy status" if: always() && steps.deploy.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Deploy (${{ inputs.tg_dir }})" status: ${{ steps.deploy.outcome == 'success' && 'success' || diff --git a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml index b50ffda..5e03276 100644 --- a/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml +++ b/.github/workflows/reusable-terragrunt-destroy-ephemeral-aws.yml @@ -76,7 +76,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only-aws.yml b/.github/workflows/reusable-terragrunt-plan-only-aws.yml index 6c8a56d..ce47d86 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-aws.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-aws.yml @@ -81,7 +81,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only-azure.yml b/.github/workflows/reusable-terragrunt-plan-only-azure.yml index d2d1100..5843c1c 100644 --- a/.github/workflows/reusable-terragrunt-plan-only-azure.yml +++ b/.github/workflows/reusable-terragrunt-plan-only-azure.yml @@ -80,7 +80,7 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} diff --git a/.github/workflows/reusable-terragrunt-plan-only.yml b/.github/workflows/reusable-terragrunt-plan-only.yml index 438b35c..099fbf9 100644 --- a/.github/workflows/reusable-terragrunt-plan-only.yml +++ b/.github/workflows/reusable-terragrunt-plan-only.yml @@ -228,13 +228,13 @@ jobs: - name: Configure Mise id: configure-mise - uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/terragrunt-configure-mise@0.15.0 with: tf_version: ${{ inputs.tf_version }} tg_version: ${{ inputs.tg_version }} - name: "Set Terragrunt Plan status to pending" - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: "pending" @@ -269,7 +269,7 @@ jobs: - name: "Update Terragrunt Plan status" if: always() && steps.plan.outcome != 'skipped' - uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/update-status-check@0.15.0 with: check_name: "Terragrunt Plan (${{ inputs.tg_dir }})" status: ${{ steps.plan.outcome == 'success' && 'success' || steps.plan.outcome diff --git a/.github/workflows/reusable-update-from-skeleton.yml b/.github/workflows/reusable-update-from-skeleton.yml index d62d5ef..8944b8c 100644 --- a/.github/workflows/reusable-update-from-skeleton.yml +++ b/.github/workflows/reusable-update-from-skeleton.yml @@ -58,7 +58,7 @@ jobs: - id: get-repo-custom-properties name: Get Repository Custom Properties - uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@feat/unify-provider-auth + uses: launchbynttdata/launch-workflows/.github/actions/get-custom-properties@0.15.0 - id: run-updates name: Run Updates from Skeleton