97 lines
3.6 KiB
JavaScript
97 lines
3.6 KiB
JavaScript
// .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);
|
||
}); |