@mutmutco/cli 4.6.38 → 4.6.39

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.
Files changed (2) hide show
  1. package/dist/main.cjs +42 -21
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -28405,10 +28405,10 @@ var rollout_plan_default = {
28405
28405
  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)."
28406
28406
  },
28407
28407
  baseline: {
28408
- version: "4.6.38",
28409
- tag: "v4.6.38",
28410
- commit: "975581f0f6ce",
28411
- npm: "@mutmutco/cli@4.6.38"
28408
+ version: "4.6.39",
28409
+ tag: "v4.6.39",
28410
+ commit: "2669c496b69e",
28411
+ npm: "@mutmutco/cli@4.6.39"
28412
28412
  },
28413
28413
  exitCriterion: "fleet-n-of-n",
28414
28414
  hubOnlyShortcut: "forbidden",
@@ -28425,14 +28425,14 @@ var rollout_plan_default = {
28425
28425
  repo: "mutmutco/mmi-hub",
28426
28426
  role: "canary",
28427
28427
  schedule: "train",
28428
- v3Target: "v4.6.38"
28428
+ v3Target: "v4.6.39"
28429
28429
  }
28430
28430
  ],
28431
28431
  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.",
28432
28432
  rollback: {
28433
28433
  independent: true,
28434
- mechanism: "npm dist-tag latest -> 4.6.38 and redeploy the Hub Lambda from tag v4.6.38 (975581f0f6ce); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28435
- v3Target: "v4.6.38 (@mutmutco/cli@4.6.38, tag commit 975581f0f6ce \u2014 last known-good release carrying the repo-index v4-only contract)"
28434
+ mechanism: "npm dist-tag latest -> 4.6.39 and redeploy the Hub Lambda from tag v4.6.39 (2669c496b69e); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28435
+ v3Target: "v4.6.39 (@mutmutco/cli@4.6.39, tag commit 2669c496b69e \u2014 last known-good release carrying the repo-index v4-only contract)"
28436
28436
  }
28437
28437
  },
