@mutmutco/cli 4.1.6 → 4.1.8
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 +65 -33
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -8220,7 +8220,7 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
8220
8220
|
|
|
8221
8221
|
// src/gate-budget.ts
|
|
8222
8222
|
var BLESSED_RUN_WITH_BUDGET_SHA = "ea2cf8710949dec53566c29836e29cd7515a4e23";
|
|
8223
|
-
var BLESSED_RUNNER_GATE_SHA = "
|
|
8223
|
+
var BLESSED_RUNNER_GATE_SHA = "a6ee756d94fd95884451381e94408f0348eb11db";
|
|
8224
8224
|
var REMOTE_USE = /^mutmutco\/MMI-Hub\/\.github\/actions\/run-with-budget@(\S+)$/;
|
|
8225
8225
|
var LOCAL_USE = "./.github/actions/run-with-budget";
|
|
8226
8226
|
var FULL_SHA = /^[0-9a-f]{40}$/;
|
|
@@ -13152,10 +13152,10 @@ var rollout_plan_default = {
|
|
|
13152
13152
|
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)."
|
|
13153
13153
|
},
|
|
13154
13154
|
baseline: {
|
|
13155
|
-
version: "4.1.
|
|
13156
|
-
tag: "v4.1.
|
|
13157
|
-
commit: "
|
|
13158
|
-
npm: "@mutmutco/cli@4.1.
|
|
13155
|
+
version: "4.1.8",
|
|
13156
|
+
tag: "v4.1.8",
|
|
13157
|
+
commit: "a1c8f5bd7c68",
|
|
13158
|
+
npm: "@mutmutco/cli@4.1.8"
|
|
13159
13159
|
},
|
|
13160
13160
|
exitCriterion: "fleet-n-of-n",
|
|
13161
13161
|
hubOnlyShortcut: "forbidden",
|
|
@@ -13172,14 +13172,14 @@ var rollout_plan_default = {
|
|
|
13172
13172
|
repo: "mutmutco/mmi-hub",
|
|
13173
13173
|
role: "canary",
|
|
13174
13174
|
schedule: "train",
|
|
13175
|
-
v3Target: "v4.1.
|
|
13175
|
+
v3Target: "v4.1.8"
|
|
13176
13176
|
}
|
|
13177
13177
|
],
|
|
13178
13178
|
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.",
|
|
13179
13179
|
rollback: {
|
|
13180
13180
|
independent: true,
|
|
13181
|
-
mechanism: "npm dist-tag latest -> 4.1.
|
|
13182
|
-
v3Target: "v4.1.
|
|
13181
|
+
mechanism: "npm dist-tag latest -> 4.1.8 and redeploy the Hub Lambda from tag v4.1.8 (a1c8f5bd7c68); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
13182
|
+
v3Target: "v4.1.8 (@mutmutco/cli@4.1.8, tag commit a1c8f5bd7c68 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
13183
13183
|
}
|
|
13184
13184
|
},
|
|
13185
13185
|
{
|
|
@@ -15941,6 +15941,41 @@ var HUB_REPO3 = "mutmutco/MMI-Hub";
|
|
|
15941
15941
|
function isHubControlRepo(repo) {
|
|
15942
15942
|
return repo.toLowerCase() === HUB_REPO3.toLowerCase();
|
|
15943
15943
|
}
|
|
15944
|
+
function supportsReleaseAbort(_repo, meta, _branchHints) {
|
|
15945
|
+
return DEPLOY_MODELS.includes(meta.deployModel);
|
|
15946
|
+
}
|
|
15947
|
+
function releaseAbortNeedsNpmProof(meta, repo) {
|
|
15948
|
+
return isHubControlRepo(repo) || meta.deployModel === "registry-publish" || meta.publishRequired === true;
|
|
15949
|
+
}
|
|
15950
|
+
function resolveReleaseAbortNpmPackage(meta, repo) {
|
|
15951
|
+
if (isHubControlRepo(repo)) return "@mutmutco/cli";
|
|
15952
|
+
const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
|
|
15953
|
+
try {
|
|
15954
|
+
const pkg = JSON.parse((0, import_node_fs15.readFileSync)((0, import_node_path14.join)(publishDir, "package.json"), "utf8"));
|
|
15955
|
+
const name = pkg.name?.trim();
|
|
15956
|
+
if (!name) throw new Error("missing name field");
|
|
15957
|
+
return name;
|
|
15958
|
+
} catch (e) {
|
|
15959
|
+
throw new Error(
|
|
15960
|
+
`release --abort: cannot read npm publish name from ${publishDir}/package.json (${e instanceof Error ? e.message : String(e)}); nothing was written`
|
|
15961
|
+
);
|
|
15962
|
+
}
|
|
15963
|
+
}
|
|
15964
|
+
async function proveNpmVersionUnpublished(deps, packageName, version, tag) {
|
|
15965
|
+
try {
|
|
15966
|
+
const published = clean2(await deps.run("npm", ["view", `${packageName}@${version}`, "version", "--json"]));
|
|
15967
|
+
if (published) {
|
|
15968
|
+
throw new Error(`release --abort: ${packageName}@${version} is already published; ${tag} cannot be reused`);
|
|
15969
|
+
}
|
|
15970
|
+
throw new Error("npm registry returned an empty successful response");
|
|
15971
|
+
} catch (error) {
|
|
15972
|
+
const detail = `${error instanceof Error ? error.message : String(error)} ${String(error.stderr ?? "")}`;
|
|
15973
|
+
if (!/E404|not found|No match found/i.test(detail)) {
|
|
15974
|
+
if (/already published/.test(detail)) throw error;
|
|
15975
|
+
throw new Error(`release --abort: npm publish absence could not be proven (${detail.trim()}); nothing was written`);
|
|
15976
|
+
}
|
|
15977
|
+
}
|
|
15978
|
+
}
|
|
15944
15979
|
function projectGetFailureText(e) {
|
|
15945
15980
|
const err = e;
|
|
15946
15981
|
return [err.message, err.stderr, err.stdout].filter(Boolean).join(" ");
|
|
@@ -16387,8 +16422,9 @@ function partialTrainRecoveryError(cause, input) {
|
|
|
16387
16422
|
- origin/${branch}: NOT pushed
|
|
16388
16423
|
- ${releaseState}
|
|
16389
16424
|
` + deployLine;
|
|
16390
|
-
const
|
|
16391
|
-
|
|
16425
|
+
const releaseAbortEligible = input.meta ? supportsReleaseAbort(input.repo, input.meta, input.branchHints) : isHubControlRepo(input.repo);
|
|
16426
|
+
const failedAbortEligibleMainGate = input.stage === "main" && releaseAbortEligible && /^required train check failed:/i.test(causeMessage);
|
|
16427
|
+
if (failedAbortEligibleMainGate) {
|
|
16392
16428
|
return new Error(
|
|
16393
16429
|
`${causeMessage}
|
|
16394
16430
|
|
|
@@ -17229,7 +17265,7 @@ async function gateTrueMergeCommit(deps, ctx, tag, releaseSha, requiredChecks) {
|
|
|
17229
17265
|
}
|
|
17230
17266
|
}
|
|
17231
17267
|
}
|
|
17232
|
-
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe) {
|
|
17268
|
+
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe, branchHints) {
|
|
17233
17269
|
const resumeCommand = options.dev ? "mmi-cli devops release --dev --apply" : "mmi-cli devops release --apply";
|
|
17234
17270
|
try {
|
|
17235
17271
|
await verifyPublishDryRun(deps, ctx, meta, deployModel);
|
|
@@ -17265,16 +17301,17 @@ async function completeMainRelease(deps, ctx, meta, deployModel, watch, options,
|
|
|
17265
17301
|
}
|
|
17266
17302
|
const tagPushSince = (deps.now ?? Date.now)();
|
|
17267
17303
|
let checks;
|
|
17304
|
+
const recoveryInput = { repo: ctx.repo, tag, stage: "main", deployModel, meta, branchHints };
|
|
17268
17305
|
try {
|
|
17269
17306
|
checks = await waitForRequiredTrainChecks(deps, ctx, releaseSha, requiredChecks, tagPush.pushed ? tagPushSince : void 0);
|
|
17270
17307
|
} catch (e) {
|
|
17271
|
-
throw partialTrainRecoveryError(e,
|
|
17308
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17272
17309
|
}
|
|
17273
17310
|
if (trueMergeGateNote) checks = `${trueMergeGateNote}; ${checks}`;
|
|
17274
17311
|
try {
|
|
17275
17312
|
await runGitPush(deps, ["push", "origin", "main"]);
|
|
17276
17313
|
} catch (e) {
|
|
17277
|
-
throw partialTrainRecoveryError(e,
|
|
17314
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17278
17315
|
}
|
|
17279
17316
|
const releaseUrl = clean2(await deps.run("gh", ["release", "create", tag, "--target", "main", "--generate-notes", "--latest", "--repo", ctx.repo])) || void 0;
|
|
17280
17317
|
await verifyPublishedRelease(deps, ctx.repo, tag, "main", releaseSha);
|
|
@@ -17446,16 +17483,17 @@ async function runReleaseResume(deps, options = {}) {
|
|
|
17446
17483
|
}
|
|
17447
17484
|
const steps = [];
|
|
17448
17485
|
let requiredChecks;
|
|
17486
|
+
const recoveryInput = { repo: ctx.repo, tag, stage: "main", deployModel, meta, branchHints };
|
|
17449
17487
|
try {
|
|
17450
17488
|
requiredChecks = await discoverRequiredCheckContexts(deps, ctx, "main");
|
|
17451
17489
|
} catch (e) {
|
|
17452
|
-
throw partialTrainRecoveryError(e,
|
|
17490
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17453
17491
|
}
|
|
17454
17492
|
assertTagAddressableRequiredContexts(deps, requiredChecks, ctx.repo);
|
|
17455
17493
|
try {
|
|
17456
17494
|
steps.push(await waitForRequiredTrainChecks(deps, ctx, tagSha, requiredChecks, void 0));
|
|
17457
17495
|
} catch (e) {
|
|
17458
|
-
throw partialTrainRecoveryError(e,
|
|
17496
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17459
17497
|
}
|
|
17460
17498
|
await runGitPush(deps, ["push", "origin", `${tagSha}:refs/heads/main`]);
|
|
17461
17499
|
steps.push(`pushed ${tagSha.slice(0, 12)} to origin/main`);
|
|
@@ -17500,8 +17538,11 @@ async function runReleaseAbort(deps, options = {}) {
|
|
|
17500
17538
|
throw new Error("release --abort requires --apply after explicit approval; nothing was written");
|
|
17501
17539
|
}
|
|
17502
17540
|
const ctx = await buildTrainApplyContext(deps);
|
|
17503
|
-
|
|
17504
|
-
|
|
17541
|
+
const meta = requireProjectMetaForTrain(await loadProjectMeta(deps, ctx), ctx.repo);
|
|
17542
|
+
if (!supportsReleaseAbort(ctx.repo, meta)) {
|
|
17543
|
+
throw new Error(
|
|
17544
|
+
`release --abort: registry META deployModel ${JSON.stringify(meta.deployModel)} has no proven abort contract; nothing was written`
|
|
17545
|
+
);
|
|
17505
17546
|
}
|
|
17506
17547
|
await requireCleanTree(deps);
|
|
17507
17548
|
if (await currentBranch(deps) !== "main") {
|
|
@@ -17536,18 +17577,9 @@ async function runReleaseAbort(deps, options = {}) {
|
|
|
17536
17577
|
throw new Error(`release --abort: ${tag} is released or its unpublished state could not be proven; nothing was written`);
|
|
17537
17578
|
}
|
|
17538
17579
|
const version = tag.slice(1);
|
|
17539
|
-
|
|
17540
|
-
const
|
|
17541
|
-
|
|
17542
|
-
throw new Error(`release --abort: @mutmutco/cli@${version} is already published; ${tag} cannot be reused`);
|
|
17543
|
-
}
|
|
17544
|
-
throw new Error("npm registry returned an empty successful response");
|
|
17545
|
-
} catch (error) {
|
|
17546
|
-
const detail = `${error instanceof Error ? error.message : String(error)} ${String(error.stderr ?? "")}`;
|
|
17547
|
-
if (!/E404|not found|No match found/i.test(detail)) {
|
|
17548
|
-
if (/already published/.test(detail)) throw error;
|
|
17549
|
-
throw new Error(`release --abort: npm publish absence could not be proven (${detail.trim()}); nothing was written`);
|
|
17550
|
-
}
|
|
17580
|
+
if (releaseAbortNeedsNpmProof(meta, ctx.repo)) {
|
|
17581
|
+
const npmPackage = resolveReleaseAbortNpmPackage(meta, ctx.repo);
|
|
17582
|
+
await proveNpmVersionUnpublished(deps, npmPackage, version, tag);
|
|
17551
17583
|
}
|
|
17552
17584
|
await runGitPush(deps, ["push", "origin", "--delete", tag]);
|
|
17553
17585
|
if (await probeRemoteTag(deps, tag)) {
|
|
@@ -17710,7 +17742,7 @@ async function runTrainApplyPipeline(mode, input) {
|
|
|
17710
17742
|
const releaseSha3 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
17711
17743
|
return { versionFold: versionFold3, releaseSha: releaseSha3 };
|
|
17712
17744
|
});
|
|
17713
|
-
const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, dispatch: d2 } = await completeMainRelease(deps, ctx, meta, deployModel2, watch, options, tag2, releaseSha2, "development", preFold2, tagProbe2);
|
|
17745
|
+
const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, dispatch: d2 } = await completeMainRelease(deps, ctx, meta, deployModel2, watch, options, tag2, releaseSha2, "development", preFold2, tagProbe2, branchHints);
|
|
17714
17746
|
const devRollForward2 = await rollDevelopmentForward(deps, ctx, tag2);
|
|
17715
17747
|
if (directTrack) {
|
|
17716
17748
|
return {
|
|
@@ -17797,7 +17829,7 @@ async function runTrainApplyPipeline(mode, input) {
|
|
|
17797
17829
|
const releaseSha2 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
17798
17830
|
return { versionFold: versionFold2, releaseSha: releaseSha2 };
|
|
17799
17831
|
});
|
|
17800
|
-
const { checks, releaseUrl, announceNote, dispatch: d } = await completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, "rc", preFold, tagProbe);
|
|
17832
|
+
const { checks, releaseUrl, announceNote, dispatch: d } = await completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, "rc", preFold, tagProbe, branchHints);
|
|
17801
17833
|
const retirement = await retireRcRuntime(deps, ctx, deployModel, d.deployStatus, releasedRcSha);
|
|
17802
17834
|
const devRollForward = await rollDevelopmentForward(deps, ctx, tag);
|
|
17803
17835
|
const rcAlignment = await alignRcForward(deps, ctx, tag);
|
|
@@ -42776,7 +42808,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
42776
42808
|
{ flags: "--announce-summary-file <path>", description: "agent-curated 3-6 line Hub Slack summary; required for a new MMI-Hub --apply (#883/#3901)" },
|
|
42777
42809
|
{ flags: "--ack <shas>", description: "comma-separated dev shas a human verified are in the candidate, overriding the hotfix-coverage guard for a conflicted port whose -x trailer was lost (#958)" },
|
|
42778
42810
|
{ flags: "--dev", description: "full-track repos release development -> main directly, skipping rc (refuses if rc carries content not in development; no-op on direct-track repos) (#1062)" },
|
|
42779
|
-
{ flags: "--abort", description: "with --apply, delete only a proven unpublished failed
|
|
42811
|
+
{ flags: "--abort", description: "with --apply, delete only a proven unpublished failed release candidate on any registered deploy model and restore local main for a same-version recut (#3944/#5650/#5657)" },
|
|
42780
42812
|
{ flags: "--retry-publish <run-id>", description: "with --apply, retry failed jobs of one proven Hub publish release run (#3949)" }
|
|
42781
42813
|
];
|
|
42782
42814
|
for (const f of RELEASE_ONLY_FLAGS) {
|
|
@@ -42802,7 +42834,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
42802
42834
|
return fail(`${commandName}: --announce-summary-file applies only to release \u2014 rcand posts no Hub Slack announcement. Run: mmi-cli devops release --announce-summary-file <path>`);
|
|
42803
42835
|
}
|
|
42804
42836
|
if (o.abort && commandName !== "release") {
|
|
42805
|
-
return fail(`${commandName}: --abort applies only to release \u2014 it rolls back a proven unpublished
|
|
42837
|
+
return fail(`${commandName}: --abort applies only to release \u2014 it rolls back a proven unpublished release tag. Run: mmi-cli devops release --abort --apply`);
|
|
42806
42838
|
}
|
|
42807
42839
|
if (o.retryPublish && commandName !== "release") {
|
|
42808
42840
|
return fail(`${commandName}: --retry-publish applies only to release. Run: mmi-cli devops release --retry-publish <run-id> --apply --watch`);
|
package/package.json
CHANGED