Skip to content

#34 deploy.sh: gate a deploy on the commit's CI - #36

Merged
gregoryfoster merged 10 commits into
mainfrom
34-deploy-ci-gate
Oct 6, 2026
Merged

gregoryfoster merged 10 commits into
mainfrom
34-deploy-ci-gate

Conversation

@gregoryfoster

Copy link
Copy Markdown
Contributor

Closes #34.

scripts/deploy.sh now asks GitHub whether the commit's CI passed before it builds anything. This is Status's gate (status#11), ported. Plan: docs/plans/2026-10-06-34-deploy-ci-gate.md.

What the gate checks

  • The run: the newest push run of ci.yml on main for exactly this SHA. A pull_request twin, a dispatch, or a push elsewhere doesn't count.
  • The verdict: the run's conclusion and every job's must be success, with CI_JOBS=(lint test) as a floor. A test holds ci.yml to that floor.
  • A pending run (or the tip's run, not yet queued) is waited for, up to 600 s, polling every 30 s.
  • A commit behind the tip with no run is refused at once, with one API call. An FF merge pushes every commit, and CI runs only on the tip.
  • cancelled says to re-run it, since a re-run counts. On Spec §6: the cross-repo notices never posted (replicator charter, archiver#179, cannobserv, observo token) #23's PR a run timed out unscheduled.
  • GitHub refusing (a 403 rate limit, a 5xx, a timeout, non-JSON runs or jobs) refuses with GitHub's message and the --skip-ci hint, and builds nothing. It never passes.
  • --skip-ci skips the gate, and is logged before the build.
  • Logs: logger -t processor-deploy, either "CI passed for : " or "CI not checked for (--skip-ci)".

Rollbacks: option (a). The gate applies to every deploy, rollbacks included, and --skip-ci is the logged escape. A kept release proves it was built, not that its CI passed. Option (b) would need a ledger of verified deploys, which the script doesn't keep. Every deploy so far was the tip of its push, so a normal rollback passes. test_a_rollback_is_gated_too pins this.

Dropped from Status: --dev, the live/dev branching, and the "put it on dev" remedy.

Docs: DEPLOYMENT has a new § The CI gate. It covers the intermediate-commit refusal, the rollback rule and the rate limit. The variables table, the prerequisites (curl, api.github.com), § Rollback and the AGENTS command line are updated too.

Tests: 37 new, against a stubbed curl and never the real API. They cover every case in the hand-off, plus:

  • a failed job the checkout doesn't know;
  • the newest of two push runs;
  • a run that finishes within the wait.

The full suite gives 411 passed and 4 skipped.

I checked the real API's answer by hand for fe19a2b (run 37499560960): one push run on main, with jobs lint and test, about 2.5 min.

After the FF merge: git pull --ff-only, then scripts/deploy.sh with the new script. Evidence to collect:

  • the "CI passed" journal line;
  • the usual verify;
  • one harmless refusal of an intermediate commit of this PR, 3d04ee9.

🤖 Generated with Claude Code

gregoryfoster and others added 10 commits October 6, 2026 20:08
The plan, and the red tests: status#11's gate cases ported, plus processor's
own (an intermediate commit of an FF push, a pull_request twin run, a gated
rollback, GitHub timing out).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
status#11's gate, ported between `build=` and the build, so a refusal builds
nothing: the newest push run of ci.yml on main for exactly this SHA, its
conclusion and every job's `success`, lint and test as the floor. A pending
run is waited for (600 s); a commit behind the tip with no run is refused at
once (an FF push runs CI on its tip only); cancelled says re-run it; GitHub
refusing never passes. Rollbacks are gated too (option a); --skip-ci is the
logged escape. No --dev target here, and the log tag is processor-deploy.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ci.yml's comment said runs on main are never cancelled

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…rvice exactly as they were

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…NDS tick cannot flake it

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…pty jobs body passed the gate

jq reads an empty body as no input: it prints nothing and exits 0, so no job
looked failed and a run concluded success passed. github() now accepts a JSON
object only.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.

deploy.sh: gate a deploy on the commit's CI (status#11's CI gate)

1 participant