Merge pull request 'ci: fix anno apply/reject workflows (yaml valid)' (#116) from chore/fix-anno-workflows into main
Reviewed-on: #116
This commit was merged in pull request #116.
This commit is contained in:
@@ -34,106 +34,106 @@ jobs:
|
|||||||
- name: Derive context (event.json / workflow_dispatch)
|
- name: Derive context (event.json / workflow_dispatch)
|
||||||
env:
|
env:
|
||||||
INPUT_ISSUE: ${{ inputs.issue }}
|
INPUT_ISSUE: ${{ inputs.issue }}
|
||||||
|
FORGE_API: ${{ vars.FORGE_API || vars.FORGE_BASE }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
export EVENT_JSON="/var/run/act/workflow/event.json"
|
export EVENT_JSON="/var/run/act/workflow/event.json"
|
||||||
test -f "$EVENT_JSON" || { echo "❌ Missing $EVENT_JSON"; exit 1; }
|
test -f "$EVENT_JSON" || { echo "❌ Missing $EVENT_JSON"; exit 1; }
|
||||||
|
|
||||||
node --input-type=module - <<'NODE' > /tmp/anno.env
|
node --input-type=module - <<'NODE' > /tmp/anno.env
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
||||||
|
|
||||||
const repoObj = ev?.repository || {};
|
const repoObj = ev?.repository || {};
|
||||||
const cloneUrl =
|
const cloneUrl =
|
||||||
repoObj?.clone_url ||
|
repoObj?.clone_url ||
|
||||||
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
||||||
|
|
||||||
if (!cloneUrl) throw new Error("No repository clone_url/html_url in event.json");
|
if (!cloneUrl) throw new Error("No repository clone_url/html_url in event.json");
|
||||||
|
|
||||||
let owner =
|
let owner =
|
||||||
repoObj?.owner?.login ||
|
repoObj?.owner?.login ||
|
||||||
repoObj?.owner?.username ||
|
repoObj?.owner?.username ||
|
||||||
(repoObj?.full_name ? repoObj.full_name.split("/")[0] : "");
|
(repoObj?.full_name ? repoObj.full_name.split("/")[0] : "");
|
||||||
|
|
||||||
let repo =
|
let repo =
|
||||||
repoObj?.name ||
|
repoObj?.name ||
|
||||||
(repoObj?.full_name ? repoObj.full_name.split("/")[1] : "");
|
(repoObj?.full_name ? repoObj.full_name.split("/")[1] : "");
|
||||||
|
|
||||||
if (!owner || !repo) {
|
if (!owner || !repo) {
|
||||||
// fallback parse from clone url
|
const m = cloneUrl.match(/[:/](?<o>[^/]+)\/(?<r>[^/]+?)(?:\.git)?$/);
|
||||||
const m = cloneUrl.match(/[:/](?<o>[^/]+)\/(?<r>[^/]+?)(?:\.git)?$/);
|
if (m?.groups) { owner = owner || m.groups.o; repo = repo || m.groups.r; }
|
||||||
if (m?.groups) { owner = owner || m.groups.o; repo = repo || m.groups.r; }
|
}
|
||||||
}
|
if (!owner || !repo) throw new Error("Cannot infer owner/repo");
|
||||||
if (!owner || !repo) throw new Error("Cannot infer owner/repo");
|
|
||||||
|
|
||||||
const defaultBranch = repoObj?.default_branch || "master";
|
const defaultBranch = repoObj?.default_branch || "main";
|
||||||
|
|
||||||
const issueNumber =
|
const issueNumber =
|
||||||
ev?.issue?.number ||
|
ev?.issue?.number ||
|
||||||
ev?.issue?.index ||
|
ev?.issue?.index ||
|
||||||
(process.env.INPUT_ISSUE ? Number(process.env.INPUT_ISSUE) : 0);
|
(process.env.INPUT_ISSUE ? Number(process.env.INPUT_ISSUE) : 0);
|
||||||
|
|
||||||
if (!issueNumber || !Number.isFinite(Number(issueNumber))) {
|
if (!issueNumber || !Number.isFinite(Number(issueNumber))) {
|
||||||
throw new Error("No issue number in event.json or workflow_dispatch input");
|
throw new Error("No issue number in event.json or workflow_dispatch input");
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelName =
|
const labelName =
|
||||||
ev?.label?.name ||
|
ev?.label?.name ||
|
||||||
ev?.label ||
|
ev?.label ||
|
||||||
"workflow_dispatch";
|
"workflow_dispatch";
|
||||||
|
|
||||||
const u = new URL(cloneUrl);
|
const u = new URL(cloneUrl);
|
||||||
const origin = u.origin; // https://gitea...
|
const origin = u.origin;
|
||||||
const apiBase = (process.env.FORGE_API && process.env.FORGE_API.trim())
|
|
||||||
? process.env.FORGE_API.trim().replace(/\/+$/,"")
|
|
||||||
: origin;
|
|
||||||
|
|
||||||
function sh(s){ return JSON.stringify(String(s)); }
|
const apiBase = (process.env.FORGE_API && String(process.env.FORGE_API).trim())
|
||||||
|
? String(process.env.FORGE_API).trim().replace(/\/+$/,"")
|
||||||
|
: origin;
|
||||||
|
|
||||||
process.stdout.write([
|
function sh(s){ return JSON.stringify(String(s)); }
|
||||||
`CLONE_URL=${sh(cloneUrl)}`,
|
|
||||||
`OWNER=${sh(owner)}`,
|
process.stdout.write([
|
||||||
`REPO=${sh(repo)}`,
|
`CLONE_URL=${sh(cloneUrl)}`,
|
||||||
`DEFAULT_BRANCH=${sh(defaultBranch)}`,
|
`OWNER=${sh(owner)}`,
|
||||||
`ISSUE_NUMBER=${sh(issueNumber)}`,
|
`REPO=${sh(repo)}`,
|
||||||
`LABEL_NAME=${sh(labelName)}`,
|
`DEFAULT_BRANCH=${sh(defaultBranch)}`,
|
||||||
`API_BASE=${sh(apiBase)}`,
|
`ISSUE_NUMBER=${sh(issueNumber)}`,
|
||||||
].join("\n") + "\n");
|
`LABEL_NAME=${sh(labelName)}`,
|
||||||
NODE
|
`API_BASE=${sh(apiBase)}`
|
||||||
|
].join("\n") + "\n");
|
||||||
|
NODE
|
||||||
|
|
||||||
echo "✅ context:"
|
echo "✅ context:"
|
||||||
sed -n '1,80p' /tmp/anno.env
|
sed -n '1,120p' /tmp/anno.env
|
||||||
|
|
||||||
- name: Gate on label state/approved
|
- name: Gate on label state/approved
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
if [[ "$LABEL_NAME" != "state/approved" && "$LABEL_NAME" != "workflow_dispatch" ]]; then
|
if [[ "$LABEL_NAME" != "state/approved" && "$LABEL_NAME" != "workflow_dispatch" ]]; then
|
||||||
echo "ℹ️ label=$LABEL_NAME => skip (only state/approved triggers apply)"
|
echo "ℹ️ label=$LABEL_NAME => skip"
|
||||||
|
echo 'SKIP=1' >> /tmp/anno.env
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "✅ proceed (label=$LABEL_NAME issue=$ISSUE_NUMBER)"
|
echo "✅ proceed (issue=$ISSUE_NUMBER)"
|
||||||
|
|
||||||
- name: Checkout default branch (from event.json, no external actions)
|
- name: Checkout default branch
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
|
|
||||||
rm -rf .git
|
rm -rf .git
|
||||||
git init -q
|
git init -q
|
||||||
git remote add origin "$CLONE_URL"
|
git remote add origin "$CLONE_URL"
|
||||||
|
|
||||||
echo "Repo URL: $CLONE_URL"
|
|
||||||
echo "Base: $DEFAULT_BRANCH"
|
|
||||||
|
|
||||||
git fetch --depth 1 origin "$DEFAULT_BRANCH"
|
git fetch --depth 1 origin "$DEFAULT_BRANCH"
|
||||||
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
||||||
git log -1 --oneline
|
|
||||||
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
source /tmp/anno.env
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
npm ci
|
npm ci
|
||||||
|
|
||||||
- name: Apply ticket on bot branch (strict+verify, commit)
|
- name: Apply ticket on bot branch (strict+verify, commit)
|
||||||
@@ -144,21 +144,18 @@ NODE
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; }
|
test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; }
|
||||||
|
|
||||||
# git identity (required for commits)
|
|
||||||
git config user.name "${BOT_GIT_NAME:-archicratie-bot}"
|
git config user.name "${BOT_GIT_NAME:-archicratie-bot}"
|
||||||
git config user.email "${BOT_GIT_EMAIL:-bot@archicratie.local}"
|
git config user.email "${BOT_GIT_EMAIL:-bot@archicratie.local}"
|
||||||
|
|
||||||
START_SHA="$(git rev-parse HEAD)"
|
START_SHA="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
TS="$(date -u +%Y%m%d-%H%M%S)"
|
TS="$(date -u +%Y%m%d-%H%M%S)"
|
||||||
BR="bot/anno-${ISSUE_NUMBER}-${TS}"
|
BR="bot/anno-${ISSUE_NUMBER}-${TS}"
|
||||||
echo "BRANCH=$BR" >> /tmp/anno.env
|
echo "BRANCH=$BR" >> /tmp/anno.env
|
||||||
git checkout -b "$BR"
|
git checkout -b "$BR"
|
||||||
|
|
||||||
# env for script
|
|
||||||
export FORGE_API="$API_BASE"
|
export FORGE_API="$API_BASE"
|
||||||
export GITEA_OWNER="$OWNER"
|
export GITEA_OWNER="$OWNER"
|
||||||
export GITEA_REPO="$REPO"
|
export GITEA_REPO="$REPO"
|
||||||
@@ -169,11 +166,9 @@ NODE
|
|||||||
RC=$?
|
RC=$?
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "== apply log (tail) =="
|
tail -n 160 "$LOG" || true
|
||||||
tail -n 120 "$LOG" || true
|
|
||||||
|
|
||||||
END_SHA="$(git rev-parse HEAD)"
|
END_SHA="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
if [[ "$RC" -ne 0 ]]; then
|
if [[ "$RC" -ne 0 ]]; then
|
||||||
echo "APPLY_RC=$RC" >> /tmp/anno.env
|
echo "APPLY_RC=$RC" >> /tmp/anno.env
|
||||||
exit "$RC"
|
exit "$RC"
|
||||||
@@ -186,46 +181,17 @@ NODE
|
|||||||
echo "END_SHA=$END_SHA" >> /tmp/anno.env
|
echo "END_SHA=$END_SHA" >> /tmp/anno.env
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Comment issue on failure (strict/verify/etc)
|
|
||||||
if: ${{ always() }}
|
|
||||||
env:
|
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
source /tmp/anno.env
|
|
||||||
# si apply a échoué, la step précédente s'arrête => ce step tourne quand même (always)
|
|
||||||
if [[ -z "${APPLY_RC:-}" ]]; then
|
|
||||||
echo "ℹ️ no failure detected"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
BODY="$(tail -n 120 /tmp/apply.log | sed 's/\r$//' )"
|
|
||||||
MSG="❌ apply-annotation-ticket a échoué (rc=${APPLY_RC}).\n\n\`\`\`\n${BODY}\n\`\`\`\n"
|
|
||||||
|
|
||||||
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.env.MSG}))' \
|
|
||||||
MSG="$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"
|
|
||||||
|
|
||||||
exit "${APPLY_RC}"
|
|
||||||
|
|
||||||
- name: Comment issue if no-op (already applied)
|
- name: Comment issue if no-op (already applied)
|
||||||
env:
|
env:
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
if [[ "${NOOP:-0}" != "1" ]]; then
|
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||||
echo "ℹ️ changes exist -> will create PR"
|
[[ "${NOOP:-0}" == "1" ]] || exit 0
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
MSG="ℹ️ Ticket #${ISSUE_NUMBER} : rien à appliquer (déjà présent / dédupliqué)."
|
MSG="ℹ️ Ticket #${ISSUE_NUMBER} : rien à appliquer (déjà présent / dédupliqué)."
|
||||||
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.env.MSG}))' MSG="$MSG")"
|
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")"
|
||||||
|
|
||||||
curl -fsS -X POST \
|
curl -fsS -X POST \
|
||||||
-H "Authorization: token $FORGE_TOKEN" \
|
-H "Authorization: token $FORGE_TOKEN" \
|
||||||
@@ -233,24 +199,22 @@ NODE
|
|||||||
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
||||||
--data-binary "$PAYLOAD"
|
--data-binary "$PAYLOAD"
|
||||||
|
|
||||||
echo "✅ no-op handled"
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
- name: Push bot branch
|
- name: Push bot branch
|
||||||
env:
|
env:
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
test "${NOOP:-0}" = "0" || { echo "ℹ️ no-op -> skip push"; exit 0; }
|
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||||
|
[[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip push"; exit 0; }
|
||||||
|
|
||||||
# auth remote (Gitea supports oauth2:<token>)
|
|
||||||
AUTH_URL="$(node --input-type=module -e '
|
AUTH_URL="$(node --input-type=module -e '
|
||||||
const u = new URL(process.env.CLONE_URL);
|
const [clone, tok] = process.argv.slice(1);
|
||||||
|
const u = new URL(clone);
|
||||||
u.username = "oauth2";
|
u.username = "oauth2";
|
||||||
u.password = process.env.FORGE_TOKEN;
|
u.password = tok;
|
||||||
console.log(u.toString());
|
console.log(u.toString());
|
||||||
' CLONE_URL="$CLONE_URL" FORGE_TOKEN="$FORGE_TOKEN")"
|
' "$CLONE_URL" "$FORGE_TOKEN")"
|
||||||
|
|
||||||
git remote set-url origin "$AUTH_URL"
|
git remote set-url origin "$AUTH_URL"
|
||||||
git push -u origin "$BRANCH"
|
git push -u origin "$BRANCH"
|
||||||
@@ -261,20 +225,16 @@ NODE
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
test "${NOOP:-0}" = "0" || { echo "ℹ️ no-op -> skip PR"; exit 0; }
|
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||||
|
[[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip PR"; exit 0; }
|
||||||
|
|
||||||
PR_TITLE="anno: apply ticket #${ISSUE_NUMBER}"
|
PR_TITLE="anno: apply ticket #${ISSUE_NUMBER}"
|
||||||
PR_BODY="PR générée automatiquement à partir du ticket #${ISSUE_NUMBER} (label state/approved).\n\n- Branche: ${BRANCH}\n- Commit: ${END_SHA}\n\nMerge si CI OK."
|
PR_BODY="PR auto depuis ticket #${ISSUE_NUMBER} (state/approved).\n\n- Branche: ${BRANCH}\n- Commit: ${END_SHA}\n\nMerge si CI OK."
|
||||||
|
|
||||||
PR_PAYLOAD="$(node --input-type=module -e '
|
PR_PAYLOAD="$(node --input-type=module -e '
|
||||||
console.log(JSON.stringify({
|
const [title, body, base, head] = process.argv.slice(1);
|
||||||
title: process.env.PR_TITLE,
|
console.log(JSON.stringify({ title, body, base, head, allow_maintainer_edit: true }));
|
||||||
body: process.env.PR_BODY,
|
' "$PR_TITLE" "$PR_BODY" "$DEFAULT_BRANCH" "${OWNER}:${BRANCH}")"
|
||||||
base: process.env.DEFAULT_BRANCH,
|
|
||||||
head: `${process.env.OWNER}:${process.env.BRANCH}`,
|
|
||||||
allow_maintainer_edit: true
|
|
||||||
}));
|
|
||||||
' PR_TITLE="$PR_TITLE" PR_BODY="$PR_BODY" OWNER="$OWNER" BRANCH="$BRANCH" DEFAULT_BRANCH="$DEFAULT_BRANCH")"
|
|
||||||
|
|
||||||
PR_JSON="$(curl -fsS -X POST \
|
PR_JSON="$(curl -fsS -X POST \
|
||||||
-H "Authorization: token $FORGE_TOKEN" \
|
-H "Authorization: token $FORGE_TOKEN" \
|
||||||
@@ -283,19 +243,17 @@ NODE
|
|||||||
--data-binary "$PR_PAYLOAD")"
|
--data-binary "$PR_PAYLOAD")"
|
||||||
|
|
||||||
PR_URL="$(node --input-type=module -e '
|
PR_URL="$(node --input-type=module -e '
|
||||||
const pr = JSON.parse(process.env.PR_JSON);
|
const pr = JSON.parse(process.argv[1] || "{}");
|
||||||
console.log(pr.html_url || pr.url || "");
|
console.log(pr.html_url || pr.url || "");
|
||||||
' PR_JSON="$PR_JSON")"
|
' "$PR_JSON")"
|
||||||
|
|
||||||
test -n "$PR_URL" || { echo "❌ PR URL missing. Raw: $PR_JSON"; exit 1; }
|
test -n "$PR_URL" || { echo "❌ PR URL missing. Raw: $PR_JSON"; exit 1; }
|
||||||
|
|
||||||
MSG="✅ PR créée pour ticket #${ISSUE_NUMBER} : ${PR_URL}"
|
MSG="✅ PR créée pour ticket #${ISSUE_NUMBER} : ${PR_URL}"
|
||||||
C_PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.env.MSG}))' MSG="$MSG")"
|
C_PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")"
|
||||||
|
|
||||||
curl -fsS -X POST \
|
curl -fsS -X POST \
|
||||||
-H "Authorization: token $FORGE_TOKEN" \
|
-H "Authorization: token $FORGE_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
||||||
--data-binary "$C_PAYLOAD"
|
--data-binary "$C_PAYLOAD"
|
||||||
|
|
||||||
echo "✅ PR: $PR_URL"
|
|
||||||
@@ -25,46 +25,44 @@ jobs:
|
|||||||
test -f "$EVENT_JSON" || { echo "❌ Missing $EVENT_JSON"; exit 1; }
|
test -f "$EVENT_JSON" || { echo "❌ Missing $EVENT_JSON"; exit 1; }
|
||||||
|
|
||||||
node --input-type=module - <<'NODE' > /tmp/reject.env
|
node --input-type=module - <<'NODE' > /tmp/reject.env
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
||||||
const repoObj = ev?.repository || {};
|
const repoObj = ev?.repository || {};
|
||||||
const cloneUrl =
|
const cloneUrl =
|
||||||
repoObj?.clone_url ||
|
repoObj?.clone_url ||
|
||||||
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
||||||
if (!cloneUrl) throw new Error("No repository url");
|
if (!cloneUrl) throw new Error("No repository url");
|
||||||
|
|
||||||
let owner =
|
let owner =
|
||||||
repoObj?.owner?.login ||
|
repoObj?.owner?.login ||
|
||||||
repoObj?.owner?.username ||
|
repoObj?.owner?.username ||
|
||||||
(repoObj?.full_name ? repoObj.full_name.split("/")[0] : "");
|
(repoObj?.full_name ? repoObj.full_name.split("/")[0] : "");
|
||||||
let repo =
|
let repo =
|
||||||
repoObj?.name ||
|
repoObj?.name ||
|
||||||
(repoObj?.full_name ? repoObj.full_name.split("/")[1] : "");
|
(repoObj?.full_name ? repoObj.full_name.split("/")[1] : "");
|
||||||
|
|
||||||
if (!owner || !repo) {
|
if (!owner || !repo) {
|
||||||
const m = cloneUrl.match(/[:/](?<o>[^/]+)\/(?<r>[^/]+?)(?:\.git)?$/);
|
const m = cloneUrl.match(/[:/](?<o>[^/]+)\/(?<r>[^/]+?)(?:\.git)?$/);
|
||||||
if (m?.groups) { owner = owner || m.groups.o; repo = repo || m.groups.r; }
|
if (m?.groups) { owner = owner || m.groups.o; repo = repo || m.groups.r; }
|
||||||
}
|
}
|
||||||
if (!owner || !repo) throw new Error("Cannot infer owner/repo");
|
if (!owner || !repo) throw new Error("Cannot infer owner/repo");
|
||||||
|
|
||||||
const issueNumber = ev?.issue?.number || ev?.issue?.index;
|
const issueNumber = ev?.issue?.number || ev?.issue?.index;
|
||||||
if (!issueNumber) throw new Error("No issue number");
|
if (!issueNumber) throw new Error("No issue number");
|
||||||
|
|
||||||
const labelName = ev?.label?.name || ev?.label || "";
|
const labelName = ev?.label?.name || ev?.label || "";
|
||||||
|
const u = new URL(cloneUrl);
|
||||||
|
|
||||||
const u = new URL(cloneUrl);
|
function sh(s){ return JSON.stringify(String(s)); }
|
||||||
const apiBase = u.origin;
|
process.stdout.write([
|
||||||
|
`OWNER=${sh(owner)}`,
|
||||||
function sh(s){ return JSON.stringify(String(s)); }
|
`REPO=${sh(repo)}`,
|
||||||
process.stdout.write([
|
`ISSUE_NUMBER=${sh(issueNumber)}`,
|
||||||
`OWNER=${sh(owner)}`,
|
`LABEL_NAME=${sh(labelName)}`,
|
||||||
`REPO=${sh(repo)}`,
|
`API_BASE=${sh(u.origin)}`
|
||||||
`ISSUE_NUMBER=${sh(issueNumber)}`,
|
].join("\n") + "\n");
|
||||||
`LABEL_NAME=${sh(labelName)}`,
|
NODE
|
||||||
`API_BASE=${sh(apiBase)}`
|
|
||||||
].join("\n") + "\n");
|
|
||||||
NODE
|
|
||||||
|
|
||||||
- name: Gate on label state/rejected
|
- name: Gate on label state/rejected
|
||||||
run: |
|
run: |
|
||||||
@@ -85,7 +83,7 @@ NODE
|
|||||||
test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; }
|
test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; }
|
||||||
|
|
||||||
MSG="❌ Ticket #${ISSUE_NUMBER} refusé (label state/rejected)."
|
MSG="❌ Ticket #${ISSUE_NUMBER} refusé (label state/rejected)."
|
||||||
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.env.MSG}))' MSG="$MSG")"
|
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")"
|
||||||
|
|
||||||
curl -fsS -X POST \
|
curl -fsS -X POST \
|
||||||
-H "Authorization: token $FORGE_TOKEN" \
|
-H "Authorization: token $FORGE_TOKEN" \
|
||||||
@@ -97,6 +95,4 @@ NODE
|
|||||||
-H "Authorization: token $FORGE_TOKEN" \
|
-H "Authorization: token $FORGE_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER" \
|
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER" \
|
||||||
--data-binary '{"state":"closed"}'
|
--data-binary '{"state":"closed"}'
|
||||||
|
|
||||||
echo "✅ closed #$ISSUE_NUMBER"
|
|
||||||
Reference in New Issue
Block a user