mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-03 18:47:04 +09:00
CODEOWNERS is last-match-wins, so a new scoped rule that omits the default owners silently strips their ownership for that path. Add a hack/*.bats unit test (auto-discovered by make bats-unit-tests) that requires every rule listing owners to repeat the owners of the * catch-all, exempting ownerless rules and the governance roster. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
49 lines
2.3 KiB
Bash
49 lines
2.3 KiB
Bash
#!/usr/bin/env bats
|
|
# -----------------------------------------------------------------------------
|
|
# Coverage invariant for .github/CODEOWNERS.
|
|
#
|
|
# CODEOWNERS applies only the LAST matching rule, and matching is not
|
|
# additive: a scoped rule fully replaces the * catch-all instead of extending
|
|
# it. The only way to keep the default owners able to review everything is to
|
|
# repeat their handles in every scoped rule. A rule that omits them silently
|
|
# carves its path out from under the catch-all — that is how /hack/,
|
|
# /.github/, /Makefile, /.pre-commit-config.yaml and /docs/ ended up owned by
|
|
# exactly two people, deadlocking every PR one of them authored while the
|
|
# other was away ("Require review from Code Owners" is enforced on main, and
|
|
# stale reviews are dismissed on push, so there is no way around a missing
|
|
# owner short of an admin override).
|
|
#
|
|
# The invariant: every rule that lists owners must include every owner of the
|
|
# * catch-all. Two deliberate exceptions:
|
|
# - ownerless rules — generated files whose review is waived on purpose;
|
|
# - the governance roster, owned by exactly @tym83 @kvaps. It is identified
|
|
# by that owner set rather than by its position in the file, so the
|
|
# exemption cannot leak to rules appended under other sections.
|
|
#
|
|
# Changing the catch-all owners or growing the governance roster is a policy
|
|
# change; this test failing on such a change is the point — adjust the
|
|
# expectation here in the same PR, with the policy discussion linked.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
@test "every CODEOWNERS rule that lists owners repeats the catch-all owners (governance excepted)" {
|
|
[ -f .github/CODEOWNERS ]
|
|
|
|
awk '
|
|
/^[[:space:]]*(#|$)/ { next }
|
|
$1 == "*" { for (i = 2; i <= NF; i++) defaults[$i]; ndef = NF - 1; next }
|
|
NF < 2 { next }
|
|
NF == 3 && (($2 == "@tym83" && $3 == "@kvaps") || ($2 == "@kvaps" && $3 == "@tym83")) { next }
|
|
{
|
|
for (d in defaults) {
|
|
found = 0
|
|
for (i = 2; i <= NF; i++) if ($i == d) found = 1
|
|
if (!found) { printf "line %d: rule %s is missing default owner %s\n", FNR, $1, d; bad = 1 }
|
|
}
|
|
}
|
|
END {
|
|
if (ndef == 0) { print "no * catch-all rule with owners found"; exit 1 }
|
|
exit bad
|
|
}
|
|
' .github/CODEOWNERS
|
|
}
|