@mutmutco/cli 4.3.24 → 4.3.25
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 +276 -372
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -15522,10 +15522,10 @@ var rollout_plan_default = {
|
|
|
15522
15522
|
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)."
|
|
15523
15523
|
},
|
|
15524
15524
|
baseline: {
|
|
15525
|
-
version: "4.3.
|
|
15526
|
-
tag: "v4.3.
|
|
15527
|
-
commit: "
|
|
15528
|
-
npm: "@mutmutco/cli@4.3.
|
|
15525
|
+
version: "4.3.25",
|
|
15526
|
+
tag: "v4.3.25",
|
|
15527
|
+
commit: "fc9a141cca17",
|
|
15528
|
+
npm: "@mutmutco/cli@4.3.25"
|
|
15529
15529
|
},
|
|
15530
15530
|
exitCriterion: "fleet-n-of-n",
|
|
15531
15531
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15542,14 +15542,14 @@ var rollout_plan_default = {
|
|
|
15542
15542
|
repo: "mutmutco/mmi-hub",
|
|
15543
15543
|
role: "canary",
|
|
15544
15544
|
schedule: "train",
|
|
15545
|
-
v3Target: "v4.3.
|
|
15545
|
+
v3Target: "v4.3.25"
|
|
15546
15546
|
}
|
|
15547
15547
|
],
|
|
15548
15548
|
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.",
|
|
15549
15549
|
rollback: {
|
|
15550
15550
|
independent: true,
|
|
15551
|
-
mechanism: "npm dist-tag latest -> 4.3.
|
|
15552
|
-
v3Target: "v4.3.
|
|
15551
|
+
mechanism: "npm dist-tag latest -> 4.3.25 and redeploy the Hub Lambda from tag v4.3.25 (fc9a141cca17); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15552
|
+
v3Target: "v4.3.25 (@mutmutco/cli@4.3.25, tag commit fc9a141cca17 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15553
15553
|
}
|
|
15554
15554
|
},
|
|
15555
15555
|
{
|
|
@@ -19141,6 +19141,7 @@ Resume it: ${resumeCommand}
|
|
|
19141
19141
|
}
|
|
19142
19142
|
|
|
19143
19143
|
// src/train-doctor.ts
|
|
19144
|
+
var import_node_child_process9 = require("node:child_process");
|
|
19144
19145
|
var import_node_fs23 = require("node:fs");
|
|
19145
19146
|
var import_node_os13 = require("node:os");
|
|
19146
19147
|
var import_node_path22 = require("node:path");
|
|
@@ -21232,19 +21233,18 @@ var TRAIN_LANES = ["release", "rcand", "hotfix"];
|
|
|
21232
21233
|
var TROUBLESHOOTING_GUIDE = "docs/Guides/train-troubleshooting.md";
|
|
21233
21234
|
var SCRATCH_BRANCH_GLOBS = ["train/check/*", "hotfix-fold/*--port-*"];
|
|
21234
21235
|
var COMPOSE_GUARD_HARD_FAIL = /^secrets preflight: .*noEnvFile is (not )?true.*$/m;
|
|
21235
|
-
function
|
|
21236
|
-
const
|
|
21237
|
-
let
|
|
21236
|
+
function readOriginWorkflowsDefault(root, ref) {
|
|
21237
|
+
const git3 = (args) => (0, import_node_child_process9.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
21238
|
+
let paths;
|
|
21238
21239
|
try {
|
|
21239
|
-
|
|
21240
|
-
} catch
|
|
21241
|
-
if (e.code === "ENOENT") return [];
|
|
21240
|
+
paths = git3(["ls-tree", "--name-only", ref, ".github/workflows/"]).split("\n").map((l) => l.trim()).filter((l) => /\.ya?ml$/i.test(l));
|
|
21241
|
+
} catch {
|
|
21242
21242
|
return null;
|
|
21243
21243
|
}
|
|
21244
21244
|
const files = [];
|
|
21245
|
-
for (const
|
|
21245
|
+
for (const path2 of paths) {
|
|
21246
21246
|
try {
|
|
21247
|
-
files.push({ path:
|
|
21247
|
+
files.push({ path: path2, body: git3(["show", `${ref}:${path2}`]) });
|
|
21248
21248
|
} catch {
|
|
21249
21249
|
}
|
|
21250
21250
|
}
|
|
@@ -21280,7 +21280,7 @@ var defaultDeps2 = {
|
|
|
21280
21280
|
selfConverge: selfConvergeTrainCli,
|
|
21281
21281
|
readGitignore,
|
|
21282
21282
|
writeGitignore,
|
|
21283
|
-
readWorkflows:
|
|
21283
|
+
readWorkflows: readOriginWorkflowsDefault,
|
|
21284
21284
|
ledgerPath: releaseLedgerPath,
|
|
21285
21285
|
readLedgerRaw: (path2) => {
|
|
21286
21286
|
try {
|
|
@@ -21491,9 +21491,10 @@ async function runTrainDoctor(input) {
|
|
|
21491
21491
|
add(linked ? { code: "worktree-isolated", severity: "blocker", source: "local", title: `this is a linked worktree on ${currentBranch2 || "(detached)"}, not the lane's start branch ${startBranch} (#2770)`, remedy: `run the ${lane} lane from the primary checkout on ${startBranch}; a linked worktree never carries the train` } : { code: "branch-mismatch", severity: "blocker", source: "local", title: `on ${currentBranch2 || "(detached)"}; the ${lane} lane starts from ${startBranch}`, remedy: `git checkout ${startBranch}, then rerun` });
|
|
21492
21492
|
}
|
|
21493
21493
|
const stage = laneStage(lane);
|
|
21494
|
-
const
|
|
21494
|
+
const workflowsRef = `origin/${startBranch ?? "main"}`;
|
|
21495
|
+
const workflows = deps.readWorkflows(cwd, workflowsRef);
|
|
21495
21496
|
if (workflows === null) {
|
|
21496
|
-
add({ code: "workflows-unreadable", severity: "blocker", source: "local", title: `.github/workflows
|
|
21497
|
+
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` });
|
|
21497
21498
|
}
|
|
21498
21499
|
if (hints) {
|
|
21499
21500
|
const missing = [
|
|
@@ -23490,6 +23491,7 @@ var GATE_GREEN_ON_BASE_LABEL = "gate is green on the default branch (#3819)";
|
|
|
23490
23491
|
var REQUIRED_CONTEXTS_EMITTED_LABEL = "required check contexts match PR workflows";
|
|
23491
23492
|
var TAG_ADDRESSABLE_CONTEXTS_LABEL = "rc/main required contexts are tag-addressable (#3880)";
|
|
23492
23493
|
var RELEASE_BRANCH_REACHABLE_LABEL = "rc/main required contexts are reachable from a release-base head (#5193)";
|
|
23494
|
+
var RULESET_TRACK_SCOPE_LABEL = "product ruleset branch scope covers the release track (#6327)";
|
|
23493
23495
|
var RECONCILE_SEED_BRANCH_PREFIX = "bootstrap-seed-ruleset-ref";
|
|
23494
23496
|
function slugFromRepo(repo) {
|
|
23495
23497
|
return (repo.includes("/") ? repo.split("/")[1] : repo).toLowerCase();
|
|
@@ -23556,6 +23558,10 @@ function gateWorkflowFiles(prWorkflowPaths) {
|
|
|
23556
23558
|
return files.length ? files : DEFAULT_GATE_FILES;
|
|
23557
23559
|
}
|
|
23558
23560
|
async function resolveEmittedPrContexts(deps, repo, branch) {
|
|
23561
|
+
const workflows = await resolveBranchWorkflows(deps, repo, branch);
|
|
23562
|
+
return workflows === void 0 ? void 0 : collectPullRequestWorkflowContexts(workflows);
|
|
23563
|
+
}
|
|
23564
|
+
async function resolveBranchWorkflows(deps, repo, branch) {
|
|
23559
23565
|
const paths = await listWorkflowPaths(deps, repo, branch);
|
|
23560
23566
|
if (paths === void 0) return void 0;
|
|
23561
23567
|
const workflows = [];
|
|
@@ -23563,7 +23569,7 @@ async function resolveEmittedPrContexts(deps, repo, branch) {
|
|
|
23563
23569
|
const body = await fetchFileContent(deps, repo, branch, path2);
|
|
23564
23570
|
if (body) workflows.push({ path: path2, body });
|
|
23565
23571
|
}
|
|
23566
|
-
return
|
|
23572
|
+
return workflows;
|
|
23567
23573
|
}
|
|
23568
23574
|
function registryRequiredContexts(meta) {
|
|
23569
23575
|
const raw = meta?.requiredChecks;
|
|
@@ -23576,6 +23582,9 @@ function refPatternCovers(pattern, ref) {
|
|
|
23576
23582
|
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
23577
23583
|
return new RegExp(`^${escaped}$`).test(ref);
|
|
23578
23584
|
}
|
|
23585
|
+
function uncoveredTrackBranches(liveIncludes, trackBranches) {
|
|
23586
|
+
return trackBranches.filter((branch) => !liveIncludes.some((pattern) => refPatternCovers(pattern, `refs/heads/${branch}`)));
|
|
23587
|
+
}
|
|
23579
23588
|
function rulesetCoversReleaseBranches(payload, track) {
|
|
23580
23589
|
const conditions = payload.conditions;
|
|
23581
23590
|
const include = conditions?.ref_name?.include;
|
|
@@ -23785,10 +23794,14 @@ async function auditRepoCi(repo, deps) {
|
|
|
23785
23794
|
prWorkflowPaths = listedWorkflowPaths === void 0 ? [] : await filterPullRequestTriggered(deps, repo, baseBranch, listedWorkflowPaths);
|
|
23786
23795
|
}
|
|
23787
23796
|
const hasGateWorkflow = hasCanonicalGateWorkflow || prWorkflowPaths.length > 0;
|
|
23788
|
-
let
|
|
23797
|
+
let branchWorkflows;
|
|
23798
|
+
const getBranchWorkflows = async () => {
|
|
23799
|
+
branchWorkflows ??= await resolveBranchWorkflows(deps, repo, baseBranch);
|
|
23800
|
+
return branchWorkflows;
|
|
23801
|
+
};
|
|
23789
23802
|
const getEmittedPrContexts = async () => {
|
|
23790
|
-
|
|
23791
|
-
return
|
|
23803
|
+
const workflows = await getBranchWorkflows();
|
|
23804
|
+
return workflows === void 0 ? void 0 : collectPullRequestWorkflowContexts(workflows);
|
|
23792
23805
|
};
|
|
23793
23806
|
const committedReferenceRaw = deployableGated ? await fetchFileContent(deps, repo, baseBranch, PRODUCT_RULESET_REF) : null;
|
|
23794
23807
|
let authoritativeRuleset = null;
|
|
@@ -23872,6 +23885,18 @@ async function auditRepoCi(repo, deps) {
|
|
|
23872
23885
|
});
|
|
23873
23886
|
}
|
|
23874
23887
|
}
|
|
23888
|
+
if (productRuleset != null) {
|
|
23889
|
+
const missingTrackBranches = [];
|
|
23890
|
+
for (const branch of uncoveredTrackBranches(liveBranchIncludes, branchesForTrack(resolveReleaseTrack(meta, void 0, repo)))) {
|
|
23891
|
+
if (await branchPresence(deps, repo, branch) === true) missingTrackBranches.push(branch);
|
|
23892
|
+
}
|
|
23893
|
+
checks.push({
|
|
23894
|
+
ok: missingTrackBranches.length === 0,
|
|
23895
|
+
label: RULESET_TRACK_SCOPE_LABEL,
|
|
23896
|
+
detail: missingTrackBranches.length ? `live ${PRODUCT_RULESET_NAME} includes [${liveBranchIncludes.join(", ")}] but the release track also requires [${missingTrackBranches.join(", ")}] \u2014 those branches tag and merge with no required check` : void 0,
|
|
23897
|
+
remediation: missingTrackBranches.length ? `mmi-cli oracle org project set ${repo} --var requiredCheckBranches=${JSON.stringify(branchesForTrack(resolveReleaseTrack(meta, void 0, repo)))} then mmi-cli devops bootstrap apply ${repo} --execute` : void 0
|
|
23898
|
+
});
|
|
23899
|
+
}
|
|
23875
23900
|
const contextAuthority = authoritativeRuleset ?? registryAuthorityWithoutReference(meta, repo);
|
|
23876
23901
|
if (contextAuthority != null) {
|
|
23877
23902
|
const emitted = await getEmittedPrContexts();
|
|
@@ -23886,11 +23911,12 @@ async function auditRepoCi(repo, deps) {
|
|
|
23886
23911
|
});
|
|
23887
23912
|
}
|
|
23888
23913
|
const prOnly = contextAuthority.coversReleaseBranches ? contextAuthority.contexts.filter((context) => TRAIN_PR_ONLY_CONTEXTS.has(context)) : [];
|
|
23914
|
+
const tagBlind = contextAuthority.coversReleaseBranches ? contextsUnreachableOnTagPush(contextAuthority.contexts, await getBranchWorkflows() ?? [], TRAIN_PR_ONLY_CONTEXTS) : [];
|
|
23889
23915
|
checks.push({
|
|
23890
|
-
ok: prOnly.length === 0,
|
|
23916
|
+
ok: prOnly.length === 0 && tagBlind.length === 0,
|
|
23891
23917
|
label: TAG_ADDRESSABLE_CONTEXTS_LABEL,
|
|
23892
|
-
detail: prOnly.length ? `${contextAuthority.source} requires [${prOnly.join(", ")}] on rc/main, but those contexts can only materialize for pull_request` : void 0,
|
|
23893
|
-
remediation: prOnly.length ? `Remove [${prOnly.join(", ")}] from rc/main requirements in registry META or ${PRODUCT_RULESET_REF}` : void 0
|
|
23918
|
+
detail: prOnly.length ? `${contextAuthority.source} requires [${prOnly.join(", ")}] on rc/main, but those contexts can only materialize for pull_request` : tagBlind.length ? `${contextAuthority.source} requires [${tagBlind.join(", ")}] on rc/main, but their workflows never trigger on a v* tag push (#5428) \u2014 the train would tag and wait forever` : void 0,
|
|
23919
|
+
remediation: prOnly.length ? `Remove [${prOnly.join(", ")}] from rc/main requirements in registry META or ${PRODUCT_RULESET_REF}` : tagBlind.length ? `Add push: tags: ['v*'] to the workflow(s) emitting [${tagBlind.join(", ")}] on ${baseBranch} (MMI-Hub .github/workflows/gate.yml is the shape)` : void 0
|
|
23894
23920
|
});
|
|
23895
23921
|
if (productRuleset != null && liveContexts.length > 0) {
|
|
23896
23922
|
const releaseBranches = releaseBranchRefsCovered(productRuleset.conditions, resolveReleaseTrack(meta, void 0, repo));
|
|
@@ -25480,10 +25506,10 @@ async function loadConfigForBoardSelector2(selector, repoOption) {
|
|
|
25480
25506
|
}
|
|
25481
25507
|
|
|
25482
25508
|
// src/statusline-invalidate.ts
|
|
25483
|
-
var
|
|
25509
|
+
var import_node_child_process10 = require("node:child_process");
|
|
25484
25510
|
function invalidateStatuslineBoardCache() {
|
|
25485
25511
|
try {
|
|
25486
|
-
const child2 = (0,
|
|
25512
|
+
const child2 = (0, import_node_child_process10.spawn)("jerv-cli", ["lane", "ops", "invalidate-board"], {
|
|
25487
25513
|
detached: true,
|
|
25488
25514
|
stdio: "ignore",
|
|
25489
25515
|
windowsHide: true
|
|
@@ -28358,6 +28384,7 @@ LIVE apply to ${repo}:
|
|
|
28358
28384
|
branchExists = false;
|
|
28359
28385
|
}
|
|
28360
28386
|
if (!branchExists) await gh(["api", `repos/${rec.repo}/git/refs`, "-f", `ref=refs/heads/${branch}`, "-f", `sha=${baseSha}`]);
|
|
28387
|
+
else await gh(["api", "-X", "PATCH", `repos/${rec.repo}/git/refs/heads/${branch}`, "-f", `sha=${baseSha}`, "-F", "force=true"]);
|
|
28361
28388
|
let existingSha;
|
|
28362
28389
|
try {
|
|
28363
28390
|
const cur = await gh(["api", `repos/${rec.repo}/contents/${enc(seed.target)}?ref=${branch}`]);
|
|
@@ -29557,7 +29584,7 @@ function deriveComposeProjectName(worktreePath) {
|
|
|
29557
29584
|
}
|
|
29558
29585
|
|
|
29559
29586
|
// src/stage-runner.ts
|
|
29560
|
-
var
|
|
29587
|
+
var import_node_child_process11 = require("node:child_process");
|
|
29561
29588
|
var import_node_fs28 = require("node:fs");
|
|
29562
29589
|
var import_node_path27 = require("node:path");
|
|
29563
29590
|
var import_node_net = require("node:net");
|
|
@@ -29606,7 +29633,7 @@ function findEnvFiles(root) {
|
|
|
29606
29633
|
}
|
|
29607
29634
|
|
|
29608
29635
|
// src/stage-runner.ts
|
|
29609
|
-
var execFileP3 = (0, import_node_util5.promisify)(
|
|
29636
|
+
var execFileP3 = (0, import_node_util5.promisify)(import_node_child_process11.execFile);
|
|
29610
29637
|
var DOCKER_TIMEOUT_MS = 15e3;
|
|
29611
29638
|
var EARLY_EXIT_GRACE_MS = 2e3;
|
|
29612
29639
|
function earlyExitGraceMs() {
|
|
@@ -30124,7 +30151,7 @@ async function startStage(config = {}, opts = {}) {
|
|
|
30124
30151
|
let up = sub(config.up.trim());
|
|
30125
30152
|
if (opts.forceRecreate) up = appendForceRecreate(up);
|
|
30126
30153
|
const identity = await resolveStageIdentity(cwd);
|
|
30127
|
-
const child2 = (0,
|
|
30154
|
+
const child2 = (0, import_node_child_process11.spawn)(up, {
|
|
30128
30155
|
cwd,
|
|
30129
30156
|
shell: true,
|
|
30130
30157
|
// POSIX-only: the process group exists for the group-kill in stopStage. On win32 teardown is
|
|
@@ -34644,9 +34671,9 @@ function writeError(res) {
|
|
|
34644
34671
|
|
|
34645
34672
|
// src/schedules-commands.ts
|
|
34646
34673
|
var import_promises5 = require("node:fs/promises");
|
|
34647
|
-
var
|
|
34674
|
+
var import_node_child_process12 = require("node:child_process");
|
|
34648
34675
|
var import_node_util6 = require("node:util");
|
|
34649
|
-
var execFileP4 = (0, import_node_util6.promisify)(
|
|
34676
|
+
var execFileP4 = (0, import_node_util6.promisify)(import_node_child_process12.execFile);
|
|
34650
34677
|
var AWS_REGION = "eu-central-1";
|
|
34651
34678
|
var AWS_TIMEOUT_MS = 3e4;
|
|
34652
34679
|
var AWS_RETRY_DELAY_MS = 1500;
|
|
@@ -36166,7 +36193,7 @@ function renderVerifySecrets(body) {
|
|
|
36166
36193
|
}
|
|
36167
36194
|
|
|
36168
36195
|
// src/command-register-collaboration.ts
|
|
36169
|
-
var
|
|
36196
|
+
var import_node_child_process17 = require("node:child_process");
|
|
36170
36197
|
var import_node_fs43 = require("node:fs");
|
|
36171
36198
|
var import_promises7 = require("node:fs/promises");
|
|
36172
36199
|
|
|
@@ -36381,14 +36408,6 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
36381
36408
|
};
|
|
36382
36409
|
}
|
|
36383
36410
|
}
|
|
36384
|
-
const queue = await deps.queueMerge?.(prNumber, repo);
|
|
36385
|
-
if (queue) return {
|
|
36386
|
-
...base,
|
|
36387
|
-
queue,
|
|
36388
|
-
status: queue.state === "merged" ? "merged" : "failed",
|
|
36389
|
-
mergeStatus: queue.state === "merged" ? "merged" : "failed",
|
|
36390
|
-
...queue.state === "merged" ? {} : { error: queue.detail }
|
|
36391
|
-
};
|
|
36392
36411
|
const ciPolicy = await deps.resolveCiPolicy(repo);
|
|
36393
36412
|
base.ciPolicy = ciPolicy;
|
|
36394
36413
|
const checksWaitError = (checksWait) => {
|
|
@@ -36548,12 +36567,12 @@ function boardAdvanceFailureMessage(result) {
|
|
|
36548
36567
|
}
|
|
36549
36568
|
|
|
36550
36569
|
// src/test-policy-core.ts
|
|
36551
|
-
var
|
|
36570
|
+
var import_node_child_process14 = require("node:child_process");
|
|
36552
36571
|
var import_node_fs36 = require("node:fs");
|
|
36553
36572
|
var import_node_path33 = require("node:path");
|
|
36554
36573
|
|
|
36555
36574
|
// src/test-command-policy-shared.mjs
|
|
36556
|
-
var
|
|
36575
|
+
var import_node_child_process13 = require("node:child_process");
|
|
36557
36576
|
var TEST_COMMAND_CLASS = "test";
|
|
36558
36577
|
var TRAILER_KEY = "Test-Policy-Override";
|
|
36559
36578
|
var OVERRIDE_RE = /^Test-Policy-Override:\s*(.+)$/im;
|
|
@@ -36653,7 +36672,7 @@ function evaluateTestCommandPolicy({ paths, mandatory, regulated = true, overrid
|
|
|
36653
36672
|
};
|
|
36654
36673
|
}
|
|
36655
36674
|
function git(args, cwd) {
|
|
36656
|
-
return (0,
|
|
36675
|
+
return (0, import_node_child_process13.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
|
|
36657
36676
|
}
|
|
36658
36677
|
function parseScope(value) {
|
|
36659
36678
|
const scoped = /^\[([^\]]*)\]\s*([\s\S]*)$/.exec(value);
|
|
@@ -37152,14 +37171,14 @@ function evaluate(changed, policy, present = () => false) {
|
|
|
37152
37171
|
return findings;
|
|
37153
37172
|
}
|
|
37154
37173
|
function git2(args, cwd) {
|
|
37155
|
-
return (0,
|
|
37174
|
+
return (0, import_node_child_process14.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
|
|
37156
37175
|
}
|
|
37157
37176
|
var COAUTHOR_KEY = "Co-authored-by";
|
|
37158
37177
|
var GH_MESSAGE_SEPARATOR = /^-{5,}$/;
|
|
37159
37178
|
var LIFTED_KEYS = new RegExp(`^(?:${TRAILER_KEY}|${COAUTHOR_KEY}):`, "i");
|
|
37160
37179
|
function parseTrailers(message2, cwd) {
|
|
37161
37180
|
try {
|
|
37162
|
-
return (0,
|
|
37181
|
+
return (0, import_node_child_process14.execFileSync)("git", ["interpret-trailers", "--parse", "--unfold"], {
|
|
37163
37182
|
windowsHide: true,
|
|
37164
37183
|
cwd,
|
|
37165
37184
|
input: message2,
|
|
@@ -37700,287 +37719,9 @@ async function deleteMergedRemoteBranch(options) {
|
|
|
37700
37719
|
};
|
|
37701
37720
|
}
|
|
37702
37721
|
|
|
37703
|
-
// src/
|
|
37704
|
-
var import_node_child_process14 = require("node:child_process");
|
|
37722
|
+
// src/post-merge-recon.ts
|
|
37705
37723
|
var import_node_fs38 = require("node:fs");
|
|
37706
|
-
var import_node_os19 = require("node:os");
|
|
37707
37724
|
var import_node_path35 = require("node:path");
|
|
37708
|
-
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
37709
|
-
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
37710
|
-
function isReviewVerdict(value) {
|
|
37711
|
-
return typeof value === "string" && REVIEW_VERDICTS.includes(value);
|
|
37712
|
-
}
|
|
37713
|
-
function renderReviewVerdictComment(input) {
|
|
37714
|
-
const payload = {
|
|
37715
|
-
v: 1,
|
|
37716
|
-
patch: input.patch,
|
|
37717
|
-
head: input.head,
|
|
37718
|
-
verdict: input.verdict,
|
|
37719
|
-
scope: input.scope,
|
|
37720
|
-
risk: input.risk,
|
|
37721
|
-
unverified: input.unverified,
|
|
37722
|
-
reviewer: input.reviewer
|
|
37723
|
-
};
|
|
37724
|
-
const findings = input.findings?.trim();
|
|
37725
|
-
return `${REVIEW_VERDICT_MARKER}
|
|
37726
|
-
\`\`\`json
|
|
37727
|
-
${JSON.stringify(payload, null, 2)}
|
|
37728
|
-
\`\`\`
|
|
37729
|
-
${findings ? `
|
|
37730
|
-
${findings}
|
|
37731
|
-
` : ""}`;
|
|
37732
|
-
}
|
|
37733
|
-
function isReviewVerdictComment(body) {
|
|
37734
|
-
return body.trimStart().startsWith(REVIEW_VERDICT_MARKER);
|
|
37735
|
-
}
|
|
37736
|
-
var FENCE_RE = /^(?:`{3,}|~{3,})[^\n]*\n([\s\S]*?)\n(?:`{3,}|~{3,})\s*$/m;
|
|
37737
|
-
function parseReviewVerdictComment(body) {
|
|
37738
|
-
if (!isReviewVerdictComment(body)) return void 0;
|
|
37739
|
-
const rest = body.trimStart().slice(REVIEW_VERDICT_MARKER.length);
|
|
37740
|
-
const fence = FENCE_RE.exec(rest);
|
|
37741
|
-
if (!fence) return void 0;
|
|
37742
|
-
let parsed;
|
|
37743
|
-
try {
|
|
37744
|
-
parsed = JSON.parse(fence[1]);
|
|
37745
|
-
} catch {
|
|
37746
|
-
return void 0;
|
|
37747
|
-
}
|
|
37748
|
-
if (!parsed || typeof parsed !== "object") return void 0;
|
|
37749
|
-
const p = parsed;
|
|
37750
|
-
if (p.v !== 1 || !isReviewVerdict(p.verdict)) return void 0;
|
|
37751
|
-
if (typeof p.patch !== "string" || !/^[0-9a-f]{40}$/.test(p.patch)) return void 0;
|
|
37752
|
-
if (typeof p.head !== "string" || typeof p.scope !== "string" || typeof p.risk !== "string" || typeof p.reviewer !== "string") return void 0;
|
|
37753
|
-
const unverified = Array.isArray(p.unverified) ? p.unverified.filter((u) => typeof u === "string") : [];
|
|
37754
|
-
return { v: 1, patch: p.patch, head: p.head, verdict: p.verdict, scope: p.scope, risk: p.risk, unverified, reviewer: p.reviewer };
|
|
37755
|
-
}
|
|
37756
|
-
function latestReviewComment(comments) {
|
|
37757
|
-
let latest;
|
|
37758
|
-
for (const c of comments) {
|
|
37759
|
-
if (!isReviewVerdictComment(c.body)) continue;
|
|
37760
|
-
if (!latest || c.createdAt > latest.createdAt || c.createdAt === latest.createdAt && (c.id ?? 0) >= (latest.id ?? 0)) latest = c;
|
|
37761
|
-
}
|
|
37762
|
-
return latest;
|
|
37763
|
-
}
|
|
37764
|
-
function evaluateReviewVerdict(comments, currentPatchId) {
|
|
37765
|
-
const latest = latestReviewComment(comments);
|
|
37766
|
-
if (!latest) return { ok: false, reason: "none" };
|
|
37767
|
-
const payload = parseReviewVerdictComment(latest.body);
|
|
37768
|
-
if (!payload) return { ok: false, reason: "malformed" };
|
|
37769
|
-
if (payload.verdict !== "PROCEED") return { ok: false, reason: "not-proceed", verdict: payload.verdict, patch: payload.patch };
|
|
37770
|
-
if (payload.patch !== currentPatchId) return { ok: false, reason: "stale", verdict: payload.verdict, patch: payload.patch };
|
|
37771
|
-
return { ok: true, reason: "proceed", verdict: payload.verdict, patch: payload.patch };
|
|
37772
|
-
}
|
|
37773
|
-
function evaluateTrustedReviewVerdict(comments, patch, head) {
|
|
37774
|
-
const latest = latestReviewComment(comments);
|
|
37775
|
-
if (!latest) return { ok: false, reason: "none" };
|
|
37776
|
-
const identity = { commentId: latest.id, commentCreatedAt: latest.createdAt };
|
|
37777
|
-
if (latest.author?.toLowerCase() !== "jervaise") return { ...identity, ok: false, reason: "untrusted-author" };
|
|
37778
|
-
const evaluation = evaluateReviewVerdict([latest], patch);
|
|
37779
|
-
if (!evaluation.ok) return { ...identity, ok: false, reason: evaluation.reason };
|
|
37780
|
-
if (parseReviewVerdictComment(latest.body)?.head !== head) return { ...identity, ok: false, reason: "stale-head" };
|
|
37781
|
-
return { ...identity, ok: true, reason: "proceed" };
|
|
37782
|
-
}
|
|
37783
|
-
async function checkPrReview(number, repo, head, deps = {
|
|
37784
|
-
readHead: readPrHeadSha,
|
|
37785
|
-
readComments: readPrIssueComments,
|
|
37786
|
-
computePatch: computePrPatchId
|
|
37787
|
-
}) {
|
|
37788
|
-
const base = { repo, number, head };
|
|
37789
|
-
if (!/^[1-9][0-9]*$/.test(number) || !/^[\w.-]+\/[\w.-]+$/.test(repo) || !/^[0-9a-f]{40}$/.test(head)) {
|
|
37790
|
-
return { ...base, ok: false, reason: "invalid-input", detail: "expected a PR number, owner/repo and exact lowercase 40-character head SHA" };
|
|
37791
|
-
}
|
|
37792
|
-
try {
|
|
37793
|
-
if (await deps.readHead(number, repo) !== head) return { ...base, ok: false, reason: "stale-head" };
|
|
37794
|
-
const [comments, patch] = await Promise.all([deps.readComments(number, repo), deps.computePatch(number, repo)]);
|
|
37795
|
-
if (await deps.readHead(number, repo) !== head) return { ...base, ok: false, reason: "stale-head" };
|
|
37796
|
-
return { ...base, patch, ...evaluateTrustedReviewVerdict(comments, patch, head) };
|
|
37797
|
-
} catch (e) {
|
|
37798
|
-
return { ...base, ok: false, reason: "unreadable", detail: e.message };
|
|
37799
|
-
}
|
|
37800
|
-
}
|
|
37801
|
-
function computePrPatchId(number, repo) {
|
|
37802
|
-
return new Promise((resolve7, reject) => {
|
|
37803
|
-
const gh = (0, import_node_child_process14.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
37804
|
-
const git3 = (0, import_node_child_process14.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
|
|
37805
|
-
let out = "";
|
|
37806
|
-
let ghErr = "";
|
|
37807
|
-
let gitErr = "";
|
|
37808
|
-
const timer = setTimeout(() => {
|
|
37809
|
-
gh.kill();
|
|
37810
|
-
git3.kill();
|
|
37811
|
-
reject(new Error(`patch-id: timed out after ${GC_GH_TIMEOUT_MS4}ms`));
|
|
37812
|
-
}, GC_GH_TIMEOUT_MS4);
|
|
37813
|
-
gh.stdout.pipe(git3.stdin);
|
|
37814
|
-
gh.stderr.on("data", (d) => {
|
|
37815
|
-
ghErr += d.toString();
|
|
37816
|
-
});
|
|
37817
|
-
git3.stderr.on("data", (d) => {
|
|
37818
|
-
gitErr += d.toString();
|
|
37819
|
-
});
|
|
37820
|
-
git3.stdout.on("data", (d) => {
|
|
37821
|
-
out += d.toString();
|
|
37822
|
-
});
|
|
37823
|
-
gh.on("error", (e) => {
|
|
37824
|
-
clearTimeout(timer);
|
|
37825
|
-
reject(e);
|
|
37826
|
-
});
|
|
37827
|
-
git3.on("error", (e) => {
|
|
37828
|
-
clearTimeout(timer);
|
|
37829
|
-
reject(e);
|
|
37830
|
-
});
|
|
37831
|
-
let ghCode;
|
|
37832
|
-
let gitCode;
|
|
37833
|
-
const finish = () => {
|
|
37834
|
-
if (ghCode === void 0 || gitCode === void 0) return;
|
|
37835
|
-
clearTimeout(timer);
|
|
37836
|
-
if (ghCode !== 0) return reject(Object.assign(new Error(`gh pr diff ${number} --repo ${repo} exited ${ghCode}: ${ghErr.trim()}`), { stderr: ghErr }));
|
|
37837
|
-
if (gitCode !== 0) return reject(new Error(`git patch-id --stable exited ${gitCode}: ${gitErr.trim()}`));
|
|
37838
|
-
const id = out.trim().split(/\s+/)[0];
|
|
37839
|
-
if (!/^[0-9a-f]{40}$/.test(id ?? "")) return reject(new Error(`patch-id: PR #${number} diff is empty or unreadable (gh: ${ghErr.trim() || "no stderr"})`));
|
|
37840
|
-
resolve7(id);
|
|
37841
|
-
};
|
|
37842
|
-
gh.on("close", (code) => {
|
|
37843
|
-
ghCode = code;
|
|
37844
|
-
finish();
|
|
37845
|
-
});
|
|
37846
|
-
git3.on("close", (code) => {
|
|
37847
|
-
gitCode = code;
|
|
37848
|
-
finish();
|
|
37849
|
-
});
|
|
37850
|
-
git3.stdin.on("error", (e) => {
|
|
37851
|
-
clearTimeout(timer);
|
|
37852
|
-
gh.kill();
|
|
37853
|
-
git3.kill();
|
|
37854
|
-
reject(e);
|
|
37855
|
-
});
|
|
37856
|
-
});
|
|
37857
|
-
}
|
|
37858
|
-
async function readPrHeadSha(number, repo) {
|
|
37859
|
-
const { stdout } = await execFileP("gh", ["api", `repos/${repo}/pulls/${number}`, "--jq", ".head.sha"], { timeout: GC_GH_TIMEOUT_MS4 });
|
|
37860
|
-
const sha = stdout.trim();
|
|
37861
|
-
if (!/^[0-9a-f]{40}$/.test(sha)) throw new Error(`could not read PR #${number} head sha`);
|
|
37862
|
-
return sha;
|
|
37863
|
-
}
|
|
37864
|
-
async function readPrIssueComments(number, repo) {
|
|
37865
|
-
const { stdout } = await execFileP("gh", ["api", "--paginate", `repos/${repo}/issues/${number}/comments?per_page=100`, "--jq", ".[] | {id, body, createdAt: .created_at, author: .user.login}"], { timeout: GC_GH_TIMEOUT_MS4 });
|
|
37866
|
-
const comments = parseNdjsonLines(stdout);
|
|
37867
|
-
if (comments.some((c) => !c || !Number.isSafeInteger(c.id) || c.id <= 0 || typeof c.body !== "string" || typeof c.createdAt !== "string" || !Number.isFinite(Date.parse(c.createdAt)) || c.author !== null && typeof c.author !== "string")) throw new Error("unreadable PR comment identity");
|
|
37868
|
-
return comments;
|
|
37869
|
-
}
|
|
37870
|
-
async function postPrCommentFromFile(number, repo, body) {
|
|
37871
|
-
const dir = (0, import_node_fs38.mkdtempSync)((0, import_node_path35.join)((0, import_node_os19.tmpdir)(), "mmi-review-verdict-"));
|
|
37872
|
-
const path2 = (0, import_node_path35.join)(dir, "body.md");
|
|
37873
|
-
try {
|
|
37874
|
-
(0, import_node_fs38.writeFileSync)(path2, body, "utf8");
|
|
37875
|
-
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
37876
|
-
return stdout.trim();
|
|
37877
|
-
} finally {
|
|
37878
|
-
try {
|
|
37879
|
-
(0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
|
|
37880
|
-
} catch {
|
|
37881
|
-
}
|
|
37882
|
-
}
|
|
37883
|
-
}
|
|
37884
|
-
|
|
37885
|
-
// src/pr-mergify-queue.ts
|
|
37886
|
-
var MERGIFY_PILOT_REPO = "mutmutco/Jerv-JervCode";
|
|
37887
|
-
var MERGIFY_PILOT_VARIABLE = "JERV_BATCH_QUEUE_PILOT";
|
|
37888
|
-
var MERGIFY_READY_LABEL = "ready-to-merge";
|
|
37889
|
-
async function ghJson(args) {
|
|
37890
|
-
return JSON.parse((await execFileP("gh", ["api", ...args], { timeout: GC_GH_TIMEOUT_MS4 })).stdout);
|
|
37891
|
-
}
|
|
37892
|
-
async function usesMergifyPilot(repo, base, readVariable = async () => ghJson([`repos/${repo}/actions/variables/${MERGIFY_PILOT_VARIABLE}`])) {
|
|
37893
|
-
if (repo.toLowerCase() !== MERGIFY_PILOT_REPO.toLowerCase() || base !== "development") return false;
|
|
37894
|
-
const variable = await readVariable();
|
|
37895
|
-
if (variable?.value === "true") return true;
|
|
37896
|
-
if (variable?.value === "false") return false;
|
|
37897
|
-
throw new Error(`Mergify pilot activation is missing or malformed on ${repo}; refusing native merge`);
|
|
37898
|
-
}
|
|
37899
|
-
function queueCheckState(checks, head) {
|
|
37900
|
-
const check = checks.filter((c) => c.name === "Mergify Merge Queue" && c.head_sha === head && c.app?.id === 10562 && c.app.slug === "mergify").sort((a, b) => b.id - a.id)[0];
|
|
37901
|
-
if (!check) return "refused";
|
|
37902
|
-
if (check.conclusion && !["success", "neutral"].includes(check.conclusion)) return "refused";
|
|
37903
|
-
if (["In merge queue", "Running merge queue checks"].includes(check.output?.title ?? "")) return "pending";
|
|
37904
|
-
return "requested";
|
|
37905
|
-
}
|
|
37906
|
-
async function requestMergifyMerge(number, repo, guardedText, expectedHead, deps = {
|
|
37907
|
-
readPull: () => ghJson([`repos/${repo}/pulls/${number}`]),
|
|
37908
|
-
readChecks: async (head) => parseNdjsonLines((await execFileP("gh", [
|
|
37909
|
-
"api",
|
|
37910
|
-
"--paginate",
|
|
37911
|
-
`repos/${repo}/commits/${head}/check-runs?per_page=100`,
|
|
37912
|
-
"--jq",
|
|
37913
|
-
".check_runs[]"
|
|
37914
|
-
], { timeout: GC_GH_TIMEOUT_MS4 })).stdout),
|
|
37915
|
-
addLabel: async () => {
|
|
37916
|
-
await ghJson([`repos/${repo}/issues/${number}/labels`, "--method", "POST", "-f", `labels[]=${MERGIFY_READY_LABEL}`]);
|
|
37917
|
-
},
|
|
37918
|
-
review: (head) => checkPrReview(number, repo, head),
|
|
37919
|
-
now: () => Date.now(),
|
|
37920
|
-
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))
|
|
37921
|
-
}, timeoutMs = 6e5) {
|
|
37922
|
-
let head = expectedHead ?? "";
|
|
37923
|
-
let state = "refused";
|
|
37924
|
-
const receipt = (detail) => ({ provider: "mergify", state, head, detail });
|
|
37925
|
-
try {
|
|
37926
|
-
if (repo.toLowerCase() !== MERGIFY_PILOT_REPO.toLowerCase()) return receipt("repository is outside the Mergify pilot");
|
|
37927
|
-
const initial = await deps.readPull();
|
|
37928
|
-
head = expectedHead ?? initial.head.sha;
|
|
37929
|
-
const sameTarget = (pr) => /^[0-9a-f]{40}$/.test(head) && pr.head.sha === head && pr.base.ref === "development";
|
|
37930
|
-
if (!sameTarget(initial)) return receipt("PR head or target base changed");
|
|
37931
|
-
if (initial.merged === true) {
|
|
37932
|
-
state = "merged";
|
|
37933
|
-
return receipt("GitHub confirms the PR merged");
|
|
37934
|
-
}
|
|
37935
|
-
const validate = (pr) => pr.state === "open" && sameTarget(pr) && `${pr.title}
|
|
37936
|
-
${pr.body ?? ""}` === guardedText;
|
|
37937
|
-
if (!validate(initial)) return receipt("PR state, head, base or guarded title/body changed");
|
|
37938
|
-
const initialState = queueCheckState(await deps.readChecks(head), head);
|
|
37939
|
-
if (initialState === "refused") return receipt("trusted current-head Mergify check is absent or failed");
|
|
37940
|
-
if (!(await deps.review(head)).ok) return receipt("current trusted review verdict does not permit queue admission");
|
|
37941
|
-
if (!validate(await deps.readPull())) return receipt("PR changed before queue request");
|
|
37942
|
-
let mutationDetail = "";
|
|
37943
|
-
if (!initial.labels.some((label) => label.name === MERGIFY_READY_LABEL)) {
|
|
37944
|
-
try {
|
|
37945
|
-
await deps.addLabel();
|
|
37946
|
-
} catch {
|
|
37947
|
-
mutationDetail = "Label response was ambiguous; no replay was attempted. ";
|
|
37948
|
-
}
|
|
37949
|
-
}
|
|
37950
|
-
state = "requested";
|
|
37951
|
-
const deadline = deps.now() + timeoutMs;
|
|
37952
|
-
while (true) {
|
|
37953
|
-
const pr = await deps.readPull();
|
|
37954
|
-
if (!sameTarget(pr)) {
|
|
37955
|
-
state = "refused";
|
|
37956
|
-
return receipt("PR head or target base changed while queued");
|
|
37957
|
-
}
|
|
37958
|
-
if (pr.merged === true) {
|
|
37959
|
-
state = "merged";
|
|
37960
|
-
return receipt("GitHub confirms the PR merged");
|
|
37961
|
-
}
|
|
37962
|
-
if (!validate(pr)) {
|
|
37963
|
-
state = "refused";
|
|
37964
|
-
return receipt("PR state, head, base or guarded title/body changed while queued");
|
|
37965
|
-
}
|
|
37966
|
-
state = queueCheckState(await deps.readChecks(head), head);
|
|
37967
|
-
if (state === "refused") return receipt("trusted current-head Mergify check is absent or failed");
|
|
37968
|
-
if (!pr.labels.some((label) => label.name === MERGIFY_READY_LABEL)) {
|
|
37969
|
-
state = "refused";
|
|
37970
|
-
return receipt(`${mutationDetail}Queue request label is absent`);
|
|
37971
|
-
}
|
|
37972
|
-
if (deps.now() >= deadline) return receipt(`${mutationDetail}${state === "pending" ? "Mergify confirms queue admission" : "Queue requested; Mergify has not confirmed admission"}; PR has not merged within the wait window`);
|
|
37973
|
-
await deps.sleep(3e4);
|
|
37974
|
-
}
|
|
37975
|
-
} catch {
|
|
37976
|
-
state = "refused";
|
|
37977
|
-
return receipt("Mergify or GitHub state is unreadable; no native merge was attempted");
|
|
37978
|
-
}
|
|
37979
|
-
}
|
|
37980
|
-
|
|
37981
|
-
// src/post-merge-recon.ts
|
|
37982
|
-
var import_node_fs39 = require("node:fs");
|
|
37983
|
-
var import_node_path36 = require("node:path");
|
|
37984
37725
|
|
|
37985
37726
|
// src/cross-repo-filing-issue.ts
|
|
37986
37727
|
function crossRepoFilingRetryCommand(prRepo, prNumber) {
|
|
@@ -38146,16 +37887,16 @@ function buildPostMergeReconRecovery(input) {
|
|
|
38146
37887
|
}
|
|
38147
37888
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
38148
37889
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
38149
|
-
(0,
|
|
38150
|
-
(0,
|
|
37890
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(path2), { recursive: true });
|
|
37891
|
+
(0, import_node_fs38.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
|
|
38151
37892
|
`, "utf8");
|
|
38152
37893
|
return path2;
|
|
38153
37894
|
}
|
|
38154
37895
|
function clearPostMergeReconRecovery(cwd, repo, pr) {
|
|
38155
37896
|
const path2 = postMergeReconStatePath(cwd, repo, pr);
|
|
38156
|
-
if (!(0,
|
|
37897
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return;
|
|
38157
37898
|
try {
|
|
38158
|
-
(0,
|
|
37899
|
+
(0, import_node_fs38.unlinkSync)(path2);
|
|
38159
37900
|
} catch {
|
|
38160
37901
|
}
|
|
38161
37902
|
}
|
|
@@ -38185,15 +37926,197 @@ function postMergeReconWarnings(input) {
|
|
|
38185
37926
|
return lines2;
|
|
38186
37927
|
}
|
|
38187
37928
|
|
|
38188
|
-
// src/
|
|
37929
|
+
// src/review-verdict.ts
|
|
38189
37930
|
var import_node_child_process15 = require("node:child_process");
|
|
37931
|
+
var import_node_fs39 = require("node:fs");
|
|
37932
|
+
var import_node_os19 = require("node:os");
|
|
37933
|
+
var import_node_path36 = require("node:path");
|
|
37934
|
+
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
37935
|
+
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
37936
|
+
function isReviewVerdict(value) {
|
|
37937
|
+
return typeof value === "string" && REVIEW_VERDICTS.includes(value);
|
|
37938
|
+
}
|
|
37939
|
+
function renderReviewVerdictComment(input) {
|
|
37940
|
+
const payload = {
|
|
37941
|
+
v: 1,
|
|
37942
|
+
patch: input.patch,
|
|
37943
|
+
head: input.head,
|
|
37944
|
+
verdict: input.verdict,
|
|
37945
|
+
scope: input.scope,
|
|
37946
|
+
risk: input.risk,
|
|
37947
|
+
unverified: input.unverified,
|
|
37948
|
+
reviewer: input.reviewer
|
|
37949
|
+
};
|
|
37950
|
+
const findings = input.findings?.trim();
|
|
37951
|
+
return `${REVIEW_VERDICT_MARKER}
|
|
37952
|
+
\`\`\`json
|
|
37953
|
+
${JSON.stringify(payload, null, 2)}
|
|
37954
|
+
\`\`\`
|
|
37955
|
+
${findings ? `
|
|
37956
|
+
${findings}
|
|
37957
|
+
` : ""}`;
|
|
37958
|
+
}
|
|
37959
|
+
function isReviewVerdictComment(body) {
|
|
37960
|
+
return body.trimStart().startsWith(REVIEW_VERDICT_MARKER);
|
|
37961
|
+
}
|
|
37962
|
+
var FENCE_RE = /^(?:`{3,}|~{3,})[^\n]*\n([\s\S]*?)\n(?:`{3,}|~{3,})\s*$/m;
|
|
37963
|
+
function parseReviewVerdictComment(body) {
|
|
37964
|
+
if (!isReviewVerdictComment(body)) return void 0;
|
|
37965
|
+
const rest = body.trimStart().slice(REVIEW_VERDICT_MARKER.length);
|
|
37966
|
+
const fence = FENCE_RE.exec(rest);
|
|
37967
|
+
if (!fence) return void 0;
|
|
37968
|
+
let parsed;
|
|
37969
|
+
try {
|
|
37970
|
+
parsed = JSON.parse(fence[1]);
|
|
37971
|
+
} catch {
|
|
37972
|
+
return void 0;
|
|
37973
|
+
}
|
|
37974
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
37975
|
+
const p = parsed;
|
|
37976
|
+
if (p.v !== 1 || !isReviewVerdict(p.verdict)) return void 0;
|
|
37977
|
+
if (typeof p.patch !== "string" || !/^[0-9a-f]{40}$/.test(p.patch)) return void 0;
|
|
37978
|
+
if (typeof p.head !== "string" || typeof p.scope !== "string" || typeof p.risk !== "string" || typeof p.reviewer !== "string") return void 0;
|
|
37979
|
+
const unverified = Array.isArray(p.unverified) ? p.unverified.filter((u) => typeof u === "string") : [];
|
|
37980
|
+
return { v: 1, patch: p.patch, head: p.head, verdict: p.verdict, scope: p.scope, risk: p.risk, unverified, reviewer: p.reviewer };
|
|
37981
|
+
}
|
|
37982
|
+
function latestReviewComment(comments) {
|
|
37983
|
+
let latest;
|
|
37984
|
+
for (const c of comments) {
|
|
37985
|
+
if (!isReviewVerdictComment(c.body)) continue;
|
|
37986
|
+
if (!latest || c.createdAt > latest.createdAt || c.createdAt === latest.createdAt && (c.id ?? 0) >= (latest.id ?? 0)) latest = c;
|
|
37987
|
+
}
|
|
37988
|
+
return latest;
|
|
37989
|
+
}
|
|
37990
|
+
function evaluateReviewVerdict(comments, currentPatchId) {
|
|
37991
|
+
const latest = latestReviewComment(comments);
|
|
37992
|
+
if (!latest) return { ok: false, reason: "none" };
|
|
37993
|
+
const payload = parseReviewVerdictComment(latest.body);
|
|
37994
|
+
if (!payload) return { ok: false, reason: "malformed" };
|
|
37995
|
+
if (payload.verdict !== "PROCEED") return { ok: false, reason: "not-proceed", verdict: payload.verdict, patch: payload.patch };
|
|
37996
|
+
if (payload.patch !== currentPatchId) return { ok: false, reason: "stale", verdict: payload.verdict, patch: payload.patch };
|
|
37997
|
+
return { ok: true, reason: "proceed", verdict: payload.verdict, patch: payload.patch };
|
|
37998
|
+
}
|
|
37999
|
+
function evaluateTrustedReviewVerdict(comments, patch, head) {
|
|
38000
|
+
const latest = latestReviewComment(comments);
|
|
38001
|
+
if (!latest) return { ok: false, reason: "none" };
|
|
38002
|
+
const identity = { commentId: latest.id, commentCreatedAt: latest.createdAt };
|
|
38003
|
+
if (latest.author?.toLowerCase() !== "jervaise") return { ...identity, ok: false, reason: "untrusted-author" };
|
|
38004
|
+
const evaluation = evaluateReviewVerdict([latest], patch);
|
|
38005
|
+
if (!evaluation.ok) return { ...identity, ok: false, reason: evaluation.reason };
|
|
38006
|
+
if (parseReviewVerdictComment(latest.body)?.head !== head) return { ...identity, ok: false, reason: "stale-head" };
|
|
38007
|
+
return { ...identity, ok: true, reason: "proceed" };
|
|
38008
|
+
}
|
|
38009
|
+
async function checkPrReview(number, repo, head, deps = {
|
|
38010
|
+
readHead: readPrHeadSha,
|
|
38011
|
+
readComments: readPrIssueComments,
|
|
38012
|
+
computePatch: computePrPatchId
|
|
38013
|
+
}) {
|
|
38014
|
+
const base = { repo, number, head };
|
|
38015
|
+
if (!/^[1-9][0-9]*$/.test(number) || !/^[\w.-]+\/[\w.-]+$/.test(repo) || !/^[0-9a-f]{40}$/.test(head)) {
|
|
38016
|
+
return { ...base, ok: false, reason: "invalid-input", detail: "expected a PR number, owner/repo and exact lowercase 40-character head SHA" };
|
|
38017
|
+
}
|
|
38018
|
+
try {
|
|
38019
|
+
if (await deps.readHead(number, repo) !== head) return { ...base, ok: false, reason: "stale-head" };
|
|
38020
|
+
const [comments, patch] = await Promise.all([deps.readComments(number, repo), deps.computePatch(number, repo)]);
|
|
38021
|
+
if (await deps.readHead(number, repo) !== head) return { ...base, ok: false, reason: "stale-head" };
|
|
38022
|
+
return { ...base, patch, ...evaluateTrustedReviewVerdict(comments, patch, head) };
|
|
38023
|
+
} catch (e) {
|
|
38024
|
+
return { ...base, ok: false, reason: "unreadable", detail: e.message };
|
|
38025
|
+
}
|
|
38026
|
+
}
|
|
38027
|
+
function computePrPatchId(number, repo) {
|
|
38028
|
+
return new Promise((resolve7, reject) => {
|
|
38029
|
+
const gh = (0, import_node_child_process15.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
38030
|
+
const git3 = (0, import_node_child_process15.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
|
|
38031
|
+
let out = "";
|
|
38032
|
+
let ghErr = "";
|
|
38033
|
+
let gitErr = "";
|
|
38034
|
+
const timer = setTimeout(() => {
|
|
38035
|
+
gh.kill();
|
|
38036
|
+
git3.kill();
|
|
38037
|
+
reject(new Error(`patch-id: timed out after ${GC_GH_TIMEOUT_MS4}ms`));
|
|
38038
|
+
}, GC_GH_TIMEOUT_MS4);
|
|
38039
|
+
gh.stdout.pipe(git3.stdin);
|
|
38040
|
+
gh.stderr.on("data", (d) => {
|
|
38041
|
+
ghErr += d.toString();
|
|
38042
|
+
});
|
|
38043
|
+
git3.stderr.on("data", (d) => {
|
|
38044
|
+
gitErr += d.toString();
|
|
38045
|
+
});
|
|
38046
|
+
git3.stdout.on("data", (d) => {
|
|
38047
|
+
out += d.toString();
|
|
38048
|
+
});
|
|
38049
|
+
gh.on("error", (e) => {
|
|
38050
|
+
clearTimeout(timer);
|
|
38051
|
+
reject(e);
|
|
38052
|
+
});
|
|
38053
|
+
git3.on("error", (e) => {
|
|
38054
|
+
clearTimeout(timer);
|
|
38055
|
+
reject(e);
|
|
38056
|
+
});
|
|
38057
|
+
let ghCode;
|
|
38058
|
+
let gitCode;
|
|
38059
|
+
const finish = () => {
|
|
38060
|
+
if (ghCode === void 0 || gitCode === void 0) return;
|
|
38061
|
+
clearTimeout(timer);
|
|
38062
|
+
if (ghCode !== 0) return reject(Object.assign(new Error(`gh pr diff ${number} --repo ${repo} exited ${ghCode}: ${ghErr.trim()}`), { stderr: ghErr }));
|
|
38063
|
+
if (gitCode !== 0) return reject(new Error(`git patch-id --stable exited ${gitCode}: ${gitErr.trim()}`));
|
|
38064
|
+
const id = out.trim().split(/\s+/)[0];
|
|
38065
|
+
if (!/^[0-9a-f]{40}$/.test(id ?? "")) return reject(new Error(`patch-id: PR #${number} diff is empty or unreadable (gh: ${ghErr.trim() || "no stderr"})`));
|
|
38066
|
+
resolve7(id);
|
|
38067
|
+
};
|
|
38068
|
+
gh.on("close", (code) => {
|
|
38069
|
+
ghCode = code;
|
|
38070
|
+
finish();
|
|
38071
|
+
});
|
|
38072
|
+
git3.on("close", (code) => {
|
|
38073
|
+
gitCode = code;
|
|
38074
|
+
finish();
|
|
38075
|
+
});
|
|
38076
|
+
git3.stdin.on("error", (e) => {
|
|
38077
|
+
clearTimeout(timer);
|
|
38078
|
+
gh.kill();
|
|
38079
|
+
git3.kill();
|
|
38080
|
+
reject(e);
|
|
38081
|
+
});
|
|
38082
|
+
});
|
|
38083
|
+
}
|
|
38084
|
+
async function readPrHeadSha(number, repo) {
|
|
38085
|
+
const { stdout } = await execFileP("gh", ["api", `repos/${repo}/pulls/${number}`, "--jq", ".head.sha"], { timeout: GC_GH_TIMEOUT_MS4 });
|
|
38086
|
+
const sha = stdout.trim();
|
|
38087
|
+
if (!/^[0-9a-f]{40}$/.test(sha)) throw new Error(`could not read PR #${number} head sha`);
|
|
38088
|
+
return sha;
|
|
38089
|
+
}
|
|
38090
|
+
async function readPrIssueComments(number, repo) {
|
|
38091
|
+
const { stdout } = await execFileP("gh", ["api", "--paginate", `repos/${repo}/issues/${number}/comments?per_page=100`, "--jq", ".[] | {id, body, createdAt: .created_at, author: .user.login}"], { timeout: GC_GH_TIMEOUT_MS4 });
|
|
38092
|
+
const comments = parseNdjsonLines(stdout);
|
|
38093
|
+
if (comments.some((c) => !c || !Number.isSafeInteger(c.id) || c.id <= 0 || typeof c.body !== "string" || typeof c.createdAt !== "string" || !Number.isFinite(Date.parse(c.createdAt)) || c.author !== null && typeof c.author !== "string")) throw new Error("unreadable PR comment identity");
|
|
38094
|
+
return comments;
|
|
38095
|
+
}
|
|
38096
|
+
async function postPrCommentFromFile(number, repo, body) {
|
|
38097
|
+
const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path36.join)((0, import_node_os19.tmpdir)(), "mmi-review-verdict-"));
|
|
38098
|
+
const path2 = (0, import_node_path36.join)(dir, "body.md");
|
|
38099
|
+
try {
|
|
38100
|
+
(0, import_node_fs39.writeFileSync)(path2, body, "utf8");
|
|
38101
|
+
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
38102
|
+
return stdout.trim();
|
|
38103
|
+
} finally {
|
|
38104
|
+
try {
|
|
38105
|
+
(0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
|
|
38106
|
+
} catch {
|
|
38107
|
+
}
|
|
38108
|
+
}
|
|
38109
|
+
}
|
|
38110
|
+
|
|
38111
|
+
// src/pr-create-docs-check.ts
|
|
38112
|
+
var import_node_child_process16 = require("node:child_process");
|
|
38190
38113
|
var GIT_TIMEOUT_MS2 = 15e3;
|
|
38191
38114
|
function catFileBatch(root, ref, paths) {
|
|
38192
38115
|
if (paths.length === 0) return Promise.resolve([]);
|
|
38193
38116
|
return new Promise((resolve7) => {
|
|
38194
38117
|
const chunks = [];
|
|
38195
38118
|
let settled = false;
|
|
38196
|
-
const child2 = (0,
|
|
38119
|
+
const child2 = (0, import_node_child_process16.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
|
|
38197
38120
|
const finish = () => {
|
|
38198
38121
|
if (settled) return;
|
|
38199
38122
|
settled = true;
|
|
@@ -39309,7 +39232,7 @@ function ciAuditDeps() {
|
|
|
39309
39232
|
}
|
|
39310
39233
|
};
|
|
39311
39234
|
}
|
|
39312
|
-
async function
|
|
39235
|
+
async function ghJson(args, timeout = 1e4) {
|
|
39313
39236
|
const { stdout } = await execFileP("gh", args, { timeout });
|
|
39314
39237
|
return JSON.parse(stdout);
|
|
39315
39238
|
}
|
|
@@ -39387,7 +39310,7 @@ function scheduleRelatedDiscovery(o) {
|
|
|
39387
39310
|
try {
|
|
39388
39311
|
const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
|
|
39389
39312
|
if (o.repo) args.push("--repo", o.repo);
|
|
39390
|
-
spawnDetachedSelf(args, { spawn:
|
|
39313
|
+
spawnDetachedSelf(args, { spawn: import_node_child_process17.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
|
|
39391
39314
|
} catch {
|
|
39392
39315
|
}
|
|
39393
39316
|
}
|
|
@@ -39596,7 +39519,7 @@ function registerCollaborationCommands(program3) {
|
|
|
39596
39519
|
async function readParentField(number, repo) {
|
|
39597
39520
|
let payload;
|
|
39598
39521
|
try {
|
|
39599
|
-
payload = await
|
|
39522
|
+
payload = await ghJson(["api", `repos/${repo}/issues/${number}`]);
|
|
39600
39523
|
} catch (e) {
|
|
39601
39524
|
const err = e;
|
|
39602
39525
|
return { parentReadError: (err.stderr || err.message || String(e)).trim() };
|
|
@@ -39628,7 +39551,7 @@ function registerCollaborationCommands(program3) {
|
|
|
39628
39551
|
emit(data2, await readParentField(n, repo));
|
|
39629
39552
|
return;
|
|
39630
39553
|
}
|
|
39631
|
-
const data = await
|
|
39554
|
+
const data = await ghJson(["issue", "view", String(n), "--repo", repo, "--json", gh.ghFields]);
|
|
39632
39555
|
emit(data, await readParentField(n, repo));
|
|
39633
39556
|
} catch (e) {
|
|
39634
39557
|
const err = e;
|
|
@@ -39643,7 +39566,7 @@ function registerCollaborationCommands(program3) {
|
|
|
39643
39566
|
const repo = await resolveRepo(o.repo);
|
|
39644
39567
|
if (!repo) return fail("issue discover-related: could not resolve repo");
|
|
39645
39568
|
try {
|
|
39646
|
-
const issues = await
|
|
39569
|
+
const issues = await ghJson([
|
|
39647
39570
|
"issue",
|
|
39648
39571
|
"list",
|
|
39649
39572
|
"--repo",
|
|
@@ -39658,7 +39581,7 @@ function registerCollaborationCommands(program3) {
|
|
|
39658
39581
|
const candidates = findRelatedIssues({ number, title: o.title, body: o.body }, issues);
|
|
39659
39582
|
if (o.json) return console.log(JSON.stringify({ number, repo, candidates }, null, 2));
|
|
39660
39583
|
if (!candidates.length) return;
|
|
39661
|
-
const viewed = await
|
|
39584
|
+
const viewed = await ghJson([
|
|
39662
39585
|
"issue",
|
|
39663
39586
|
"view",
|
|
39664
39587
|
String(number),
|
|
@@ -39732,7 +39655,7 @@ function registerCollaborationCommands(program3) {
|
|
|
39732
39655
|
const checked = o.off !== true;
|
|
39733
39656
|
let body;
|
|
39734
39657
|
try {
|
|
39735
|
-
const viewed = await
|
|
39658
|
+
const viewed = await ghJson(["issue", "view", String(parsed.number), "--repo", repo, "--json", "body"]);
|
|
39736
39659
|
body = viewed.body ?? "";
|
|
39737
39660
|
} catch (e) {
|
|
39738
39661
|
return fail(`issue check: could not read ${repo}#${parsed.number}: ${e.message}`);
|
|
@@ -39834,7 +39757,7 @@ ${list}`);
|
|
|
39834
39757
|
if (!o.force) {
|
|
39835
39758
|
let openLessons = [];
|
|
39836
39759
|
try {
|
|
39837
|
-
openLessons = await
|
|
39760
|
+
openLessons = await ghJson([
|
|
39838
39761
|
"issue",
|
|
39839
39762
|
"list",
|
|
39840
39763
|
"--repo",
|
|
@@ -39940,7 +39863,7 @@ ${list}`);
|
|
|
39940
39863
|
console.log(JSON.stringify(data2));
|
|
39941
39864
|
return;
|
|
39942
39865
|
}
|
|
39943
|
-
const data = await
|
|
39866
|
+
const data = await ghJson(["pr", "view", String(n), "--repo", repo, "--json", effective]);
|
|
39944
39867
|
console.log(JSON.stringify(data));
|
|
39945
39868
|
} catch (e) {
|
|
39946
39869
|
const err = e;
|
|
@@ -40205,7 +40128,7 @@ ${list}`);
|
|
|
40205
40128
|
await readClosingGuardInput(number, repoArgs, landRepoForGuard, "pr land"),
|
|
40206
40129
|
async (n) => {
|
|
40207
40130
|
if (!landRepoForGuard) return void 0;
|
|
40208
|
-
const viewed = await
|
|
40131
|
+
const viewed = await ghJson(["issue", "view", String(n), "--repo", landRepoForGuard, "--json", "state"]);
|
|
40209
40132
|
return typeof viewed.state === "string" ? viewed.state : void 0;
|
|
40210
40133
|
}
|
|
40211
40134
|
);
|
|
@@ -40223,14 +40146,6 @@ ${list}`);
|
|
|
40223
40146
|
}
|
|
40224
40147
|
if (landClosingGuardVerdict.message) console.warn(landClosingGuardVerdict.message);
|
|
40225
40148
|
const result = await runPrLand(number, { repo: o.repo, requireTrain: o.requireTrain !== false }, {
|
|
40226
|
-
queueMerge: async (prNumber, repo) => {
|
|
40227
|
-
const meta = await ghJson2(["pr", "view", prNumber, "--repo", repo, "--json", "baseRefName,headRefOid"]);
|
|
40228
|
-
if (!await usesMergifyPilot(repo, meta.baseRefName)) return void 0;
|
|
40229
|
-
if (!landClosingGuardInput) throw new Error("pr land: Mergify requires a readable closing-keyword guard");
|
|
40230
|
-
const guard = evaluateClosingGuard(landClosingGuardInput, { force: o.force, context: "pr land", squashBodyText: landClosingGuardInput.text });
|
|
40231
|
-
if (guard.blocked) throw new Error(guard.message);
|
|
40232
|
-
return requestMergifyMerge(prNumber, repo, landClosingGuardInput.text, meta.headRefOid);
|
|
40233
|
-
},
|
|
40234
40149
|
resolveRepo: async (prNumber, repoOpt) => {
|
|
40235
40150
|
const args = repoOpt ? ["--repo", repoOpt] : repoArgs;
|
|
40236
40151
|
const viewed = (await execFileP("gh", ["pr", "view", prNumber, ...args, "--json", "headRepository,baseRefName", "--jq", '.headRepository.nameWithOwner + " " + .baseRefName'], { timeout: GC_GH_TIMEOUT_MS4 })).stdout.trim();
|
|
@@ -40388,23 +40303,20 @@ ${list}`);
|
|
|
40388
40303
|
const baseRef = prMeta.base;
|
|
40389
40304
|
const headRefOid = (prMeta.oid ?? "").trim() || void 0;
|
|
40390
40305
|
if (!repoForPostCleanup) throw new Error("pr merge: cannot resolve target repository");
|
|
40391
|
-
const mergifyPilot = await usesMergifyPilot(repoForPostCleanup, baseRef);
|
|
40392
|
-
if (mergifyPilot && (method !== "--squash" || o.squashBodyFile)) throw new Error("pr merge: Mergify pilot uses the protected squash title/body policy; custom merge methods and body files are unsupported");
|
|
40393
40306
|
const devDeployDeps = repoForPostCleanup ? registryClientDeps(await loadConfig()) : void 0;
|
|
40394
40307
|
const devDeployPlan = repoForPostCleanup && devDeployDeps ? await planDevDeployOnDevelopmentMerge(repoForPostCleanup, baseRef, devDeployDeps).catch(() => ({ applicable: false, reason: "unreadable" })) : { applicable: false, reason: "unreadable" };
|
|
40395
40308
|
const closingGuardInput = await withAlreadyClosedCommitTargets(
|
|
40396
40309
|
await readClosingGuardInput(number, repoArgs, repoForPostCleanup, "pr merge"),
|
|
40397
40310
|
async (n) => {
|
|
40398
40311
|
if (!repoForPostCleanup) return void 0;
|
|
40399
|
-
const viewed = await
|
|
40312
|
+
const viewed = await ghJson(["issue", "view", String(n), "--repo", repoForPostCleanup, "--json", "state"]);
|
|
40400
40313
|
return typeof viewed.state === "string" ? viewed.state : void 0;
|
|
40401
40314
|
}
|
|
40402
40315
|
);
|
|
40403
40316
|
if (o.squashBodyFile && method !== "--squash") {
|
|
40404
40317
|
throw new Error("pr merge: --squash-body-file applies only to squash merges");
|
|
40405
40318
|
}
|
|
40406
|
-
|
|
40407
|
-
const mergeSquashBody = mergifyPilot ? closingGuardInput.text : squashBodyTextForMerge(
|
|
40319
|
+
const mergeSquashBody = squashBodyTextForMerge(
|
|
40408
40320
|
closingGuardInput,
|
|
40409
40321
|
method === "--squash",
|
|
40410
40322
|
o.squashBodyFile ? (0, import_node_fs43.readFileSync)(o.squashBodyFile, "utf8") : void 0
|
|
@@ -40502,7 +40414,7 @@ ${list}`);
|
|
|
40502
40414
|
}
|
|
40503
40415
|
return true;
|
|
40504
40416
|
};
|
|
40505
|
-
if (
|
|
40417
|
+
if (o.wait && !await runWaitGate()) return;
|
|
40506
40418
|
if (ciPolicy.policy === "no-ci") {
|
|
40507
40419
|
const guard = decidePrMergeNoCiGuard(await pollGhPrChecks(number, repoArgs), ciPolicy.reason);
|
|
40508
40420
|
if (guard.action === "refuse") throw new Error(`gh pr merge ${number}: ${guard.message}`);
|
|
@@ -40511,7 +40423,7 @@ ${list}`);
|
|
|
40511
40423
|
const remoteBefore = await remoteBranchExists2(headRef, { remote });
|
|
40512
40424
|
let upgradedToAuto = false;
|
|
40513
40425
|
let remoteNotAttemptedReason = "preserved-delayed-cleanup";
|
|
40514
|
-
const overrideBody =
|
|
40426
|
+
const overrideBody = mergeSquashBody ? { ...writeSquashBodyFile(mergeSquashBody), text: mergeSquashBody } : await composeOverrideBodyFile(
|
|
40515
40427
|
number,
|
|
40516
40428
|
repoArgs,
|
|
40517
40429
|
async (a, t) => (await execFileP("gh", a, { timeout: t })).stdout,
|
|
@@ -40591,15 +40503,7 @@ ${list}`);
|
|
|
40591
40503
|
});
|
|
40592
40504
|
try {
|
|
40593
40505
|
try {
|
|
40594
|
-
|
|
40595
|
-
const queue = await requestMergifyMerge(number, repoForPostCleanup, closingGuardInput.text, headRefOid);
|
|
40596
|
-
if (queue.state !== "merged") {
|
|
40597
|
-
console.log(JSON.stringify({ mergeStatus: "failed", pr: number, repo: repoForPostCleanup, queue }));
|
|
40598
|
-
process.exitCode = queue.state === "refused" ? 1 : PR_CHECKS_TIMEOUT_EXIT_CODE;
|
|
40599
|
-
return;
|
|
40600
|
-
}
|
|
40601
|
-
remoteNotAttemptedReason = "pr-already-merged";
|
|
40602
|
-
} else await mergeOnce();
|
|
40506
|
+
await mergeOnce();
|
|
40603
40507
|
} catch (e) {
|
|
40604
40508
|
if (!(e instanceof PrHeadBehindBaseError)) throw e;
|
|
40605
40509
|
const localCheckedOut = !foreignCwd && await prHeadCheckedOutHere(headRef, targetRepo2, Boolean(o.repo));
|
|
@@ -41070,7 +40974,7 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
41070
40974
|
}
|
|
41071
40975
|
|
|
41072
40976
|
// src/dist-drift.ts
|
|
41073
|
-
var
|
|
40977
|
+
var import_node_child_process18 = require("node:child_process");
|
|
41074
40978
|
var import_node_crypto13 = require("node:crypto");
|
|
41075
40979
|
var import_node_fs46 = require("node:fs");
|
|
41076
40980
|
var import_node_os21 = require("node:os");
|
|
@@ -41215,7 +41119,7 @@ function bomPathFor(root) {
|
|
|
41215
41119
|
}
|
|
41216
41120
|
}
|
|
41217
41121
|
function rebuildTo(packageRoot, outDir) {
|
|
41218
|
-
(0,
|
|
41122
|
+
(0, import_node_child_process18.execFileSync)(process.execPath, ["build.mjs"], {
|
|
41219
41123
|
cwd: packageRoot,
|
|
41220
41124
|
env: { ...process.env, MMI_DIST_OUTDIR: outDir },
|
|
41221
41125
|
windowsHide: true,
|
|
@@ -41433,7 +41337,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
41433
41337
|
}
|
|
41434
41338
|
|
|
41435
41339
|
// src/spawn-policy-core.ts
|
|
41436
|
-
var
|
|
41340
|
+
var import_node_child_process19 = require("node:child_process");
|
|
41437
41341
|
var import_node_fs47 = require("node:fs");
|
|
41438
41342
|
var import_node_path44 = require("node:path");
|
|
41439
41343
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
@@ -41504,7 +41408,7 @@ function findViolationsInSource(raw) {
|
|
|
41504
41408
|
return found;
|
|
41505
41409
|
}
|
|
41506
41410
|
function policedFiles(root) {
|
|
41507
|
-
const r = (0,
|
|
41411
|
+
const r = (0, import_node_child_process19.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
41508
41412
|
cwd: root,
|
|
41509
41413
|
encoding: "utf8",
|
|
41510
41414
|
windowsHide: true,
|
|
@@ -43041,12 +42945,12 @@ async function findInFlightHotfixVersion(deps, ctx, latestMainTag, workflows = H
|
|
|
43041
42945
|
}
|
|
43042
42946
|
|
|
43043
42947
|
// src/hotfix-coverage.ts
|
|
43044
|
-
var
|
|
42948
|
+
var import_node_child_process20 = require("node:child_process");
|
|
43045
42949
|
var CHERRY_TRAILER = /\(cherry picked from commit ([0-9a-f]{7,40})\)/g;
|
|
43046
42950
|
function checkHotfixCoverage(options = {}) {
|
|
43047
42951
|
const { cwd = process.cwd(), mainRef = "origin/main", rcRef = "origin/rc", manifestPaths = [] } = options;
|
|
43048
42952
|
const ack = (options.ack ?? []).filter(Boolean);
|
|
43049
|
-
const git3 = options.git ?? ((args, opts) => (0,
|
|
42953
|
+
const git3 = options.git ?? ((args, opts) => (0, import_node_child_process20.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
|
|
43050
42954
|
const revList = (range) => {
|
|
43051
42955
|
const out = git3(["rev-list", "--no-merges", range]).trim();
|
|
43052
42956
|
return out ? out.split("\n") : [];
|
|
@@ -43114,7 +43018,7 @@ function checkHotfixCoverage(options = {}) {
|
|
|
43114
43018
|
}
|
|
43115
43019
|
function checkHotfixCarries(options) {
|
|
43116
43020
|
const { cwd = process.cwd(), branch, baseRef, targets } = options;
|
|
43117
|
-
const git3 = options.git ?? ((args, opts) => (0,
|
|
43021
|
+
const git3 = options.git ?? ((args, opts) => (0, import_node_child_process20.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
|
|
43118
43022
|
const isAncestor = (sha, ref) => {
|
|
43119
43023
|
try {
|
|
43120
43024
|
git3(["merge-base", "--is-ancestor", sha, ref]);
|
package/package.json
CHANGED