feat(lanes): add ccam lanes sync-base CLI (E2)
This commit is contained in:
+71
-1
@@ -1900,6 +1900,71 @@ async function cmdLanesRuntime(sub, args) {
|
|||||||
`lane #${laneId} running hook ${name} — follow it with: ccam lanes logs ${laneId} ${name}`
|
`lane #${laneId} running hook ${name} — follow it with: ccam lanes logs ${laneId} ${name}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sub === "sync-base") {
|
||||||
|
const mode = laneArgs.includes("--check")
|
||||||
|
? "check"
|
||||||
|
: laneArgs.includes("--continue")
|
||||||
|
? "continue"
|
||||||
|
: "merge";
|
||||||
|
const branch = laneArgs.find((arg) => !arg.startsWith("--"));
|
||||||
|
const result = await post(
|
||||||
|
`/api/lanes/${laneId}/sync-base`,
|
||||||
|
{ mode, branch },
|
||||||
|
{ allowError: true }
|
||||||
|
);
|
||||||
|
if (result.status) {
|
||||||
|
console.error(`✖ sync-base → ${result.data?.error?.message || result.status}`);
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.code === 5) {
|
||||||
|
console.error(`✖ lane #${laneId} — MIGRATION NUMBER COLLISION (nothing merged):`);
|
||||||
|
for (const c of result.collisions) {
|
||||||
|
console.error(` ${c.file} collides with ${c.collidesWith} — rename to ${c.suggestion}`);
|
||||||
|
}
|
||||||
|
process.exitCode = 5;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.code === 4) {
|
||||||
|
console.error(`✖ lane #${laneId} — MERGE CONFLICT (left in place).`);
|
||||||
|
console.error(` conflicted: ${result.conflictedFiles.join(", ")}`);
|
||||||
|
console.error(" resolve, then: git add <resolved files> && git commit --no-edit");
|
||||||
|
console.error(
|
||||||
|
` then: ccam lanes sync-base --continue ${branch ? branch + " " : ""}${laneId}`
|
||||||
|
);
|
||||||
|
process.exitCode = 4;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === "check") {
|
||||||
|
if (result.devDelta === null) {
|
||||||
|
console.log("DEV_DELTA: unknown (no merge-base with origin/development)");
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`DEV_DELTA: ${result.devDelta.length} file(s) changed on origin/development since merge-base`
|
||||||
|
);
|
||||||
|
for (const f of result.devDelta) console.log(` ${f}`);
|
||||||
|
if (result.overlap.length) {
|
||||||
|
console.log(
|
||||||
|
`DEV_OVERLAP: ${result.overlap.length} file(s) — the upstream delta touches the feature's files:`
|
||||||
|
);
|
||||||
|
for (const f of result.overlap) console.log(` ${f}`);
|
||||||
|
} else {
|
||||||
|
console.log("DEV_OVERLAP: none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(`lane #${laneId} preflight vs origin/development: OK`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`lane #${laneId} — synced with origin/development (re-enter the pipeline at the gates)`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2266,6 +2331,11 @@ const COMMAND_GROUPS = [
|
|||||||
["lanes runtime", "[<id>]", "Slot, ports, service health and the last boot error"],
|
["lanes runtime", "[<id>]", "Slot, ports, service health and the last boot error"],
|
||||||
["lanes logs", "[<id>] <svc> [--tail N]", "Tail one of the lane's hook or service logs"],
|
["lanes logs", "[<id>] <svc> [--tail N]", "Tail one of the lane's hook or service logs"],
|
||||||
["lanes hook", "[<id>] <name> [args…]", "Run a profile hook (ci-gate, e2e, migrate, …)"],
|
["lanes hook", "[<id>] <name> [args…]", "Run a profile hook (ci-gate, e2e, migrate, …)"],
|
||||||
|
[
|
||||||
|
"lanes sync-base",
|
||||||
|
"[<id>] [--check|--continue] [branch]",
|
||||||
|
"Fetch + migration-collision preflight, or merge origin/development into the feature branch (--check: read-only; --continue: finish after a resolved conflict; bare: merge, branch defaults to the lane's current branch)",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"lanes proof-link",
|
"lanes proof-link",
|
||||||
"[<id>]",
|
"[<id>]",
|
||||||
@@ -3085,7 +3155,7 @@ async function runCommand(argv) {
|
|||||||
if (["reset", "remove", "purge"].includes(rest[0])) {
|
if (["reset", "remove", "purge"].includes(rest[0])) {
|
||||||
return cmdLanesLifecycle(rest[0], rest.slice(1));
|
return cmdLanesLifecycle(rest[0], rest.slice(1));
|
||||||
}
|
}
|
||||||
if (["up", "down", "runtime", "logs", "hook"].includes(rest[0])) {
|
if (["up", "down", "runtime", "logs", "hook", "sync-base"].includes(rest[0])) {
|
||||||
return cmdLanesRuntime(rest[0], rest.slice(1));
|
return cmdLanesRuntime(rest[0], rest.slice(1));
|
||||||
}
|
}
|
||||||
if (rest[0] === "proof-link") return cmdLanesProofLink(rest.slice(1));
|
if (rest[0] === "proof-link") return cmdLanesProofLink(rest.slice(1));
|
||||||
|
|||||||
Reference in New Issue
Block a user