@mutmutco/cli 3.44.0 → 3.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +71 -33
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -15432,11 +15432,15 @@ function renderDocsIndex(entries) {
|
|
|
15432
15432
|
}
|
|
15433
15433
|
return lines.join("\n") + "\n";
|
|
15434
15434
|
}
|
|
15435
|
+
function sameContent(a, b) {
|
|
15436
|
+
const normalize = (text) => text.replace(/\r\n/g, "\n");
|
|
15437
|
+
return normalize(a) === normalize(b);
|
|
15438
|
+
}
|
|
15435
15439
|
function docsIndex(deps, opts = {}) {
|
|
15436
15440
|
const entries = deps.listDocs().slice().sort().map((relPath) => extractDocMeta(relPath, deps.readDoc(relPath)));
|
|
15437
15441
|
const content = renderDocsIndex(entries);
|
|
15438
15442
|
const current = deps.readIndex();
|
|
15439
|
-
const drift = current
|
|
15443
|
+
const drift = current === null || !sameContent(current, content);
|
|
15440
15444
|
let wrote = false;
|
|
15441
15445
|
if (!opts.check && drift) {
|
|
15442
15446
|
deps.writeIndex(content);
|
|
@@ -20424,13 +20428,46 @@ async function pollGhPrChecks(prNumber, repoArgs) {
|
|
|
20424
20428
|
}
|
|
20425
20429
|
return state;
|
|
20426
20430
|
}
|
|
20427
|
-
|
|
20431
|
+
function ghFailureReason(e) {
|
|
20432
|
+
const err = e;
|
|
20433
|
+
const head = String(err?.message ?? "").split("\n")[0]?.trim() ?? "";
|
|
20434
|
+
const detail = `${err?.stderr ?? ""}
|
|
20435
|
+
${err?.stdout ?? ""}`.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
|
|
20436
|
+
if (detail && head) return `${head} \u2014 ${detail}`;
|
|
20437
|
+
return detail || head || "unknown error";
|
|
20438
|
+
}
|
|
20439
|
+
var defaultGhMergeAutoIo = {
|
|
20440
|
+
gh: async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout
|
|
20441
|
+
};
|
|
20442
|
+
async function ghMergeAutoEnqueue(prNumber, repo, method, io = defaultGhMergeAutoIo) {
|
|
20428
20443
|
const args = repo ? ["--repo", repo] : [];
|
|
20429
|
-
const headRef = (await
|
|
20444
|
+
const headRef = (await io.gh(["pr", "view", prNumber, ...args, "--json", "headRefName", "--jq", ".headRefName"], GC_GH_TIMEOUT_MS2).catch(() => "")).trim();
|
|
20430
20445
|
const deleteBranch = !isProtectedBranch(headRef);
|
|
20431
|
-
const readMergeState = () => readGhPrStateWithRetry(
|
|
20446
|
+
const readMergeState = () => readGhPrStateWithRetry(
|
|
20447
|
+
() => io.gh(["pr", "view", prNumber, ...args, "--json", "state", "--jq", ".state"], GC_GH_TIMEOUT_MS2)
|
|
20448
|
+
);
|
|
20449
|
+
const confirmEnqueueOutcome = async () => {
|
|
20450
|
+
const stateRead = await readMergeState();
|
|
20451
|
+
if (!stateRead.ok) {
|
|
20452
|
+
return { mergeStatus: "failed", error: `could not read PR state after merge: ${stateRead.error}` };
|
|
20453
|
+
}
|
|
20454
|
+
if (stateRead.state === "MERGED") return { mergeStatus: "merged" };
|
|
20455
|
+
const confirmation = await confirmAutoMergeEnqueued({
|
|
20456
|
+
readAutoMergeRequest: async () => io.gh(["pr", "view", prNumber, ...args, "--json", "autoMergeRequest", "--jq", '.autoMergeRequest // ""'], GC_GH_TIMEOUT_MS2),
|
|
20457
|
+
readMerged: async () => {
|
|
20458
|
+
const s = await readMergeState();
|
|
20459
|
+
return s.ok && s.state === "MERGED";
|
|
20460
|
+
},
|
|
20461
|
+
reEnqueue: async () => {
|
|
20462
|
+
await io.gh(buildPrMergeArgs({ number: prNumber, repoArgs: args, method, auto: true, deleteBranch }), GH_MUTATION_TIMEOUT_MS);
|
|
20463
|
+
}
|
|
20464
|
+
});
|
|
20465
|
+
if (confirmation === "merged") return { mergeStatus: "merged" };
|
|
20466
|
+
if (confirmation === "enqueued") return { mergeStatus: "auto-merge-enqueued" };
|
|
20467
|
+
return { mergeStatus: "failed", error: "auto-merge did not stick \u2014 GitHub reported no autoMergeRequest after enqueue; retry once the PR has a pending check" };
|
|
20468
|
+
};
|
|
20432
20469
|
try {
|
|
20433
|
-
await
|
|
20470
|
+
await io.gh(buildPrMergeArgs({ number: prNumber, repoArgs: args, method, auto: true, deleteBranch }), GH_MUTATION_TIMEOUT_MS);
|
|
20434
20471
|
} catch (e) {
|
|
20435
20472
|
const message = String(e.message || "");
|
|
20436
20473
|
if (/already been merged/i.test(message)) return { mergeStatus: "merged" };
|
|
@@ -20438,50 +20475,51 @@ async function ghMergeAutoEnqueue(prNumber, repo, method) {
|
|
|
20438
20475
|
if (note) return { mergeStatus: "failed", error: note };
|
|
20439
20476
|
if (mergeAutoRejectedPrAlreadyClean(message)) {
|
|
20440
20477
|
try {
|
|
20441
|
-
await
|
|
20478
|
+
await io.gh(buildPrMergeArgs({ number: prNumber, repoArgs: args, method, auto: false, deleteBranch }), GH_MUTATION_TIMEOUT_MS);
|
|
20442
20479
|
} catch (e2) {
|
|
20443
20480
|
const m2 = String(e2.message || "");
|
|
20444
20481
|
if (/already been merged/i.test(m2)) return { mergeStatus: "merged" };
|
|
20445
|
-
if (!ghPrMergeLocalBranchDeleteWarning(m2))
|
|
20482
|
+
if (!ghPrMergeLocalBranchDeleteWarning(m2)) {
|
|
20483
|
+
const afterDirect = await readMergeState();
|
|
20484
|
+
if (afterDirect.ok && afterDirect.state === "MERGED") return { mergeStatus: "merged" };
|
|
20485
|
+
if (!afterDirect.ok) {
|
|
20486
|
+
return { mergeStatus: "failed", error: `could not confirm PR state after clean-status fallback: ${afterDirect.error}` };
|
|
20487
|
+
}
|
|
20488
|
+
try {
|
|
20489
|
+
await io.gh(buildPrMergeArgs({ number: prNumber, repoArgs: args, method, auto: true, deleteBranch }), GH_MUTATION_TIMEOUT_MS);
|
|
20490
|
+
} catch (e3) {
|
|
20491
|
+
const m3 = String(e3.message || "");
|
|
20492
|
+
if (/already been merged/i.test(m3)) return { mergeStatus: "merged" };
|
|
20493
|
+
const afterRetry = await readMergeState();
|
|
20494
|
+
if (afterRetry.ok && afterRetry.state === "MERGED") return { mergeStatus: "merged" };
|
|
20495
|
+
const stuck = (await io.gh(["pr", "view", prNumber, ...args, "--json", "autoMergeRequest", "--jq", '.autoMergeRequest // ""'], GC_GH_TIMEOUT_MS2).catch(() => "")).trim();
|
|
20496
|
+
if (stuck) return { mergeStatus: "auto-merge-enqueued" };
|
|
20497
|
+
return { mergeStatus: "failed", error: `${ghFailureReason(e2)} (re-enqueue also failed: ${ghFailureReason(e3)})` };
|
|
20498
|
+
}
|
|
20499
|
+
return confirmEnqueueOutcome();
|
|
20500
|
+
}
|
|
20446
20501
|
}
|
|
20447
|
-
const
|
|
20448
|
-
if (
|
|
20502
|
+
const stateRead = await readMergeState();
|
|
20503
|
+
if (stateRead.ok && stateRead.state === "MERGED") return { mergeStatus: "merged" };
|
|
20449
20504
|
return {
|
|
20450
20505
|
mergeStatus: "failed",
|
|
20451
|
-
error:
|
|
20506
|
+
error: stateRead.ok ? "direct merge did not land after clean-status fallback" : `could not confirm PR state after clean-status fallback: ${stateRead.error}`
|
|
20452
20507
|
};
|
|
20453
20508
|
}
|
|
20454
20509
|
if (ghPrMergeLocalBranchDeleteWarning(message)) {
|
|
20455
|
-
const
|
|
20456
|
-
if (
|
|
20510
|
+
const stateRead = await readMergeState();
|
|
20511
|
+
if (stateRead.ok && stateRead.state === "MERGED") return { mergeStatus: "merged" };
|
|
20457
20512
|
return {
|
|
20458
20513
|
mergeStatus: "failed",
|
|
20459
|
-
error:
|
|
20514
|
+
error: stateRead.ok ? message.split("\n")[0] : `could not confirm PR state after local branch cleanup warning: ${stateRead.error}`
|
|
20460
20515
|
};
|
|
20461
20516
|
}
|
|
20462
20517
|
if (!basePolicyBlocksImmediateMerge(message)) {
|
|
20463
|
-
return { mergeStatus: "failed", error:
|
|
20518
|
+
return { mergeStatus: "failed", error: ghFailureReason(e) };
|
|
20464
20519
|
}
|
|
20465
|
-
return { mergeStatus: "failed", error: `merge blocked: ${
|
|
20520
|
+
return { mergeStatus: "failed", error: `merge blocked: ${ghFailureReason(e)} \u2014 ensure checks are green` };
|
|
20466
20521
|
}
|
|
20467
|
-
|
|
20468
|
-
if (!stateRead.ok) {
|
|
20469
|
-
return { mergeStatus: "failed", error: `could not read PR state after merge: ${stateRead.error}` };
|
|
20470
|
-
}
|
|
20471
|
-
if (stateRead.state === "MERGED") return { mergeStatus: "merged" };
|
|
20472
|
-
const confirmation = await confirmAutoMergeEnqueued({
|
|
20473
|
-
readAutoMergeRequest: async () => (await execFileP2("gh", ["pr", "view", prNumber, ...args, "--json", "autoMergeRequest", "--jq", '.autoMergeRequest // ""'], { timeout: GC_GH_TIMEOUT_MS2 })).stdout,
|
|
20474
|
-
readMerged: async () => {
|
|
20475
|
-
const s = await readMergeState();
|
|
20476
|
-
return s.ok && s.state === "MERGED";
|
|
20477
|
-
},
|
|
20478
|
-
reEnqueue: async () => {
|
|
20479
|
-
await execFileP2("gh", buildPrMergeArgs({ number: prNumber, repoArgs: args, method, auto: true, deleteBranch }), { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
20480
|
-
}
|
|
20481
|
-
});
|
|
20482
|
-
if (confirmation === "merged") return { mergeStatus: "merged" };
|
|
20483
|
-
if (confirmation === "enqueued") return { mergeStatus: "auto-merge-enqueued" };
|
|
20484
|
-
return { mergeStatus: "failed", error: "auto-merge did not stick \u2014 GitHub reported no autoMergeRequest after enqueue; retry once the PR has a pending check" };
|
|
20522
|
+
return confirmEnqueueOutcome();
|
|
20485
20523
|
}
|
|
20486
20524
|
async function remoteBranchExists2(branch, options = {}) {
|
|
20487
20525
|
return checkRemoteBranchExists(branch, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.46.0",
|
|
4
4
|
"description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|