|
| 1 | +--- |
| 2 | +# Deploy to Stage |
| 3 | +# |
| 4 | +# Runs `pulumi up` against the stage stack after a successful image push to ECR |
| 5 | +# This requires manual approval via the _staging_ environment protection rule |
| 6 | +# |
| 7 | +# Trigger options |
| 8 | +# - workflow_dispatch: manual trigger from GH Actions UI |
| 9 | +# - workflow_run: automatically after build-and-push succeeds on stage |
| 10 | +# |
| 11 | +# Authentication: GH OIDC -> AWS IAM role |
| 12 | +# Required secrets: PULUMI_ACCESS_TOKEN, PULUMI_PASSPHRASE |
| 13 | +# Required variables: AWS_ROLE_ARN |
| 14 | + |
| 15 | +name: deploy-stage |
| 16 | + |
| 17 | +concurrency: |
| 18 | + group: deploy-stage |
| 19 | + cancel-in-progress: false # To avoid cancelling in-progress deploys |
| 20 | + |
| 21 | +on: |
| 22 | + workflow_dispatch: |
| 23 | + inputs: |
| 24 | + preview_only: |
| 25 | + description: "Run pulumi preview only (no apply)" |
| 26 | + required: false |
| 27 | + default: "false" |
| 28 | + type: choice |
| 29 | + options: |
| 30 | + - "false" |
| 31 | + - "true" |
| 32 | + |
| 33 | + workflow_run: |
| 34 | + workflows: ["Build and Push to ECR"] |
| 35 | + types: [completed] |
| 36 | + branches: [stage] |
| 37 | + |
| 38 | +permissions: |
| 39 | + contents: read |
| 40 | + id-token: write # OIDC authn |
| 41 | + |
| 42 | +env: |
| 43 | + AWS_REGION: us-west-2 |
| 44 | + PULUMI_STACK: thunderbird/thunderbird-addons/stage |
| 45 | + |
| 46 | +jobs: |
| 47 | + # Gate: only proceed if the triggering workflow succeeded (or manual) |
| 48 | + check-trigger: |
| 49 | + runs-on: ubuntu-latest |
| 50 | + outputs: |
| 51 | + should-deploy: ${{ steps.check.outputs.result }} |
| 52 | + steps: |
| 53 | + - name: Evaluate trigger |
| 54 | + id: check |
| 55 | + run: | |
| 56 | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then |
| 57 | + echo "result=true" >> $GITHUB_OUTPUT |
| 58 | + elif [[ "${{ github.event.workflow_run.conclusion }}" == "success" ]]; then |
| 59 | + echo "result=true" >> $GITHUB_OUTPUT |
| 60 | + else |
| 61 | + echo "result=false" >> $GITHUB_OUTPUT |
| 62 | + echo "Skipping: triggering workflow did not succeed" |
| 63 | + fi |
| 64 | +
|
| 65 | + deploy: |
| 66 | + needs: check-trigger |
| 67 | + if: needs.check-trigger.outputs.should-deploy == 'true' |
| 68 | + runs-on: ubuntu-latest |
| 69 | + timeout-minutes: 30 |
| 70 | + environment: staging # Would require approval if environment protection rules are set |
| 71 | + steps: |
| 72 | + - name: Checkout repository |
| 73 | + uses: actions/checkout@v4 |
| 74 | + |
| 75 | + - name: Configure AWS credentials |
| 76 | + uses: aws-actions/configure-aws-credentials@v4 |
| 77 | + with: |
| 78 | + role-to-assume: ${{ vars.AWS_ROLE_ARN }} |
| 79 | + aws-region: ${{ env.AWS_REGION }} |
| 80 | + |
| 81 | + - name: Set up Python |
| 82 | + uses: actions/setup-python@v5 |
| 83 | + with: |
| 84 | + python-version: "3.13" |
| 85 | + |
| 86 | + - name: Install Pulumi CLI |
| 87 | + uses: pulumi/actions@v6 |
| 88 | + with: |
| 89 | + command: version |
| 90 | + |
| 91 | + - name: Install dependencies |
| 92 | + working-directory: infra/pulumi |
| 93 | + run: | |
| 94 | + python -m venv .venv |
| 95 | + source .venv/bin/activate |
| 96 | + pip install -r requirements.txt |
| 97 | +
|
| 98 | + - name: Pulumi preview |
| 99 | + working-directory: infra/pulumi |
| 100 | + env: |
| 101 | + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} |
| 102 | + PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_PASSPHRASE }} |
| 103 | + run: | |
| 104 | + source .venv/bin/activate |
| 105 | + pulumi stack select ${{ env.PULUMI_STACK }} |
| 106 | + pulumi preview --diff |
| 107 | +
|
| 108 | + - name: Pulumi up |
| 109 | + if: github.event.inputs.preview_only != 'true' |
| 110 | + working-directory: infra/pulumi |
| 111 | + env: |
| 112 | + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} |
| 113 | + PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_PASSPHRASE }} |
| 114 | + run: | |
| 115 | + source .venv/bin/activate |
| 116 | + pulumi stack select ${{ env.PULUMI_STACK }} |
| 117 | + pulumi up --yes --diff |
| 118 | +
|
| 119 | + - name: "Post-deploy: scale services to 0" |
| 120 | + if: github.event.inputs.preview_only != 'true' |
| 121 | + run: | |
| 122 | + echo "Scaling ECS services to 0 (safety: prevents writes to shared stage DB)" |
| 123 | + echo "Scale up manually after RO healthcheck validation" |
| 124 | + for svc in web worker versioncheck; do |
| 125 | + aws ecs update-service \ |
| 126 | + --cluster thunderbird-addons-stage-${svc} \ |
| 127 | + --service thunderbird-addons-stage-${svc} \ |
| 128 | + --desired-count 0 \ |
| 129 | + --region ${{ env.AWS_REGION }} \ |
| 130 | + --query 'service.[serviceName,desiredCount]' \ |
| 131 | + --output text |
| 132 | + done |
| 133 | +
|
| 134 | + - name: Post-deploy summary |
| 135 | + if: github.event.inputs.preview_only != 'true' |
| 136 | + working-directory: infra/pulumi |
| 137 | + env: |
| 138 | + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} |
| 139 | + PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_PASSPHRASE }} |
| 140 | + run: | |
| 141 | + source .venv/bin/activate |
| 142 | + echo "## Deploy Summary" >> $GITHUB_STEP_SUMMARY |
| 143 | + echo "" >> $GITHUB_STEP_SUMMARY |
| 144 | + echo "Stack: ${{ env.PULUMI_STACK }}" >> $GITHUB_STEP_SUMMARY |
| 145 | + echo "" >> $GITHUB_STEP_SUMMARY |
| 146 | + pulumi stack output --json | python -c " |
| 147 | + import sys, json |
| 148 | + outputs = json.load(sys.stdin) |
| 149 | + print('| Output | Value |') |
| 150 | + print('|--------|-------|') |
| 151 | + for k, v in sorted(outputs.items()): |
| 152 | + if isinstance(v, list): |
| 153 | + v = ', '.join(str(i) for i in v) |
| 154 | + print(f'| {k} | \`{v}\` |') |
| 155 | + " >> $GITHUB_STEP_SUMMARY |
| 156 | + echo "" >> $GITHUB_STEP_SUMMARY |
| 157 | + echo "Services scaled to 0. Run RO healthcheck before scaling up" >> $GITHUB_STEP_SUMMARY |
0 commit comments