Merge pull request 'Drop the claim label when an issue closes' (#103) from ci/unclaim-on-close into main
CI / check (push) Successful in 2m30s
Release / release (push) Successful in 31s
CI / e2e (push) Successful in 6m6s

Reviewed-on: #103
This commit was merged in pull request #103.
This commit is contained in:
2026-08-18 21:57:11 +00:00
2 changed files with 101 additions and 4 deletions
+86
View File
@@ -0,0 +1,86 @@
name: Unclaim
# A `Closes #N` footer in a commit body closes the issue on merge — and
# leaves `Status/In Progress` on it, because Gitea's auto-close touches
# state and nothing else. So #100 was closed and simultaneously marked
# as being actively worked on, and `scripts/issue.sh close` (which does
# drop the label) is exactly the thing the footer exists to avoid
# calling.
#
# **This hooks the close, not the merge.** Stripping the label in the
# PR would work and would be a per-PR habit; habits are what the footer
# removed. `issues: [closed]` covers every path an issue can close by —
# the footer on merge, `issue.sh close`, someone clicking Close in the
# web UI — and asks nothing of anyone at any of them.
#
# **Reopening deliberately does not restore it.** Reopening says the
# work was not finished, not that somebody is at a keyboard doing it
# now; the claim gets re-made by whoever picks it up.
#
# **This is not instant, and should not be described as it.** The
# runner has capacity 1 and is shared with an index build that can hold
# it for three hours, so a label tweak can queue behind one. Stale for
# an afternoon beats stale forever, which is what it was.
#
# The audit that answers "is this still firing" stays in CLAUDE.md and
# is one command:
#
# ./scripts/issue.sh list --state closed --label "Status/In Progress"
#
# A workflow that silently stops working is the failure mode this whole
# area has already produced once.
on:
issues:
types: [closed]
jobs:
unclaim:
runs-on: ubuntu-latest
container:
image: ubuntu:24.04
steps:
- name: Drop the claim label
env:
# The automatic Actions token, as release.yml uses for the
# floor tag. It needs no more than write access to this repo.
TOKEN: ${{ secrets.GITEA_TOKEN }}
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
ISSUE: ${{ github.event.issue.number }}
run: |
set -euo pipefail
apt-get update -qq
apt-get install -y -qq --no-install-recommends curl jq >/dev/null
label_id=$(
curl -sSf -H "Authorization: token $TOKEN" "$API/labels?limit=100" |
jq -r '.[] | select(.name == "Status/In Progress") | .id'
)
# The label not existing is a repo somebody reorganised, not a
# failure of this run — say so and stop, rather than failing a
# job on every close from then on.
if [ -z "$label_id" ]; then
echo "unclaim: no 'Status/In Progress' label in this repo; nothing to do"
exit 0
fi
# DELETE is idempotent here: an issue that never carried the
# label answers the same as one that did, which is what makes
# this safe to run on *every* close rather than only the ones
# that were claimed.
code=$(
curl -sS -o /dev/null -w '%{http_code}' -X DELETE \
-H "Authorization: token $TOKEN" \
"$API/issues/$ISSUE/labels/$label_id"
)
case "$code" in
204) echo "unclaim: #$ISSUE is closed and unclaimed" ;;
*)
echo "unclaim: DELETE returned $code for #$ISSUE" >&2
exit 1
;;
esac
+15 -4
View File
@@ -85,8 +85,18 @@ release decision. The rule that the issue number stays out of the
still drops the footer. `./scripts/issue.sh list --state open` after a
merge, looking for what you just shipped; `./scripts/issue.sh close
<n>` for whatever did not take, with a comment naming the commit.
`close` also drops `Status/In Progress`, because a claim outlives the
work if nothing takes the label off.
**Unclaiming is automatic, and it is hooked to the close rather than
to the merge.** Gitea's auto-close changes state and nothing else, so a
footer left `Status/In Progress` on a closed issue — #100 was closed
and marked as being actively worked on at the same time.
`.gitea/workflows/unclaim.yml` runs on `issues: [closed]`, which covers
the footer, `issue.sh close` and a click in the web UI alike; stripping
the label in the PR instead would have been a per-PR habit, and habits
are what the footer removed. It is not instant — the runner has
capacity 1 — and reopening deliberately does not restore the label.
`./scripts/issue.sh list --state closed --label "Status/In Progress"`
is how you find out it has stopped firing.
## Planning
@@ -2176,10 +2186,11 @@ Pre-commit runs vet, lint, codegen check, and frontend typecheck in parallel. Pr
## CI
Seven workflows in `.gitea/workflows/`. Five of them package and
Eight workflows in `.gitea/workflows/`. Five of them package and
publish (`arch-package`, `homebrew-formula`, `index-artifact`,
`android-apk`, `desktop-assets`); `release.yml` decides *whether* four of
those run at all; only `ci.yml` gates, and it is the one to look at when
those run at all; `unclaim.yml` is housekeeping on the tracker and
touches no code; only `ci.yml` gates, and it is the one to look at when
deciding whether a push was healthy.
**`release.yml` is the entry point for all of it.** On every push to