Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions .github/scripts/check-package-enumeration.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@
through it. That is the one thing the guard can call without knowing how each repo spells its walk
(a comprehension in five, `is_course_dir` in Education).

🚨 A caller that does not expose it YET is NAMED — `NOT compared` on a `::warning::` line — and does
not fail. Adoption is one PR per satellite; red-on-absence before they land would red every
satellite's required `validate` context for a condition none of them can fix without that PR (the
fleet-wide-red shape). The flip to red is a change to THIS file once every caller exposes the
function, never a date. Everything else is RED: a missing or unloadable validate-repos.py, a
`package_dirs` that raises or returns a non-list, a `main()` that does not call `package_dirs` or
also walks the tree itself (`iterdir()`), an unloadable canonical, and any disagreement.
🚨 A caller that does not expose it is RED. Until every satellite had adopted, an absent function was
only NAMED (`NOT compared`, a `::warning::`): red-on-absence before the adoption PRs landed would have
reddened every satellite's required `validate` context for a condition none of them could fix without
that PR (the fleet-wide-red shape). The flip came once every caller of the shared validate lane exposed
the function — MeshWeaver.Education#391 was the last — so a NEW node repo now adopts it on day one,
and one that drops it is told so instead of going uncompared. Everything else was always RED: a
missing or unloadable validate-repos.py, a `package_dirs` that raises or returns a non-list, a
`main()` that does not call `package_dirs` or also walks the tree itself (`iterdir()`), an unloadable
canonical, and any disagreement.

No network, no credential: two files and directory listings, so it runs on fork PRs too.

Expand Down Expand Up @@ -151,11 +153,11 @@ def check(root: Path, canonical_path: Path, say) -> int:

package_dirs = getattr(validator, "package_dirs", None)
if not callable(package_dirs):
say("::warning::package enumeration NOT compared: scripts/validate-repos.py exposes no "
say("::error::package enumeration cannot be compared: scripts/validate-repos.py exposes no "
"package_dirs(root), so this repo's second enumerator cannot be called "
"(MeshWeaver#4774). Adopt: define package_dirs(root) — SKIP plus the dot-directory rule "
"— and enumerate through it in main().")
return 0
"(MeshWeaver#4774). Define package_dirs(root) — SKIP plus the dot-directory rule — and "
"enumerate through it in main(); every node repo of the fleet already does.")
return 1

delegation = main_delegates(root / "scripts" / "validate-repos.py")
if delegation:
Expand Down Expand Up @@ -270,8 +272,8 @@ def case(name: str, want_rc: int, got: tuple[int, str], must_say: str | None = N
run({vr: VALIDATE_AGREEING},
["Alpha"], '{"skip": ["scripts", "src", "legacy"], "hashModuleSources": false}\n'),
"legacy")
case("a caller with no package_dirs is NAMED, not failed", 0,
run({vr: 'SKIP = {"scripts"}\n'}, ["Alpha"], cfg), "NOT compared")
case("a caller with no package_dirs FAILS", 1,
run({vr: 'SKIP = {"scripts"}\n'}, ["Alpha"], cfg), "exposes no package_dirs")
case("a missing validate-repos.py FAILS", 1, run({}, ["Alpha"], cfg), "does not exist")
case("a package_dirs that raises FAILS", 1,
run({vr: "def package_dirs(root):\n raise RuntimeError('boom')\n" + MAIN_OK},
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/node-repo-validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,8 @@ jobs:
# a rule in no declaration, so equal declarations over different enumerations were green.
# This calls both enumerators — on the checkout and on a fixture holding every declared name
# plus a probe dot-directory — and compares what they RETURN. A caller whose validate-repos.py
# exposes no `package_dirs(root)` yet is NAMED (`NOT compared`), not failed: the flip to red
# is a change to the guard once every satellite has adopted, never a date. The guard's
# exposes no `package_dirs(root)` is RED: every caller adopted it (Education#391 was the last),
# so the warning-only grace period is over. The guard's
# self-test runs against the canonical fetched above, so a guard that cannot fail never runs.
- name: "The package-enumeration guard can fail (self-test)"
if: ${{ !cancelled() && steps.ready.outputs.ok == 'true' }} # an independent guard REPORTS; only a PREREQUISITE masks it (#4784)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ instance on the first run: MeshWeaver.Plugins skipped `dist` in both of its SKIP
the `gen-manifests.config.json` the canonical actually reads — equal declarations, a divergent
verdict. A repo that adopts deletes its `check-skip-sets.py`; the platform guard supersedes it.

🚨 **The ordering.** A caller whose `validate-repos.py` has no `package_dirs` yet is NAMED
🚨 **The ordering.** Until every caller had adopted, a caller whose `validate-repos.py` had no `package_dirs` was NAMED
(`::warning::package enumeration NOT compared`) and not failed — reddening it first would red every
satellite's required `validate` context for a condition none of them can fix without their own PR,
the fleet-wide-red shape a dated guard already produced here. Everything else is red: a missing or
Expand All @@ -449,7 +449,10 @@ unloadable `validate-repos.py`, a `package_dirs` that raises or returns anything
an untouched `root.iterdir()` walk would otherwise pass while the gate still disagreed), a missing
config, any disagreement.
The flip of the absent case to red is a change to the guard once every caller has adopted, never a
date. Canonical first, repos adopt, guard tightens when it can only pass.
date. Canonical first, repos adopt, guard tightens when it can only pass. **It has now tightened.**
Every caller of the shared validate lane exposes `package_dirs` (Crm, FundReporting, Manufacturing,
Reinsurance, SocialMedia, Plugins, and Education last, in MeshWeaver.Education#391), so an absent
function is `::error::… exposes no package_dirs(root)`. A new node repo adopts it on day one.

Adoption is one commit per repo — add the config, drop the vendored copy, give `validate-repos.py`
its `package_dirs(root)`, retire `check-skip-sets.py`, and pass `centralized-gen-manifests: true` to
Expand Down