Add the Cloud Build pipeline for the API, on Node 24 - #265
Conversation
Runs on pushes to main that touch backend/: the backend test suite, then build and push the image to us-east4 Artifact Registry tagged with the short SHA and latest. The deploy step is an image-only `gcloud run deploy`, so env, secrets and scaling stay as configured on the service; it is off (_DEPLOY=false) until the Render cutover, so merges can't start a second prod instance beside Render. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Node 22 the db-flush recovery tests are cancelled: they await a
deliberately hung query while only unref'd timers are pending, so the
test process exits early ("Promise resolution is still pending but the
event loop has already resolved"). The server itself is unaffected
(the HTTP listener keeps it alive), but CI would fail every build.
Node 24 (current LTS) passes all 1820 tests, and the server boots and
drains on SIGTERM with production-only deps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without dynamicSubstitutions, Cloud Build passed the literal
"${PROJECT_ID}" to docker build and the tag was rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
DevAsign Code Review
No issues found
✅ Merge score: 100/100
6 of 6 acceptance criteria met.
The Cloud Build pipeline and Node 24 bump are correct and satisfy all six acceptance criteria.
Tests: 5 passed, 1 unverifiable — see the "Tests by DevAsign" comment.
Met criteria (1)
- Acceptance criterion — The full backend test suite passes on Node 24 (all tests, including the db-flush recovery tests tha…
Tests by DevAsign✅ 5 of 6 criteria verified by tests, 1 unverifiable. Each verdict below links to its evidence. 1 — The Cloud Build config runs a test step executing the backend test suite via `npm ci && npm test` on a Node 24 base image (`node:24-bookworm-slim`). (pass)Verdict: pass The cloudbuild test step runs npm ci && npm test on node:24-bookworm-slim in the backend directory, per all four subtest assertions. Test: 2 — The Cloud Build config builds and pushes the API image tagged `us-east4-docker.pkg.dev//devasign-api/api` with both the `:$SHORT_SHA` tag and the `:latest` tag. (pass)Verdict: pass The _IMAGE resolves to the expected Artifact Registry path, and build/push tag both :$SHORT_SHA and :latest. Test: 3 — The deploy step is an image-only `gcloud run deploy devasign-api` that is gated by a `_DEPLOY` substitution defaulting to `"false"`, so with the default the deploy is skipped. (pass)Verdict: pass _DEPLOY defaults to false, the deploy is an image-only gcloud run deploy devasign-api gated on _DEPLOY==true, and the simulated guard skips deploy by default. Test: 4 — The image substitution expands `PROJECT_ID` (e.g. via dynamicSubstitutions) so the literal `${PROJECT_ID}` is not passed to docker build and the resulting tag is valid. (pass)Verdict: pass dynamicSubstitutions is enabled and both build and push steps reference ${_IMAGE} rather than a literal ${PROJECT_ID}. Test: 5 — The Dockerfile and CI configuration target Node 24 rather than Node 22. (pass)Verdict: pass Both backend/Dockerfile and cloudbuild.yaml target node:24-bookworm-slim with no reference to node:22. Test: 6 — The full backend test suite passes on Node 24 (all tests, including the db-flush recovery tests that were cancelled on Node 22). (unverifiable)Verdict: unverifiable The db-flush suite errored with pending Promise resolution and cancelled subtests, so it did not complete and cannot confirm the full suite passes on Node 24. Test: |
Phase 4 of moving the API from Render to Cloud Run: a pipeline that tests, builds and pushes the API image on every backend merge to
main. Deploys stay off until cutover.backend/cloudbuild.yamlnpm ci && npm testonnode:24-bookworm-slim. The backend suite now runs somewhere other than a laptop, and a merge can't produce an image unless it passes.us-east4-docker.pkg.dev/<project>/devasign-api/apiwith:$SHORT_SHAand:latest.gcloud run deploy devasign-api, so env, secrets, scaling and the runtime service account stay as configured on the service. It is gated by_DEPLOY(default"false") and will be switched on at cutover. Deploying on every merge before then would start a second prod instance next to Render, and two bounty keepers on the same escrow.It runs as a dedicated
devasign-deployerservice account, not the default compute account (which has project-widerun.admin). Its grants: Artifact Registry writer on thedevasign-apirepo only,run.developer,logging.logWriter,serviceAccountUserondevasign-apionly, and object viewer on the_cloudbuildsource bucket (for manualgcloud builds submit).Node 22 → 24 (Dockerfile and CI)
On Node 22, 10 db-flush recovery tests are cancelled: they await a deliberately hung query with only unref'd timers pending, so the test process exits early ("Promise resolution is still pending but the event loop has already resolved"). The running server isn't affected, because its HTTP listener keeps the process alive, but every CI build would fail. Node 24 is the current LTS and passes everything.
Verification
/api/healthreturns 200, and SIGTERM drains and exits 0.db-flush.test.ts). This is the failure above.fb9d1d9f, asdevasign-deployer): test 1820/1820 (418s), build, push (api:26996a8,latest), deploy skipped with "Deploy disabled (_DEPLOY=false)". SUCCESS.After merge
The
devasign-api-maintrigger (push to^main$,backend/**, ignoringbackend/deploy/**and*.md) gets created oncedevasignhq/agentis connected in Cloud Build → Repositories (1st gen), which is a one-time console step.🤖 Generated with Claude Code