Repository navigation
219 lines (192 loc) · 8.52 KB
/
Copy pathdeploy.yml
File metadata and controls
219 lines (192 loc) · 8.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
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