@mutmutco/cli 4.5.136 → 4.5.138
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 +64 -10
- package/dist/runbook-sweep.cjs +8 -2
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -14682,7 +14682,9 @@ async function claimOneBoardItem(ctx, selector, options) {
|
|
|
14682
14682
|
const wouldWrite = flatItem.assignees.length === 0 && (flatItem.status === "Todo" || flatItem.status === "In Progress" || flatItem.status === "In Review");
|
|
14683
14683
|
if (wouldWrite && !ctx.writable.has(flatItem.repository.toLowerCase())) {
|
|
14684
14684
|
throw new NotClaimableError(
|
|
14685
|
-
|
|
14685
|
+
// #8245: name the real source. With a Hub snapshot the probe is the Hub's server-side check for the
|
|
14686
|
+
// session login, not the local gh token, so `gh repo view --json viewerPermission` can disagree.
|
|
14687
|
+
`${flatItem.ref} is not claimable: no write access to ${flatItem.repository} for @${report.viewer} (read from the Hub board snapshot's access probe when one was used, else the token from ${describeTokenSource()})`,
|
|
14686
14688
|
{ ref: flatItem.ref }
|
|
14687
14689
|
);
|
|
14688
14690
|
}
|
|
@@ -18275,10 +18277,10 @@ var rollout_plan_default = {
|
|
|
18275
18277
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
18276
18278
|
},
|
|
18277
18279
|
baseline: {
|
|
18278
|
-
version: "4.5.
|
|
18279
|
-
tag: "v4.5.
|
|
18280
|
-
commit: "
|
|
18281
|
-
npm: "@mutmutco/cli@4.5.
|
|
18280
|
+
version: "4.5.138",
|
|
18281
|
+
tag: "v4.5.138",
|
|
18282
|
+
commit: "2b2ba344f112",
|
|
18283
|
+
npm: "@mutmutco/cli@4.5.138"
|
|
18282
18284
|
},
|
|
18283
18285
|
exitCriterion: "fleet-n-of-n",
|
|
18284
18286
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18295,14 +18297,14 @@ var rollout_plan_default = {
|
|
|
18295
18297
|
repo: "mutmutco/mmi-hub",
|
|
18296
18298
|
role: "canary",
|
|
18297
18299
|
schedule: "train",
|
|
18298
|
-
v3Target: "v4.5.
|
|
18300
|
+
v3Target: "v4.5.138"
|
|
18299
18301
|
}
|
|
18300
18302
|
],
|
|
18301
18303
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
18302
18304
|
rollback: {
|
|
18303
18305
|
independent: true,
|
|
18304
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18305
|
-
v3Target: "v4.5.
|
|
18306
|
+
mechanism: "npm dist-tag latest -> 4.5.138 and redeploy the Hub Lambda from tag v4.5.138 (2b2ba344f112); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18307
|
+
v3Target: "v4.5.138 (@mutmutco/cli@4.5.138, tag commit 2b2ba344f112 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18306
18308
|
}
|
|
18307
18309
|
},
|
|
18308
18310
|
{
|
|
@@ -22179,6 +22181,10 @@ async function announceShippedRelease(deps, args, model, legs, deferred) {
|
|
|
22179
22181
|
return (await deps.announce(args)).note;
|
|
22180
22182
|
}
|
|
22181
22183
|
async function listTargetRun(deps, repo, target, headSha) {
|
|
22184
|
+
const { read: _read, ...run } = await readTargetRun(deps, repo, target, headSha);
|
|
22185
|
+
return run;
|
|
22186
|
+
}
|
|
22187
|
+
async function readTargetRun(deps, repo, target, headSha) {
|
|
22182
22188
|
let rows;
|
|
22183
22189
|
try {
|
|
22184
22190
|
rows = JSON.parse(await deps.run("gh", [
|
|
@@ -22199,11 +22205,12 @@ async function listTargetRun(deps, repo, target, headSha) {
|
|
|
22199
22205
|
]));
|
|
22200
22206
|
if (!Array.isArray(rows)) throw new Error("run list did not return an array");
|
|
22201
22207
|
} catch {
|
|
22202
|
-
return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending" };
|
|
22208
|
+
return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending", read: "failed" };
|
|
22203
22209
|
}
|
|
22204
22210
|
const row = rows.find((r) => typeof r.databaseId === "number" && r.event === target.event);
|
|
22205
|
-
if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending" };
|
|
22211
|
+
if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending", read: "absent" };
|
|
22206
22212
|
return {
|
|
22213
|
+
read: "found",
|
|
22207
22214
|
workflow: target.workflow,
|
|
22208
22215
|
runId: row.databaseId,
|
|
22209
22216
|
runUrl: row.url,
|
|
@@ -25738,6 +25745,8 @@ var COMPOSE_GUARD_HARD_FAIL = /^secrets preflight: .*noEnvFile is (not )?true.*$
|
|
|
25738
25745
|
var PREFLIGHT_TIMEOUT = /aborted due to timeout|TimeoutError|ETIMEDOUT|ESOCKETTIMEDOUT|UND_ERR_(?:HEADERS|CONNECT)_TIMEOUT/i;
|
|
25739
25746
|
var PREFLIGHT_TIMEOUT_RETRIES = 2;
|
|
25740
25747
|
var PREFLIGHT_RETRY_BASE_MS = 1e3;
|
|
25748
|
+
var CANDIDATE_PUSH_GATE_WAIT_MS = 20 * 6e4;
|
|
25749
|
+
var CANDIDATE_PUSH_GATE_POLL_MS = 3e4;
|
|
25741
25750
|
function readOriginWorkflowsDefault(root, ref) {
|
|
25742
25751
|
const git3 = (args) => (0, import_node_child_process9.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
25743
25752
|
let paths;
|
|
@@ -26019,6 +26028,51 @@ async function runTrainDoctor(input) {
|
|
|
26019
26028
|
if (workflows === null && !startBranchMissing) {
|
|
26020
26029
|
add({ code: "workflows-unreadable", severity: "blocker", source: "local", title: `.github/workflows at ${workflowsRef} could not be read from ${cwd} \u2014 the tag-addressability (#5428) and npm-major (#5666) preflights did not run`, remedy: `run from a checkout whose git can read ${workflowsRef} (fetch origin first), then rerun; an unread workflow set is unverified, not green` });
|
|
26021
26030
|
}
|
|
26031
|
+
if (lane === "release" && !startBranchMissing) {
|
|
26032
|
+
const required = meta?.requiredChecks?.length ? meta.requiredChecks : ["gate"];
|
|
26033
|
+
const emitters = (workflows ?? []).filter((f) => parseWorkflowJobIds(f.body).some((id) => required.some((context) => contextMatchesJobId(id, context))));
|
|
26034
|
+
const gateFiles = emitters.length ? emitters : (workflows ?? []).filter((f) => isGateWorkflowPath(f.path));
|
|
26035
|
+
const gates = gateFiles.length ? gateFiles.map((f) => f.path.split("/").pop()) : ["gate"];
|
|
26036
|
+
try {
|
|
26037
|
+
const tip = await git3(["rev-parse", "--verify", "--quiet", `refs/remotes/origin/${startBranch}`]);
|
|
26038
|
+
for (const workflow of gates) {
|
|
26039
|
+
let run = await readTargetRun(train, repo, { workflow, event: "push" }, tip);
|
|
26040
|
+
let lastUrl = run.runUrl;
|
|
26041
|
+
let elapsed = 0;
|
|
26042
|
+
const startedAt = Date.now();
|
|
26043
|
+
while (input.refuse && run.read === "found" && run.conclusion === "pending" && elapsed < CANDIDATE_PUSH_GATE_WAIT_MS) {
|
|
26044
|
+
train.warn?.(`candidate push gate ${run.runUrl} still running \u2014 ${elapsed / 1e3}s elapsed (20m bound)`);
|
|
26045
|
+
await deps.sleep(CANDIDATE_PUSH_GATE_POLL_MS);
|
|
26046
|
+
run = await readTargetRun(train, repo, { workflow, event: "push" }, tip);
|
|
26047
|
+
elapsed = Math.max(elapsed + CANDIDATE_PUSH_GATE_POLL_MS, Date.now() - startedAt);
|
|
26048
|
+
lastUrl = run.runUrl ?? lastUrl;
|
|
26049
|
+
}
|
|
26050
|
+
const url = run.runUrl ?? lastUrl ?? (run.runId ? `https://github.com/${repo}/actions/runs/${run.runId}` : "(no run URL)");
|
|
26051
|
+
if (run.read === "failed") {
|
|
26052
|
+
originUnverified = true;
|
|
26053
|
+
add({ code: "candidate-push-gate-unread", severity: "warning", source: "origin", title: `${workflow} push runs on ${startBranch}@${tip.slice(0, 12)} could not be read`, remedy: `repair the GitHub run-list read and rerun; unread is not a pass${elapsed ? ` \u2014 last observed run: ${url}` : ""}` });
|
|
26054
|
+
if (input.refuse && elapsed) throw new Error(`candidate push gate became unreadable while waiting \u2014 ${url}; nothing was tagged`);
|
|
26055
|
+
} else if (run.read === "absent") {
|
|
26056
|
+
add({ code: "candidate-push-gate-missing", severity: "warning", source: "origin", title: `no ${workflow} push run on ${startBranch}@${tip.slice(0, 12)}`, remedy: "no pre-tag push verdict is available; some repos intentionally run gate only on PRs and tags" });
|
|
26057
|
+
} else if (run.conclusion === "failure") {
|
|
26058
|
+
let jobs = "failed jobs unreadable";
|
|
26059
|
+
try {
|
|
26060
|
+
const rows = JSON.parse(await train.run("gh", ["run", "view", String(run.runId), "--repo", repo, "--json", "jobs"]));
|
|
26061
|
+
jobs = rows.jobs.filter((j) => !["success", "skipped", "neutral", ""].includes(j.conclusion)).map((j) => j.name).join(", ") || "no failed job names reported";
|
|
26062
|
+
} catch {
|
|
26063
|
+
}
|
|
26064
|
+
add({ code: "candidate-push-gate-red", severity: "blocker", source: "origin", title: `${workflow} push gate failed on ${startBranch}@${tip.slice(0, 12)} \u2014 ${url}`, remedy: `${url} \u2014 failed job(s): ${jobs}. Fix on development through a normal CI-gated PR and rerun; --heal never clears a red gate` });
|
|
26065
|
+
} else if (run.conclusion === "pending") {
|
|
26066
|
+
add({ code: "candidate-push-gate-running", severity: "warning", source: "origin", title: `${workflow} push gate still running \u2014 ${url}`, remedy: "wait for the run to conclude and rerun; apply waits up to 20 minutes before refusing" });
|
|
26067
|
+
if (input.refuse) throw new Error(`candidate push gate still running after 20 minutes \u2014 ${url}; nothing was tagged`);
|
|
26068
|
+
}
|
|
26069
|
+
}
|
|
26070
|
+
} catch (e) {
|
|
26071
|
+
if (input.refuse) throw e;
|
|
26072
|
+
originUnverified = true;
|
|
26073
|
+
add({ code: "candidate-push-gate-unread", severity: "warning", source: "origin", title: `candidate push gate could not be read: ${message(e)}`, remedy: "repair the candidate SHA / GitHub read and rerun; unread is not a pass" });
|
|
26074
|
+
}
|
|
26075
|
+
}
|
|
26022
26076
|
if (!startBranchMissing) {
|
|
26023
26077
|
try {
|
|
26024
26078
|
const required = await discoverRequiredCheckContexts(train, ctx, stage);
|
package/dist/runbook-sweep.cjs
CHANGED
|
@@ -4548,6 +4548,10 @@ function rcWindow(since) {
|
|
|
4548
4548
|
return since === void 0 ? void 0 : since - 6e4;
|
|
4549
4549
|
}
|
|
4550
4550
|
async function listTargetRun(deps, repo, target, headSha) {
|
|
4551
|
+
const { read: _read, ...run } = await readTargetRun(deps, repo, target, headSha);
|
|
4552
|
+
return run;
|
|
4553
|
+
}
|
|
4554
|
+
async function readTargetRun(deps, repo, target, headSha) {
|
|
4551
4555
|
let rows;
|
|
4552
4556
|
try {
|
|
4553
4557
|
rows = JSON.parse(await deps.run("gh", [
|
|
@@ -4568,11 +4572,12 @@ async function listTargetRun(deps, repo, target, headSha) {
|
|
|
4568
4572
|
]));
|
|
4569
4573
|
if (!Array.isArray(rows)) throw new Error("run list did not return an array");
|
|
4570
4574
|
} catch {
|
|
4571
|
-
return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending" };
|
|
4575
|
+
return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending", read: "failed" };
|
|
4572
4576
|
}
|
|
4573
4577
|
const row = rows.find((r) => typeof r.databaseId === "number" && r.event === target.event);
|
|
4574
|
-
if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending" };
|
|
4578
|
+
if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending", read: "absent" };
|
|
4575
4579
|
return {
|
|
4580
|
+
read: "found",
|
|
4576
4581
|
workflow: target.workflow,
|
|
4577
4582
|
runId: row.databaseId,
|
|
4578
4583
|
runUrl: row.url,
|
|
@@ -5444,6 +5449,7 @@ async function selfConvergeTrainCli(input) {
|
|
|
5444
5449
|
// src/train-doctor.ts
|
|
5445
5450
|
var TROUBLESHOOTING_GUIDE = "docs/Guides/train-troubleshooting.md";
|
|
5446
5451
|
var TROUBLESHOOTING_GUIDE_URL = `https://github.com/mutmutco/MMI-Hub/blob/development/${TROUBLESHOOTING_GUIDE}`;
|
|
5452
|
+
var CANDIDATE_PUSH_GATE_WAIT_MS = 20 * 6e4;
|
|
5447
5453
|
function readOriginWorkflowsDefault(root, ref) {
|
|
5448
5454
|
const git = (args) => (0, import_node_child_process7.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
5449
5455
|
let paths;
|
package/package.json
CHANGED