fix: the CONSUMERS.md stub's issues: types match the caller's, parity-tested #150
3 changed files with 59 additions and 21 deletions
10
changelog.d/144.md
Normal file
10
changelog.d/144.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
### Fixed
|
||||
|
||||
- The `docs/CONSUMERS.md` labels-caller stub lists the same `issues:` types
|
||||
as ceremony's own caller — `edited` and `reopened` included — so a consumer
|
||||
adopting the stub wakes when an issue body's `Blocked by #N` declaration is
|
||||
edited, and when a closed issue re-enters the queue wearing labels derived
|
||||
at close. The two lists drifted apart inside PR #32; a parity test now pins
|
||||
them together, red if either file drops a type or the lists diverge.
|
||||
Adopting the widened list is a stub edit riding the pin bump to the first
|
||||
tag carrying this change (#144).
|
||||
|
|
@ -306,7 +306,10 @@ on:
|
|||
# Available at 0.2.0 and later (the first tag carrying ceremony#32); a
|
||||
# consumer pinned to 0.1.0 omits this block.
|
||||
issues:
|
||||
types: [opened, labeled, unlabeled, assigned, unassigned, closed]
|
||||
# edited/reopened are unreleased — not in 0.2.0; add them with the pin
|
||||
# bump to the first tag carrying ceremony#144, the same bump as the
|
||||
# pull_request_target additions above.
|
||||
types: [opened, edited, assigned, unassigned, labeled, unlabeled, closed, reopened]
|
||||
permissions:
|
||||
contents: read
|
||||
checks: read # mergeability/check-rollup read for PR state
|
||||
|
|
@ -326,18 +329,23 @@ needs both explicit reads above; without them the failure appears as an empty
|
|||
The `issues:` trigger is available at `0.2.0` and later — `0.2.0` is the
|
||||
first tag carrying ceremony#32. A consumer pinned to `0.1.0` omits it. Adopt
|
||||
it only by bumping every ceremony reference to `0.2.0` or later; never mix
|
||||
refs to adopt it early.
|
||||
refs to adopt it early. At `0.2.0` the type list stops at `closed`: `edited`
|
||||
and `reopened` are newer, part of the pending stub edit below.
|
||||
|
||||
`pull_request_target` is intentional: fork PRs need the base repository's
|
||||
token to write labels. The reusable workflow executes no PR code. It checks
|
||||
out only the consumer's base branch and the pinned ceremony implementation.
|
||||
The #52 ruling invariants ride exactly these triggers — but the caller above
|
||||
is no longer the #18 shape, so adopting current triggers is a stub edit, not
|
||||
a bare pin bump. The pending edit is `review_requested` and
|
||||
`review_request_removed` (#137): the wake that clears `blocker:unrequested`
|
||||
the moment the panel is asked, without which a quiet repo wears that flag
|
||||
until the advisory cron. Make that edit with the pin bump to the first tag
|
||||
carrying ceremony#137 — never before it and never through mixed refs.
|
||||
a bare pin bump. The pending edits are `review_requested` and
|
||||
`review_request_removed` on `pull_request_target:` (#137) — the wake that
|
||||
clears `blocker:unrequested` the moment the panel is asked, without which a
|
||||
quiet repo wears that flag until the advisory cron — and `edited` and
|
||||
`reopened` on `issues:` (#144): the wakes for a body edit rewriting the
|
||||
`Blocked by #N` declaration the reconcile sweep parses, and for a closed
|
||||
issue re-entering the queue wearing labels derived when it closed. Make both
|
||||
edits together, with the pin bump to the first tag carrying ceremony#137 and
|
||||
ceremony#144 — never before it and never through mixed refs.
|
||||
|
||||
`.github/labels.conf` has one mandatory panel setting, one mandatory
|
||||
`triage-actors` setting, and then zero or more scope rows:
|
||||
|
|
|
|||
|
|
@ -65,41 +65,61 @@ check "PR author is recused from the required panel" 0 "one three" printf '%s\n'
|
|||
check "LABELS.md enumerates no repo's scope labels" 1 "0" \
|
||||
grep -c 'scope:[a-z0-9]' "$ROOT/LABELS.md"
|
||||
|
||||
# The caller's pull_request_target list and the CONSUMERS.md stub's must be
|
||||
# the same list. review_requested/review_request_removed are the wake that
|
||||
# The caller's trigger type lists and the CONSUMERS.md stub's must be the
|
||||
# same lists. review_requested/review_request_removed are the wake that
|
||||
# clears blocker:unrequested — the label sat false for as long as a quiet
|
||||
# repo stayed quiet because the one event that falsifies it was never
|
||||
# listed (#137). The stub is prose, so nothing but this row keeps the two
|
||||
# lists from drifting: a type in one file only is a wake that fires at home
|
||||
# and nowhere in the fleet, or the reverse.
|
||||
pr_target_types() { # $1 = file → its pull_request_target types line, unindented
|
||||
awk '/pull_request_target:/{f=1; next} f && /types: /{sub(/^ */,""); print; exit}' "$1"
|
||||
# listed (#137). edited/reopened are the wakes for the two events that
|
||||
# falsify issue labels silently — an edited body rewrites the `Blocked by
|
||||
# #N` declaration the reconcile sweep parses, and a reopened issue
|
||||
# re-enters the queue wearing labels derived at close; PR #32 widened the
|
||||
# caller by both and the stub never followed (#144). The stub is prose, so
|
||||
# nothing but these rows keeps the lists from drifting: a type in one file
|
||||
# only is a wake that fires at home and nowhere in the fleet, or the
|
||||
# reverse. The NF guard keeps `issues: write` under permissions: from
|
||||
# matching the issues: trigger key.
|
||||
event_types() { # $1 = file, $2 = trigger key → that trigger's types line, unindented
|
||||
awk -v key="$2:" '$1 == key && NF == 1 {f=1; next} f && /types: /{sub(/^ */,""); print; exit}' "$1"
|
||||
}
|
||||
types_in_sync() { # $1 = caller, $2 = stub → 0 when both lists exist and match
|
||||
types_in_sync() { # $1 = trigger key, $2 = caller, $3 = stub → 0 when both lists exist and match
|
||||
local a b
|
||||
a="$(pr_target_types "$1")" b="$(pr_target_types "$2")"
|
||||
a="$(event_types "$2" "$1")" b="$(event_types "$3" "$1")"
|
||||
[ -n "$a" ] && [ "$a" = "$b" ]
|
||||
}
|
||||
CALLER="$ROOT/.github/workflows/self-labels.yml"
|
||||
STUB="$ROOT/docs/CONSUMERS.md"
|
||||
check "caller and stub pull_request_target lists are identical" 0 "" \
|
||||
types_in_sync "$CALLER" "$STUB"
|
||||
types_in_sync pull_request_target "$CALLER" "$STUB"
|
||||
# shellcheck disable=SC2016 # expansion belongs to the nested bash
|
||||
check "the caller lists both review-request wakes" 0 "" bash -c \
|
||||
'awk "/pull_request_target:/{f=1; next} f && /types: /{print; exit}" "$1" |
|
||||
grep -F review_requested | grep -qF review_request_removed' _ "$CALLER"
|
||||
check "caller and stub issues lists are identical" 0 "" \
|
||||
types_in_sync issues "$CALLER" "$STUB"
|
||||
check "the caller still lists all eight issue types" 0 \
|
||||
"types: [opened, edited, assigned, unassigned, labeled, unlabeled, closed, reopened]" \
|
||||
event_types "$CALLER" issues
|
||||
# the failing cases: drop a type from either file, or reorder one list only,
|
||||
# and the identity row above goes red — exercised here on mutated copies
|
||||
# and the identity rows above go red — exercised here on mutated copies
|
||||
mut_caller="$TMP/mut-caller.yml" mut_stub="$TMP/mut-stub.md"
|
||||
sed 's/, review_request_removed//' "$CALLER" >"$mut_caller"
|
||||
check "a type dropped from the caller goes red" 1 "" \
|
||||
types_in_sync "$mut_caller" "$STUB"
|
||||
types_in_sync pull_request_target "$mut_caller" "$STUB"
|
||||
sed 's/, review_request_removed//' "$STUB" >"$mut_stub"
|
||||
check "a type dropped from the stub goes red" 1 "" \
|
||||
types_in_sync "$CALLER" "$mut_stub"
|
||||
types_in_sync pull_request_target "$CALLER" "$mut_stub"
|
||||
sed 's/review_requested, review_request_removed/review_request_removed, review_requested/' \
|
||||
"$STUB" >"$mut_stub"
|
||||
check "a reorder in one list only goes red" 1 "" \
|
||||
types_in_sync "$CALLER" "$mut_stub"
|
||||
types_in_sync pull_request_target "$CALLER" "$mut_stub"
|
||||
sed 's/, edited//' "$CALLER" >"$mut_caller"
|
||||
check "an issue type dropped from the caller goes red" 1 "" \
|
||||
types_in_sync issues "$mut_caller" "$STUB"
|
||||
sed 's/, edited//' "$STUB" >"$mut_stub"
|
||||
check "an issue type dropped from the stub goes red" 1 "" \
|
||||
types_in_sync issues "$CALLER" "$mut_stub"
|
||||
sed 's/closed, reopened/reopened, closed/' "$STUB" >"$mut_stub"
|
||||
check "an issue-list reorder in one file only goes red" 1 "" \
|
||||
types_in_sync issues "$CALLER" "$mut_stub"
|
||||
|
||||
summary
|
||||
|
|
|
|||
Loading…
Reference in a new issue