forked from heavy-duty/ceremony
docs: the additive-scope contract in CONSUMERS/LABELS; changelog fragment
Part of #130. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
16dfdb9a4f
commit
d0b857eb10
5 changed files with 25 additions and 4 deletions
|
|
@ -170,8 +170,10 @@ re-arms mentions, but only the writer can declare that a move is owed (#83).
|
|||
## Scope — which surface? (PRs and issues, any number)
|
||||
|
||||
All scopes share one calm color, `#C5DEF5` — scopes locate, states alert. The
|
||||
set is per-repo: PRs get theirs from changed paths via actions/labeler, issues
|
||||
get theirs from triage. This file never enumerates a set — it is mirrored
|
||||
set is per-repo: PRs get theirs from changed paths via the labels workflow's
|
||||
scope job — an additive write only, so a label applied by hand or by an agent
|
||||
while the machine runs always survives it (#130) — and issues get theirs from
|
||||
triage. This file never enumerates a set — it is mirrored
|
||||
byte-identically into every governed repo, and any list it carried would be
|
||||
true in one repo and false in the rest (#104). The set for the repo you are
|
||||
standing in lives in the two places that are true wherever you read them: its
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ glob_to_regex() { # $1 = glob (the subset above) → anchored ERE, one line
|
|||
i=$((i + 2))
|
||||
continue
|
||||
fi
|
||||
out="$out[^/]*"
|
||||
out="${out}[^/]*"
|
||||
;;
|
||||
\?) out="$out[^/]" ;;
|
||||
\?) out="${out}[^/]" ;;
|
||||
[a-zA-Z0-9_/-]) out="$out$c" ;;
|
||||
*) out="$out\\$c" ;; # every other byte is literal — ., +, {, (, …
|
||||
esac
|
||||
|
|
|
|||
1
changelog.d/130.md
Normal file
1
changelog.d/130.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
- `actions/labels-scope` replaces `actions/labeler@v5` in the labels workflow's scope job: labeler wrote the whole label set (`PUT`) even under `sync-labels: false`, silently removing any label applied while it ran — #128 lost its `release` that way — so the scope job now derives from the same `.github/labeler.yml` mapping (the `changed-files`/`any-glob-to-any-file` shape, block or flow; anything else refuses loudly) and its only write is an additive `POST`. The reconcile sweep also warns — never sets — when a non-draft PR is release-shaped (bare version differing from its base) but carries no `release` label (#130).
|
||||
|
|
@ -276,6 +276,21 @@ never writes it). The consumer keeps its path mapping in
|
|||
`.github/labeler.yml` and its review panel plus scope taxonomy in
|
||||
`.github/labels.conf`.
|
||||
|
||||
**Additive means additive** (unreleased — #130): the scope job's only label
|
||||
write is `POST /issues/{n}/labels`, which adds the derived scopes and removes
|
||||
nothing, so a label applied while the job runs survives it. Earlier tags used
|
||||
`actions/labeler@v5`, which — even under `sync-labels: false` — replaces the
|
||||
whole label set and silently drops a label written mid-job (ceremony#128 lost
|
||||
its `release` that way). With the same pin bump, `.github/labeler.yml` keeps
|
||||
its format but the accepted shape becomes exactly the one this guide has
|
||||
always shown: label → `changed-files` → `any-glob-to-any-file`, block or flow
|
||||
style, globs over `**`, `*` and `?` (`**` crosses `/`, the others do not; the
|
||||
whole path must match). Any other labeler key — `all-globs-to-all-files`,
|
||||
branch matchers, negations — fails the run loudly instead of being
|
||||
half-honoured. The reconcile sweep also warns (never sets) when a non-draft
|
||||
PR carries a bare `X.Y.Z` version differing from its base but no `release`
|
||||
label — the merge door would refuse that merge, and the sweep says so first.
|
||||
|
||||
The complete caller is:
|
||||
|
||||
```yaml
|
||||
|
|
|
|||
|
|
@ -31,12 +31,15 @@ scope:docs${TAB}README"
|
|||
|
||||
check "derive: ** matches nested paths" 0 "scope:release-flow" \
|
||||
derive_labels "$cfg" 'lib/deep/facts.sh'
|
||||
# shellcheck disable=SC2016 # expansion belongs to the nested bash
|
||||
check "derive: ** does not match the bare directory" 1 "" \
|
||||
bash -c 'source "$1"; [ -n "$(derive_labels "$2" lib)" ]' _ \
|
||||
"$ROOT/actions/labels-scope/labels-scope.sh" "$cfg"
|
||||
# shellcheck disable=SC2016 # expansion belongs to the nested bash
|
||||
check "derive: literal glob does not match a nested twin" 1 "" \
|
||||
bash -c 'source "$1"; [ -n "$(derive_labels "$2" docs2/README)" ]' _ \
|
||||
"$ROOT/actions/labels-scope/labels-scope.sh" "$cfg"
|
||||
# shellcheck disable=SC2016 # expansion belongs to the nested bash
|
||||
check "derive: one label per line, config order, deduped" 0 "" \
|
||||
bash -c 'source "$1"; got="$(derive_labels "$2" "$(printf "%s\n" README VERSION lib/x docs/a.md)")"
|
||||
[ "$got" = "$(printf "%s\n" scope:release-flow scope:docs)" ] || { printf "%s\n" "$got"; exit 1; }' _ \
|
||||
|
|
|
|||
Loading…
Reference in a new issue