@mutmutco/cli 4.5.50 → 4.5.52
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 +52 -14
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -17043,10 +17043,10 @@ var rollout_plan_default = {
|
|
|
17043
17043
|
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)."
|
|
17044
17044
|
},
|
|
17045
17045
|
baseline: {
|
|
17046
|
-
version: "4.5.
|
|
17047
|
-
tag: "v4.5.
|
|
17048
|
-
commit: "
|
|
17049
|
-
npm: "@mutmutco/cli@4.5.
|
|
17046
|
+
version: "4.5.52",
|
|
17047
|
+
tag: "v4.5.52",
|
|
17048
|
+
commit: "7a3313c15760",
|
|
17049
|
+
npm: "@mutmutco/cli@4.5.52"
|
|
17050
17050
|
},
|
|
17051
17051
|
exitCriterion: "fleet-n-of-n",
|
|
17052
17052
|
hubOnlyShortcut: "forbidden",
|
|
@@ -17063,14 +17063,14 @@ var rollout_plan_default = {
|
|
|
17063
17063
|
repo: "mutmutco/mmi-hub",
|
|
17064
17064
|
role: "canary",
|
|
17065
17065
|
schedule: "train",
|
|
17066
|
-
v3Target: "v4.5.
|
|
17066
|
+
v3Target: "v4.5.52"
|
|
17067
17067
|
}
|
|
17068
17068
|
],
|
|
17069
17069
|
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.",
|
|
17070
17070
|
rollback: {
|
|
17071
17071
|
independent: true,
|
|
17072
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
17073
|
-
v3Target: "v4.5.
|
|
17072
|
+
mechanism: "npm dist-tag latest -> 4.5.52 and redeploy the Hub Lambda from tag v4.5.52 (7a3313c15760); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
17073
|
+
v3Target: "v4.5.52 (@mutmutco/cli@4.5.52, tag commit 7a3313c15760 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
17074
17074
|
}
|
|
17075
17075
|
},
|
|
17076
17076
|
{
|
|
@@ -35113,7 +35113,7 @@ async function carriedPins(deps, member, bundles) {
|
|
|
35113
35113
|
}
|
|
35114
35114
|
throw new Error(`${member.repo}: nothing new since rc, but no pinned MM-Work bundle carries development ${member.development.slice(0, 12)}; pin it before the suite cut`);
|
|
35115
35115
|
}
|
|
35116
|
-
function suiteAbandon(recordPath, ownerGo = false) {
|
|
35116
|
+
function suiteAbandon(recordPath, ownerGo = false, now = /* @__PURE__ */ new Date()) {
|
|
35117
35117
|
const record = readSuiteCut(recordPath);
|
|
35118
35118
|
if (!record) throw new Error("no suite cut record to abandon");
|
|
35119
35119
|
if (record.leadReleased || record.members.some((m) => m.released)) {
|
|
@@ -35122,7 +35122,7 @@ function suiteAbandon(recordPath, ownerGo = false) {
|
|
|
35122
35122
|
if (record.pinPr && !ownerGo) {
|
|
35123
35123
|
throw new Error(`the cut already opened pin PR ${record.pinPr}; its pins may be visible, so resume it (suite rcand --owner-go), release it (suite release), or retire it with suite abandon --owner-go`);
|
|
35124
35124
|
}
|
|
35125
|
-
const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}.json`;
|
|
35125
|
+
const archive = `${recordPath}.abandoned-${record.leadDevelopment.slice(0, 12)}-${now.toISOString().replace(/[:.]/g, "")}.json`;
|
|
35126
35126
|
if ((0, import_node_fs29.existsSync)(archive)) throw new Error(`abandoned-cut archive already exists at ${archive}; inspect before abandoning again`);
|
|
35127
35127
|
(0, import_node_fs29.renameSync)(recordPath, archive);
|
|
35128
35128
|
return { archive, orphanTags: record.members.filter((m) => m.tag).map((m) => `${m.repo}@${m.tag}`) };
|
|
@@ -35266,8 +35266,12 @@ async function suiteRelease(deps, ownerGo) {
|
|
|
35266
35266
|
continue;
|
|
35267
35267
|
}
|
|
35268
35268
|
const [sha, live, rcHead] = await Promise.all([deps.tagSha(member.repo, member.tag), deps.backend({ repo: member.repo, id: member.id, bundles: {} }), deps.head(member.repo, "rc")]);
|
|
35269
|
-
if (!
|
|
35270
|
-
|
|
35269
|
+
if (!member.released && !member.releasedAs && rcHead?.toLowerCase() !== member.sha?.toLowerCase()) {
|
|
35270
|
+
const shipped = await deps.shippedTag(member.repo, member.sha);
|
|
35271
|
+
if (shipped) member.releasedAs = shipped;
|
|
35272
|
+
}
|
|
35273
|
+
if (!sha || sha.toLowerCase() !== member.sha?.toLowerCase() || !member.released && !member.releasedAs && rcHead?.toLowerCase() !== member.sha?.toLowerCase()) throw new Error(`${member.repo}: rc tag/branch ${member.tag} changed after the cut; release refused`);
|
|
35274
|
+
const katipReleaseSha = member.id === "katip" ? await deps.tagSha(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag)) : void 0;
|
|
35271
35275
|
const expectedBackend = member.id === "katip" && member.released ? member.backendAfterRelease ?? katipReleaseSha : member.backend;
|
|
35272
35276
|
if (live.version !== expectedBackend && !(member.id === "katip" && !member.released && katipReleaseSha && live.version === katipReleaseSha))
|
|
35273
35277
|
throw new Error(`${member.repo}: live backend changed after the cut (${expectedBackend} \u2192 ${live.version}); release refused`);
|
|
@@ -35275,9 +35279,10 @@ async function suiteRelease(deps, ownerGo) {
|
|
|
35275
35279
|
if ((await deps.tagSha(SUITE_REPO, record.leadRcTag))?.toLowerCase() !== record.leadRcSha?.toLowerCase()) throw new Error("MM-Work rc tag changed after the cut; release refused");
|
|
35276
35280
|
for (const member of record.members) {
|
|
35277
35281
|
if (member.released || member.carried) continue;
|
|
35278
|
-
|
|
35282
|
+
if (member.releasedAs) console.warn(`${member.repo}: its rc already shipped as ${member.releasedAs}, not ${suiteReleaseTag(member.tag)}; finishing that release (#7464)`);
|
|
35283
|
+
await deps.release(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag), member.sha);
|
|
35279
35284
|
if (member.id === "katip") {
|
|
35280
|
-
const expected = await deps.tagSha(member.repo, suiteReleaseTag(member.tag));
|
|
35285
|
+
const expected = await deps.tagSha(member.repo, member.releasedAs ?? suiteReleaseTag(member.tag));
|
|
35281
35286
|
const live = await deps.backend({ repo: member.repo, id: member.id, bundles: {} });
|
|
35282
35287
|
if (!expected || live.version !== expected) throw new Error(`${member.repo}: normal main deploy not stamped at released tag SHA; resume after verifying live backend`);
|
|
35283
35288
|
member.backendAfterRelease = live.version;
|
|
@@ -45191,6 +45196,32 @@ async function gh(args) {
|
|
|
45191
45196
|
function isMissingRef(message2) {
|
|
45192
45197
|
return /404|Not Found|No commit found for SHA/.test(message2);
|
|
45193
45198
|
}
|
|
45199
|
+
function releaseTagsFrom(out) {
|
|
45200
|
+
const parse = (t) => t.slice(1).split(".").map(Number);
|
|
45201
|
+
return out.split(/\s+/).filter((t) => /^v\d+\.\d+\.\d+$/.test(t)).sort((a, b) => {
|
|
45202
|
+
const [x, y] = [parse(a), parse(b)];
|
|
45203
|
+
return x[0] - y[0] || x[1] - y[1] || x[2] - y[2];
|
|
45204
|
+
});
|
|
45205
|
+
}
|
|
45206
|
+
async function withEnv(name, value, fn) {
|
|
45207
|
+
const had = Object.prototype.hasOwnProperty.call(process.env, name);
|
|
45208
|
+
const before = process.env[name];
|
|
45209
|
+
process.env[name] = value;
|
|
45210
|
+
try {
|
|
45211
|
+
return await fn();
|
|
45212
|
+
} finally {
|
|
45213
|
+
if (had) process.env[name] = before;
|
|
45214
|
+
else delete process.env[name];
|
|
45215
|
+
}
|
|
45216
|
+
}
|
|
45217
|
+
async function prepareRcCheckout(git3, repo) {
|
|
45218
|
+
if ((await git3(["status", "--porcelain"])).trim()) throw new Error(`${repo}: checkout has uncommitted changes; refuse to switch it to rc for release`);
|
|
45219
|
+
await git3(["fetch", "origin", "--tags"]);
|
|
45220
|
+
await git3(["switch", "rc"]);
|
|
45221
|
+
await git3(["merge", "--ff-only", "origin/rc"]);
|
|
45222
|
+
const [head, origin] = (await git3(["rev-parse", "HEAD", "origin/rc"])).trim().split(/\s+/);
|
|
45223
|
+
if (!head || head !== origin) throw new Error(`${repo}: local rc ${head?.slice(0, 12)} is not origin/rc ${origin?.slice(0, 12)}; stop`);
|
|
45224
|
+
}
|
|
45194
45225
|
function rcRunCauseFromLog(log) {
|
|
45195
45226
|
const causes = [...new Set([...log.matchAll(/##\[error\](?!Process completed with exit code)([^\r\n]+)/g)].map((m) => m[1].trim()).filter(Boolean))];
|
|
45196
45227
|
return causes.length ? `: ${causes.join("; ")}` : "";
|
|
@@ -45293,6 +45324,7 @@ function suiteTrainIo(root, summaryFile) {
|
|
|
45293
45324
|
}
|
|
45294
45325
|
});
|
|
45295
45326
|
const release = async (repo, expected, rcSha) => inTrain(repo, async (deps) => {
|
|
45327
|
+
await prepareRcCheckout((args) => deps.run("git", args), repo);
|
|
45296
45328
|
const current = await tagSha(repo, expected);
|
|
45297
45329
|
if (current) {
|
|
45298
45330
|
await deps.run("git", ["fetch", "origin", "--tags"]);
|
|
@@ -45304,10 +45336,15 @@ function suiteTrainIo(root, summaryFile) {
|
|
|
45304
45336
|
const result = await runReleaseResume(deps, { watch: true });
|
|
45305
45337
|
if (result.tag !== expected || result.state !== "aligned") throw new Error(`${repo}: release resume not complete at ${expected} (${result.tag}/${result.state})`);
|
|
45306
45338
|
} else {
|
|
45307
|
-
const result = await runTrainApply("release", deps, { watch: true });
|
|
45339
|
+
const result = await withEnv("MMI_RELEASE_VERSION", expected.replace(/^v/, ""), () => runTrainApply("release", deps, { watch: true }));
|
|
45308
45340
|
if (result.tag !== expected || result.deployStatus !== "success") throw new Error(`${repo}: release is not green at expected ${expected} (${result.tag}/${result.deployStatus})`);
|
|
45309
45341
|
}
|
|
45310
45342
|
});
|
|
45343
|
+
const shippedTag = async (repo, rcSha) => {
|
|
45344
|
+
const target = await checkout(repo);
|
|
45345
|
+
await exec("git", ["fetch", "origin", "--tags"], target);
|
|
45346
|
+
return releaseTagsFrom(await exec("git", ["tag", "--contains", rcSha, "--list", "v*"], target))[0];
|
|
45347
|
+
};
|
|
45311
45348
|
const rcRuns = async () => JSON.parse(await gh(["run", "list", "--repo", "mutmutco/MMI-Hub", "--workflow", "module-rc-publish.yml", "--event", "workflow_dispatch", "--limit", "100", "--json", "databaseId,displayTitle,conclusion,status,createdAt"]));
|
|
45312
45349
|
const watchRcRun = async (title, fields, reuse) => {
|
|
45313
45350
|
const since = Date.now() - 1e4;
|
|
@@ -45394,6 +45431,7 @@ function suiteTrainIo(root, summaryFile) {
|
|
|
45394
45431
|
}
|
|
45395
45432
|
},
|
|
45396
45433
|
release,
|
|
45434
|
+
shippedTag,
|
|
45397
45435
|
announce: async (record) => {
|
|
45398
45436
|
if (!summaryFile) throw new Error("suite announcement requires --announce-summary-file; outcome was not posted");
|
|
45399
45437
|
const result = await trainApplyDeps().announce?.({ repo: SUITE_REPO, tag: record.leadRcTag.replace(/-rc\.\d+$/, ""), summaryFile });
|
package/package.json
CHANGED