Skip the test gate on docs-only branches #34
Reference in New Issue
Block a user
Delete Branch "ci-docs-only-skip"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
ci.ymlskipsbash ci.shwhen every path a branch changes against its merge-base withmainends in.md.The job still runs and still builds + pushes the commit-hash image —
CI / full-gate (push)stays green for the merge gate, andrelease.ymlstill finds an image for everymaincommit. Anything else in the diff, an empty diff, or an unreadable range falls through to the full gate.@@ -12,0 +12,4 @@fetch-depth: 0 # the merge-base below needs history; checkout defaults to depth 1- name: Detect a docs-only branchid: scoperun: |There is a bunch of scripts here in "run". Could this be written in the ci.sh script instead, to make this all testable locally?
Agreed — moved in
175717f. The whole decision is now adocs_only()function at the top ofci.sh, and the workflow is back to a plain- run: bash ci.sh(it keeps onlyfetch-depth: 0, since a shallow clone has no merge-base to compare against).So
bash ci.shon your branch now tells you exactly what CI will do. Two things that fell out of moving it:main, no merge-base) falls through to the full gate, never to a skip.Verified against a throwaway repo with its own origin — real
bash ci.shon a docs-only branch exits 0 without touching docker, and the function across the rest:*.mdonly*.md.ts*.mdrenamed to*.tsOne thing I could not do: unit-test the git plumbing in the normal suite — the test container is
node:24-alpineand has nogit, and adding it just for that felt like the wrong trade.src/ci-gate.test.tscovers what is checkable from the files: the decision lives inci.shand not the workflow, checkout stays unshallow, and the image push is never conditioned (release.yml needs an image for everymaincommit).@@ -11,1 +11,4 @@with:fetch-depth: 0 # ci.sh's docs-only check needs history; checkout defaults to depth 1- run: bash ci.sh# Runs even when ci.sh no-ops on a docs-only branch: release.yml re-tags this exact image, andRemove this comment, it is the inner workings of ci.sh and should be obvious if you read the shell scripts code. It is also not very important to know when you are day to day developing.
@@ -1166,6 +1166,12 @@ Each E2E suite **owns a clean stack** — never point two suites at one backendrevokes the admin's sessions; full-flow writes users/groups/roles to Keto), which is why thegate runs them serially, one stack up/down per suite.It **no-ops on a docs-only change** — when every path that differs from `main` (committed *and*Does this really help anyone? If someone really wants to know why some runs went faster than others, then can quickliy find out why by looking at the logs or reading the ci.sh script. This big blob of text in the README only makes it cluttered and harder to consume for both humans and machines. Please fix this and also adjust the projects AGENTS.md to not do this kind of documentation in these places again.
@@ -1188,6 +1194,12 @@ no repo files involved): direct pushes are blocked, changes land via PR only, th**fast-forward-only** — history stays linear and `main`'s head is the exact commit hash ofthe merged branch, which is why the branch's push-triggered status carries over.**Docs-only branches skip the gate** — [`ci.sh` no-ops](#the-full-gate-one-command) when a branchMore of the same as the previous comment. Look through the README to see if there are more stuff like this we can remove that is not relevant for the day to day developer and can be easily found out if you dig into the code.
Removed in
6db0f57.The one comment I kept in
ci.ymlisfetch-depth: 0's — that one is not about ci.sh, it records thatactions/checkoutdefaults to depth 1, so dropping the line silently breaks the check with no error. Say the word if you want it gone too.The invariant the removed comment was carrying (image push must never be conditioned) is asserted in
src/ci-gate.test.ts, which is where it actually holds.You're right — both blobs are gone in
6db0f57, along with the clause I had added to theci.shline in the file map. The only trace left in the README is six words in the existing workflow table (bash ci.sh, a no-op on a docs-only branch), since that table's job is to say what each workflow does. Happy to drop that too if you'd rather have nothing.AGENTS.mdgained a rule under README structure: don't document internals there — how a script reaches a decision, why one run behaved differently, what a function guards. It belongs in the code it describes, or nowhere. The README earns its length on what you can't dig out: usage, operation, external contracts, one-time setup.On the wider sweep you asked for — I read the whole thing. Two more places recited an algorithm that already lives in a linked, unit-tested script, so I compressed them in the same commit:
sha256:…child manifests go too. Now:registry-cleanup/cleanup.tsdefines what survives. The operational warning next to it (don't add a pattern-based org cleanup rule) stays — that one is a Gitea setting you can't learn from the code.major→minor,minor/patch→patch pre-1.0 mapping, restated fromnext-version.ts. Now just: it never auto-crosses into1.0.0, which stays a hand-cut tag. TheRelease-Bumptrailer and the renovate-bot-PAT-or-it-won't-fire constraint stay — both are external facts.Net for the README across this PR: -33 lines, +10.
One judgment call I did not make on my own: the per-suite prose in End-to-end (Playwright) (~70 lines) is the same pattern — it narrates what each spec asserts and why the full-flow suite needs a same-origin proxy, all readable in the specs. But unlike a script's internals, a short "what does this suite cover" line genuinely helps you pick which suite to run. I'd cut each suite down to one sentence plus its run command, roughly halving the section. Want that, here or as its own PR?
I left the rest alone deliberately: Architecture (the system's shape, not internals), the Ory/cookie and canonical-host explanations (real footguns you'd hit blind), and every one-time-setup block (secrets, accounts, tokens — nowhere in the code).