fix(labels): defer fork-head writes to sweep
All checks were successful
CI / test (pull_request) Successful in 3m47s
CI / release-exercise (pull_request) Successful in 25s
CI / self-guards (pull_request) Successful in 21s
CI / action-exercise (pull_request) Successful in 20s
CI / docs-sync-exercise (pull_request) Successful in 20s
labels / labels (pull_request) Successful in 22s
Refs guard / refs-not-closing (pull_request) Successful in 20s
All checks were successful
CI / test (pull_request) Successful in 3m47s
CI / release-exercise (pull_request) Successful in 25s
CI / self-guards (pull_request) Successful in 21s
CI / action-exercise (pull_request) Successful in 20s
CI / docs-sync-exercise (pull_request) Successful in 20s
labels / labels (pull_request) Successful in 22s
Refs guard / refs-not-closing (pull_request) Successful in 20s
This commit is contained in:
parent
311ef304fc
commit
ffbc1afc3d
1 changed files with 31 additions and 17 deletions
48
.github/workflows/labels.yml
vendored
48
.github/workflows/labels.yml
vendored
|
|
@ -2,12 +2,14 @@ name: labels
|
|||
# Reusable half of the labels automation. Triggers and permissions live in
|
||||
# the caller; docs/CONSUMERS.md carries the complete caller stub.
|
||||
#
|
||||
# The caller uses pull_request_target, not pull_request: every PR in this
|
||||
# family arrives from a fork, where pull_request runs with a READ-ONLY token
|
||||
# and cannot label anything. _target is safe in this workflow because no PR
|
||||
# code is ever checked out or executed — scope reads changed paths and the
|
||||
# path mapping via the API and checks out only the ceremony implementation.
|
||||
# Keep it that way.
|
||||
# The caller uses pull_request_target, not pull_request, so same-repository PRs
|
||||
# keep the base repository's write token without running PR code. On this
|
||||
# Forgejo, unlike GitHub, fork-headed _target runs still receive a read-only
|
||||
# token. Those runs therefore attempt no writes and leave labeling to the
|
||||
# scheduled sweep; the explicit fork_head job below records that disposition
|
||||
# as a successful check. Both write paths execute only for same-repository
|
||||
# heads. Scope reads changed paths and the path mapping through the API and
|
||||
# checks out only the ceremony implementation. Keep it that way (#241).
|
||||
#
|
||||
# The reconcile sweep lived here until #209. Riding the PR-triggered run
|
||||
# meant every displacement in the sweep's shared concurrency queue recorded
|
||||
|
|
@ -21,8 +23,11 @@ name: labels
|
|||
# sweep now lives in labels-sweep.yml behind its own caller, and the
|
||||
# trigger job below is its wake: it fires on every event this caller
|
||||
# subscribes — the exact surface that used to run reconcile directly — so
|
||||
# the wake latency (#137) is unchanged, while a displaced sweep cancels on
|
||||
# the Actions tab, attached to no PR. PR checks show scope + trigger only.
|
||||
# same-repository wake latency (#137) remains seconds-scale, while a displaced
|
||||
# sweep cancels on the Actions tab, attached to no PR. Fork-headed runs cannot
|
||||
# dispatch with their read-only token, so their labels arrive on the scheduled
|
||||
# sweep cadence. PR checks show scope + trigger for same-repository heads, or
|
||||
# fork_head for fork heads.
|
||||
#
|
||||
# This cannot loop: the trigger's dispatch and the reconciler's label
|
||||
# writes both use GITHUB_TOKEN. GitHub does not create workflow runs from
|
||||
|
|
@ -60,6 +65,7 @@ jobs:
|
|||
# scope run is clobbered.
|
||||
if: >-
|
||||
github.event_name == 'pull_request_target' &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository &&
|
||||
github.event.action != 'labeled' &&
|
||||
github.event.action != 'unlabeled' &&
|
||||
github.event.action != 'review_requested' &&
|
||||
|
|
@ -106,15 +112,10 @@ jobs:
|
|||
CONFIG_REF: ${{ github.sha }}
|
||||
|
||||
trigger:
|
||||
# The sweep's wake (#209). No `if:`: reconcile carried none, so the
|
||||
# trigger keeps the whole event surface the caller subscribes —
|
||||
# workflow_dispatch of the labels caller itself included. That cannot
|
||||
# double-fire bootstrap: this dispatch always carries bootstrap=no, so
|
||||
# a dispatched labels caller yields one plain sweep, and the taxonomy
|
||||
# bootstrap fires solely on a manual dispatch of the sweep caller
|
||||
# (whose input defaults to "yes"). Excluding workflow_dispatch here
|
||||
# would instead make a dispatched labels caller do nothing at all —
|
||||
# a silent no-op run is worse than a redundant sweep.
|
||||
# The sweep's instant wake (#209) keeps the whole non-PR event surface and
|
||||
# same-repository PRs. Fork-headed PRs are excluded because this Forgejo
|
||||
# gives their pull_request_target run a read-only token (#241); fork_head
|
||||
# records the successful deferral to the scheduled sweep instead.
|
||||
#
|
||||
# LOUD on failure — never `|| true`: a red trigger is the
|
||||
# misconfiguration alarm. A consumer that bumps the pin without adding
|
||||
|
|
@ -122,6 +123,9 @@ jobs:
|
|||
# `bootstrap` input (unexpected input), or without `actions: write`
|
||||
# on this caller (permission denied) fails HERE, visibly on the PR,
|
||||
# instead of silently never sweeping again.
|
||||
if: >-
|
||||
github.event_name != 'pull_request_target' ||
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: dispatch the sweep
|
||||
|
|
@ -199,3 +203,13 @@ jobs:
|
|||
exit 1
|
||||
fi
|
||||
echo "labels: sweep dispatched — $SWEEP_WORKFLOW on $branch (bootstrap=no)"
|
||||
|
||||
fork_head:
|
||||
if: >-
|
||||
github.event_name == 'pull_request_target' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: explain deferred fork labels
|
||||
run: >-
|
||||
echo "labels: fork head has a read-only token; writes deferred to the scheduled sweep cadence"
|
||||
|
|
|
|||
Loading…
Reference in a new issue