From f54de62511f69a59627b40db5799c792270e5638 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Mon, 20 Jul 2026 20:38:01 -0700 Subject: [PATCH] =?UTF-8?q?ci:=20add=20issue-triage=20workflow=20=E2=80=94?= =?UTF-8?q?=20PR=20open=20=E2=86=92=20status:review=20on=20referenced=20is?= =?UTF-8?q?sues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copied from cf-agents/workflows/issue-triage.yml. Requires FORGEJO_TOKEN org secret (read:issue + write:issue scopes). --- .forgejo/workflows/issue-triage.yml | 72 +++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .forgejo/workflows/issue-triage.yml diff --git a/.forgejo/workflows/issue-triage.yml b/.forgejo/workflows/issue-triage.yml new file mode 100644 index 0000000..8da213f --- /dev/null +++ b/.forgejo/workflows/issue-triage.yml @@ -0,0 +1,72 @@ +# issue-triage.yml — Automatic Forgejo issue status label transitions +# +# Copy to .forgejo/workflows/issue-triage.yml in any CF product repo. +# +# Transitions: +# PR opened/reopened → status:review on issues referenced in PR body +# +# Note: status:in-progress is handled by the pre-push hook in circuitforge-hooks, +# which fires deterministically on the developer's machine when pushing a branch +# named feat/N-*, fix/N-*, etc. +# +# Requires org-level secret: FORGEJO_TOKEN (read:issue + write:issue scopes) + +name: Issue Triage + +on: + pull_request: + types: [opened, reopened] + +jobs: + label-review: + runs-on: ubuntu-latest + steps: + - name: Mark referenced issues as status:review + env: + FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} + PR_BODY: ${{ github.event.pull_request.body }} + REPO: ${{ github.repository }} + SERVER: ${{ github.server_url }} + run: | + # Extract issue numbers from PR body — handles: + # Closes: https://git.../issues/42 + # Closes #42, Fixes #42, Refs #42, #42 + ISSUES=$(printf '%s' "$PR_BODY" \ + | grep -oE '(Closes|Fixes|Refs|See)[[:space:]]*:?[[:space:]]*(#|.*/issues/)[0-9]+|#[0-9]+' \ + | grep -oE '[0-9]+' \ + | sort -u) + + if [ -z "$ISSUES" ]; then + echo "No issue references found in PR body — nothing to label." + exit 0 + fi + + API="${SERVER}/api/v1" + + # Get the ID of the status:review label for this repo + LABEL_ID=$(curl -sf \ + -H "Authorization: token ${FORGEJO_TOKEN}" \ + "${API}/repos/${REPO}/labels?limit=50" \ + | python3 -c " + import sys, json + labels = json.load(sys.stdin) + print(next((str(l['id']) for l in labels if l['name'] == 'status:review'), '')) + ") + + if [ -z "$LABEL_ID" ]; then + echo "No 'status:review' label found in ${REPO} — skipping." + exit 0 + fi + + for N in $ISSUES; do + HTTP=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \ + -H "Authorization: token ${FORGEJO_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"labels\":[${LABEL_ID}]}" \ + "${API}/repos/${REPO}/issues/${N}/labels") + if [ "$HTTP" = "200" ] || [ "$HTTP" = "201" ]; then + echo " OK #${N} → status:review" + else + echo " SKIP #${N} (HTTP ${HTTP} — may already be labeled or issue not found)" + fi + done