Repository navigation
Deploy to Cloudflare #715
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: Deploy to Cloudflare | |
| permissions: | |
| contents: read | |
| deployments: write | |
| checks: write | |
| on: | |
| workflow_run: | |
| workflows: ["Test"] | |
| types: | |
| - completed | |
| branches: [main] | |
| concurrency: | |
| group: mcp-production-deploy | |
| cancel-in-progress: false | |
| jobs: | |
| deploy: | |
| name: Deploy to Cloudflare | |
| runs-on: ubuntu-latest | |
| environment: production | |
| if: >- | |
| ${{ github.event.workflow_run.conclusion == 'success' && | |
| github.event.workflow_run.event == 'push' && | |
| github.event.workflow_run.head_repository.id == github.event.repository.id && | |
| github.event.workflow_run.head_branch == 'main' }} | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| with: | |
| ref: ${{ github.event.workflow_run.head_sha }} | |
| persist-credentials: false | |
| - name: Require tested revision on main | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EXPECTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: | | |
| current_sha="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/heads/main" --jq '.object.sha')" | |
| if [[ "$current_sha" != "$EXPECTED_SHA" ]]; then | |
| echo 'The tested revision is no longer at main; refusing deployment.' >&2 | |
| exit 1 | |
| fi | |
| - name: Setup Node.js | |
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: "22" | |
| # 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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 | |
| 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 --frozen-lockfile | |
| # Upload one production Worker version. A version includes code, assets, | |
| # bindings and compatibility settings; the upload does not move traffic. | |
| - name: Build | |
| run: pnpm --filter '@sentry/mcp-cloudflare...' run build | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} | |
| VITE_SENTRY_ENVIRONMENT: production | |
| - name: Capture active production version | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: node scripts/cloudflare-deployment.mjs capture | |
| - name: Upload production version without moving traffic | |
| id: upload | |
| working-directory: packages/mcp-cloudflare | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| WRANGLER_OUTPUT_FILE_PATH: ${{ runner.temp }}/wrangler-upload.jsonl | |
| run: | | |
| test -s dist/client/index.html | |
| test -s dist/sentry_mcp/wrangler.json | |
| pnpm exec wrangler versions upload --experimental-auto-create=false \ | |
| --config dist/sentry_mcp/wrangler.json \ | |
| --assets dist/client \ | |
| --message "toolkit-mcp:$GITHUB_RUN_ID:$GITHUB_RUN_ATTEMPT:$TESTED_SHA:upload" | |
| - name: Identify uploaded production version | |
| id: uploaded | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| WRANGLER_OUTPUT_FILE_PATH: ${{ runner.temp }}/wrangler-upload.jsonl | |
| run: node scripts/cloudflare-deployment.mjs uploaded | |
| - name: Require tested revision on main before staging | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EXPECTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: | | |
| current_sha="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/heads/main" --jq '.object.sha')" | |
| if [[ "$current_sha" != "$EXPECTED_SHA" ]]; then | |
| echo 'Main advanced before candidate staging; refusing deployment.' >&2 | |
| exit 1 | |
| fi | |
| - name: Stage exact candidate at zero percent | |
| id: stage | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: node scripts/cloudflare-deployment.mjs stage | |
| - name: Wait for staged candidate to propagate | |
| run: sleep 30 | |
| - name: Smoke test exact production Worker version | |
| id: candidate_smoke_tests | |
| env: | |
| PREVIEW_URL: https://mcp.sentry.dev | |
| CLOUDFLARE_WORKER_NAME: sentry-mcp | |
| CLOUDFLARE_VERSION_OVERRIDE: ${{ steps.uploaded.outputs.candidate_version }} | |
| EXPECTED_VERSION_ID: ${{ steps.uploaded.outputs.candidate_version }} | |
| run: | | |
| cd packages/smoke-tests | |
| pnpm test:ci | |
| - name: Publish Candidate Smoke Test Report | |
| uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857 | |
| if: always() && steps.candidate_smoke_tests.outcome != 'skipped' | |
| with: | |
| report_paths: "packages/smoke-tests/tests.junit.xml" | |
| check_name: "Candidate Smoke Test Results" | |
| fail_on_failure: false | |
| - name: Require tested revision on main before promotion | |
| if: steps.candidate_smoke_tests.outcome == 'success' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| EXPECTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: | | |
| current_sha="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/heads/main" --jq '.object.sha')" | |
| if [[ "$current_sha" != "$EXPECTED_SHA" ]]; then | |
| echo 'Main advanced during candidate testing; refusing promotion.' >&2 | |
| exit 1 | |
| fi | |
| - name: Promote tested version to production | |
| id: promote | |
| if: steps.candidate_smoke_tests.outcome == 'success' | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: node scripts/cloudflare-deployment.mjs promote | |
| - name: Verify production deployment ownership | |
| id: verify_production | |
| if: steps.promote.outcome == 'success' | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: node scripts/cloudflare-deployment.mjs verify | |
| - name: Wait for Production to Propagate | |
| if: steps.verify_production.outcome == 'success' | |
| run: | | |
| echo "Waiting 30 seconds for production deployment to propagate..." | |
| sleep 30 | |
| # === SMOKE TEST PRODUCTION === | |
| - name: Run Smoke Tests on Production | |
| id: production_smoke_tests | |
| if: steps.verify_production.outcome == 'success' | |
| env: | |
| PREVIEW_URL: https://mcp.sentry.dev | |
| EXPECTED_VERSION_ID: ${{ steps.uploaded.outputs.candidate_version }} | |
| run: | | |
| echo "Running smoke tests on production..." | |
| cd packages/smoke-tests | |
| pnpm test:ci | |
| - name: Recover captured previous version if owned transition fails | |
| if: failure() && steps.uploaded.outcome == 'success' && steps.stage.outcome != 'skipped' | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| TESTED_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: node scripts/cloudflare-deployment.mjs recover | |
| # Report publication must not turn a verified promotion into a rollback. | |
| - name: Publish Production Smoke Test Report | |
| uses: mikepenz/action-junit-report@cf701569b05ccdd861a76b8607a66d76f6fd4857 | |
| if: always() && steps.production_smoke_tests.outcome != 'skipped' | |
| with: | |
| report_paths: "packages/smoke-tests/tests.junit.xml" | |
| check_name: "Production Smoke Test Results" | |
| fail_on_failure: false |