Skip to content

Deploy Worker on release with post-deploy smoke test + rollback#24

Open
sergical wants to merge 1 commit into
mainfrom
ci/deploy-on-release
Open

Deploy Worker on release with post-deploy smoke test + rollback#24
sergical wants to merge 1 commit into
mainfrom
ci/deploy-on-release

Conversation

@sergical

Copy link
Copy Markdown
Member

Automates Worker deployment so production tracks released versions — fixing the gap that left prod on 0.2.0 while we'd released 0.3.1/0.4.0.

What

  • .github/workflows/deploy.yml — triggers on release: published (craft's GitHub Release) and workflow_dispatch. Steps: pnpm run deploy → wait → smoke test → wrangler rollback if the smoke fails.
  • bin/smoke.mjs (+ pnpm smoke) — MCP initialize handshake against the live /mcp endpoint, asserting the worker is reachable and reports the just-released version. Verified locally: passes on 0.4.0, fails on a mismatch.

Why release-triggered (not on-main)

Deploy-on-main would ship unreleased commits while serverInfo.version stayed frozen at the last release — the drift we just fixed, reintroduced. Triggering on the release tag keeps prod == a released version and the smoke test asserts exactly that. (sentry-mcp deploys continuously on main + canary; we don't have canary infra and prefer version-pinned deploys here.)

Required repo secrets (add before enabling)

  • CLOUDFLARE_API_TOKEN — account-scoped "Edit Cloudflare Workers" (CF tokens can't scope to a single Worker; account-scoped is the tightest).
  • CLOUDFLARE_ACCOUNT_ID
  • SENTRY_AUTH_TOKEN — for the release + sourcemap upload.

Follow-up (not in this PR)

pnpm deploy runs the deploy script despite deploy being a pnpm builtin — an easy footgun (even pnpm deploy --help runs it). Consider renaming the script to deploy:cf. The workflow uses the explicit pnpm run deploy.

🤖 Generated with Claude Code

Deploys the Worker to Cloudflare when a new version is released (on
release: published), so production always tracks a released tag rather than raw
main — keeping serverInfo.version honest. Also runnable via workflow_dispatch.

- deploy.yml: pnpm run deploy (wrangler + Sentry release/sourcemaps, all via env
  tokens — no interactive login) → wait → smoke test → wrangler rollback if the
  smoke test fails.
- bin/smoke.mjs (+ `pnpm smoke`): MCP initialize handshake against the live /mcp
  endpoint asserting the worker is up and reports the released version.

Requires repo secrets: CLOUDFLARE_API_TOKEN (account-scoped "Edit Cloudflare
Workers"), CLOUDFLARE_ACCOUNT_ID, SENTRY_AUTH_TOKEN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread bin/smoke.mjs
Comment on lines +69 to +70
if (EXPECTED && serverInfo.version !== EXPECTED)
fail(`version mismatch: live=${serverInfo.version} expected=${EXPECTED}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The server version is hardcoded in src/server.ts, but the smoke test compares it against the dynamic version from package.json, which will cause future deployment failures.
Severity: CRITICAL

Suggested Fix

To prevent future deployment failures, replace the hardcoded version string in src/server.ts. Import the version from package.json directly into src/server.ts so that the server always reports the correct, current version. This ensures the smoke test will pass after a version bump.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: bin/smoke.mjs#L69-L70

Potential issue: The server's version is hardcoded as "0.4.0" in `src/server.ts`.
However, the smoke test in `bin/smoke.mjs` dynamically reads the expected version from
`package.json`. While both versions currently match, any future update to the
`package.json` version for a new release will cause a mismatch. This will lead the smoke
test to fail with a "version mismatch" error, consequently breaking the automated
deployment pipeline for all subsequent releases.

Also affects:

  • src/server.ts

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validated as a false positive — no change needed.

src/server.ts and package.json don't drift: bin/bump-version.sh (added in #23, craft's preReleaseCommand) seds the released version into src/server.ts on every release, with a grep -q guard that fails the release loudly if the substitution doesn't take. deploy.yml triggers on the release tag, so the checked-out commit always has server.ts == package.json (confirmed: both 0.4.0 on main today).

So the smoke test comparing the live serverInfo.version to package.json is an intentional end-to-end check on that sync — if it ever broke, the smoke fails and the deploy rolls back. That's the guard working as designed, not a latent failure.

The suggested fix (import the version from package.json into server.ts) is the approach we deliberately rejected in #23: the same createServer() is bundled into the Cloudflare Worker, which has no filesystem, and a JSON import breaks the tsc rootDir layout. The build-time sed is what works for both targets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant