#!/usr/bin/env node /** * seed-gitea-labels — crée les labels attendus (idempotent) * * Usage: * FORGE_TOKEN=... FORGE_API=http://192.168.1.20:3000 node scripts/seed-gitea-labels.mjs * (ou FORGE_BASE=https://gitea... si pas de FORGE_API) * * Optionnel: * GITEA_OWNER / GITEA_REPO (sinon auto-détecté via git remote origin) */ import { spawnSync } from "node:child_process"; function getEnv(name, fallback = "") { return (process.env[name] ?? fallback).trim(); } function inferOwnerRepoFromGit() { const r = spawnSync("git", ["remote", "get-url", "origin"], { encoding: "utf-8" }); if (r.status !== 0) return null; const u = (r.stdout || "").trim(); const m = u.match(/[:/](?[^/]+)\/(?[^/]+?)(?:\.git)?$/); if (!m?.groups) return null; return { owner: m.groups.owner, repo: m.groups.repo }; } async function apiReq(base, token, method, path, payload = null) { const url = `${base.replace(/\/+$/, "")}/api/v1${path}`; const headers = { Authorization: `token ${token}`, Accept: "application/json", "User-Agent": "archicratie-seed-labels/1.0", }; const init = { method, headers }; if (payload != null) { init.headers["Content-Type"] = "application/json"; init.body = JSON.stringify(payload); } const res = await fetch(url, init); const text = await res.text().catch(() => ""); let json = null; try { json = text ? JSON.parse(text) : null; } catch {} if (!res.ok) throw new Error(`HTTP ${res.status} ${method} ${url}\n${text}`); return json; } async function main() { const token = getEnv("FORGE_TOKEN"); if (!token) throw new Error("FORGE_TOKEN manquant"); const inferred = inferOwnerRepoFromGit() || {}; const owner = getEnv("GITEA_OWNER", inferred.owner || ""); const repo = getEnv("GITEA_REPO", inferred.repo || ""); if (!owner || !repo) throw new Error("Impossible de déterminer owner/repo (GITEA_OWNER/GITEA_REPO ou git remote)"); const base = getEnv("FORGE_API") || getEnv("FORGE_BASE"); if (!base) throw new Error("FORGE_API ou FORGE_BASE manquant"); const wanted = [ // type/* { name: "type/comment", color: "1d76db", description: "Commentaire éditorial (site)" }, { name: "type/media", color: "1d76db", description: "Media à intégrer (image/audio/video)" }, { name: "type/correction", color: "1d76db", description: "Correction proposée" }, { name: "type/fact-check", color: "1d76db", description: "Vérification / sourçage" }, // state/* { name: "state/a-trier", color: "0e8a16", description: "À trier" }, { name: "state/recevable", color: "0e8a16", description: "Recevable" }, { name: "state/a-sourcer", color: "0e8a16", description: "À sourcer" }, // scope/* { name: "scope/readers", color: "5319e7", description: "Signalé par lecteur" }, { name: "scope/editors", color: "5319e7", description: "Signalé par éditeur" }, ]; const labels = (await apiReq(base, token, "GET", `/repos/${owner}/${repo}/labels?limit=1000`)) || []; const existing = new Set(labels.map((x) => x?.name).filter(Boolean)); let created = 0; for (const L of wanted) { if (existing.has(L.name)) continue; await apiReq(base, token, "POST", `/repos/${owner}/${repo}/labels`, { name: L.name, color: L.color, description: L.description, }); created++; console.log("✅ created:", L.name); } if (created === 0) console.log("ℹ️ seed: nothing to do (all labels already exist)"); else console.log(`✅ seed done: created=${created}`); } main().catch((e) => { console.error("💥 seed-gitea-labels:", e?.message || e); process.exit(1); });