Files
AgentHub/server/lib/ci-status.js
T

62 lines
1.8 KiB
JavaScript

/**
* @file Turns a GitHub Actions run for one ref into a single derived fact —
* {state, checks} — for ship-feature-lane's Stage 13 CI-wait. Deliberately a
* snapshot, not a poll loop: the driving skill owns the wait/retry decision
* (docs/LANES.md "Orchestration: what CCAM does NOT do"), this module only
* reports what gh already knows.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
const { gh } = require("./gh");
/** A 7-40 char hex string reads as a commit sha; anything else is a branch name. */
const SHA_RE = /^[0-9a-f]{7,40}$/i;
/**
* @param {string} cwd - The lane's repo directory (gh resolves the GitHub
* repo from this directory's git remote).
* @param {string} ref - A branch name or commit sha.
* @returns {Promise<{state: "success"|"failure"|"pending", ref: string, checks: Array}>}
*/
async function ciStatus(cwd, ref) {
const refFlag = SHA_RE.test(ref) ? "--commit" : "--branch";
const { stdout: listOut } = await gh(cwd, [
"run",
"list",
refFlag,
ref,
"--json",
"databaseId,status,conclusion",
"--limit",
"1",
]);
const runs = JSON.parse(listOut);
if (runs.length === 0) {
return { state: "pending", ref, checks: [] };
}
const run = runs[0];
if (run.status !== "completed") {
return { state: "pending", ref, checks: [] };
}
const { stdout: viewOut } = await gh(cwd, [
"run",
"view",
String(run.databaseId),
"--json",
"jobs",
]);
const { jobs } = JSON.parse(viewOut);
const checks = jobs.map((job) => ({
name: job.name,
conclusion: job.conclusion || job.status,
url: job.url || null,
}));
const FAILING = new Set(["failure", "cancelled", "timed_out", "action_required"]);
const state = checks.some((c) => FAILING.has(c.conclusion)) ? "failure" : "success";
return { state, ref, checks };
}
module.exports = { ciStatus };