// .gitea/scripts/getLatestRunWithArtifacts.js // Robust finder: uses only Gitea API (no GUI URLs). const fs = require("fs"); const path = require("path"); const BASE = process.env.GITEA_BASE_URL; // e.g. https://code.bim-it.pl const OWNER = process.env.OWNER; // e.g. mz const REPO = process.env.REPO; // e.g. DiunaBI const TOKEN = process.env.GITEA_PAT; const SCAN_LIMIT = Number(process.env.SCAN_LIMIT || "100"); const REQUIRED_ARTIFACTS = (process.env.REQUIRED_ARTIFACTS || "frontend,webapi") .split(",").map(s => s.trim()).filter(Boolean); if (!BASE || !OWNER || !REPO) { console.error("Missing one of: GITEA_BASE_URL, OWNER, REPO"); process.exit(1); } if (!TOKEN) { console.error("Missing GITEA_PAT"); process.exit(1); } const cacheDir = path.join(".gitea", ".cache"); fs.mkdirSync(cacheDir, { recursive: true }); async function apiJSON(url) { const res = await fetch(url, { headers: { Authorization: `token ${TOKEN}` } }); if (!res.ok) { const t = await res.text().catch(()=>""); throw new Error(`API ${res.status} for ${url}\n${t}`); } return res.json(); } (async () => { // 1) Pobierz listę tasków (runs) const listUrl = `${BASE}/api/v1/repos/${OWNER}/${REPO}/actions/tasks?limit=${SCAN_LIMIT}`; const resp = await apiJSON(listUrl); // Gitea 1.24 może zwracać różne kształty – normalizujemy: const raw = Array.isArray(resp) ? resp : (resp.workflow_runs || resp.tasks || resp.data || []); if (!Array.isArray(raw) || raw.length === 0) { console.error("No runs returned by API."); process.exit(1); } // 2) Filtrujemy „successful” const isSuccess = (r) => { const s = (r.status || "").toLowerCase(); // "success" / "completed" const c = (r.conclusion || "").toLowerCase(); // "success" (czasem brak) return s === "success" || (s === "completed" && c === "success"); }; const candidates = raw .filter(r => r && (r.id != null)) .sort((a, b) => (b.id ?? 0) - (a.id ?? 0)) .filter(isSuccess); if (candidates.length === 0) { console.error("No successful runs found."); process.exit(1); } console.log(`Scanning ${candidates.length} successful runs for artifacts: ${REQUIRED_ARTIFACTS.join(", ")}`); // 3) Sprawdź artefakty przez API let pickedId = null; for (const r of candidates) { const runId = r.id; const artsUrl = `${BASE}/api/v1/repos/${OWNER}/${REPO}/actions/runs/${runId}/artifacts`; try { const arts = await apiJSON(artsUrl); const names = (Array.isArray(arts?.artifacts) ? arts.artifacts : arts || []) .map(a => a?.name) .filter(Boolean); const ok = REQUIRED_ARTIFACTS.every(req => names.includes(req)); if (ok) { pickedId = runId; break; } console.log(`Run ${runId}: lacks required artifacts (has: ${names.join(", ") || "none"})`); } catch (e) { console.log(`Run ${runId}: cannot read artifacts via API -> ${e.message.split("\n")[0]}`); } } if (!pickedId) { console.error("No run exposes all required artifacts via API."); process.exit(1); } // 4) Zapisz outputy fs.writeFileSync(path.join(cacheDir, "run_id"), String(pickedId), "utf8"); if (process.env.GITHUB_OUTPUT) { fs.appendFileSync(process.env.GITHUB_OUTPUT, `run_id=${pickedId}\n`); } console.log(`Picked run_id=${pickedId}`); })().catch(err => { console.error(err.stack || err.message || String(err)); process.exit(1); });