forked from heavy-duty/ceremony
Merge pull request #143 from claude-bot-andresmgsl/build/137-review-request-wake
fix: review_requested wakes the labels sweep — blocker:unrequested clears when the ask lands
This commit is contained in:
commit
6a16a30bab
5 changed files with 81 additions and 14 deletions
8
.github/workflows/labels.yml
vendored
8
.github/workflows/labels.yml
vendored
|
|
@ -31,10 +31,16 @@ jobs:
|
||||||
scope:
|
scope:
|
||||||
# Not on labeled/unlabeled: those events change no paths, so scope has
|
# Not on labeled/unlabeled: those events change no paths, so scope has
|
||||||
# nothing new to derive — and label churn is precisely what they are.
|
# nothing new to derive — and label churn is precisely what they are.
|
||||||
|
# review_requested/review_request_removed likewise change no paths — they
|
||||||
|
# exist to wake reconcile (#137) — and running labeler on them widens
|
||||||
|
# exactly the window #130 documents, where a label written during a
|
||||||
|
# scope run is clobbered.
|
||||||
if: >-
|
if: >-
|
||||||
github.event_name == 'pull_request_target' &&
|
github.event_name == 'pull_request_target' &&
|
||||||
github.event.action != 'labeled' &&
|
github.event.action != 'labeled' &&
|
||||||
github.event.action != 'unlabeled'
|
github.event.action != 'unlabeled' &&
|
||||||
|
github.event.action != 'review_requested' &&
|
||||||
|
github.event.action != 'review_request_removed'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
concurrency:
|
concurrency:
|
||||||
group: labels-scope-${{ github.event.pull_request.number }}
|
group: labels-scope-${{ github.event.pull_request.number }}
|
||||||
|
|
|
||||||
6
.github/workflows/self-labels.yml
vendored
6
.github/workflows/self-labels.yml
vendored
|
|
@ -10,7 +10,11 @@ on:
|
||||||
issues:
|
issues:
|
||||||
types: [opened, edited, assigned, unassigned, labeled, unlabeled, closed, reopened]
|
types: [opened, edited, assigned, unassigned, labeled, unlabeled, closed, reopened]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled]
|
# review_requested/review_request_removed wake the sweep that clears (or
|
||||||
|
# restores) blocker:unrequested — without them the one event that makes
|
||||||
|
# the label false could not clear it, and a quiet repo wore the red flag
|
||||||
|
# until the advisory cron (#137).
|
||||||
|
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
checks: read # mergeability/check-rollup read for PR state
|
checks: read # mergeability/check-rollup read for PR state
|
||||||
|
|
|
||||||
10
changelog.d/137.md
Normal file
10
changelog.d/137.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `blocker:unrequested` now clears the moment the panel is asked: the labels
|
||||||
|
caller (and the `docs/CONSUMERS.md` stub) listens on `review_requested` and
|
||||||
|
`review_request_removed`, so the one event that falsifies the label — or
|
||||||
|
makes it true again — wakes the reconcile sweep instead of waiting for an
|
||||||
|
unrelated push or the advisory cron. The `scope` job skips both events:
|
||||||
|
they change no paths, and running the labeler on them widens the #130
|
||||||
|
clobber window. Adopting the new triggers is a stub edit riding the pin
|
||||||
|
bump to the first tag carrying this change (#137).
|
||||||
|
|
@ -299,8 +299,12 @@ on:
|
||||||
schedule: [{cron: "*/15 * * * *"}] # advisory; the handoff label is the real wake
|
schedule: [{cron: "*/15 * * * *"}] # advisory; the handoff label is the real wake
|
||||||
workflow_dispatch: # bootstraps missing labels on a fresh repo
|
workflow_dispatch: # bootstraps missing labels on a fresh repo
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled]
|
# review_requested/review_request_removed are unreleased — not in 0.2.0;
|
||||||
# Unreleased — not in 0.1.0; add only with the first tag carrying ceremony#32.
|
# add them with the pin bump to the first tag carrying ceremony#137. They
|
||||||
|
# wake the sweep that clears blocker:unrequested when the panel is asked.
|
||||||
|
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
|
||||||
|
# Available at 0.2.0 and later (the first tag carrying ceremony#32); a
|
||||||
|
# consumer pinned to 0.1.0 omits this block.
|
||||||
issues:
|
issues:
|
||||||
types: [opened, labeled, unlabeled, assigned, unassigned, closed]
|
types: [opened, labeled, unlabeled, assigned, unassigned, closed]
|
||||||
permissions:
|
permissions:
|
||||||
|
|
@ -319,15 +323,21 @@ repositories allow check data to be read regardless, but a private consumer
|
||||||
needs both explicit reads above; without them the failure appears as an empty
|
needs both explicit reads above; without them the failure appears as an empty
|
||||||
`state:*` axis on the board rather than a red workflow run.
|
`state:*` axis on the board rather than a red workflow run.
|
||||||
|
|
||||||
The `issues:` trigger is **unreleased** and is not in `0.1.0`. A consumer
|
The `issues:` trigger is available at `0.2.0` and later — `0.2.0` is the
|
||||||
pinned to `0.1.0` omits it. Add it only when bumping every ceremony reference
|
first tag carrying ceremony#32. A consumer pinned to `0.1.0` omits it. Adopt
|
||||||
to the first tag carrying ceremony#32; never mix refs to adopt it early.
|
it only by bumping every ceremony reference to `0.2.0` or later; never mix
|
||||||
|
refs to adopt it early.
|
||||||
|
|
||||||
`pull_request_target` is intentional: fork PRs need the base repository's
|
`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
|
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.
|
out only the consumer's base branch and the pinned ceremony implementation.
|
||||||
The #52 ruling invariants ride exactly these triggers — the caller above is
|
The #52 ruling invariants ride exactly these triggers — but the caller above
|
||||||
unchanged since #18, so adopting them is a pin bump, not a stub edit.
|
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.
|
||||||
|
|
||||||
`.github/labels.conf` has one mandatory panel setting, one mandatory
|
`.github/labels.conf` has one mandatory panel setting, one mandatory
|
||||||
`triage-actors` setting, and then zero or more scope rows:
|
`triage-actors` setting, and then zero or more scope rows:
|
||||||
|
|
@ -339,11 +349,11 @@ scope:cli|C5DEF5|The command-line surface
|
||||||
scope:docs|C5DEF5|Documentation
|
scope:docs|C5DEF5|Documentation
|
||||||
```
|
```
|
||||||
|
|
||||||
The mandatory `triage-actors=` setting is also **unreleased** and is not
|
The mandatory `triage-actors=` setting is likewise accepted at `0.2.0` and
|
||||||
accepted by `0.1.0`. At that tag the file contains `panel=` plus scope rows
|
later, and not by `0.1.0`. At that tag the file contains `panel=` plus scope
|
||||||
only; adding `triage-actors=` is a parse failure, not an ignored setting. Add
|
rows only; adding `triage-actors=` is a parse failure, not an ignored setting.
|
||||||
it at the same pin bump as the `issues:` trigger, to the first tag carrying
|
Add it at the same pin bump as the `issues:` trigger — `0.2.0` or later —
|
||||||
ceremony#32 — never before it and never through mixed refs.
|
never before it and never through mixed refs.
|
||||||
|
|
||||||
Both actor lists are whitespace-separated. `triage-actors` names the identities
|
Both actor lists are whitespace-separated. `triage-actors` names the identities
|
||||||
allowed to mint issues without the sweep applying `needs-triage`. Label rows use exactly
|
allowed to mint issues without the sweep applying `needs-triage`. Label rows use exactly
|
||||||
|
|
|
||||||
|
|
@ -65,4 +65,41 @@ 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" \
|
check "LABELS.md enumerates no repo's scope labels" 1 "0" \
|
||||||
grep -c 'scope:[a-z0-9]' "$ROOT/LABELS.md"
|
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
|
||||||
|
# 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"
|
||||||
|
}
|
||||||
|
types_in_sync() { # $1 = caller, $2 = stub → 0 when both lists exist and match
|
||||||
|
local a b
|
||||||
|
a="$(pr_target_types "$1")" b="$(pr_target_types "$2")"
|
||||||
|
[ -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"
|
||||||
|
# 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"
|
||||||
|
# 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
|
||||||
|
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"
|
||||||
|
sed 's/, review_request_removed//' "$STUB" >"$mut_stub"
|
||||||
|
check "a type dropped from the stub goes red" 1 "" \
|
||||||
|
types_in_sync "$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"
|
||||||
|
|
||||||
summary
|
summary
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue