@mutmutco/cli 4.5.81 → 4.5.83
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 +79 -15
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -6390,6 +6390,16 @@ var RUNNER_INFRA_PRESTART_CONCLUSIONS = /* @__PURE__ */ new Set([
|
|
|
6390
6390
|
"cancelled",
|
|
6391
6391
|
"startup_failure"
|
|
6392
6392
|
]);
|
|
6393
|
+
var TEST_FAILURE_LINE = /^(?:✖|not ok\b|FAIL\b|×)|\bAssertionError\b/;
|
|
6394
|
+
function firstTestFailureLine(log) {
|
|
6395
|
+
for (const raw of log.split(/\r?\n/)) {
|
|
6396
|
+
const line = raw.replace(/^\uFEFF?\d{4}-\d\d-\d\dT[\d:.]+Z\s*/, "").replace(/\x1b\[[0-9;]*m/g, "").trim();
|
|
6397
|
+
if (TEST_FAILURE_LINE.test(line)) {
|
|
6398
|
+
return line.replace(/\b(?:gh[pousr]_|github_pat_|AKIA|sk-)[\w-]+/g, "[redacted]").slice(0, 200);
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
6401
|
+
return void 0;
|
|
6402
|
+
}
|
|
6393
6403
|
var BARE_CHECKS_FAILURE_MESSAGE = "GitHub reported a checks failure but exposed no per-check data.";
|
|
6394
6404
|
function actionRunIdFromDetailsUrl(detailsUrl) {
|
|
6395
6405
|
const match = detailsUrl?.match(/\/actions\/runs\/(\d+)(?:\/|$)/);
|
|
@@ -6430,7 +6440,7 @@ function classifyFailedChecks(failing) {
|
|
|
6430
6440
|
for (const check of failing) {
|
|
6431
6441
|
const errors = check.annotations.filter(isErrorAnnotation);
|
|
6432
6442
|
if (errors.length > 0) {
|
|
6433
|
-
const allInfra = errors.every((a) => isRunnerInfraAnnotation(a));
|
|
6443
|
+
const allInfra = errors.every((a) => isRunnerInfraAnnotation(a)) && !check.testFailureLine;
|
|
6434
6444
|
(allInfra ? infraFailures : otherFailures).push(check.name);
|
|
6435
6445
|
continue;
|
|
6436
6446
|
}
|
|
@@ -6449,12 +6459,14 @@ function classifyFailedChecks(failing) {
|
|
|
6449
6459
|
reason: `${infraFailures.length} check(s) failed on RUNNER INFRASTRUCTURE, not your diff: ${infraFailures.join(", ")}. No test failed \u2014 the shared runner hit a wall-clock budget kill, ran out of disk, was missing a toolchain, could not acquire an mmi-live lane, or Actions returned Service Unavailable before checkout (the check annotation / conclusion names which). Re-run once the runner drains/heals (gh run rerun --failed); do not debug the diff.`
|
|
6450
6460
|
};
|
|
6451
6461
|
}
|
|
6462
|
+
const failedTests = failing.filter((c) => c.testFailureLine);
|
|
6463
|
+
const testNote = failedTests.length ? ` Test failures in the job log (first: ${failedTests[0].testFailureLine})` + (failedTests.some((c) => c.annotations.some((a) => isErrorAnnotation(a) && isRunnerInfraAnnotation(a))) ? ", followed by a runner wall-clock budget kill" : "") + "; fix the failing test(s)." : "";
|
|
6452
6464
|
return {
|
|
6453
6465
|
cause: "checks-failure",
|
|
6454
6466
|
infraFailures,
|
|
6455
6467
|
otherFailures,
|
|
6456
6468
|
failedChecks: [],
|
|
6457
|
-
reason: infraFailures.length ? `checks failed: ${otherFailures.join(", ")}; separately, ${infraFailures.join(", ")} failed on runner infrastructure, not a test.` : `checks failed: ${otherFailures.join(", ") || "unknown"}.`
|
|
6469
|
+
reason: testNote && !infraFailures.length ? `checks failed: ${otherFailures.join(", ")}.${testNote}` : infraFailures.length ? `checks failed: ${otherFailures.join(", ")}; separately, ${infraFailures.join(", ")} failed on runner infrastructure, not a test.` : `checks failed: ${otherFailures.join(", ") || "unknown"}.`
|
|
6458
6470
|
};
|
|
6459
6471
|
}
|
|
6460
6472
|
async function diagnoseFailedRestChecks(prNumber, repo, gh2 = defaultGhApi) {
|
|
@@ -6489,11 +6501,18 @@ async function diagnoseFailedRestChecks(prNumber, repo, gh2 = defaultGhApi) {
|
|
|
6489
6501
|
if (!failing.length) return { state: "absent", reason: "no failing check-run on the current head to diagnose" };
|
|
6490
6502
|
const failedChecks = failing.map((run) => failedCheckReceipt(run, repo));
|
|
6491
6503
|
try {
|
|
6492
|
-
const annotated = await Promise.all(failing.map(async (run) =>
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6504
|
+
const annotated = await Promise.all(failing.map(async (run) => {
|
|
6505
|
+
const annotations = JSON.parse(await gh2([`repos/${repo}/check-runs/${run.id}/annotations`]));
|
|
6506
|
+
const errors = annotations.filter(isErrorAnnotation);
|
|
6507
|
+
let testFailureLine;
|
|
6508
|
+
if (errors.length && errors.every(isRunnerInfraAnnotation)) {
|
|
6509
|
+
try {
|
|
6510
|
+
testFailureLine = firstTestFailureLine(await gh2([`repos/${repo}/actions/jobs/${run.id}/logs`]));
|
|
6511
|
+
} catch {
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
return { name: run.name ?? `check-run ${run.id}`, conclusion: run.conclusion ?? null, annotations, testFailureLine };
|
|
6515
|
+
}));
|
|
6497
6516
|
return { state: "ok", diagnosis: { ...classifyFailedChecks(annotated), failedChecks } };
|
|
6498
6517
|
} catch (e) {
|
|
6499
6518
|
return {
|
|
@@ -17249,10 +17268,10 @@ var rollout_plan_default = {
|
|
|
17249
17268
|
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)."
|
|
17250
17269
|
},
|
|
17251
17270
|
baseline: {
|
|
17252
|
-
version: "4.5.
|
|
17253
|
-
tag: "v4.5.
|
|
17254
|
-
commit: "
|
|
17255
|
-
npm: "@mutmutco/cli@4.5.
|
|
17271
|
+
version: "4.5.83",
|
|
17272
|
+
tag: "v4.5.83",
|
|
17273
|
+
commit: "d092dda5d5e6",
|
|
17274
|
+
npm: "@mutmutco/cli@4.5.83"
|
|
17256
17275
|
},
|
|
17257
17276
|
exitCriterion: "fleet-n-of-n",
|
|
17258
17277
|
hubOnlyShortcut: "forbidden",
|
|
@@ -17269,14 +17288,14 @@ var rollout_plan_default = {
|
|
|
17269
17288
|
repo: "mutmutco/mmi-hub",
|
|
17270
17289
|
role: "canary",
|
|
17271
17290
|
schedule: "train",
|
|
17272
|
-
v3Target: "v4.5.
|
|
17291
|
+
v3Target: "v4.5.83"
|
|
17273
17292
|
}
|
|
17274
17293
|
],
|
|
17275
17294
|
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.",
|
|
17276
17295
|
rollback: {
|
|
17277
17296
|
independent: true,
|
|
17278
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
17279
|
-
v3Target: "v4.5.
|
|
17297
|
+
mechanism: "npm dist-tag latest -> 4.5.83 and redeploy the Hub Lambda from tag v4.5.83 (d092dda5d5e6); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
17298
|
+
v3Target: "v4.5.83 (@mutmutco/cli@4.5.83, tag commit d092dda5d5e6 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
17280
17299
|
}
|
|
17281
17300
|
},
|
|
17282
17301
|
{
|
|
@@ -21627,7 +21646,51 @@ async function dispatchCanary(deps, targetRepo2, nonce) {
|
|
|
21627
21646
|
attempts.every((a) => isCanaryAccessBlockText(a)) ? `${detail} Every door answered with an access refusal \u2014 the caller may read MMI-Hub but not start its workflows.` : detail
|
|
21628
21647
|
);
|
|
21629
21648
|
}
|
|
21649
|
+
var HOSTED_LABEL_RE = /\b(?:ubuntu|windows|macos)-(?:latest|\d[\w.-]*)\b/;
|
|
21650
|
+
var AUTOMATIC_TRIGGERS = /* @__PURE__ */ new Set(["push", "pull_request", "pull_request_target", "release", "schedule", "workflow_run", "merge_group", "create", "deployment", "repository_dispatch", "check_run", "check_suite", "issues", "issue_comment"]);
|
|
21651
|
+
function workflowTriggers(yaml) {
|
|
21652
|
+
const lines2 = yaml.split(/\r?\n/);
|
|
21653
|
+
const i = lines2.findIndex((l) => /^(?:on|"on"|'on'):(?:\s|$)/.test(l));
|
|
21654
|
+
if (i < 0) return [];
|
|
21655
|
+
const inline = lines2[i].replace(/^[^:]+:\s*/, "").replace(/\s+#.*$/, "").trim();
|
|
21656
|
+
if (inline) return inline.replace(/^\[|\]$/g, "").split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean);
|
|
21657
|
+
const out = [];
|
|
21658
|
+
for (const line of lines2.slice(i + 1)) {
|
|
21659
|
+
if (/^\S/.test(line)) break;
|
|
21660
|
+
const m = /^ {2}([A-Za-z_]+):/.exec(line) ?? /^ {2}- ([A-Za-z_]+)\s*$/.exec(line);
|
|
21661
|
+
if (m) out.push(m[1]);
|
|
21662
|
+
}
|
|
21663
|
+
return out;
|
|
21664
|
+
}
|
|
21665
|
+
function workflowNeedsHostedRunner(yaml) {
|
|
21666
|
+
const body = yaml.split(/\r?\n/).filter((l) => !/^\s*#/.test(l)).join("\n");
|
|
21667
|
+
return HOSTED_LABEL_RE.test(body) && workflowTriggers(yaml).some((t) => AUTOMATIC_TRIGGERS.has(t));
|
|
21668
|
+
}
|
|
21669
|
+
async function hostedWorkflowsOf(deps, repo) {
|
|
21670
|
+
const list = parseJson(
|
|
21671
|
+
await deps.run("gh", ["api", `repos/${repo}/contents/.github/workflows`]),
|
|
21672
|
+
`${repo} workflow listing`
|
|
21673
|
+
);
|
|
21674
|
+
const hosted = [];
|
|
21675
|
+
for (const f of list) {
|
|
21676
|
+
if (f.type !== "file" || !f.path || !/\.ya?ml$/.test(f.path) || f.name === CANARY_WORKFLOW) continue;
|
|
21677
|
+
const raw = parseJson(await deps.run("gh", ["api", `repos/${repo}/contents/${f.path}`]), `${repo} ${f.path}`);
|
|
21678
|
+
if (workflowNeedsHostedRunner(Buffer.from(raw.content ?? "", "base64").toString("utf8"))) hosted.push(f.path);
|
|
21679
|
+
}
|
|
21680
|
+
return hosted;
|
|
21681
|
+
}
|
|
21630
21682
|
async function assertActionsJobsCanStart(deps, targetRepo2) {
|
|
21683
|
+
let hosted;
|
|
21684
|
+
try {
|
|
21685
|
+
hosted = await hostedWorkflowsOf(deps, targetRepo2);
|
|
21686
|
+
} catch {
|
|
21687
|
+
hosted = void 0;
|
|
21688
|
+
}
|
|
21689
|
+
if (hosted && hosted.length === 0) {
|
|
21690
|
+
process.stderr.write(`actions preflight: ${targetRepo2} has no automatically triggered GitHub-hosted job; hosted canary skipped (#7721)
|
|
21691
|
+
`);
|
|
21692
|
+
return;
|
|
21693
|
+
}
|
|
21631
21694
|
const scanned = await scanRepoForBillingBlock(deps, targetRepo2);
|
|
21632
21695
|
if (scanned) throw actionsBillingRefusal(scanned);
|
|
21633
21696
|
if (targetRepo2.toLowerCase() !== CANARY_REPO.toLowerCase()) {
|
|
@@ -26834,6 +26897,7 @@ async function runReleaseResume(deps, options = {}) {
|
|
|
26834
26897
|
async function runReleaseResumeLocked(deps, options) {
|
|
26835
26898
|
const ctx = await buildTrainApplyContext(deps);
|
|
26836
26899
|
await requireCleanTree(deps);
|
|
26900
|
+
const entryBranch = await currentBranch(deps).catch(() => "");
|
|
26837
26901
|
await runGitRemoteRead(deps, ["fetch", "origin", "--tags"]);
|
|
26838
26902
|
const meta = requireProjectMetaForTrain(await loadProjectMeta(deps, ctx), ctx.repo);
|
|
26839
26903
|
const suiteRefusal = suiteMemberRefusal(ctx.repo, meta, "release", options.suiteSolo === true, deps.suiteCut);
|
|
@@ -26841,7 +26905,7 @@ async function runReleaseResumeLocked(deps, options) {
|
|
|
26841
26905
|
const branchHints = await loadReleaseTrackBranchHints(deps);
|
|
26842
26906
|
const directTrack = isHubControlRepo(ctx.repo) || resolveReleaseTrack(meta, branchHints) === "direct";
|
|
26843
26907
|
const deployModel = await preflight(deps, ctx, "main", meta);
|
|
26844
|
-
const startBranch = directTrack ? "development" : "rc";
|
|
26908
|
+
const startBranch = TRAIN_BRANCHES.includes(entryBranch) ? entryBranch : directTrack ? "development" : "rc";
|
|
26845
26909
|
return withCheckoutRestoredAfterReleaseResume(
|
|
26846
26910
|
deps,
|
|
26847
26911
|
startBranch,
|
package/package.json
CHANGED