Implement canary deployment strategy with separate workers #7
Workflow file for this run
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: Canary | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| statuses: write # Required for creating commit statuses | |
| deployments: write # Required for creating deployment records | |
| jobs: | |
| preview: | |
| name: Deploy and Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| # pnpm/action-setup@v4 | |
| - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda | |
| name: Install pnpm | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache@v4 | |
| name: Setup pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Build | |
| run: pnpm build | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| - name: Create GitHub Deployment | |
| id: deployment | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const deployment = await github.rest.repos.createDeployment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: context.payload.pull_request.head.sha, | |
| environment: 'canary', | |
| description: `Canary deployment for PR #${{ github.event.pull_request.number }}`, | |
| transient_environment: true, | |
| production_environment: false, | |
| required_contexts: [], | |
| auto_merge: false, | |
| payload: JSON.stringify({ | |
| pr_number: ${{ github.event.pull_request.number }}, | |
| branch: '${{ github.head_ref }}', | |
| deployed_at: new Date().toISOString() | |
| }) | |
| }); | |
| core.setOutput('id', deployment.data.id); | |
| // Set initial status | |
| await github.rest.repos.createDeploymentStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| deployment_id: deployment.data.id, | |
| state: 'in_progress', | |
| description: 'Deploying canary environment', | |
| auto_inactive: true // Auto-mark previous deployments as inactive | |
| }); | |
| - name: Deploy Canary Worker | |
| id: deploy | |
| uses: cloudflare/wrangler-action@v3 | |
| with: | |
| apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| workingDirectory: packages/mcp-cloudflare | |
| command: deploy --name sentry-mcp-pr-${{ github.event.pull_request.number }} | |
| packageManager: pnpm | |
| - name: Get Canary URL | |
| id: canary_url | |
| run: | | |
| # Worker URL format: <worker-name>.<subdomain>.workers.dev | |
| CANARY_URL="https://sentry-mcp-pr-${{ github.event.pull_request.number }}.getsentry.workers.dev" | |
| echo "url=$CANARY_URL" >> $GITHUB_OUTPUT | |
| echo "Canary URL: $CANARY_URL" | |
| - name: Update Deployment Status | |
| if: always() | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const deploySuccess = '${{ steps.deploy.outcome }}' === 'success'; | |
| const canaryUrl = '${{ steps.canary_url.outputs.url }}'; | |
| // Update GitHub deployment status | |
| await github.rest.repos.createDeploymentStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| deployment_id: ${{ steps.deployment.outputs.id }}, | |
| state: deploySuccess ? 'success' : 'failure', | |
| environment_url: deploySuccess ? canaryUrl : undefined, | |
| description: deploySuccess ? 'Canary deployed successfully' : 'Deployment failed', | |
| auto_inactive: false | |
| }); | |
| // Also create a commit status for visibility | |
| try { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.payload.pull_request.head.sha, | |
| state: deploySuccess ? 'success' : 'failure', | |
| target_url: deploySuccess ? canaryUrl : `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, | |
| description: deploySuccess ? 'Canary environment ready' : 'Deployment failed', | |
| context: 'Canary URL' | |
| }); | |
| } catch (error) { | |
| console.error('Failed to create commit status:', error); | |
| } | |
| - name: Wait for deployment to propagate | |
| if: success() | |
| run: | | |
| echo "Waiting for deployment to propagate..." | |
| sleep 30 | |
| - name: Run Smoke Tests | |
| id: smoke_tests | |
| if: success() | |
| working-directory: packages/smoke-tests | |
| env: | |
| PREVIEW_URL: ${{ steps.canary_url.outputs.url }} | |
| run: | | |
| echo "Running smoke tests against $PREVIEW_URL" | |
| pnpm test:ci | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857 | |
| if: always() && steps.smoke_tests.outcome != 'skipped' | |
| with: | |
| report_paths: "**/tests.junit.xml" | |
| check_name: "Smoke Test Results" | |
| fail_on_failure: false | |
| - name: Update Commit Status with Test Results | |
| if: always() && steps.deploy.outcome == 'success' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const testsSuccess = '${{ steps.smoke_tests.outcome }}' === 'success'; | |
| let state = testsSuccess ? 'success' : 'failure'; | |
| let description = testsSuccess ? 'Passed' : 'Failed'; | |
| try { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.payload.pull_request.head.sha, | |
| state: state, | |
| target_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, | |
| description: description, | |
| context: 'Smoke Tests' | |
| }); | |
| } catch (error) { | |
| console.error('Failed to create commit status:', error); | |
| } |