ci: gate the CDN purge on the real Railway deployment status - #1193
Draft
vivek7405 wants to merge 2 commits into
Draft
ci: gate the CDN purge on the real Railway deployment status#1193vivek7405 wants to merge 2 commits into
vivek7405 wants to merge 2 commits into
Conversation
The first version inferred the deploy by watching the origin's /__webjs/version uptime for a restart, on the assumption that every push to main produces a Railway deploy. It does not. Railway marked #1189's own merge commit SKIPPED (it touched only .github and a .md), so no restart ever happened, the wait ran its full 15 minute budget, and the job failed. Left alone it would red-X every docs-only and CI-only commit, and a job that cries wolf on routine commits stops being read. Ask Railway instead of guessing. Its GraphQL API returns, per deployment, both a status and the originating meta.commitHash, so the job now resolves the deployment for github.sha and branches on the real status: SUCCESS purges, SKIPPED exits 0 with a notice (nothing was deployed, so nothing is stale), FAILED / CRASHED / REMOVED exit 0 with a warning (no new content reached the origin), anything in progress keeps polling. An unresolved deployment now warns and leaves the run GREEN rather than failing, which is the whole point. The purge and verify steps become conditional on that outcome, and workflow_dispatch still purges immediately with no wait. Two API details worth keeping: Railway sits behind Cloudflare, which answers `error code: 1010` to automated-looking user agents (python urllib is blocked outright, curl is fine), and a GraphQL error arrives with HTTP 200 plus an `errors` array, so the status code alone proves nothing. Token type is not knowable ahead of time either, since a project token uses Project-Access-Token and an account token uses Authorization: Bearer, so both are tried. Verified by exercising the extraction and branching against the real response shape for both known commits: 93883bb resolves to SKIPPED (the commit that broke the previous version, now a clean no-op) and 086b3c7 to SUCCESS. Closes #1192
Review of the new gating step found two defects of the same class: both turned a misconfiguration into a GREEN run that silently never purges, which is precisely the failure the workflow exists to catch. 1. `meta` may arrive as an object or as a JSON-encoded string, and this was not verifiable against the live API beforehand. Indexing a string with `.commitHash` is a jq ERROR rather than a null, so the unguarded filter would have swallowed every response, polled to the deadline and reported green without ever purging. Normalize both shapes, and leave a null `meta` resolving to empty so it keeps polling instead of crashing. 2. A wrong, expired, or mis-scoped RAILWAY_TOKEN produced an auth error on every poll, which read as "no deployment yet" and ended in the same green no-op. Track whether ANY clean response ever arrived: none means the credential or endpoint is wrong, so exit 1 and print the server's own error body (never the token). "Answered fine but the sha never reached a terminal status" stays a warning and stays green, which is the case #1192 was about. Also dump the deployments actually seen on the timeout path, so a field-name or response-shape mismatch is diagnosable in the log instead of looking identical to "the deploy never happened". Verified: object, string, and null `meta` all resolve without a jq crash, and the bad-token path exits 1 carrying the API's message.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The purge workflow from #1189 inferred the deploy from the origin's
/__webjs/versionuptime, assuming every push tomainproduces a Railway deploy. It doesn't. Railway marked #1189's own merge commit SKIPPED (it touched only.githuband a.md), so no restart happened, the wait burned its full 15 minutes, and the job failed. Left as-is it red-Xes every docs-only and CI-only commit.Now it asks Railway directly. The GraphQL API returns per-deployment
statusplusmeta.commitHash, so the job resolves the deployment forgithub.shaand branches on the real status:SUCCESSSKIPPEDFAILED/CRASHED/REMOVEDWhy a separate workflow, not
release.ymlrelease.ymlfires only on pushes touchingchangelog/**(an npm package release). None of the four website merges on 2026-07-30 touchedchangelog/, so a purge living there would have fired for none of them, including the SVG mask fix that is still stale at the edge.Test plan
runblocks passbash -n93883bbcresolves toSKIPPED(the commit that broke v1, now a clean no-op) and086b3c75toSUCCESSset -eguard verified: a non-JSON body (Cloudflare'serror code: 1010page) does not abort the stepframework-dev.mdupdated: heuristic description replaced,RAILWAY_TOKENdocumented with token type and header, repository-vs-environment secret gotcha called outmainNotes
error code: 1010to automated-looking user agents (pythonurllibis blocked outright,curlis fine).errorsarray, so the status code alone proves nothing; the check asserts.errors == null.Project-Access-Token, account tokens useAuthorization: Bearer. Which applies depends on the token created, so both are tried.Closes #1192