forked from heavy-duty/ceremony
docs(labels): split fork and same-repo wake latency
This commit is contained in:
parent
ffbc1afc3d
commit
e639e67f09
5 changed files with 61 additions and 45 deletions
7
.github/workflows/labels-sweep.yml
vendored
7
.github/workflows/labels-sweep.yml
vendored
|
|
@ -3,9 +3,10 @@ name: labels-sweep
|
||||||
# jobs that rode labels.yml until #209. Triggers and permissions live in the
|
# jobs that rode labels.yml until #209. Triggers and permissions live in the
|
||||||
# caller; docs/CONSUMERS.md carries the complete caller stub
|
# caller; docs/CONSUMERS.md carries the complete caller stub
|
||||||
# (workflow_dispatch plus the hourly cron, which relocated here with the
|
# (workflow_dispatch plus the hourly cron, which relocated here with the
|
||||||
# sweep). Board events still yield a sweep within seconds: labels.yml's
|
# sweep). Issue events and same-repository PR events still yield a sweep within
|
||||||
# trigger job dispatches this workflow's caller on every event it used to
|
# seconds: labels.yml's trigger job dispatches this workflow's caller on those
|
||||||
# run reconcile on.
|
# events. Fork-headed PR events carry a read-only token on this Forgejo and
|
||||||
|
# wait for the caller's scheduled cadence instead (#241).
|
||||||
#
|
#
|
||||||
# Detached on purpose (#209): every sweep covers every open PR and all
|
# Detached on purpose (#209): every sweep covers every open PR and all
|
||||||
# sweeps serialize through ONE shared concurrency group, so GitHub's
|
# sweeps serialize through ONE shared concurrency group, so GitHub's
|
||||||
|
|
|
||||||
13
.github/workflows/self-labels-sweep.yml
vendored
13
.github/workflows/self-labels-sweep.yml
vendored
|
|
@ -7,12 +7,14 @@ name: labels-sweep
|
||||||
on:
|
on:
|
||||||
# The consumer owns this cadence (#203). Hourly is the recommended default
|
# The consumer owns this cadence (#203). Hourly is the recommended default
|
||||||
# when no other engine drives board state: the cron is then the sweep's ONLY
|
# when no other engine drives board state: the cron is then the sweep's ONLY
|
||||||
# wake for four transition classes — a review verdict landing (there is no
|
# wake for a review verdict landing (there is no
|
||||||
# pull_request_review trigger on the labels caller), blocker:ci-red set or
|
# pull_request_review trigger on the labels caller), blocker:ci-red set or
|
||||||
# cleared (no check_suite/check_run/workflow_run), a blocker:conflict when
|
# cleared (no check_suite/check_run/workflow_run), a blocker:conflict when
|
||||||
# ANOTHER PR merges under this one, and the time-based stale / 48h
|
# ANOTHER PR merges under this one, and the time-based stale / 48h
|
||||||
# claim-reclaim. The labels caller's events carry the rest in seconds, one
|
# claim-reclaim, plus every fork-headed PR transition on this Forgejo because
|
||||||
# trigger-job dispatch away. Hourly trades ≤1h of latency on those four
|
# its pull_request_target token is read-only (#241). Issue events and
|
||||||
|
# same-repository PR events carry the rest in seconds, one trigger-job
|
||||||
|
# dispatch away. Hourly trades ≤1h of latency on the scheduled classes
|
||||||
# while cutting nominal scheduled sweeps from four an hour to one at
|
# while cutting nominal scheduled sweeps from four an hour to one at
|
||||||
# GitHub's 1-minute billing floor. Do not delete the cron: it is their
|
# GitHub's 1-minute billing floor. Do not delete the cron: it is their
|
||||||
# discovery path. If another engine writes some of those transitions, only
|
# discovery path. If another engine writes some of those transitions, only
|
||||||
|
|
@ -22,8 +24,9 @@ on:
|
||||||
# A manual full-board sweep. A bare dispatch (input default "yes") also
|
# A manual full-board sweep. A bare dispatch (input default "yes") also
|
||||||
# bootstraps the taxonomy on a fresh repo — what dispatching the labels
|
# bootstraps the taxonomy on a fresh repo — what dispatching the labels
|
||||||
# caller did before #209. The reusable's trigger job wakes this workflow
|
# caller did before #209. The reusable's trigger job wakes this workflow
|
||||||
# with bootstrap=no on every board event — an event-woken sweep must not
|
# with bootstrap=no on every issue and same-repository PR event — an
|
||||||
# re-upsert ~20 labels each time — so declaring this input is part of the
|
# event-woken sweep must not re-upsert ~20 labels each time — so declaring
|
||||||
|
# this input is part of the
|
||||||
# caller contract: a dispatch naming an undeclared input is refused, and
|
# caller contract: a dispatch naming an undeclared input is refused, and
|
||||||
# the trigger job goes loudly red.
|
# the trigger job goes loudly red.
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
|
||||||
22
.github/workflows/self-labels.yml
vendored
22
.github/workflows/self-labels.yml
vendored
|
|
@ -8,8 +8,10 @@ name: labels
|
||||||
# Since #209 this caller carries the PR/issue event surface only. The
|
# Since #209 this caller carries the PR/issue event surface only. The
|
||||||
# reconcile sweep no longer rides these runs — the reusable's trigger job
|
# reconcile sweep no longer rides these runs — the reusable's trigger job
|
||||||
# dispatches the sweep caller (self-labels-sweep.yml here), which owns the
|
# dispatches the sweep caller (self-labels-sweep.yml here), which owns the
|
||||||
# hourly cron and the manual/bootstrap workflow_dispatch. A board event
|
# hourly cron and the manual/bootstrap workflow_dispatch. Issue events and
|
||||||
# below still yields a sweep within seconds, one dispatch hop later.
|
# same-repository PR events below still yield a sweep within seconds, one
|
||||||
|
# dispatch hop later. Fork-headed PRs carry a read-only token on this Forgejo,
|
||||||
|
# so their successful labels run leaves writes to the hourly sweep (#241).
|
||||||
on:
|
on:
|
||||||
# Narrowed (#199) to the actions that carry a queue-state change the hourly
|
# Narrowed (#199) to the actions that carry a queue-state change the hourly
|
||||||
# cron cannot wait one cadence for — dropping only labeled/unlabeled/assigned/
|
# cron cannot wait one cadence for — dropping only labeled/unlabeled/assigned/
|
||||||
|
|
@ -26,14 +28,14 @@ on:
|
||||||
issues:
|
issues:
|
||||||
types: [opened, closed, edited, reopened]
|
types: [opened, closed, edited, reopened]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
# Every PR arrives from a fork, so these carry the head/draft/review facts
|
# These carry the head/draft/review facts the sweep derives state:* from.
|
||||||
# the sweep derives state:* from. labeled/unlabeled are the handoff wake —
|
# Same-repository heads wake that sweep in seconds; fork heads cannot write
|
||||||
# the author's optimistic state:needs-human write, confirmed or corrected
|
# with this Forgejo's read-only token and wait for its scheduled cadence.
|
||||||
# here in seconds (#11); synchronize re-derives on every push;
|
# labeled/unlabeled are the same-repository handoff wake — the author's
|
||||||
# review_requested/review_request_removed wake the sweep that clears (or
|
# optimistic state:needs-human write, confirmed or corrected here in
|
||||||
# restores) blocker:unrequested — without them the one event that makes
|
# seconds (#11); synchronize re-derives on every push; review_requested/
|
||||||
# the label false could not clear it, and a quiet repo wore the red flag
|
# review_request_removed clear (or restore) blocker:unrequested on that
|
||||||
# until the advisory cron (#137).
|
# same instant path (#137).
|
||||||
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
|
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
|
||||||
3
changelog.d/241.md
Normal file
3
changelog.d/241.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fork-headed label runs now stay green without attempting writes their read-only token cannot make, while same-repository heads keep instant labeling (#241).
|
||||||
|
|
@ -337,14 +337,16 @@ The labels automation is two reusable workflows since #209, adopted
|
||||||
together at the same pin:
|
together at the same pin:
|
||||||
|
|
||||||
- **`labels.yml`** — the event-facing half, called on PR and issue events.
|
- **`labels.yml`** — the event-facing half, called on PR and issue events.
|
||||||
Two jobs: additive path-based `scope:*` labels, and a few-seconds
|
Same-repository PRs keep two write-capable jobs: additive path-based
|
||||||
`trigger` job that wakes the sweep by dispatching the consumer's sweep
|
`scope:*` labels, and a few-seconds `trigger` job that wakes the sweep by
|
||||||
caller (a REST `POST` to the forge's own
|
dispatching the consumer's sweep caller (a REST `POST` to the forge's own
|
||||||
`${GITHUB_API_URL}/repos/{owner}/{repo}/actions/workflows/{file}/dispatches`,
|
`${GITHUB_API_URL}/repos/{owner}/{repo}/actions/workflows/{file}/dispatches`,
|
||||||
plain `GITHUB_TOKEN` — `workflow_dispatch` is
|
plain `GITHUB_TOKEN` — `workflow_dispatch` is
|
||||||
one of the two documented exemptions from the token's no-retrigger rule,
|
one of the two documented exemptions from the token's no-retrigger rule,
|
||||||
so no PAT anywhere in the path and no loop: the sweep dispatches
|
so no PAT anywhere in the path and no loop: the sweep dispatches
|
||||||
nothing).
|
nothing). On this Forgejo a fork-headed `pull_request_target` token is
|
||||||
|
read-only, so those two jobs do not run; a successful `fork_head` job names
|
||||||
|
the deferral, and the scheduled sweep owns their labels.
|
||||||
- **`labels-sweep.yml`** — the reconcile sweep: PR state, blockers,
|
- **`labels-sweep.yml`** — the reconcile sweep: PR state, blockers,
|
||||||
handoff, stale status, the issue work queue, and the `needs-ruling`
|
handoff, stale status, the issue work queue, and the `needs-ruling`
|
||||||
invariants on both surfaces — the bare-flag check and the 7-day
|
invariants on both surfaces — the bare-flag check and the 7-day
|
||||||
|
|
@ -356,8 +358,9 @@ together at the same pin:
|
||||||
as fake red CI that GitHub refuses to rerun (crew#250: `gh run rerun`
|
as fake red CI that GitHub refuses to rerun (crew#250: `gh run rerun`
|
||||||
and its `--failed`/`--job` forms all decline a queue-displaced run).
|
and its `--failed`/`--job` forms all decline a queue-displaced run).
|
||||||
Behind its own caller, a displaced sweep cancels on the
|
Behind its own caller, a displaced sweep cancels on the
|
||||||
Actions tab, attached to no PR; PR checks show `scope` and the green
|
Actions tab, attached to no PR. Same-repository PR checks show `scope` and
|
||||||
`trigger` only.
|
the green `trigger`; fork-headed PRs show the green `fork_head` disposition
|
||||||
|
and wait for the scheduled sweep cadence.
|
||||||
|
|
||||||
The consumer keeps its path mapping in `.github/labeler.yml` and its
|
The consumer keeps its path mapping in `.github/labeler.yml` and its
|
||||||
review panel plus scope taxonomy in `.github/labels.conf`.
|
review panel plus scope taxonomy in `.github/labels.conf`.
|
||||||
|
|
@ -384,11 +387,12 @@ The complete event-facing caller is:
|
||||||
name: labels
|
name: labels
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
# Fork PRs; these carry the head/draft/review facts state:* derives from.
|
# These carry the head/draft/review facts state:* derives from. Same-repo
|
||||||
# labeled/unlabeled are the handoff wake (state:needs-human confirmed here);
|
# heads take the instant write + sweep-dispatch path; this Forgejo gives
|
||||||
# synchronize re-derives on every push. review_requested/review_request_removed
|
# fork heads a read-only token, so they wait for the scheduled sweep.
|
||||||
# (shipped in 0.3.0, ceremony#137) wake the sweep that clears
|
# labeled/unlabeled are the same-repo handoff wake; synchronize re-derives
|
||||||
# blocker:unrequested when the panel is asked.
|
# on every push. review_requested/review_request_removed shipped in 0.3.0
|
||||||
|
# (ceremony#137) and wake the same-repo sweep when the panel is asked.
|
||||||
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
|
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
|
# Available at 0.2.0 and later (the first tag carrying ceremony#32); a
|
||||||
# consumer pinned to 0.1.0 omits this block.
|
# consumer pinned to 0.1.0 omits this block.
|
||||||
|
|
@ -425,20 +429,21 @@ name: labels-sweep
|
||||||
on:
|
on:
|
||||||
# The consumer owns this cadence (#203). Hourly is the recommended default
|
# The consumer owns this cadence (#203). Hourly is the recommended default
|
||||||
# when no other engine drives board state: the cron is then the sweep's only
|
# when no other engine drives board state: the cron is then the sweep's only
|
||||||
# wake for four transition classes — a review verdict landing (no
|
# wake for a review verdict landing (no
|
||||||
# pull_request_review trigger on the labels caller), blocker:ci-red
|
# pull_request_review trigger on the labels caller), blocker:ci-red
|
||||||
# set/cleared, blocker:conflict when another PR merges under this one, and
|
# set/cleared, blocker:conflict when another PR merges under this one, and
|
||||||
# time-based stale / 48h claim-reclaim. The labels caller's events carry the
|
# time-based stale / 48h claim-reclaim, plus every fork-headed PR transition
|
||||||
# rest in seconds, one trigger-job dispatch away. Hourly trades ≤1h of
|
# on this Forgejo. Issue events and same-repo PR
|
||||||
# latency on those four while cutting nominal scheduled sweeps from four an
|
# events carry the rest in seconds, one trigger-job dispatch away. Hourly
|
||||||
# hour to one at GitHub's 1-minute floor. Do not delete the cron: it is their
|
# trades ≤1h of latency on the scheduled classes while cutting nominal
|
||||||
# discovery path. If another engine writes some of those transitions, only
|
# sweeps from four an hour to one at GitHub's 1-minute floor. Do not delete
|
||||||
# the classes with no other writer bound the cadence; relax it only as that
|
# the cron: it is their discovery path. If another engine writes some of
|
||||||
# list shrinks.
|
# those transitions, only the classes with no other writer bound the cadence;
|
||||||
|
# relax it only as that list shrinks.
|
||||||
schedule: [{cron: "0 * * * *"}]
|
schedule: [{cron: "0 * * * *"}]
|
||||||
# A manual full-board sweep. A bare dispatch (input default "yes") also
|
# A manual full-board sweep. A bare dispatch (input default "yes") also
|
||||||
# bootstraps the taxonomy on a fresh repo. The labels caller's trigger job
|
# bootstraps the taxonomy on a fresh repo. The labels caller's trigger job
|
||||||
# wakes this workflow with bootstrap=no on every board event, so the
|
# wakes this workflow with bootstrap=no on every issue and same-repo PR event, so the
|
||||||
# declared input is part of the contract: a dispatch naming an undeclared
|
# declared input is part of the contract: a dispatch naming an undeclared
|
||||||
# input is refused, and the trigger job goes loudly red.
|
# input is refused, and the trigger job goes loudly red.
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
@ -542,16 +547,18 @@ Bump without the sweep caller and the trigger job goes red on every PR
|
||||||
and issue event — the loud failure mode above — so never split these
|
and issue event — the loud failure mode above — so never split these
|
||||||
four edits across PRs.
|
four edits across PRs.
|
||||||
|
|
||||||
`pull_request_target` is intentional: fork PRs need the base repository's
|
`pull_request_target` is intentional: same-repository PRs keep the base
|
||||||
token to write labels. The reusable workflows execute no PR code. They check
|
repository's write token without executing PR code. This Forgejo still gives
|
||||||
out only the consumer's base branch and the pinned ceremony implementation.
|
fork-headed `_target` runs a read-only token, so they attempt no writes and
|
||||||
|
leave labels to the scheduled sweep. The reusable workflows check out only the
|
||||||
|
consumer's base branch and the pinned ceremony implementation.
|
||||||
The #52 ruling invariants ride exactly these triggers — but the caller above
|
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
|
is no longer the #18 shape, so adopting current triggers is a stub edit, not
|
||||||
a bare pin bump. `review_requested` and `review_request_removed` on
|
a bare pin bump. `review_requested` and `review_request_removed` on
|
||||||
`pull_request_target:` shipped in `0.3.0` (ceremony#137) — the wake that
|
`pull_request_target:` shipped in `0.3.0` (ceremony#137). It clears
|
||||||
clears `blocker:unrequested` the moment the panel is asked, without which a
|
`blocker:unrequested` the moment the panel is asked on a same-repository head;
|
||||||
quiet repo wears that flag until the backstop cron; a consumer picks them up
|
fork heads wait for the sweep cadence on this Forgejo. A consumer picks the
|
||||||
by pinning `0.3.0` or later, never through mixed refs.
|
events up by pinning `0.3.0` or later, 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, zero or more optional per-author panel rows, and
|
`triage-actors` setting, zero or more optional per-author panel rows, and
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue