fix(ci): check CONTRIBUTING links, not just the README's - #353
Conversation
check-readme-links.sh read README.md and nothing else, so a dead link in CONTRIBUTING.md — the file a first-time contributor reads — passed all sixteen checks. Two fixtures make the gate fail on the shapes that slipped through: a misspelled org repository (vyncint#351) and a renamed in-repo target. The README's absolute-only rule is crates.io's and stays on README.md alone: CONTRIBUTING is not packaged and legitimately links AGENTS.md, docs/RELEASING.md and .github/workflows/ci.yml relatively, so pointing the old script at it would have failed on all three. Both files now get the rule that generalises — an in-repo target must exist — and a link naming no in-repo path is checked against the org list, offline. Signed-off-by: jarik2014 <46443045+jarik2014@users.noreply.github.com>
The allow-list held four names and the comment called them "the four that share this contributor pattern". Two more projects have joined the pattern since (oxmera, oxidelake), and `docs/DESIGN.md` already links `vyncint/termlens-demo` for the coverage study. So a real, already-linked repository was reported as "names no repository in the org" — a false claim, and the kind a gate should never make. It costs nothing today, because the gate reads README.md and CONTRIBUTING.md and neither links those three. It would cost the next person something: the file list is a parameter now precisely so the gate can be pointed at more files, and DESIGN.md is the obvious next one. The list stays deliberately short rather than becoming every repository the account holds — a list of everything would wave through the typo this exists to catch. What changes is that the message no longer claims the repository does not exist, only that this gate has not been told about it, and says how to add one. The good fixture links termlens-demo, so the distinction is pinned rather than argued. Signed-off-by: Vyncint Ng <vyncint@icloud.com>
vyncint
left a comment
There was a problem hiding this comment.
Thanks — this is an unusually complete piece of work, and it closes #352 on every point.
I checked each Done-when item against your branch rather than taking the evidence in the description on trust:
- A misspelled
vyncint/temlenslink inCONTRIBUTING.mdfails, and the selftest pins it. - A renamed in-repo target linked from
CONTRIBUTING.mdfails. - The absolute-only rule still applies to
README.mdalone, and CONTRIBUTING's six legitimate relative links still pass. - The reason the two rules differ is in the script header, where the next person editing either half will actually read it.
The selftest is the part I liked most. Proving the gate can go red before trusting it to be green is what tools/semver-gate-selftest/ established, and following that shape without being asked is the right instinct. Running it in gates-listed is the right home for it too, since it is shell-only and single-OS.
One thing I pushed a commit for
known_repos held four names and the comment called them "the four that share this contributor pattern". That was true when the pattern was written down and is not any more: oxmera and oxidelake have since joined it, and docs/DESIGN.md already links vyncint/termlens-demo for the coverage study. So the gate reported a real, already-linked repository as names no repository in the org.
It costs nothing today, because the gate reads two files and none of those three appear in them. It would have cost the next person, though, and precisely because of what you built: the file list is a parameter now, so pointing the gate at docs/DESIGN.md is the obvious next step, and it would have failed on a correct link with a message asserting something false.
What I changed:
- The list gains
oxmera,oxidelakeandtermlens-demo. It stays deliberately short rather than becoming every repository the account holds, for your reason: a list of everything waves through the typo the gate exists to catch. - The message no longer claims the repository does not exist. It says the gate has not been told about it, and how to add one. A gate should not assert a falsehood while failing.
- The good fixture links
termlens-demo, so the distinction between "typo" and "real but unlisted" is pinned instead of argued.
Your temlens fixture still fails, which is the thing that matters.
Two notes on what you said you did not do, and I agree with both. No CHANGELOG entry is right, since nothing here is user-facing. And leaving the rename for a follow-up is right too, since it touches ci.yml, CONTRIBUTING.md and a CHANGELOG entry naming the old spelling. If you want to do that follow-up, I will take it.
What was broken
.github/scripts/check-readme-links.shreadREADME.mdand nothing else, soCONTRIBUTING.md— the file a first-time contributor reads, and the one mostlikely to accumulate link rot because it points at scripts and workflows that
get renamed — had no link check at all.
#351proved it: a link one lettershort of the repository name sat in
CONTRIBUTING.mdand all sixteen checksreported success.
What this changes
The script now takes a file list and gives each file the rule that applies:
resolved against the repository root, which is where both files live.
README.mdonly. That rule is crates.io's:crates/termlens/Cargo.tomlsetsreadme = "../../README.md", so a relativelink is rewritten against the crate directory.
CONTRIBUTING.mdis notpackaged and legitimately links
AGENTS.md,docs/RELEASING.mdand.github/workflows/ci.ymlrelatively — pointing the old script at it wouldhave failed on all of those, which is why
#351did not simply do it.github.com/vyncint/<repo>is assertedagainst the four repositories in the org, offline. That is what catches
temlens. It stays offline on purpose: a link checker that asks GitHub isonline, flaky, and can report a 200 for the wrong reason, which is the
failure mode this gate exists to avoid.
Why the two rules differ is now written down in the script header, next to the
reason for each, and the two commands are listed in
CONTRIBUTING.md§1 withthe rest of the gates.
tools/link-gate-selftest/run.shproves the gate can fail before it is trustedto pass, in the shape
tools/semver-gate-selftest/already uses: five fixturesthat must go red, and two runs that must stay green — the fixture that models
what
CONTRIBUTING.mdlegitimately does, and this repository's own two files.CI runs it in
gates-listed, which is shell-only and single-OS.Evidence
Done whenitem by item, from this branch (tools/link-gate-selftest/run.sh):And the same gate against the real files with each fault introduced by hand
and reverted, which is the deliberate failing run the issue asks for:
With the three files restored, the gate and the docs-consistency gate CI already
runs both stay green:
What I did not do
CHANGELOG.mdentry: nothing here is user-facing, it is the contributorgate itself. Say the word if you want one anyway.
check-readme-links.shalthough it now reads twofiles. A rename touches
ci.yml,CONTRIBUTING.mdand aCHANGELOG.mdentry that names the old spelling, so I kept it out of this diff — happy to
do it in a follow-up if you prefer the honest name.
known_repos), not a network call. If afifth repository ever lands, the gate fails on its links until the list grows
by one word, which seemed the right trade against a flaky external check.
Closes #352