name: SES - juntekim.com [Simple Email Service] on: pull_request: push: branches: - main paths: - "aws_environment/ses-juntekim/**" workflow_dispatch: env: TF_VERSION: "1.6.6" WORKING_DIR: "aws_environment/ses-juntekim" jobs: terraform: name: Terraform SES runs-on: mealcraft-runners permissions: contents: read pull-requests: write steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install modern Node.js run: | curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt-get install -y nodejs node --version - name: Setup Terraform uses: hashicorp/setup-terraform@v3 with: terraform_version: ${{ env.TF_VERSION }} - name: Install AWS CLI v2 run: | sudo apt-get update sudo apt-get install -y unzip curl curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install aws --version # Optional but recommended once - name: Verify AWS identity run: aws sts get-caller-identity - name: Terraform Init working-directory: ${{ env.WORKING_DIR }} run: terraform init - name: Terraform Validate working-directory: ${{ env.WORKING_DIR }} run: terraform validate - name: Force unlock stale terraform state working-directory: ${{ env.WORKING_DIR }} run: | # Try to force unlock any stale locks for this specific state file # The lock ID is found in the error message, so we attempt unlock with common patterns echo "Attempting to clear stale locks..." # Get all items from the locks table ITEMS=$(aws dynamodb scan \ --table-name "terraform-locks" \ --region eu-west-2 \ --output json) # Extract lock IDs where the Path matches our state file LOCK_IDS=$(echo "$ITEMS" | jq -r '.Items[] | select(.Path.S == "juntekim-terraform-state/ses/terraform.tfstate") | .ID.S' 2>/dev/null || echo "") if [ ! -z "$LOCK_IDS" ]; then while IFS= read -r LOCK_ID; do if [ ! -z "$LOCK_ID" ]; then echo "Removing lock: $LOCK_ID" terraform force-unlock -force "$LOCK_ID" 2>&1 || true fi done <<< "$LOCK_IDS" else echo "No locks found for ses state file, proceeding..." fi continue-on-error: true - name: Terraform Plan if: github.event_name == 'pull_request' id: plan working-directory: ${{ env.WORKING_DIR }} run: terraform plan -input=false - name: Wait for terraform-plan workflow if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: actions/github-script@v6 with: script: | const maxAttempts = 120; // 10 minutes with 5 second intervals let attempt = 0; while (attempt < maxAttempts) { const runs = await github.rest.actions.listWorkflowRuns({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: 'terraform-plan.yml', }); const latestPlan = runs.data.workflow_runs[0]; if (latestPlan && (latestPlan.status === 'completed')) { if (latestPlan.conclusion === 'success') { console.log('✅ terraform-plan workflow completed successfully'); return; } else { throw new Error(`terraform-plan workflow failed with conclusion: ${latestPlan.conclusion}`); } } attempt++; if (attempt % 12 === 0) { console.log(`Waiting for terraform-plan... (attempt ${attempt}/${maxAttempts})`); } await new Promise(resolve => setTimeout(resolve, 5000)); } throw new Error('Timeout waiting for terraform-plan workflow'); - name: Terraform Apply if: github.ref == 'refs/heads/main' working-directory: ${{ env.WORKING_DIR }} run: terraform apply -auto-approve -input=false