28438
28438
  {
@@ -44015,7 +44015,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
44015
44015
  for (let readAttempt = 0; readAttempt < maxReads; readAttempt++) {
44016
44016
  if (readAttempt) await sleep3(readAttempt * 1e3);
44017
44017
  try {
44018
- const observed = await readPrMergeQueue(pr, repo, read);
44018
+ const observed = await readPrMergeQueue(pr, repo, read, options.sleep);
44019
44019
  if (observed.state === "MERGED" && observed.headRefOid === head) return markReenqueued({ mergeStatus: "merged" });
44020
44020
  if (observed.isInMergeQueue && observed.headRefOid === head) {
44021
44021
  const entry = observed.mergeQueueEntry;
@@ -44057,13 +44057,13 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
44057
44057
  if (receipt && (receipt.state === "enqueued" || receipt.state === "merged")) {
44058
44058
  if (receipt.head.toLowerCase() !== head.toLowerCase()) {
44059
44059
  try {
44060
- const observed = await readPrMergeQueue(pr, repo, read);
44060
+ const observed = await readPrMergeQueue(pr, repo, read, options.sleep);
44061
44061
  superseded = observed.state === "OPEN" && !observed.isInMergeQueue;
44062
44062
  } catch {
44063
44063
  }
44064
44064
  } else {
44065
44065
  try {
44066
- const observed = await readPrMergeQueue(pr, repo, read);
44066
+ const observed = await readPrMergeQueue(pr, repo, read, options.sleep);
44067
44067
  if (observed.state === "OPEN" && !observed.isInMergeQueue && observed.headRefOid?.toLowerCase() === receipt.head.toLowerCase()) {
44068
44068
  const boundMs = receipt.queueEntry ? Date.parse(receipt.queueEntry.enqueuedAt) : receipt.observedAt + UNWITNESSED_EJECTION_GRACE_MS;
44069
44069
  const events = await readArrayPages(
@@ -44266,6 +44266,15 @@ ${list}
44266
44266
  Co-authored-by: GitHub <noreply@github.com>
44267
44267
  `;
44268
44268
  }
44269
+ var WAIVER_KEYS = /^(?:Test-Policy-Override|Runbook-Unaffected)\s*:/i;
44270
+ function clipTrailer(trailer) {
44271
+ return trailer.length > 120 ? `${trailer.slice(0, 117)}...` : trailer;
44272
+ }
44273
+ function describeWaiverText(label, message2, cwd) {
44274
+ const block = parseTrailers(message2, cwd).filter((trailer) => WAIVER_KEYS.test(trailer));
44275
+ const found = block.length ? `final trailer block holds ${block.map((trailer) => `\`${clipTrailer(trailer)}\``).join(" and ")}` : "git parses no Test-Policy-Override or Runbook-Unaffected trailer there";
44276
+ return `${label}: ${found}`;
44277
+ }
44269
44278
  function checkQueueSquashOverride(title, pr, messages, root) {
44270
44279
  if (messages.length <= 1 || !messages.some((message2) => /^\s*Test-Policy-Override\s*:/im.test(`${message2.headline}
44271
44280
  ${message2.body}`)) || readMessageOverride2(githubQueueSquashMessage(title, pr, messages), root)) return void 0;
@@ -44399,7 +44408,8 @@ ${pull.body}`;
44399
44408
  }
44400
44409
  const requiredBody = options.bodyText ?? composedBody;
44401
44410
  const prBodyPreservesOverrides = requiredBody != null && method === "SQUASH" && policy.body === "PR_BODY" && options.bodyText == null && prBodyPreservesCommitOverrides(messages, headline, pull.body, process.cwd());
44402
- if (requiredBody && !prBodyPreservesOverrides && (method !== "SQUASH" || requiredBody.trim() !== body.trim())) {
44411
+ const queueKeepsWaiver = options.bodyText == null && method !== "SQUASH" && Boolean(readMessageOverride2(actualMessage, process.cwd()));
44412
+ if (requiredBody && !prBodyPreservesOverrides && !queueKeepsWaiver && (method !== "SQUASH" || requiredBody.trim() !== body.trim())) {
44403
44413
  if (method === "SQUASH" && policy.body === "PR_BODY" && options.bodyText == null) {
44404
44414
  return {
44405
44415
  kind: "refused",
@@ -44411,7 +44421,9 @@ ${pull.body}`;
44411
44421
  issueTargets: [],
44412
44422
  nextAction: `PR author: this repository squashes with PR_BODY, so place the required Test-Policy-Override trailer(s) in the PR body final trailer block (e.g. \`mmi-cli devops pr edit ${pr} --repo ${repo} --body-file .jerv/tmp/pr-${pr}-body.md\`) without a body override, then rerun \`pr land\`. Keep repository settings unchanged.`
44413
44423
  },
44414
- error: "queue preparation needed: repository squash policy is PR_BODY, and the PR body does not carry the required Test-Policy-Override trailer(s) in its final Git-recognized trailer block"
44424
+ error: `queue preparation needed: repository squash policy is PR_BODY, and the PR body does not carry the required Test-Policy-Override trailer(s) in its final Git-recognized trailer block \u2014 ${describeWaiverText("the PR body", pull.body, process.cwd())}; ${describeWaiverText("the source commit messages", messages.map((message2) => `${message2.headline}
44425
+
44426
+ ${message2.body}`).join("\n\n"), process.cwd())}`
44415
44427
  }
44416
44428
  };
44417
44429
  }
@@ -44420,9 +44432,12 @@ ${pull.body}`;
44420
44432
  return keys.length ? keys.join(", ") : "none";
44421
44433
  };
44422
44434
  const source = options.bodyText != null ? "the explicit body override" : "the body composed from the source commit messages";
44435
+ const sentLabel = method === "SQUASH" ? `squash ${policy.body ?? "unknown"}, ${messages.length} commit message${messages.length === 1 ? "" : "s"}` : `${method}${repository.merge_commit_message === "PR_BODY" ? " + PR body" : ""}`;
44423
44436
  const detail = `the requested sanitized body or trailer arrangement cannot be sent to queue admission: queue merge method ${method}, squash body policy ${policy.body ?? "unknown"}; required body is ${source} (trailer keys: ${trailerKeys(`${headline}
44424
44437
 
44425
- ${requiredBody}`)}), but the message the queue would send carries trailer keys: ${trailerKeys(actualMessage)}`;
44438
+ ${requiredBody}`)}), but the message the queue would send carries trailer keys: ${trailerKeys(actualMessage)}. ${describeWaiverText(`the message the queue sends (${sentLabel})`, actualMessage, process.cwd())}; ${describeWaiverText("the source commit messages", messages.map((message2) => `${message2.headline}
44439
+
44440
+ ${message2.body}`).join("\n\n"), process.cwd())}.`;
44426
44441
  const next = options.bodyText != null ? `PR author: a merge queue accepts no body override; drop --body/--squash-body-file and place the required trailer(s) where the queue's ${method}${method === "SQUASH" ? ` (${policy.body})` : ""} message reads them, then rerun \`mmi-cli devops pr land ${pr} --repo ${repo}\`. Keep repository settings unchanged.` : method !== "SQUASH" ? `PR author: the queue's ${method} method keeps the original commit messages, so the required trailer(s) must sit in a source commit message's final trailer block; amend the commit, push, re-run checks and \`mmi-cli devops pr land ${pr} --repo ${repo}\`. Keep repository settings unchanged.` : policy.body === "BLANK" ? `PR author: squash body policy BLANK sends an empty body, so no trailer from the commits or PR body reaches the queue commit; the waiver cannot survive queue admission with unchanged repository settings \u2014 remove the need for the override or ask a maintainer. Keep repository settings unchanged.` : `PR author: squash body policy ${policy.body} does not reproduce the composed body; consolidate the required trailer(s) into one source commit message's final trailer block, push, re-run checks and \`mmi-cli devops pr land ${pr} --repo ${repo}\`. Keep repository settings unchanged.`;
44427
44442
  const caveat = " GitHub may append coauthors even to one source commit, so source consolidation alone does not prove the generated message passes test policy; the combined queue candidate must pass with the shared trailer reader.";
44428
44443
  return { kind: "refused", result: preparation("queue-message-override", [], detail, next + caveat) };
@@ -44472,7 +44487,7 @@ async function abandonQueueAdmission(pr, repo, options = {}) {
44472
44487
  }
44473
44488
  let snapshot;
44474
44489
  try {
44475
- snapshot = await readPrMergeQueue(pr, repo, options.read ?? actorReadApi);
44490
+ snapshot = await readPrMergeQueue(pr, repo, options.read ?? actorReadApi, options.sleep);
44476
44491
  } catch (error) {
44477
44492
  return refuse(`the PR and queue state could not be read (${error.message}); the admission is unchanged`);
44478
44493
  }
@@ -44497,13 +44512,19 @@ function decideQueueMergeRoute(hasQueue, method, headRef) {
44497
44512
  if (!hasQueue) return "normal";
44498
44513
  return method === "--merge" && /^(release-align|hotfix-fold)\//.test(headRef) ? "admin-true-merge" : "pr-land";
44499
44514
  }
44500
- async function readPrMergeQueue(pr, repo, gh2 = actorReadApi) {
44515
+ async function readPrMergeQueue(pr, repo, gh2 = actorReadApi, sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))) {
44501
44516
  if (!/^\d+$/.test(pr)) throw new Error("merge queue read requires a PR number");
44502
- const result = await queueGraphql(
44503
- repo,
44504
- `pullRequest(number:${pr}) { state isInMergeQueue mergeQueueEntry { state position enqueuedAt headCommit { oid } } autoMergeRequest { enabledAt } headRefOid }`,
44505
- gh2
44506
- );
44517
+ const fields = `pullRequest(number:${pr}) { state isInMergeQueue mergeQueueEntry { state position enqueuedAt headCommit { oid } } autoMergeRequest { enabledAt } headRefOid }`;
44518
+ let result;
44519
+ for (let attempt = 0; ; attempt++) {
44520
+ try {
44521
+ result = await queueGraphql(repo, fields, gh2);
44522
+ break;
44523
+ } catch (error) {
44524
+ if (attempt >= 2 || !isUpstreamGitHubFault(execErrorText(error))) throw error;
44525
+ await sleep2(2e3 * (attempt + 1));
44526
+ }
44527
+ }
44507
44528
  if (!result.pullRequest) throw new Error(`merge queue PR #${pr} not found`);
44508
44529
  const entry = result.pullRequest.mergeQueueEntry;
44509
44530
  if (entry && (entry.enqueuedAt !== void 0 && !Number.isFinite(Date.parse(entry.enqueuedAt)) || entry.headCommit && !/^[a-f0-9]{40}$/i.test(entry.headCommit.oid))) throw new Error("queue entry identity is unreadable");
@@ -44932,7 +44953,7 @@ async function dispatchWorkflow(repo, workflow, ref, inputs, deps) {
44932
44953
  const fields = ["-f", `ref=${ref}`];
44933
44954
  const names = /* @__PURE__ */ new Set();
44934
44955
  for (const input of inputs) {
44935
- const match = /^([A-Za-z_][A-Za-z0-9_]{0,63})=([^\r\n]{0,2048})$/.exec(input);
44956
+ const match = /^([A-Za-z_][A-Za-z0-9_-]{0,63})=([^\r\n]{0,2048})$/.exec(input);
44936
44957
  if (!match || names.has(match[1])) throw new Error("run dispatch: invalid or duplicate input");
44937
44958
  names.add(match[1]);
44938
44959
  fields.push("-f", `inputs[${match[1]}]=${match[2]}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.6.38",
3
+ "version": "4.6.39",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",