feat(cli): add ccam lanes ci status

This commit is contained in:
2026-08-25 09:33:26 +07:00
parent db9b1fcafa
commit a2fcd9bafc
3 changed files with 121 additions and 3 deletions
+40
View File
@@ -2263,6 +2263,38 @@ async function cmdLanesIntegration(args) {
process.exitCode = enabled ? 0 : 1;
}
/** `ccam lanes ci status <branch-or-sha> [<lane-id>]` — one-shot GitHub
* Actions status snapshot for a ref, via GET /:id/ci/status. Never polls;
* the caller (ship-feature-lane Stage 13) owns the wait loop. Exit code
* mirrors the derived state: 0 success, 1 failure or any error, 3 pending. */
async function cmdLanesCi(args) {
if (args[0] !== "status") {
console.error("usage: ccam lanes ci status <branch-or-sha> [<lane-id>]");
process.exitCode = 1;
return;
}
const ref = args[1];
if (!ref) {
console.error("usage: ccam lanes ci status <branch-or-sha> [<lane-id>]");
process.exitCode = 1;
return;
}
const resolved = await resolveLaneArg(args.slice(2));
if (!resolved) return;
const result = await get(
`/api/lanes/${resolved.laneId}/ci/status?ref=${encodeURIComponent(ref)}`,
undefined,
{ allowError: true }
);
if (result.status) {
console.error(`✖ ci status → ${result.data?.error?.message || result.status}`);
process.exitCode = 1;
return;
}
console.log(JSON.stringify(result, null, 2));
process.exitCode = result.state === "success" ? 0 : result.state === "pending" ? 3 : 1;
}
/**
* `ccam lanes pipeline [<template-id>] [<id>]` — show or switch which pipeline
* template a lane renders against. `ccam lanes add --pipeline` could only set
@@ -2552,6 +2584,11 @@ const COMMAND_GROUPS = [
"<name> [<id>]",
"Check whether a named integration (tracker, dev_qc, ci_wait) is on for this lane — exit 0/1",
],
[
"lanes ci status",
"<branch-or-sha> [<id>]",
"One-shot GitHub Actions status for a ref — exit 0 success / 1 failure / 3 pending",
],
[
"lanes gc",
"[--dry-run]",
@@ -3389,6 +3426,9 @@ async function runCommand(argv) {
if (rest[0] === "integration") {
return cmdLanesIntegration(rest.slice(1));
}
if (rest[0] === "ci") {
return cmdLanesCi(rest.slice(1));
}
if (rest[0] === "pipeline") {
return cmdLanesPipeline(rest.slice(1));
}