name: Anno Reject on: issues: types: [labeled] env: NODE_OPTIONS: --dns-result-order=ipv4first defaults: run: shell: bash jobs: reject: runs-on: ubuntu-latest container: image: mcr.microsoft.com/devcontainers/javascript-node:22-bookworm steps: - name: Derive context run: | set -euo pipefail export EVENT_JSON="/var/run/act/workflow/event.json" test -f "$EVENT_JSON" || { echo "❌ Missing $EVENT_JSON"; exit 1; } node --input-type=module - <<'NODE' > /tmp/reject.env import fs from "node:fs"; const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8")); const repoObj = ev?.repository || {}; const cloneUrl = repoObj?.clone_url || (repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : ""); if (!cloneUrl) throw new Error("No repository url"); let owner = repoObj?.owner?.login || repoObj?.owner?.username || (repoObj?.full_name ? repoObj.full_name.split("/")[0] : ""); let repo = repoObj?.name || (repoObj?.full_name ? repoObj.full_name.split("/")[1] : ""); if (!owner || !repo) { const m = cloneUrl.match(/[:/](?[^/]+)\/(?[^/]+?)(?:\.git)?$/); if (m?.groups) { owner = owner || m.groups.o; repo = repo || m.groups.r; } } if (!owner || !repo) throw new Error("Cannot infer owner/repo"); const issueNumber = ev?.issue?.number || ev?.issue?.index; if (!issueNumber) throw new Error("No issue number"); const labelName = ev?.label?.name || ev?.label || ""; const u = new URL(cloneUrl); function sh(s){ return JSON.stringify(String(s)); } process.stdout.write([ `OWNER=${sh(owner)}`, `REPO=${sh(repo)}`, `ISSUE_NUMBER=${sh(issueNumber)}`, `LABEL_NAME=${sh(labelName)}`, `API_BASE=${sh(u.origin)}` ].join("\n") + "\n"); NODE - name: Gate on label state/rejected run: | set -euo pipefail source /tmp/reject.env if [[ "$LABEL_NAME" != "state/rejected" ]]; then echo "ℹ️ label=$LABEL_NAME => skip" exit 0 fi echo "✅ reject issue=$ISSUE_NUMBER" - name: Comment + close issue env: FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }} run: | set -euo pipefail source /tmp/reject.env test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; } MSG="❌ Ticket #${ISSUE_NUMBER} refusé (label state/rejected)." PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")" curl -fsS -X POST \ -H "Authorization: token $FORGE_TOKEN" \ -H "Content-Type: application/json" \ "$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \ --data-binary "$PAYLOAD" curl -fsS -X PATCH \ -H "Authorization: token $FORGE_TOKEN" \ -H "Content-Type: application/json" \ "$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER" \ --data-binary '{"state":"closed"}'