feat: adds EBS CSI argo addon to eu-west-2 for StorageClass tracking #46
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Terraform Validation" | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| paths: | |
| - 'infra/**' | |
| - '.github/workflows/terraform-*.yml' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| id-token: write # Required for AWS OIDC | |
| concurrency: | |
| group: terraform-validate-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| TERRAFORM_VERSION: "1.15.8" | |
| TERRAGRUNT_VERSION: "0.99.1" | |
| jobs: | |
| discover-changes: | |
| name: Discover Changed Directories | |
| runs-on: ubuntu-latest | |
| outputs: | |
| changed_dirs: ${{ steps.find-changes.outputs.changed_dirs }} | |
| filter_args: ${{ steps.build-filters.outputs.filter_args }} | |
| has_changes: ${{ steps.find-changes.outputs.has_changes }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Find changed directories | |
| id: find-changes | |
| shell: bash | |
| run: | | |
| # Get the base branch | |
| BASE_REF="${{ github.event.pull_request.base.sha }}" | |
| HEAD_REF="${{ github.sha }}" | |
| # Find all changed files in infra/ | |
| changed_files=$(git diff --name-only "$BASE_REF" "$HEAD_REF" -- infra/ || echo "") | |
| if [ -z "$changed_files" ]; then | |
| echo "No changes detected in infra/" | |
| echo "has_changes=false" >> $GITHUB_OUTPUT | |
| echo "changed_dirs=[]" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "Changed files:" | |
| echo "$changed_files" | |
| echo "" | |
| # Find directories containing terragrunt.hcl files | |
| terragrunt_dirs=$(find infra -type f -name "terragrunt.hcl" -not -path "*/.terraform/*" | sed 's|/terragrunt.hcl||' | sort -u) | |
| # Identify which Terragrunt directories were affected | |
| changed_dirs="" | |
| while IFS= read -r file; do | |
| file_dir=$(dirname "$file") | |
| # Find the closest parent directory that contains a terragrunt.hcl | |
| while [ "$file_dir" != "." ] && [ "$file_dir" != "infra" ]; do | |
| if echo "$terragrunt_dirs" | grep -q "^$file_dir$"; then | |
| changed_dirs="${changed_dirs}${file_dir}"$'\n' | |
| break | |
| fi | |
| file_dir=$(dirname "$file_dir") | |
| done | |
| done <<< "$changed_files" | |
| # Remove duplicates and sort | |
| changed_dirs=$(echo "$changed_dirs" | sort -u | grep -v '^$' || echo "") | |
| if [ -z "$changed_dirs" ]; then | |
| # Changes were in infra but not in any terragrunt module directory | |
| echo "Changes detected but not in terragrunt module directories" | |
| echo "has_changes=true" >> $GITHUB_OUTPUT | |
| echo "changed_dirs=[]" >> $GITHUB_OUTPUT | |
| else | |
| echo "Changed Terragrunt directories:" | |
| echo "$changed_dirs" | |
| # Strip "infra/" prefix since terragrunt commands run from within infra/ | |
| changed_dirs_relative=$(echo "$changed_dirs" | sed 's|^infra/||') | |
| echo "Relative paths (for filters):" | |
| echo "$changed_dirs_relative" | |
| # Convert to JSON array | |
| changed_dirs_json=$(echo "$changed_dirs_relative" | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| echo "has_changes=true" >> $GITHUB_OUTPUT | |
| echo "changed_dirs=$changed_dirs_json" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Build filter arguments | |
| id: build-filters | |
| shell: bash | |
| run: | | |
| changed_dirs='${{ steps.find-changes.outputs.changed_dirs }}' | |
| if [ "$changed_dirs" = "[]" ] || [ -z "$changed_dirs" ]; then | |
| echo "filter_args=" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Build --filter arguments for each changed directory | |
| filter_args="" | |
| for dir in $(echo "$changed_dirs" | jq -r '.[]'); do | |
| filter_args="${filter_args} --filter=${dir}" | |
| done | |
| # Trim leading space | |
| filter_args=$(echo "$filter_args" | sed 's/^ //') | |
| echo "Filter arguments: $filter_args" | |
| echo "filter_args=$filter_args" >> $GITHUB_OUTPUT | |
| validate: | |
| name: Validate Infrastructure | |
| needs: discover-changes | |
| runs-on: ubuntu-latest | |
| env: | |
| # Repository Variables | |
| TERRAGRUNT_ARGS: ${{ vars.TERRAGRUNT_ARGS }} | |
| TERRAFORM_INIT_ARGS: ${{ vars.TERRAFORM_INIT_ARGS }} | |
| TERRAFORM_VALIDATE_ARGS: ${{ vars.TERRAFORM_VALIDATE_ARGS }} | |
| TERRAFORM_APPLY_ARGS: ${{ vars.TERRAFORM_APPLY_ARGS }} | |
| CODER_TF_BACKEND_AWS_BUCKET_NAME: ${{ vars.CODER_TF_BACKEND_AWS_BUCKET_NAME }} | |
| CODER_TF_BACKEND_AWS_REGION: ${{ vars.CODER_TF_BACKEND_AWS_REGION }} | |
| CODER_TF_BACKEND_AWS_PROFILE: ${{ vars.CODER_TF_BACKEND_AWS_PROFILE }} | |
| CODER_TF_BACKEND_ENCRYPT: ${{ vars.CODER_TF_BACKEND_ENCRYPT }} | |
| CODER_AWS_PROFILE: ${{ vars.CODER_AWS_PROFILE }} | |
| CODER_AWS_REGION: ${{ vars.CODER_AWS_REGION }} | |
| CODER_AWS_AZS: ${{ vars.CODER_AWS_AZS }} | |
| CODER_CLUSTER_NAME: ${{ vars.CODER_CLUSTER_NAME }} | |
| CODER_CLUSTER_VERSION: ${{ vars.CODER_CLUSTER_VERSION }} | |
| CODER_CLUSTER_INSTANCE_TYPE: ${{ vars.CODER_CLUSTER_INSTANCE_TYPE }} | |
| CODER_VPC_NAME: ${{ vars.CODER_VPC_NAME }} | |
| CODER_VPC_CIDR: ${{ vars.CODER_VPC_CIDR }} | |
| CODER_VPC_AZS: ${{ vars.CODER_VPC_AZS }} | |
| CODER_VPC_NAT_NAME: ${{ vars.CODER_VPC_NAT_NAME }} | |
| CODER_DB_SUBNET_GROUP_NAME: ${{ vars.CODER_DB_SUBNET_GROUP_NAME }} | |
| CODER_PUBLIC_SUBNET_SUFFIX: ${{ vars.CODER_PUBLIC_SUBNET_SUFFIX }} | |
| CODER_PRIVATE_SUBNET_SUFFIX: ${{ vars.CODER_PRIVATE_SUBNET_SUFFIX }} | |
| CODER_DB_RDS_ID: ${{ vars.CODER_DB_RDS_ID }} | |
| CODER_DB_USERNAME: ${{ vars.CODER_DB_USERNAME }} | |
| CODER_DB_NAME: ${{ vars.CODER_DB_NAME }} | |
| CODER_IMAGE_REPO: ${{ vars.CODER_IMAGE_REPO }} | |
| CODER_IMAGE_TAG: ${{ vars.CODER_IMAGE_TAG }} | |
| LOKI_S3_BUCKET_NAME: ${{ vars.LOKI_S3_BUCKET_NAME }} | |
| LOKI_S3_BUCKET_REGION: ${{ vars.LOKI_S3_BUCKET_REGION }} | |
| GRAFANA_DOMAIN_NAME: ${{ vars.GRAFANA_DOMAIN_NAME }} | |
| GRAFANA_DB_USERNAME: ${{ vars.GRAFANA_DB_USERNAME }} | |
| CODER_DOMAIN_NAME: ${{ vars.CODER_DOMAIN_NAME }} | |
| CODER_WILDCARD_URL: ${{ vars.CODER_WILDCARD_URL }} | |
| CODER_LICENSE: ${{ vars.CODER_LICENSE }} | |
| CODER_EXPERIMENTS: ${{ vars.CODER_EXPERIMENTS }} | |
| CODER_BUILT_IN_PROVISIONER_COUNT: ${{ vars.CODER_BUILT_IN_PROVISIONER_COUNT }} | |
| CODER_OIDC_SIGN_IN_TEXT: ${{ vars.CODER_OIDC_SIGN_IN_TEXT }} | |
| CODER_OIDC_ICON_URL: ${{ vars.CODER_OIDC_ICON_URL }} | |
| CODER_OIDC_SCOPES: ${{ vars.CODER_OIDC_SCOPES }} | |
| CODER_OIDC_EMAIL_DOMAIN: ${{ vars.CODER_OIDC_EMAIL_DOMAIN }} | |
| CODER_OIDC_ISSUER_URL: ${{ vars.CODER_OIDC_ISSUER_URL }} | |
| # Secrets | |
| CF_EMAIL: ${{ secrets.CF_EMAIL }} | |
| CF_TOKEN: ${{ secrets.CF_TOKEN }} | |
| CODER_GITHUB_EXTERN_AUTH_CLIENT_ID: ${{ secrets.CODER_GITHUB_EXTERN_AUTH_CLIENT_ID }} | |
| CODER_GITHUB_EXTERN_AUTH_CLIENT_SECRET: ${{ secrets.CODER_GITHUB_EXTERN_AUTH_CLIENT_SECRET }} | |
| CODER_GITHUB_OAUTH_CLIENT_ID: ${{ secrets.CODER_GITHUB_OAUTH_CLIENT_ID }} | |
| CODER_GITHUB_OAUTH_CLIENT_SECRET: ${{ secrets.CODER_GITHUB_OAUTH_CLIENT_SECRET }} | |
| CODER_OIDC_CLIENT_ID: ${{ secrets.CODER_OIDC_CLIENT_ID }} | |
| CODER_OIDC_CLIENT_SECRET: ${{ secrets.CODER_OIDC_CLIENT_SECRET }} | |
| CODER_RUNNER_TOKEN: ${{ secrets.CODER_RUNNER_TOKEN }} | |
| GRAFANA_USER_PASSWORD: ${{ secrets.GRAFANA_USER_PASSWORD }} | |
| VANTAGE_API_TOKEN: ${{ secrets.VANTAGE_API_TOKEN }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Terraform | |
| uses: hashicorp/setup-terraform@v3 | |
| with: | |
| terraform_version: ${{ env.TERRAFORM_VERSION }} | |
| - name: Setup Terragrunt | |
| uses: gruntwork-io/terragrunt-action@v3 | |
| with: | |
| tf_path: "terraform" | |
| tg_version: ${{ env.TERRAGRUNT_VERSION }} | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v6.2.3 | |
| with: | |
| role-to-assume: ${{ vars.AWS_RUNNER_ROLE_ARN }} | |
| aws-region: ${{ vars.AWS_RUNNER_REGION }} | |
| aws-profile: ${{ vars.CODER_AWS_PROFILE }} | |
| - name: Terragrunt hclfmt check | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Checking Terragrunt formatting" | |
| FILTER_ARGS="${{ needs.discover-changes.outputs.filter_args }}" | |
| echo "Filter args: $FILTER_ARGS" | |
| if ! terragrunt hcl format --exclude-dir=.terraform --check; then | |
| echo "" | |
| echo "::error::Terragrunt files are not formatted." | |
| echo "::error::Run 'terragrunt hclfmt' in the infra directory before pushing." | |
| exit 1 | |
| fi | |
| echo "✓ Terragrunt formatting is correct" | |
| echo "::endgroup::" | |
| - name: Terraform fmt check | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Checking Terraform formatting" | |
| if ! terraform fmt -check -recursive; then | |
| echo "" | |
| echo "::error::Terraform files are not formatted." | |
| echo "::error::Run 'terraform fmt -recursive' in the infra directory before pushing." | |
| exit 1 | |
| fi | |
| echo "✓ Terraform formatting is correct" | |
| echo "::endgroup::" | |
| - name: Terragrunt validate-inputs | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Validating Terragrunt inputs" | |
| FILTER_ARGS="${{ needs.discover-changes.outputs.filter_args }}" | |
| # Build the full command with filters | |
| CMD="terragrunt hcl validate --inputs" | |
| if [ -n "$FILTER_ARGS" ]; then | |
| CMD="$CMD $FILTER_ARGS" | |
| fi | |
| if [ -n "${TERRAGRUNT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAGRUNT_ARGS}" | |
| fi | |
| echo "Running: $CMD" | |
| if ! eval "$CMD"; then | |
| echo "" | |
| echo "::error::Terragrunt inputs are not valid." | |
| echo "::error::[View Full Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) to see what failed." | |
| exit 1 | |
| fi | |
| echo "✓ Terragrunt inputs are valid" | |
| echo "::endgroup::" | |
| - name: Terragrunt init | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Initializing all modules" | |
| FILTER_ARGS="${{ needs.discover-changes.outputs.filter_args }}" | |
| # Build the full command with filters | |
| CMD="terragrunt run --all --queue-exclude-dir='./' --provider-cache" | |
| if [ -n "$FILTER_ARGS" ]; then | |
| CMD="$CMD $FILTER_ARGS" | |
| fi | |
| if [ -n "${TERRAGRUNT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAGRUNT_ARGS}" | |
| fi | |
| CMD="$CMD -- init -input=false -reconfigure -upgrade" | |
| if [ -n "${TERRAFORM_INIT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAFORM_INIT_ARGS}" | |
| fi | |
| echo "Running: $CMD" | |
| eval "$CMD" | |
| echo "✓ Initialization successful" | |
| echo "::endgroup::" | |
| - name: Terragrunt validate | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Validating Terraform configuration" | |
| FILTER_ARGS="${{ needs.discover-changes.outputs.filter_args }}" | |
| # Build the full command with filters | |
| CMD="terragrunt run --all --queue-exclude-dir='./' --provider-cache" | |
| if [ -n "$FILTER_ARGS" ]; then | |
| CMD="$CMD $FILTER_ARGS" | |
| fi | |
| if [ -n "${TERRAGRUNT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAGRUNT_ARGS}" | |
| fi | |
| CMD="$CMD -- validate" | |
| if [ -n "${TERRAFORM_VALIDATE_ARGS}" ]; then | |
| CMD="$CMD ${TERRAFORM_VALIDATE_ARGS}" | |
| fi | |
| echo "Running: $CMD" | |
| eval "$CMD" | |
| echo "✓ Terraform configuration is valid" | |
| echo "::endgroup::" | |
| plan: | |
| name: Plan Infrastructure | |
| needs: [validate, discover-changes] | |
| runs-on: ubuntu-latest | |
| env: | |
| # Repository Variables | |
| TERRAGRUNT_ARGS: ${{ vars.TERRAGRUNT_ARGS }} | |
| TERRAFORM_PLAN_ARGS: ${{ vars.TERRAFORM_PLAN_ARGS }} | |
| TERRAFORM_INIT_ARGS: ${{ vars.TERRAFORM_INIT_ARGS }} | |
| CODER_TF_BACKEND_AWS_BUCKET_NAME: ${{ vars.CODER_TF_BACKEND_AWS_BUCKET_NAME }} | |
| CODER_TF_BACKEND_AWS_REGION: ${{ vars.CODER_TF_BACKEND_AWS_REGION }} | |
| CODER_TF_BACKEND_AWS_PROFILE: ${{ vars.CODER_TF_BACKEND_AWS_PROFILE }} | |
| CODER_TF_BACKEND_ENCRYPT: ${{ vars.CODER_TF_BACKEND_ENCRYPT }} | |
| CODER_AWS_PROFILE: ${{ vars.CODER_AWS_PROFILE }} | |
| CODER_AWS_REGION: ${{ vars.CODER_AWS_REGION }} | |
| CODER_AWS_AZS: ${{ vars.CODER_AWS_AZS }} | |
| CODER_CLUSTER_NAME: ${{ vars.CODER_CLUSTER_NAME }} | |
| CODER_CLUSTER_VERSION: ${{ vars.CODER_CLUSTER_VERSION }} | |
| CODER_CLUSTER_INSTANCE_TYPE: ${{ vars.CODER_CLUSTER_INSTANCE_TYPE }} | |
| CODER_VPC_NAME: ${{ vars.CODER_VPC_NAME }} | |
| CODER_VPC_CIDR: ${{ vars.CODER_VPC_CIDR }} | |
| CODER_VPC_AZS: ${{ vars.CODER_VPC_AZS }} | |
| CODER_VPC_NAT_NAME: ${{ vars.CODER_VPC_NAT_NAME }} | |
| CODER_DB_SUBNET_GROUP_NAME: ${{ vars.CODER_DB_SUBNET_GROUP_NAME }} | |
| CODER_PUBLIC_SUBNET_SUFFIX: ${{ vars.CODER_PUBLIC_SUBNET_SUFFIX }} | |
| CODER_PRIVATE_SUBNET_SUFFIX: ${{ vars.CODER_PRIVATE_SUBNET_SUFFIX }} | |
| CODER_DB_RDS_ID: ${{ vars.CODER_DB_RDS_ID }} | |
| CODER_DB_USERNAME: ${{ vars.CODER_DB_USERNAME }} | |
| CODER_DB_NAME: ${{ vars.CODER_DB_NAME }} | |
| CODER_IMAGE_REPO: ${{ vars.CODER_IMAGE_REPO }} | |
| CODER_IMAGE_TAG: ${{ vars.CODER_IMAGE_TAG }} | |
| LOKI_S3_BUCKET_NAME: ${{ vars.LOKI_S3_BUCKET_NAME }} | |
| LOKI_S3_BUCKET_REGION: ${{ vars.LOKI_S3_BUCKET_REGION }} | |
| GRAFANA_DOMAIN_NAME: ${{ vars.GRAFANA_DOMAIN_NAME }} | |
| GRAFANA_DB_USERNAME: ${{ vars.GRAFANA_DB_USERNAME }} | |
| CODER_DOMAIN_NAME: ${{ vars.CODER_DOMAIN_NAME }} | |
| CODER_WILDCARD_URL: ${{ vars.CODER_WILDCARD_URL }} | |
| CODER_LICENSE: ${{ vars.CODER_LICENSE }} | |
| CODER_EXPERIMENTS: ${{ vars.CODER_EXPERIMENTS }} | |
| CODER_BUILT_IN_PROVISIONER_COUNT: ${{ vars.CODER_BUILT_IN_PROVISIONER_COUNT }} | |
| CODER_OIDC_SIGN_IN_TEXT: ${{ vars.CODER_OIDC_SIGN_IN_TEXT }} | |
| CODER_OIDC_ICON_URL: ${{ vars.CODER_OIDC_ICON_URL }} | |
| CODER_OIDC_SCOPES: ${{ vars.CODER_OIDC_SCOPES }} | |
| CODER_OIDC_EMAIL_DOMAIN: ${{ vars.CODER_OIDC_EMAIL_DOMAIN }} | |
| CODER_OIDC_ISSUER_URL: ${{ vars.CODER_OIDC_ISSUER_URL }} | |
| # Secrets | |
| CF_EMAIL: ${{ secrets.CF_EMAIL }} | |
| CF_TOKEN: ${{ secrets.CF_TOKEN }} | |
| CODER_GITHUB_EXTERN_AUTH_CLIENT_ID: ${{ secrets.CODER_GITHUB_EXTERN_AUTH_CLIENT_ID }} | |
| CODER_GITHUB_EXTERN_AUTH_CLIENT_SECRET: ${{ secrets.CODER_GITHUB_EXTERN_AUTH_CLIENT_SECRET }} | |
| CODER_GITHUB_OAUTH_CLIENT_ID: ${{ secrets.CODER_GITHUB_OAUTH_CLIENT_ID }} | |
| CODER_GITHUB_OAUTH_CLIENT_SECRET: ${{ secrets.CODER_GITHUB_OAUTH_CLIENT_SECRET }} | |
| CODER_OIDC_CLIENT_ID: ${{ secrets.CODER_OIDC_CLIENT_ID }} | |
| CODER_OIDC_CLIENT_SECRET: ${{ secrets.CODER_OIDC_CLIENT_SECRET }} | |
| CODER_RUNNER_TOKEN: ${{ secrets.CODER_RUNNER_TOKEN }} | |
| GRAFANA_USER_PASSWORD: ${{ secrets.GRAFANA_USER_PASSWORD }} | |
| VANTAGE_API_TOKEN: ${{ secrets.VANTAGE_API_TOKEN }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Terraform | |
| uses: hashicorp/setup-terraform@v3 | |
| with: | |
| terraform_version: ${{ env.TERRAFORM_VERSION }} | |
| terraform_wrapper: false | |
| - name: Setup Terragrunt | |
| uses: gruntwork-io/terragrunt-action@v3 | |
| with: | |
| tf_path: "terraform" | |
| tg_version: ${{ env.TERRAGRUNT_VERSION }} | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v6.2.3 | |
| with: | |
| role-to-assume: ${{ vars.AWS_RUNNER_ROLE_ARN }} | |
| aws-region: ${{ vars.AWS_RUNNER_REGION }} | |
| aws-profile: ${{ vars.CODER_AWS_PROFILE }} | |
| - name: Terragrunt init | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Initializing all modules" | |
| FILTER_ARGS="${{ needs.discover-changes.outputs.filter_args }}" | |
| # Build the full command with filters | |
| CMD="terragrunt run --all --queue-exclude-dir='./' --provider-cache" | |
| if [ -n "$FILTER_ARGS" ]; then | |
| CMD="$CMD $FILTER_ARGS" | |
| fi | |
| if [ -n "${TERRAGRUNT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAGRUNT_ARGS}" | |
| fi | |
| CMD="$CMD -- init -input=false -reconfigure -upgrade" | |
| if [ -n "${TERRAFORM_INIT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAFORM_INIT_ARGS}" | |
| fi | |
| echo "Running: $CMD" | |
| eval "$CMD" | |
| echo "✓ Initialization successful" | |
| echo "::endgroup::" | |
| - name: Terragrunt plan | |
| id: plan | |
| shell: bash | |
| working-directory: infra | |
| run: | | |
| echo "::group::Running Terragrunt plan on all modules" | |
| FILTER_ARGS="${{ needs.discover-changes.outputs.filter_args }}" | |
| # Build the full command with filters | |
| CMD="terragrunt run --all --queue-exclude-dir='./' --provider-cache" | |
| if [ -n "$FILTER_ARGS" ]; then | |
| CMD="$CMD $FILTER_ARGS" | |
| fi | |
| if [ -n "${TERRAGRUNT_ARGS}" ]; then | |
| CMD="$CMD ${TERRAGRUNT_ARGS}" | |
| fi | |
| CMD="$CMD -- plan -input=false -no-color -detailed-exitcode" | |
| if [ -n "${TERRAFORM_PLAN_ARGS}" ]; then | |
| CMD="$CMD ${TERRAFORM_PLAN_ARGS}" | |
| fi | |
| # Run plan and capture output | |
| set +e | |
| echo "Running: $CMD" | |
| eval "$CMD" 2>&1 | tee plan.log | |
| EXIT_CODE=${PIPESTATUS[0]} | |
| set -e | |
| echo "::endgroup::" | |
| # Exit code meanings: | |
| # 0 = succeeded with no changes | |
| # 1 = error | |
| # 2 = succeeded with changes | |
| if [[ $EXIT_CODE -eq 0 ]]; then | |
| echo "summary=No changes detected" >> "$GITHUB_OUTPUT" | |
| echo "status=success" >> "$GITHUB_OUTPUT" | |
| echo "✓ Plan succeeded with no changes" | |
| elif [[ $EXIT_CODE -eq 2 ]]; then | |
| echo "summary=Changes detected" >> "$GITHUB_OUTPUT" | |
| echo "status=success" >> "$GITHUB_OUTPUT" | |
| echo "✓ Plan succeeded with changes" | |
| exit 0 | |
| else | |
| echo "summary=Plan failed" >> "$GITHUB_OUTPUT" | |
| echo "status=failure" >> "$GITHUB_OUTPUT" | |
| echo "::error::Terraform plan failed" | |
| exit 1 | |
| fi | |
| - name: Upload plan log | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: plan-log | |
| path: infra/plan.log | |
| retention-days: 30 | |
| summary: | |
| name: Validation Summary | |
| needs: [discover-changes, validate, plan] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check validation results | |
| shell: bash | |
| run: | | |
| echo "## Terraform Validation Summary" | |
| echo "" | |
| changed_dirs='${{ needs.discover-changes.outputs.changed_dirs }}' | |
| has_changes="${{ needs.discover-changes.outputs.has_changes }}" | |
| validate_result="${{ needs.validate.result }}" | |
| plan_result="${{ needs.plan.result }}" | |
| # Display changed directories | |
| if [ "$has_changes" = "true" ] && [ "$changed_dirs" != "[]" ]; then | |
| echo "Changed Terragrunt directories:" | |
| echo "$changed_dirs" | jq -r '.[]' | sed 's/^/ - /' | |
| echo "" | |
| elif [ "$has_changes" = "true" ]; then | |
| echo "Changes detected in infra/ but not in terragrunt module directories" | |
| echo "" | |
| else | |
| echo "No changes detected in infra/" | |
| echo "" | |
| fi | |
| echo "Validation result: $validate_result" | |
| echo "Plan result: $plan_result" | |
| echo "" | |
| if [[ "$validate_result" == "success" ]] && [[ "$plan_result" == "success" ]]; then | |
| echo "✅ All checks passed!" | |
| echo "- Formatting is correct" | |
| echo "- Configuration is valid" | |
| echo "- Plan succeeded" | |
| echo "" | |
| echo "This PR is ready to merge." | |
| exit 0 | |
| else | |
| echo "❌ Validation or planning failed" | |
| echo "" | |
| if [[ "$validate_result" != "success" ]]; then | |
| echo "- Validation failed: Check formatting and configuration" | |
| fi | |
| if [[ "$plan_result" != "success" ]]; then | |
| echo "- Planning failed: Check plan output in job logs" | |
| fi | |
| echo "" | |
| echo "Please fix the issues before merging." | |
| exit 1 | |
| fi | |
| - name: Post summary comment | |
| if: always() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const changedDirs = JSON.parse('${{ needs.discover-changes.outputs.changed_dirs }}' || '[]'); | |
| const hasChanges = '${{ needs.discover-changes.outputs.has_changes }}' === 'true'; | |
| const validateResult = '${{ needs.validate.result }}'; | |
| const planResult = '${{ needs.plan.result }}'; | |
| let body = '## 🔍 Terraform Validation Summary\n\n'; | |
| // Show changed directories | |
| if (hasChanges && changedDirs.length > 0) { | |
| body += '### 📁 Changed Directories\n\n'; | |
| body += 'The following Terragrunt modules were affected:\n\n'; | |
| changedDirs.forEach(dir => { | |
| body += `- \`${dir}\`\n`; | |
| }); | |
| body += '\n'; | |
| } else if (hasChanges) { | |
| body += '### ℹ️ Changes detected in `infra/` but not in terragrunt module directories\n\n'; | |
| } else { | |
| body += '### ℹ️ No changes detected in `infra/`\n\n'; | |
| } | |
| const allPassed = validateResult === 'success' && planResult === 'success'; | |
| if (allPassed) { | |
| body += '### ✅ All validation checks passed!\n\n'; | |
| body += '- ✅ Formatting is correct\n'; | |
| body += '- ✅ Configuration is valid\n'; | |
| body += '- ✅ Plan succeeded\n\n'; | |
| body += '🚀 This PR is **ready to merge**. Infrastructure changes will be applied automatically after merge.\n'; | |
| } else { | |
| body += '### ❌ Validation checks failed\n\n'; | |
| if (validateResult !== 'success') { | |
| body += '- ❌ **Validation failed**: Check formatting and configuration errors in job logs\n'; | |
| } | |
| if (planResult !== 'success') { | |
| body += '- ❌ **Planning failed**: Review the plan output in job logs\n'; | |
| } | |
| body += '\n⚠️ Please fix the issues before merging.\n'; | |
| } | |
| body += `\n---\n*[View Full Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*`; | |
| // Find existing summary comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const summaryComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('🔍 Terraform Validation Summary') | |
| ); | |
| if (summaryComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: summaryComment.id, | |
| body: body | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: body | |
| }); | |
| } |