diff --git a/.gitea/workflows/anno-apply-pr.yml b/.gitea/workflows/anno-apply-pr.yml index 8bf69ea..e3895b8 100644 --- a/.gitea/workflows/anno-apply-pr.yml +++ b/.gitea/workflows/anno-apply-pr.yml @@ -136,8 +136,16 @@ jobs: -H "Accept: application/json" \ "$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER")" - node --input-type=module - <<'NODE' "$ISSUE_JSON" >> /tmp/anno.env - const issue = JSON.parse(process.argv[1] || "{}"); + # ✅ Robust: write JSON to file (avoid argv/stdi n "-" issue) + printf '%s' "$ISSUE_JSON" > /tmp/issue.json + + node --input-type=module - /tmp/issue.json >> /tmp/anno.env <<'NODE' + import fs from "node:fs"; + + const fp = process.argv[2] || ""; + const raw = fp ? fs.readFileSync(fp, "utf8") : "{}"; + const issue = JSON.parse(raw || "{}"); + const title = String(issue.title || ""); const body = String(issue.body || "").replace(/\r\n/g, "\n"); @@ -185,12 +193,11 @@ jobs: source /tmp/anno.env || true [[ "${SKIP:-0}" == "1" ]] || exit 0 - [[ "$LABEL_NAME" == "state/approved" || "$LABEL_NAME" == "workflow_dispatch" ]] || exit 0 + [[ "${LABEL_NAME:-}" == "state/approved" || "${LABEL_NAME:-}" == "workflow_dispatch" ]] || exit 0 + test -n "${FORGE_TOKEN:-}" || { echo "ℹ️ missing FORGE_TOKEN -> skip comment"; exit 0; } - # message différent si Proposer REASON="${SKIP_REASON:-}" TYPE="${ISSUE_TYPE:-}" - TITLE="${ISSUE_TITLE:-}" if [[ "$REASON" == proposer_type:* ]]; then MSG="ℹ️ Ticket #${ISSUE_NUMBER} détecté comme **Proposer** (${TYPE}).\n\n- Ce type est **traité manuellement par les editors** (correction/fact-check + cat/*).\n- Le bot n'applique **jamais** Proposer et n'ajoute **jamais** state/approved automatiquement.\n\n✅ Action : traitement éditorial manuel." @@ -245,7 +252,7 @@ jobs: source /tmp/anno.env [[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; } - npm run build + npm run build:clean test -f dist/para-index.json || { echo "❌ missing dist/para-index.json after build" @@ -320,6 +327,8 @@ jobs: exit 0 fi + test -n "${FORGE_TOKEN:-}" || { echo "ℹ️ missing FORGE_TOKEN -> skip comment"; exit 0; } + if [[ -f /tmp/apply.log ]]; then BODY="$(tail -n 160 /tmp/apply.log | sed 's/\r$//')" else @@ -347,6 +356,8 @@ jobs: [[ "${APPLY_RC:-0}" == "0" ]] || exit 0 [[ "${NOOP:-0}" == "1" ]] || exit 0 + test -n "${FORGE_TOKEN:-}" || { echo "ℹ️ missing FORGE_TOKEN -> skip comment"; exit 0; } + MSG="ℹ️ Ticket #${ISSUE_NUMBER} : rien à appliquer (déjà présent / dédupliqué)." PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")" @@ -368,6 +379,10 @@ jobs: [[ "${APPLY_RC:-0}" == "0" ]] || { echo "ℹ️ apply failed -> skip push"; exit 0; } [[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip push"; exit 0; } + test -d .git || { echo "ℹ️ no git repo -> skip push"; exit 0; } + test -n "${BRANCH:-}" || { echo "ℹ️ missing BRANCH -> skip push"; exit 0; } + test -n "${FORGE_TOKEN:-}" || { echo "ℹ️ missing FORGE_TOKEN -> skip push"; exit 0; } + AUTH_URL="$(node --input-type=module -e ' const [clone, tok] = process.argv.slice(1); const u = new URL(clone); @@ -391,6 +406,10 @@ jobs: [[ "${APPLY_RC:-0}" == "0" ]] || { echo "ℹ️ apply failed -> skip PR"; exit 0; } [[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip PR"; exit 0; } + test -n "${BRANCH:-}" || { echo "ℹ️ missing BRANCH -> skip PR"; exit 0; } + test -n "${END_SHA:-}" || { echo "ℹ️ missing END_SHA -> skip PR"; exit 0; } + test -n "${FORGE_TOKEN:-}" || { echo "ℹ️ missing FORGE_TOKEN -> skip PR"; exit 0; } + PR_TITLE="anno: apply ticket #${ISSUE_NUMBER}" PR_BODY="PR auto depuis ticket #${ISSUE_NUMBER} (state/approved).\n\n- Branche: ${BRANCH}\n- Commit: ${END_SHA}\n\nMerge si CI OK." diff --git a/.gitea/workflows/anno-reject.yml b/.gitea/workflows/anno-reject.yml index 5fcd57a..c6bca55 100644 --- a/.gitea/workflows/anno-reject.yml +++ b/.gitea/workflows/anno-reject.yml @@ -131,12 +131,23 @@ jobs: -H "Accept: application/json" \ "$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER")" - # conflict guard: approved + rejected => do nothing, comment warning - node --input-type=module - <<'NODE' "$ISSUE_JSON" > /tmp/reject.flags - const issue = JSON.parse(process.argv[1] || "{}"); - const labels = Array.isArray(issue.labels) ? issue.labels.map(l => String(l.name || "")).filter(Boolean) : []; + # ✅ Robust: write JSON to file (avoid argv/stdi n "-" issue) + printf '%s' "$ISSUE_JSON" > /tmp/issue.json + + node --input-type=module - /tmp/issue.json > /tmp/reject.flags <<'NODE' + import fs from "node:fs"; + + const fp = process.argv[2] || ""; + const raw = fp ? fs.readFileSync(fp, "utf8") : "{}"; + const issue = JSON.parse(raw || "{}"); + + const labels = Array.isArray(issue.labels) + ? issue.labels.map(l => String(l.name || "")).filter(Boolean) + : []; + const hasApproved = labels.includes("state/approved"); const hasRejected = labels.includes("state/rejected"); + process.stdout.write(`HAS_APPROVED=${hasApproved ? "1":"0"}\nHAS_REJECTED=${hasRejected ? "1":"0"}\n`); NODE @@ -154,7 +165,6 @@ jobs: exit 0 fi - # comment reject MSG="❌ Ticket #${ISSUE_NUMBER} refusé (label state/rejected)." PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")" @@ -164,7 +174,6 @@ jobs: "$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \ --data-binary "$PAYLOAD" - # close issue curl -fsS -X PATCH \ -H "Authorization: token $FORGE_TOKEN" \ -H "Content-Type: application/json" \