pullfrog 0.1.46 → 0.1.47
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/README.md +1 -1
- package/dist/cli.mjs +165 -42
- package/dist/external.d.ts +8 -0
- package/dist/index.js +151 -35
- package/dist/internal/index.d.ts +2 -0
- package/dist/internal.js +112 -0
- package/dist/toolState.d.ts +1 -0
- package/dist/utils/payload.d.ts +8 -1
- package/dist/utils/runContext.d.ts +1 -0
- package/dist/utils/runStatusCheck.d.ts +170 -0
- package/dist/utils/statusChecks.d.ts +14 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ jobs:
|
|
|
101
101
|
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
Every PR run posts a `Pullfrog` commit-status check: `in_progress` from the moment the run is dispatched, then success when it finishes or failure on error/timeout. It is on by default (turn it off per-repo in the console). To also gate merges on Pullfrog's review verdict, add `status_checks: enabled`, which additionally posts a `Pullfrog approval` check (whether Pullfrog would approve the PR). Both are requireable as branch-protection status checks. See [PR reviews → Status checks](https://docs.pullfrog.dev/pr-reviews#status-checks).
|
|
105
105
|
|
|
106
106
|
#### 2. Create `triggers.yml`
|
|
107
107
|
|
package/dist/cli.mjs
CHANGED
|
@@ -101356,6 +101356,10 @@ async function setPullfrogSecret(ctx) {
|
|
|
101356
101356
|
}
|
|
101357
101357
|
return { saved: false, error: result.data.error || `api returned ${result.status}` };
|
|
101358
101358
|
}
|
|
101359
|
+
function describeSecretTarget(ctx) {
|
|
101360
|
+
if (ctx.scope === "account") return `account ${import_picocolors.default.cyan(`@${ctx.owner}`)}`;
|
|
101361
|
+
return `repo ${import_picocolors.default.cyan(`${ctx.owner}/${ctx.repo}`)}`;
|
|
101362
|
+
}
|
|
101359
101363
|
async function promptScope(ctx) {
|
|
101360
101364
|
const scope2 = await _t({
|
|
101361
101365
|
message: "secret scope",
|
|
@@ -101579,7 +101583,8 @@ async function runCodexAuth() {
|
|
|
101579
101583
|
O2.warn(err instanceof Error ? err.message : String(err));
|
|
101580
101584
|
savable = auth2;
|
|
101581
101585
|
}
|
|
101582
|
-
|
|
101586
|
+
const target = describeSecretTarget({ owner: remote.owner, repo: remote.repo, scope: scope2 });
|
|
101587
|
+
spin.start(`saving ${import_picocolors2.default.cyan(CODEX_AUTH_SECRET)} to ${target}`);
|
|
101583
101588
|
const result = await setPullfrogSecret({
|
|
101584
101589
|
token,
|
|
101585
101590
|
owner: remote.owner,
|
|
@@ -101596,7 +101601,7 @@ async function runCodexAuth() {
|
|
|
101596
101601
|
);
|
|
101597
101602
|
process.exit(1);
|
|
101598
101603
|
}
|
|
101599
|
-
spin.stop(`saved ${import_picocolors2.default.cyan(CODEX_AUTH_SECRET)} to
|
|
101604
|
+
spin.stop(`saved ${import_picocolors2.default.cyan(CODEX_AUTH_SECRET)} to ${target}`);
|
|
101600
101605
|
setActiveSpin(null);
|
|
101601
101606
|
gt("done.");
|
|
101602
101607
|
} catch (error49) {
|
|
@@ -101693,7 +101698,8 @@ async function runClaudeAuth() {
|
|
|
101693
101698
|
`that doesn't look like a ${import_picocolors2.default.cyan("claude setup-token")} token (expected ${import_picocolors2.default.cyan(`${CLAUDE_OAUTH_TOKEN_PREFIX}\u2026`)}). saving it anyway.`
|
|
101694
101699
|
);
|
|
101695
101700
|
}
|
|
101696
|
-
|
|
101701
|
+
const target = describeSecretTarget({ owner: remote.owner, repo: remote.repo, scope: scope2 });
|
|
101702
|
+
spin.start(`saving ${import_picocolors2.default.cyan(CLAUDE_OAUTH_SECRET)} to ${target}`);
|
|
101697
101703
|
const result = await setPullfrogSecret({
|
|
101698
101704
|
token,
|
|
101699
101705
|
owner: remote.owner,
|
|
@@ -101710,7 +101716,7 @@ async function runClaudeAuth() {
|
|
|
101710
101716
|
);
|
|
101711
101717
|
process.exit(1);
|
|
101712
101718
|
}
|
|
101713
|
-
spin.stop(`saved ${import_picocolors2.default.cyan(CLAUDE_OAUTH_SECRET)} to
|
|
101719
|
+
spin.stop(`saved ${import_picocolors2.default.cyan(CLAUDE_OAUTH_SECRET)} to ${target}`);
|
|
101714
101720
|
setActiveSpin(null);
|
|
101715
101721
|
gt("done.");
|
|
101716
101722
|
} catch (error49) {
|
|
@@ -103050,7 +103056,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
103050
103056
|
// package.json
|
|
103051
103057
|
var package_default = {
|
|
103052
103058
|
name: "pullfrog",
|
|
103053
|
-
version: "0.1.
|
|
103059
|
+
version: "0.1.47",
|
|
103054
103060
|
type: "module",
|
|
103055
103061
|
bin: {
|
|
103056
103062
|
pullfrog: "dist/cli.mjs",
|
|
@@ -159967,6 +159973,9 @@ var JsonPayload = type({
|
|
|
159967
159973
|
id: "string",
|
|
159968
159974
|
type: "'issue' | 'review'"
|
|
159969
159975
|
}).or("undefined"),
|
|
159976
|
+
// optional so a payload from an older server build (pre-`checkRun`) still parses
|
|
159977
|
+
// against a newer action across a rolling deploy.
|
|
159978
|
+
"checkRun?": type({ id: "string" }).or("undefined"),
|
|
159970
159979
|
"generateSummary?": "boolean | undefined"
|
|
159971
159980
|
});
|
|
159972
159981
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
@@ -160080,13 +160089,19 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
160080
160089
|
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
160081
160090
|
cwd: resolveCwd(inputs.cwd),
|
|
160082
160091
|
progressComment: jsonPayload?.progressComment,
|
|
160092
|
+
checkRun: jsonPayload?.checkRun,
|
|
160083
160093
|
generateSummary: jsonPayload?.generateSummary,
|
|
160084
160094
|
// permissions: inputs > repoSettings > fallbacks
|
|
160085
160095
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
160086
160096
|
shell: resolvedShell,
|
|
160087
|
-
//
|
|
160088
|
-
//
|
|
160089
|
-
|
|
160097
|
+
// the `pullfrog` run-lifecycle check. ON by default — the whole point is that a PR
|
|
160098
|
+
// shows whether Pullfrog is running without anyone having to opt in. the workflow
|
|
160099
|
+
// input is the source of truth when set (mirrors `push`); otherwise the repo
|
|
160100
|
+
// setting decides.
|
|
160101
|
+
runStatusCheck: inputs.status_checks === void 0 ? repoSettings.statusChecks : inputs.status_checks === "enabled",
|
|
160102
|
+
// the `pullfrog-approval` verdict check stays opt-in and workflow-only. it exists to
|
|
160103
|
+
// be *required* by branch protection, so it must never turn itself on.
|
|
160104
|
+
approvalCheck: inputs.status_checks === "enabled",
|
|
160090
160105
|
// temporary progress chrome. the workflow input is the source of truth when
|
|
160091
160106
|
// set (mirrors `push`); otherwise the repo setting decides. defaults to true.
|
|
160092
160107
|
progressComments: inputs.progress_comments === void 0 ? repoSettings.progressComments : inputs.progress_comments === "enabled",
|
|
@@ -160614,7 +160629,11 @@ async function approveAfterFix(ctx) {
|
|
|
160614
160629
|
approved: true,
|
|
160615
160630
|
hasComments: false
|
|
160616
160631
|
});
|
|
160617
|
-
ctx.toolState.approval = {
|
|
160632
|
+
ctx.toolState.approval = {
|
|
160633
|
+
wouldApprove: true,
|
|
160634
|
+
sha: headSha,
|
|
160635
|
+
url: result.data.html_url
|
|
160636
|
+
};
|
|
160618
160637
|
log.info(`\xBB auto-approved #${pullNumber} after fix run (review ${result.data.id})`);
|
|
160619
160638
|
await deleteProgressComment(ctx).catch((err) => {
|
|
160620
160639
|
log.debug(`progress comment cleanup after fix auto-approval failed: ${err}`);
|
|
@@ -160947,6 +160966,7 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
160947
160966
|
}
|
|
160948
160967
|
const reviewId = result.data.id;
|
|
160949
160968
|
const reviewNodeId = result.data.node_id;
|
|
160969
|
+
if (ctx.toolState.approval) ctx.toolState.approval.url = result.data.html_url;
|
|
160950
160970
|
log.info(`\xBB created review ${reviewId} on pull request #${pull_number}`);
|
|
160951
160971
|
const actuallyReviewedSha = primary.checkoutSha ?? params.commit_id;
|
|
160952
160972
|
ctx.toolState.review = {
|
|
@@ -166963,6 +166983,7 @@ var defaultSettings = {
|
|
|
166963
166983
|
autoMergeEnabled: false,
|
|
166964
166984
|
signedCommits: false,
|
|
166965
166985
|
progressComments: true,
|
|
166986
|
+
statusChecks: true,
|
|
166966
166987
|
modeInstructions: {},
|
|
166967
166988
|
learnings: null,
|
|
166968
166989
|
learningsHeadings: [],
|
|
@@ -167484,30 +167505,123 @@ function getCurrentWorkflowFilename() {
|
|
|
167484
167505
|
return match3?.[1] ?? "pullfrog.yml";
|
|
167485
167506
|
}
|
|
167486
167507
|
|
|
167487
|
-
// utils/
|
|
167488
|
-
var
|
|
167489
|
-
var
|
|
167490
|
-
|
|
167508
|
+
// utils/runStatusCheck.ts
|
|
167509
|
+
var RUN_STATUS_CHECK_NAME = "Pullfrog";
|
|
167510
|
+
var APPROVAL_CHECK_NAME = "Pullfrog approval";
|
|
167511
|
+
function parseCheckRunId(raw2) {
|
|
167512
|
+
if (!raw2?.id) return void 0;
|
|
167513
|
+
const id = parseInt(raw2.id, 10);
|
|
167514
|
+
if (Number.isNaN(id) || id <= 0) return void 0;
|
|
167515
|
+
return id;
|
|
167516
|
+
}
|
|
167517
|
+
function disableCheckLine(owner, repo) {
|
|
167518
|
+
const url4 = `https://pullfrog.com/console/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}#auto-review-prs`;
|
|
167519
|
+
return `
|
|
167520
|
+
|
|
167521
|
+
[Turn off this check \u2192](${url4}) \u2014 it reports run status only and gates nothing unless you required it in branch protection.`;
|
|
167522
|
+
}
|
|
167523
|
+
var TERMINAL_OUTPUT = {
|
|
167524
|
+
success: {
|
|
167525
|
+
title: "Pullfrog run completed",
|
|
167526
|
+
summary: "The Pullfrog run finished successfully."
|
|
167527
|
+
},
|
|
167528
|
+
failure: {
|
|
167529
|
+
title: "Pullfrog run failed",
|
|
167530
|
+
summary: "The Pullfrog run failed. See the run logs for details."
|
|
167531
|
+
},
|
|
167532
|
+
cancelled: {
|
|
167533
|
+
title: "Pullfrog run cancelled",
|
|
167534
|
+
summary: "The Pullfrog run was cancelled before it finished."
|
|
167535
|
+
},
|
|
167536
|
+
timed_out: {
|
|
167537
|
+
title: "Pullfrog run timed out",
|
|
167538
|
+
summary: "The Pullfrog run exceeded its timeout. See the run logs for details."
|
|
167539
|
+
},
|
|
167540
|
+
action_required: {
|
|
167541
|
+
title: "Pullfrog run needs attention",
|
|
167542
|
+
summary: "The Pullfrog run stopped and needs attention. See the run logs for details."
|
|
167543
|
+
},
|
|
167544
|
+
neutral: {
|
|
167545
|
+
title: "Pullfrog run finished",
|
|
167546
|
+
summary: "The Pullfrog run finished without a pass or fail outcome."
|
|
167547
|
+
},
|
|
167548
|
+
skipped: {
|
|
167549
|
+
title: "Pullfrog run skipped",
|
|
167550
|
+
summary: "This run was superseded by another Pullfrog run."
|
|
167551
|
+
},
|
|
167552
|
+
stale: {
|
|
167553
|
+
title: "Pullfrog run didn't finish",
|
|
167554
|
+
summary: "Pullfrog never received a completion signal for this run. See the run logs for details."
|
|
167555
|
+
}
|
|
167556
|
+
};
|
|
167557
|
+
function terminalOutput(params) {
|
|
167558
|
+
const base = TERMINAL_OUTPUT[params.conclusion];
|
|
167559
|
+
const review = params.reviewUrl ? `
|
|
167560
|
+
|
|
167561
|
+
[View the review Pullfrog posted \u2192](${params.reviewUrl})` : "";
|
|
167562
|
+
const disable = params.conclusion === "success" ? "" : disableCheckLine(params.owner, params.repo);
|
|
167563
|
+
return { title: base.title, summary: base.summary + review + disable };
|
|
167564
|
+
}
|
|
167565
|
+
async function finalizeRunStatusCheck(params) {
|
|
167566
|
+
const updateParams = {
|
|
167567
|
+
owner: params.owner,
|
|
167568
|
+
repo: params.repo,
|
|
167569
|
+
check_run_id: params.checkRunId,
|
|
167570
|
+
status: "completed",
|
|
167571
|
+
conclusion: params.conclusion,
|
|
167572
|
+
output: terminalOutput({
|
|
167573
|
+
conclusion: params.conclusion,
|
|
167574
|
+
owner: params.owner,
|
|
167575
|
+
repo: params.repo,
|
|
167576
|
+
reviewUrl: params.reviewUrl
|
|
167577
|
+
})
|
|
167578
|
+
};
|
|
167579
|
+
if (params.detailsUrl) updateParams.details_url = params.detailsUrl;
|
|
167580
|
+
await params.octokit.rest.checks.update(updateParams);
|
|
167581
|
+
}
|
|
167582
|
+
async function createTerminalRunStatusCheck(params) {
|
|
167491
167583
|
const createParams = {
|
|
167492
|
-
owner:
|
|
167493
|
-
repo:
|
|
167494
|
-
name:
|
|
167584
|
+
owner: params.owner,
|
|
167585
|
+
repo: params.repo,
|
|
167586
|
+
name: RUN_STATUS_CHECK_NAME,
|
|
167495
167587
|
head_sha: params.headSha,
|
|
167496
167588
|
status: "completed",
|
|
167497
167589
|
conclusion: params.conclusion,
|
|
167498
|
-
output: {
|
|
167590
|
+
output: terminalOutput({
|
|
167591
|
+
conclusion: params.conclusion,
|
|
167592
|
+
owner: params.owner,
|
|
167593
|
+
repo: params.repo,
|
|
167594
|
+
reviewUrl: params.reviewUrl
|
|
167595
|
+
})
|
|
167499
167596
|
};
|
|
167500
|
-
if (
|
|
167501
|
-
|
|
167502
|
-
}
|
|
167503
|
-
await ctx.octokit.rest.checks.create(createParams);
|
|
167504
|
-
log.info(`\xBB posted ${params.name} check (${params.conclusion}) on ${params.headSha.slice(0, 7)}`);
|
|
167597
|
+
if (params.detailsUrl) createParams.details_url = params.detailsUrl;
|
|
167598
|
+
await params.octokit.rest.checks.create(createParams);
|
|
167505
167599
|
}
|
|
167600
|
+
|
|
167601
|
+
// utils/statusChecks.ts
|
|
167506
167602
|
async function reportStatusChecks(ctx, params) {
|
|
167507
|
-
if (!ctx.payload.statusChecks) return;
|
|
167508
167603
|
const event = ctx.payload.event;
|
|
167509
167604
|
const pullNumber = event.issue_number;
|
|
167510
167605
|
if (event.is_pr !== true || typeof pullNumber !== "number") return;
|
|
167606
|
+
const checkRunId = parseCheckRunId(ctx.payload.checkRun);
|
|
167607
|
+
if (checkRunId === void 0 && !ctx.payload.runStatusCheck && !ctx.payload.approvalCheck) return;
|
|
167608
|
+
const conclusion = params.runSucceeded ? "success" : "failure";
|
|
167609
|
+
const detailsUrl = ctx.runId ? `https://github.com/${ctx.repo.owner}/${ctx.repo.name}/actions/runs/${ctx.runId}` : void 0;
|
|
167610
|
+
if (checkRunId !== void 0) {
|
|
167611
|
+
await finalizeRunStatusCheck({
|
|
167612
|
+
octokit: ctx.octokit,
|
|
167613
|
+
owner: ctx.repo.owner,
|
|
167614
|
+
repo: ctx.repo.name,
|
|
167615
|
+
checkRunId,
|
|
167616
|
+
conclusion,
|
|
167617
|
+
detailsUrl,
|
|
167618
|
+
reviewUrl: ctx.toolState.approval?.url
|
|
167619
|
+
}).then(() => log.info(`\xBB finalized ${RUN_STATUS_CHECK_NAME} check (${conclusion})`)).catch((err) => log.debug(`status checks: ${RUN_STATUS_CHECK_NAME} finalize failed: ${err}`));
|
|
167620
|
+
}
|
|
167621
|
+
const approval = ctx.toolState.approval;
|
|
167622
|
+
const needsApprovalCheck = ctx.payload.approvalCheck && params.runSucceeded && approval;
|
|
167623
|
+
const needsFallbackRunCheck = ctx.payload.runStatusCheck && checkRunId === void 0;
|
|
167624
|
+
if (!needsApprovalCheck && !needsFallbackRunCheck) return;
|
|
167511
167625
|
let headSha;
|
|
167512
167626
|
try {
|
|
167513
167627
|
const pr = await ctx.octokit.rest.pulls.get({
|
|
@@ -167520,24 +167634,32 @@ async function reportStatusChecks(ctx, params) {
|
|
|
167520
167634
|
log.debug(`status checks: failed to resolve PR #${pullNumber} head sha: ${err}`);
|
|
167521
167635
|
return;
|
|
167522
167636
|
}
|
|
167523
|
-
|
|
167524
|
-
|
|
167525
|
-
|
|
167526
|
-
|
|
167527
|
-
|
|
167528
|
-
|
|
167529
|
-
|
|
167530
|
-
|
|
167531
|
-
|
|
167532
|
-
|
|
167533
|
-
|
|
167534
|
-
|
|
167535
|
-
|
|
167536
|
-
|
|
167637
|
+
if (needsFallbackRunCheck) {
|
|
167638
|
+
await createTerminalRunStatusCheck({
|
|
167639
|
+
octokit: ctx.octokit,
|
|
167640
|
+
owner: ctx.repo.owner,
|
|
167641
|
+
repo: ctx.repo.name,
|
|
167642
|
+
headSha: primaryRepoState(ctx.toolState).checkoutSha ?? headSha,
|
|
167643
|
+
conclusion,
|
|
167644
|
+
detailsUrl,
|
|
167645
|
+
reviewUrl: ctx.toolState.approval?.url
|
|
167646
|
+
}).then(() => log.info(`\xBB posted ${RUN_STATUS_CHECK_NAME} check (${conclusion})`)).catch((err) => log.debug(`status checks: ${RUN_STATUS_CHECK_NAME} post failed: ${err}`));
|
|
167647
|
+
}
|
|
167648
|
+
if (!needsApprovalCheck || !approval) return;
|
|
167649
|
+
const createParams = {
|
|
167650
|
+
owner: ctx.repo.owner,
|
|
167651
|
+
repo: ctx.repo.name,
|
|
167652
|
+
name: APPROVAL_CHECK_NAME,
|
|
167653
|
+
head_sha: approval.sha ?? headSha,
|
|
167654
|
+
status: "completed",
|
|
167655
|
+
conclusion: approval.wouldApprove ? "success" : "failure",
|
|
167656
|
+
output: {
|
|
167537
167657
|
title: approval.wouldApprove ? "Pullfrog would approve" : "Pullfrog would not approve",
|
|
167538
167658
|
summary: approval.wouldApprove ? "Pullfrog has no outstanding review feedback on this PR." : "Pullfrog has outstanding review feedback or requested changes on this PR."
|
|
167539
|
-
}
|
|
167540
|
-
}
|
|
167659
|
+
}
|
|
167660
|
+
};
|
|
167661
|
+
if (detailsUrl) createParams.details_url = detailsUrl;
|
|
167662
|
+
await ctx.octokit.rest.checks.create(createParams).then(() => log.info(`\xBB posted ${APPROVAL_CHECK_NAME} check`)).catch((err) => log.debug(`status checks: ${APPROVAL_CHECK_NAME} post failed: ${err}`));
|
|
167541
167663
|
}
|
|
167542
167664
|
|
|
167543
167665
|
// utils/runLifecycle.ts
|
|
@@ -168938,7 +169060,8 @@ async function handleSecret(ctx) {
|
|
|
168938
169060
|
}
|
|
168939
169061
|
if (method === "pullfrog") {
|
|
168940
169062
|
const scope2 = ctx.secrets.isOrg ? await promptScope2(ctx) : "account";
|
|
168941
|
-
|
|
169063
|
+
const target = describeSecretTarget({ owner: ctx.owner, repo: ctx.repo, scope: scope2 });
|
|
169064
|
+
activeSpin2.start(`saving ${import_picocolors3.default.cyan(envVar)} to ${target}`);
|
|
168942
169065
|
let saveResult;
|
|
168943
169066
|
try {
|
|
168944
169067
|
saveResult = await setPullfrogSecret2({
|
|
@@ -168958,7 +169081,7 @@ async function handleSecret(ctx) {
|
|
|
168958
169081
|
return;
|
|
168959
169082
|
}
|
|
168960
169083
|
if (saveResult.saved) {
|
|
168961
|
-
activeSpin2.stop(`saved ${import_picocolors3.default.cyan(envVar)} to
|
|
169084
|
+
activeSpin2.stop(`saved ${import_picocolors3.default.cyan(envVar)} to ${target}`);
|
|
168962
169085
|
} else {
|
|
168963
169086
|
activeSpin2.stop(import_picocolors3.default.red("could not save secret"));
|
|
168964
169087
|
O2.warn(
|
|
@@ -169308,7 +169431,7 @@ async function runCli4(input) {
|
|
|
169308
169431
|
}
|
|
169309
169432
|
|
|
169310
169433
|
// cli.ts
|
|
169311
|
-
var VERSION10 = "0.1.
|
|
169434
|
+
var VERSION10 = "0.1.47";
|
|
169312
169435
|
var bin = basename2(process.argv[1] || "");
|
|
169313
169436
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
169314
169437
|
var rawArgs = process.argv.slice(2);
|
package/dist/external.d.ts
CHANGED
|
@@ -262,6 +262,14 @@ export interface WriteablePayload {
|
|
|
262
262
|
id: string;
|
|
263
263
|
type: "issue" | "review";
|
|
264
264
|
} | undefined;
|
|
265
|
+
/**
|
|
266
|
+
* pre-created `pullfrog` check-run, seeded `in_progress` by the server at dispatch so
|
|
267
|
+
* the PR's checks list shows the run before the GHA runner boots. the action PATCHes
|
|
268
|
+
* it to a terminal conclusion at run end. see `action/utils/runStatusCheck.ts`.
|
|
269
|
+
*/
|
|
270
|
+
checkRun?: {
|
|
271
|
+
id: string;
|
|
272
|
+
} | undefined;
|
|
265
273
|
/** when true, seed the PR summary tmpfile + persist edits at run end */
|
|
266
274
|
generateSummary?: boolean | undefined;
|
|
267
275
|
}
|
package/dist/index.js
CHANGED
|
@@ -101121,7 +101121,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
101121
101121
|
// package.json
|
|
101122
101122
|
var package_default = {
|
|
101123
101123
|
name: "pullfrog",
|
|
101124
|
-
version: "0.1.
|
|
101124
|
+
version: "0.1.47",
|
|
101125
101125
|
type: "module",
|
|
101126
101126
|
bin: {
|
|
101127
101127
|
pullfrog: "dist/cli.mjs",
|
|
@@ -158080,6 +158080,9 @@ var JsonPayload = type({
|
|
|
158080
158080
|
id: "string",
|
|
158081
158081
|
type: "'issue' | 'review'"
|
|
158082
158082
|
}).or("undefined"),
|
|
158083
|
+
// optional so a payload from an older server build (pre-`checkRun`) still parses
|
|
158084
|
+
// against a newer action across a rolling deploy.
|
|
158085
|
+
"checkRun?": type({ id: "string" }).or("undefined"),
|
|
158083
158086
|
"generateSummary?": "boolean | undefined"
|
|
158084
158087
|
});
|
|
158085
158088
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
@@ -158193,13 +158196,19 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
158193
158196
|
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
158194
158197
|
cwd: resolveCwd(inputs.cwd),
|
|
158195
158198
|
progressComment: jsonPayload?.progressComment,
|
|
158199
|
+
checkRun: jsonPayload?.checkRun,
|
|
158196
158200
|
generateSummary: jsonPayload?.generateSummary,
|
|
158197
158201
|
// permissions: inputs > repoSettings > fallbacks
|
|
158198
158202
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
158199
158203
|
shell: resolvedShell,
|
|
158200
|
-
//
|
|
158201
|
-
//
|
|
158202
|
-
|
|
158204
|
+
// the `pullfrog` run-lifecycle check. ON by default — the whole point is that a PR
|
|
158205
|
+
// shows whether Pullfrog is running without anyone having to opt in. the workflow
|
|
158206
|
+
// input is the source of truth when set (mirrors `push`); otherwise the repo
|
|
158207
|
+
// setting decides.
|
|
158208
|
+
runStatusCheck: inputs.status_checks === void 0 ? repoSettings.statusChecks : inputs.status_checks === "enabled",
|
|
158209
|
+
// the `pullfrog-approval` verdict check stays opt-in and workflow-only. it exists to
|
|
158210
|
+
// be *required* by branch protection, so it must never turn itself on.
|
|
158211
|
+
approvalCheck: inputs.status_checks === "enabled",
|
|
158203
158212
|
// temporary progress chrome. the workflow input is the source of truth when
|
|
158204
158213
|
// set (mirrors `push`); otherwise the repo setting decides. defaults to true.
|
|
158205
158214
|
progressComments: inputs.progress_comments === void 0 ? repoSettings.progressComments : inputs.progress_comments === "enabled",
|
|
@@ -158727,7 +158736,11 @@ async function approveAfterFix(ctx) {
|
|
|
158727
158736
|
approved: true,
|
|
158728
158737
|
hasComments: false
|
|
158729
158738
|
});
|
|
158730
|
-
ctx.toolState.approval = {
|
|
158739
|
+
ctx.toolState.approval = {
|
|
158740
|
+
wouldApprove: true,
|
|
158741
|
+
sha: headSha,
|
|
158742
|
+
url: result.data.html_url
|
|
158743
|
+
};
|
|
158731
158744
|
log.info(`\xBB auto-approved #${pullNumber} after fix run (review ${result.data.id})`);
|
|
158732
158745
|
await deleteProgressComment(ctx).catch((err) => {
|
|
158733
158746
|
log.debug(`progress comment cleanup after fix auto-approval failed: ${err}`);
|
|
@@ -159060,6 +159073,7 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
159060
159073
|
}
|
|
159061
159074
|
const reviewId = result.data.id;
|
|
159062
159075
|
const reviewNodeId = result.data.node_id;
|
|
159076
|
+
if (ctx.toolState.approval) ctx.toolState.approval.url = result.data.html_url;
|
|
159063
159077
|
log.info(`\xBB created review ${reviewId} on pull request #${pull_number}`);
|
|
159064
159078
|
const actuallyReviewedSha = primary.checkoutSha ?? params.commit_id;
|
|
159065
159079
|
ctx.toolState.review = {
|
|
@@ -165076,6 +165090,7 @@ var defaultSettings = {
|
|
|
165076
165090
|
autoMergeEnabled: false,
|
|
165077
165091
|
signedCommits: false,
|
|
165078
165092
|
progressComments: true,
|
|
165093
|
+
statusChecks: true,
|
|
165079
165094
|
modeInstructions: {},
|
|
165080
165095
|
learnings: null,
|
|
165081
165096
|
learningsHeadings: [],
|
|
@@ -165597,30 +165612,123 @@ function getCurrentWorkflowFilename() {
|
|
|
165597
165612
|
return match3?.[1] ?? "pullfrog.yml";
|
|
165598
165613
|
}
|
|
165599
165614
|
|
|
165600
|
-
// utils/
|
|
165601
|
-
var
|
|
165602
|
-
var
|
|
165603
|
-
|
|
165615
|
+
// utils/runStatusCheck.ts
|
|
165616
|
+
var RUN_STATUS_CHECK_NAME = "Pullfrog";
|
|
165617
|
+
var APPROVAL_CHECK_NAME = "Pullfrog approval";
|
|
165618
|
+
function parseCheckRunId(raw2) {
|
|
165619
|
+
if (!raw2?.id) return void 0;
|
|
165620
|
+
const id = parseInt(raw2.id, 10);
|
|
165621
|
+
if (Number.isNaN(id) || id <= 0) return void 0;
|
|
165622
|
+
return id;
|
|
165623
|
+
}
|
|
165624
|
+
function disableCheckLine(owner, repo) {
|
|
165625
|
+
const url4 = `https://pullfrog.com/console/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}#auto-review-prs`;
|
|
165626
|
+
return `
|
|
165627
|
+
|
|
165628
|
+
[Turn off this check \u2192](${url4}) \u2014 it reports run status only and gates nothing unless you required it in branch protection.`;
|
|
165629
|
+
}
|
|
165630
|
+
var TERMINAL_OUTPUT = {
|
|
165631
|
+
success: {
|
|
165632
|
+
title: "Pullfrog run completed",
|
|
165633
|
+
summary: "The Pullfrog run finished successfully."
|
|
165634
|
+
},
|
|
165635
|
+
failure: {
|
|
165636
|
+
title: "Pullfrog run failed",
|
|
165637
|
+
summary: "The Pullfrog run failed. See the run logs for details."
|
|
165638
|
+
},
|
|
165639
|
+
cancelled: {
|
|
165640
|
+
title: "Pullfrog run cancelled",
|
|
165641
|
+
summary: "The Pullfrog run was cancelled before it finished."
|
|
165642
|
+
},
|
|
165643
|
+
timed_out: {
|
|
165644
|
+
title: "Pullfrog run timed out",
|
|
165645
|
+
summary: "The Pullfrog run exceeded its timeout. See the run logs for details."
|
|
165646
|
+
},
|
|
165647
|
+
action_required: {
|
|
165648
|
+
title: "Pullfrog run needs attention",
|
|
165649
|
+
summary: "The Pullfrog run stopped and needs attention. See the run logs for details."
|
|
165650
|
+
},
|
|
165651
|
+
neutral: {
|
|
165652
|
+
title: "Pullfrog run finished",
|
|
165653
|
+
summary: "The Pullfrog run finished without a pass or fail outcome."
|
|
165654
|
+
},
|
|
165655
|
+
skipped: {
|
|
165656
|
+
title: "Pullfrog run skipped",
|
|
165657
|
+
summary: "This run was superseded by another Pullfrog run."
|
|
165658
|
+
},
|
|
165659
|
+
stale: {
|
|
165660
|
+
title: "Pullfrog run didn't finish",
|
|
165661
|
+
summary: "Pullfrog never received a completion signal for this run. See the run logs for details."
|
|
165662
|
+
}
|
|
165663
|
+
};
|
|
165664
|
+
function terminalOutput(params) {
|
|
165665
|
+
const base = TERMINAL_OUTPUT[params.conclusion];
|
|
165666
|
+
const review = params.reviewUrl ? `
|
|
165667
|
+
|
|
165668
|
+
[View the review Pullfrog posted \u2192](${params.reviewUrl})` : "";
|
|
165669
|
+
const disable = params.conclusion === "success" ? "" : disableCheckLine(params.owner, params.repo);
|
|
165670
|
+
return { title: base.title, summary: base.summary + review + disable };
|
|
165671
|
+
}
|
|
165672
|
+
async function finalizeRunStatusCheck(params) {
|
|
165673
|
+
const updateParams = {
|
|
165674
|
+
owner: params.owner,
|
|
165675
|
+
repo: params.repo,
|
|
165676
|
+
check_run_id: params.checkRunId,
|
|
165677
|
+
status: "completed",
|
|
165678
|
+
conclusion: params.conclusion,
|
|
165679
|
+
output: terminalOutput({
|
|
165680
|
+
conclusion: params.conclusion,
|
|
165681
|
+
owner: params.owner,
|
|
165682
|
+
repo: params.repo,
|
|
165683
|
+
reviewUrl: params.reviewUrl
|
|
165684
|
+
})
|
|
165685
|
+
};
|
|
165686
|
+
if (params.detailsUrl) updateParams.details_url = params.detailsUrl;
|
|
165687
|
+
await params.octokit.rest.checks.update(updateParams);
|
|
165688
|
+
}
|
|
165689
|
+
async function createTerminalRunStatusCheck(params) {
|
|
165604
165690
|
const createParams = {
|
|
165605
|
-
owner:
|
|
165606
|
-
repo:
|
|
165607
|
-
name:
|
|
165691
|
+
owner: params.owner,
|
|
165692
|
+
repo: params.repo,
|
|
165693
|
+
name: RUN_STATUS_CHECK_NAME,
|
|
165608
165694
|
head_sha: params.headSha,
|
|
165609
165695
|
status: "completed",
|
|
165610
165696
|
conclusion: params.conclusion,
|
|
165611
|
-
output: {
|
|
165697
|
+
output: terminalOutput({
|
|
165698
|
+
conclusion: params.conclusion,
|
|
165699
|
+
owner: params.owner,
|
|
165700
|
+
repo: params.repo,
|
|
165701
|
+
reviewUrl: params.reviewUrl
|
|
165702
|
+
})
|
|
165612
165703
|
};
|
|
165613
|
-
if (
|
|
165614
|
-
|
|
165615
|
-
}
|
|
165616
|
-
await ctx.octokit.rest.checks.create(createParams);
|
|
165617
|
-
log.info(`\xBB posted ${params.name} check (${params.conclusion}) on ${params.headSha.slice(0, 7)}`);
|
|
165704
|
+
if (params.detailsUrl) createParams.details_url = params.detailsUrl;
|
|
165705
|
+
await params.octokit.rest.checks.create(createParams);
|
|
165618
165706
|
}
|
|
165707
|
+
|
|
165708
|
+
// utils/statusChecks.ts
|
|
165619
165709
|
async function reportStatusChecks(ctx, params) {
|
|
165620
|
-
if (!ctx.payload.statusChecks) return;
|
|
165621
165710
|
const event = ctx.payload.event;
|
|
165622
165711
|
const pullNumber = event.issue_number;
|
|
165623
165712
|
if (event.is_pr !== true || typeof pullNumber !== "number") return;
|
|
165713
|
+
const checkRunId = parseCheckRunId(ctx.payload.checkRun);
|
|
165714
|
+
if (checkRunId === void 0 && !ctx.payload.runStatusCheck && !ctx.payload.approvalCheck) return;
|
|
165715
|
+
const conclusion = params.runSucceeded ? "success" : "failure";
|
|
165716
|
+
const detailsUrl = ctx.runId ? `https://github.com/${ctx.repo.owner}/${ctx.repo.name}/actions/runs/${ctx.runId}` : void 0;
|
|
165717
|
+
if (checkRunId !== void 0) {
|
|
165718
|
+
await finalizeRunStatusCheck({
|
|
165719
|
+
octokit: ctx.octokit,
|
|
165720
|
+
owner: ctx.repo.owner,
|
|
165721
|
+
repo: ctx.repo.name,
|
|
165722
|
+
checkRunId,
|
|
165723
|
+
conclusion,
|
|
165724
|
+
detailsUrl,
|
|
165725
|
+
reviewUrl: ctx.toolState.approval?.url
|
|
165726
|
+
}).then(() => log.info(`\xBB finalized ${RUN_STATUS_CHECK_NAME} check (${conclusion})`)).catch((err) => log.debug(`status checks: ${RUN_STATUS_CHECK_NAME} finalize failed: ${err}`));
|
|
165727
|
+
}
|
|
165728
|
+
const approval = ctx.toolState.approval;
|
|
165729
|
+
const needsApprovalCheck = ctx.payload.approvalCheck && params.runSucceeded && approval;
|
|
165730
|
+
const needsFallbackRunCheck = ctx.payload.runStatusCheck && checkRunId === void 0;
|
|
165731
|
+
if (!needsApprovalCheck && !needsFallbackRunCheck) return;
|
|
165624
165732
|
let headSha;
|
|
165625
165733
|
try {
|
|
165626
165734
|
const pr = await ctx.octokit.rest.pulls.get({
|
|
@@ -165633,24 +165741,32 @@ async function reportStatusChecks(ctx, params) {
|
|
|
165633
165741
|
log.debug(`status checks: failed to resolve PR #${pullNumber} head sha: ${err}`);
|
|
165634
165742
|
return;
|
|
165635
165743
|
}
|
|
165636
|
-
|
|
165637
|
-
|
|
165638
|
-
|
|
165639
|
-
|
|
165640
|
-
|
|
165641
|
-
|
|
165642
|
-
|
|
165643
|
-
|
|
165644
|
-
|
|
165645
|
-
|
|
165646
|
-
|
|
165647
|
-
|
|
165648
|
-
|
|
165649
|
-
|
|
165744
|
+
if (needsFallbackRunCheck) {
|
|
165745
|
+
await createTerminalRunStatusCheck({
|
|
165746
|
+
octokit: ctx.octokit,
|
|
165747
|
+
owner: ctx.repo.owner,
|
|
165748
|
+
repo: ctx.repo.name,
|
|
165749
|
+
headSha: primaryRepoState(ctx.toolState).checkoutSha ?? headSha,
|
|
165750
|
+
conclusion,
|
|
165751
|
+
detailsUrl,
|
|
165752
|
+
reviewUrl: ctx.toolState.approval?.url
|
|
165753
|
+
}).then(() => log.info(`\xBB posted ${RUN_STATUS_CHECK_NAME} check (${conclusion})`)).catch((err) => log.debug(`status checks: ${RUN_STATUS_CHECK_NAME} post failed: ${err}`));
|
|
165754
|
+
}
|
|
165755
|
+
if (!needsApprovalCheck || !approval) return;
|
|
165756
|
+
const createParams = {
|
|
165757
|
+
owner: ctx.repo.owner,
|
|
165758
|
+
repo: ctx.repo.name,
|
|
165759
|
+
name: APPROVAL_CHECK_NAME,
|
|
165760
|
+
head_sha: approval.sha ?? headSha,
|
|
165761
|
+
status: "completed",
|
|
165762
|
+
conclusion: approval.wouldApprove ? "success" : "failure",
|
|
165763
|
+
output: {
|
|
165650
165764
|
title: approval.wouldApprove ? "Pullfrog would approve" : "Pullfrog would not approve",
|
|
165651
165765
|
summary: approval.wouldApprove ? "Pullfrog has no outstanding review feedback on this PR." : "Pullfrog has outstanding review feedback or requested changes on this PR."
|
|
165652
|
-
}
|
|
165653
|
-
}
|
|
165766
|
+
}
|
|
165767
|
+
};
|
|
165768
|
+
if (detailsUrl) createParams.details_url = detailsUrl;
|
|
165769
|
+
await ctx.octokit.rest.checks.create(createParams).then(() => log.info(`\xBB posted ${APPROVAL_CHECK_NAME} check`)).catch((err) => log.debug(`status checks: ${APPROVAL_CHECK_NAME} post failed: ${err}`));
|
|
165654
165770
|
}
|
|
165655
165771
|
|
|
165656
165772
|
// utils/runLifecycle.ts
|
package/dist/internal/index.d.ts
CHANGED
|
@@ -15,4 +15,6 @@ export { isLeapingIntoActionCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../
|
|
|
15
15
|
export { MAX_LEARNINGS_LENGTH, truncateAtLineBoundary } from "../utils/learningsTruncate.ts";
|
|
16
16
|
export type { CreateProgressCommentTarget, ProgressComment, ProgressCommentType, } from "../utils/progressComment.ts";
|
|
17
17
|
export { createLeapingProgressComment, deleteProgressCommentApi, getProgressComment, updateProgressComment, } from "../utils/progressComment.ts";
|
|
18
|
+
export type { RunStatusCheckConclusion, RunStatusCheckOctokit, } from "../utils/runStatusCheck.ts";
|
|
19
|
+
export { APPROVAL_CHECK_NAME, createRunStatusCheck, finalizeRunStatusCheck, RUN_STATUS_CHECK_NAME, runStatusCheckNeedsFinalizing, } from "../utils/runStatusCheck.ts";
|
|
18
20
|
export { isValidTimeString, parseTimeString, TIMEOUT_DISABLED, } from "../utils/time.ts";
|
package/dist/internal.js
CHANGED
|
@@ -1329,6 +1329,113 @@ async function createLeapingProgressComment(ctx, target, body) {
|
|
|
1329
1329
|
};
|
|
1330
1330
|
}
|
|
1331
1331
|
|
|
1332
|
+
// utils/runStatusCheck.ts
|
|
1333
|
+
var RUN_STATUS_CHECK_NAME = "Pullfrog";
|
|
1334
|
+
var APPROVAL_CHECK_NAME = "Pullfrog approval";
|
|
1335
|
+
var IN_PROGRESS_OUTPUT = {
|
|
1336
|
+
title: "Pullfrog is running",
|
|
1337
|
+
summary: "Pullfrog is working on this pull request. This check updates when the run finishes."
|
|
1338
|
+
};
|
|
1339
|
+
function disableCheckLine(owner, repo) {
|
|
1340
|
+
const url = `https://pullfrog.com/console/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}#auto-review-prs`;
|
|
1341
|
+
return `
|
|
1342
|
+
|
|
1343
|
+
[Turn off this check \u2192](${url}) \u2014 it reports run status only and gates nothing unless you required it in branch protection.`;
|
|
1344
|
+
}
|
|
1345
|
+
var TERMINAL_OUTPUT = {
|
|
1346
|
+
success: {
|
|
1347
|
+
title: "Pullfrog run completed",
|
|
1348
|
+
summary: "The Pullfrog run finished successfully."
|
|
1349
|
+
},
|
|
1350
|
+
failure: {
|
|
1351
|
+
title: "Pullfrog run failed",
|
|
1352
|
+
summary: "The Pullfrog run failed. See the run logs for details."
|
|
1353
|
+
},
|
|
1354
|
+
cancelled: {
|
|
1355
|
+
title: "Pullfrog run cancelled",
|
|
1356
|
+
summary: "The Pullfrog run was cancelled before it finished."
|
|
1357
|
+
},
|
|
1358
|
+
timed_out: {
|
|
1359
|
+
title: "Pullfrog run timed out",
|
|
1360
|
+
summary: "The Pullfrog run exceeded its timeout. See the run logs for details."
|
|
1361
|
+
},
|
|
1362
|
+
action_required: {
|
|
1363
|
+
title: "Pullfrog run needs attention",
|
|
1364
|
+
summary: "The Pullfrog run stopped and needs attention. See the run logs for details."
|
|
1365
|
+
},
|
|
1366
|
+
neutral: {
|
|
1367
|
+
title: "Pullfrog run finished",
|
|
1368
|
+
summary: "The Pullfrog run finished without a pass or fail outcome."
|
|
1369
|
+
},
|
|
1370
|
+
skipped: {
|
|
1371
|
+
title: "Pullfrog run skipped",
|
|
1372
|
+
summary: "This run was superseded by another Pullfrog run."
|
|
1373
|
+
},
|
|
1374
|
+
stale: {
|
|
1375
|
+
title: "Pullfrog run didn't finish",
|
|
1376
|
+
summary: "Pullfrog never received a completion signal for this run. See the run logs for details."
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
function terminalOutput(params) {
|
|
1380
|
+
const base = TERMINAL_OUTPUT[params.conclusion];
|
|
1381
|
+
const review = params.reviewUrl ? `
|
|
1382
|
+
|
|
1383
|
+
[View the review Pullfrog posted \u2192](${params.reviewUrl})` : "";
|
|
1384
|
+
const disable = params.conclusion === "success" ? "" : disableCheckLine(params.owner, params.repo);
|
|
1385
|
+
return { title: base.title, summary: base.summary + review + disable };
|
|
1386
|
+
}
|
|
1387
|
+
async function createRunStatusCheck(params) {
|
|
1388
|
+
const existing = await params.octokit.rest.checks.listForRef({
|
|
1389
|
+
owner: params.owner,
|
|
1390
|
+
repo: params.repo,
|
|
1391
|
+
ref: params.headSha,
|
|
1392
|
+
check_name: RUN_STATUS_CHECK_NAME,
|
|
1393
|
+
status: "in_progress"
|
|
1394
|
+
}).catch(() => void 0);
|
|
1395
|
+
const reusable = existing?.data.check_runs[0];
|
|
1396
|
+
if (reusable) return reusable.id;
|
|
1397
|
+
const createParams = {
|
|
1398
|
+
owner: params.owner,
|
|
1399
|
+
repo: params.repo,
|
|
1400
|
+
name: RUN_STATUS_CHECK_NAME,
|
|
1401
|
+
head_sha: params.headSha,
|
|
1402
|
+
status: "in_progress",
|
|
1403
|
+
output: IN_PROGRESS_OUTPUT
|
|
1404
|
+
};
|
|
1405
|
+
if (params.detailsUrl) createParams.details_url = params.detailsUrl;
|
|
1406
|
+
const created = await params.octokit.rest.checks.create(createParams);
|
|
1407
|
+
return created.data.id;
|
|
1408
|
+
}
|
|
1409
|
+
async function finalizeRunStatusCheck(params) {
|
|
1410
|
+
const updateParams = {
|
|
1411
|
+
owner: params.owner,
|
|
1412
|
+
repo: params.repo,
|
|
1413
|
+
check_run_id: params.checkRunId,
|
|
1414
|
+
status: "completed",
|
|
1415
|
+
conclusion: params.conclusion,
|
|
1416
|
+
output: terminalOutput({
|
|
1417
|
+
conclusion: params.conclusion,
|
|
1418
|
+
owner: params.owner,
|
|
1419
|
+
repo: params.repo,
|
|
1420
|
+
reviewUrl: params.reviewUrl
|
|
1421
|
+
})
|
|
1422
|
+
};
|
|
1423
|
+
if (params.detailsUrl) updateParams.details_url = params.detailsUrl;
|
|
1424
|
+
await params.octokit.rest.checks.update(updateParams);
|
|
1425
|
+
}
|
|
1426
|
+
async function runStatusCheckNeedsFinalizing(params) {
|
|
1427
|
+
try {
|
|
1428
|
+
const existing = await params.octokit.rest.checks.get({
|
|
1429
|
+
owner: params.owner,
|
|
1430
|
+
repo: params.repo,
|
|
1431
|
+
check_run_id: params.checkRunId
|
|
1432
|
+
});
|
|
1433
|
+
return existing.data.status !== "completed";
|
|
1434
|
+
} catch {
|
|
1435
|
+
return false;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1332
1439
|
// utils/time.ts
|
|
1333
1440
|
var TIMEOUT_DISABLED = "none";
|
|
1334
1441
|
var TIME_STRING_REGEX = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
|
|
@@ -1344,6 +1451,7 @@ function isValidTimeString(input) {
|
|
|
1344
1451
|
return parseTimeString(input) !== null;
|
|
1345
1452
|
}
|
|
1346
1453
|
export {
|
|
1454
|
+
APPROVAL_CHECK_NAME,
|
|
1347
1455
|
AUTO_EFFICIENT,
|
|
1348
1456
|
AUTO_INTELLIGENT,
|
|
1349
1457
|
DEFAULT_PROXY_MODEL,
|
|
@@ -1351,12 +1459,15 @@ export {
|
|
|
1351
1459
|
MAX_LEARNINGS_LENGTH,
|
|
1352
1460
|
OAuthInvalidGrantError,
|
|
1353
1461
|
PULLFROG_DIVIDER,
|
|
1462
|
+
RUN_STATUS_CHECK_NAME,
|
|
1354
1463
|
TIMEOUT_DISABLED,
|
|
1355
1464
|
buildPullfrogFooter,
|
|
1356
1465
|
createLeapingProgressComment,
|
|
1466
|
+
createRunStatusCheck,
|
|
1357
1467
|
decodeJwtExpMs,
|
|
1358
1468
|
defaultAutoTier,
|
|
1359
1469
|
deleteProgressCommentApi,
|
|
1470
|
+
finalizeRunStatusCheck,
|
|
1360
1471
|
getAutoSelectHintModel,
|
|
1361
1472
|
getModelEnvVars,
|
|
1362
1473
|
getModelManagedCredentials,
|
|
@@ -1380,6 +1491,7 @@ export {
|
|
|
1380
1491
|
resolveDisplayAlias,
|
|
1381
1492
|
resolveModelSlug,
|
|
1382
1493
|
resolveOpenRouterModel,
|
|
1494
|
+
runStatusCheckNeedsFinalizing,
|
|
1383
1495
|
stringifyCodexAuthBody,
|
|
1384
1496
|
stripExistingFooter,
|
|
1385
1497
|
truncateAtLineBoundary,
|
package/dist/toolState.d.ts
CHANGED
package/dist/utils/payload.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
|
|
|
22
22
|
id: string;
|
|
23
23
|
type: "issue" | "review";
|
|
24
24
|
} | undefined;
|
|
25
|
+
checkRun?: {
|
|
26
|
+
id: string;
|
|
27
|
+
} | undefined;
|
|
25
28
|
generateSummary?: boolean | undefined;
|
|
26
29
|
}, {}>;
|
|
27
30
|
export declare const Inputs: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
@@ -68,10 +71,14 @@ export declare function resolvePayload(resolvedPromptInput: ResolvedPromptInput,
|
|
|
68
71
|
id: string;
|
|
69
72
|
type: "issue" | "review";
|
|
70
73
|
} | undefined;
|
|
74
|
+
checkRun: {
|
|
75
|
+
id: string;
|
|
76
|
+
} | undefined;
|
|
71
77
|
generateSummary: boolean | undefined;
|
|
72
78
|
push: import("../external.ts").PushPermission;
|
|
73
79
|
shell: import("../external.ts").ShellPermission;
|
|
74
|
-
|
|
80
|
+
runStatusCheck: boolean;
|
|
81
|
+
approvalCheck: boolean;
|
|
75
82
|
progressComments: boolean;
|
|
76
83
|
proxyModel: string | undefined;
|
|
77
84
|
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the `pullfrog` commit-status check-run — the row a PR's
|
|
3
|
+
* checks list shows while a run is in flight and after it ends.
|
|
4
|
+
*
|
|
5
|
+
* Pullfrog dispatches its workflow with `ref: <default branch>`, so the GitHub Actions
|
|
6
|
+
* run attaches its check suite to the default branch head and never to the PR head.
|
|
7
|
+
* Nothing about a run is therefore visible from the PR itself unless we post this
|
|
8
|
+
* check-run against the PR head sha ourselves.
|
|
9
|
+
*
|
|
10
|
+
* Created `in_progress` by the server at dispatch — before the runner boots, and
|
|
11
|
+
* upstream of every action-side failure that would otherwise leave the PR silent
|
|
12
|
+
* (billing 402, token resolution, bad model slug, missing provider key). Moved to a
|
|
13
|
+
* terminal conclusion by whichever of three actors reaches it first, all calling
|
|
14
|
+
* `finalizeRunStatusCheck`:
|
|
15
|
+
*
|
|
16
|
+
* 1. the action at run end (`reportStatusChecks`)
|
|
17
|
+
* 2. the `workflow_run.completed` webhook (covers cancel / SIGKILL / early throw)
|
|
18
|
+
* 3. the hourly stuck-run reaper (covers a dropped webhook)
|
|
19
|
+
*
|
|
20
|
+
* That three-layer close-out is what makes an `in_progress` check safe here: a check
|
|
21
|
+
* stranded `in_progress` on a required branch-protection rule would block merges
|
|
22
|
+
* forever, which is why this file did not exist before.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* the run-lifecycle check. verdict-agnostic — it reports that a run happened, not what it
|
|
26
|
+
* found. this string IS the branch-protection identifier, so changing it silently breaks
|
|
27
|
+
* any repo that required the old name.
|
|
28
|
+
*/
|
|
29
|
+
export declare const RUN_STATUS_CHECK_NAME = "Pullfrog";
|
|
30
|
+
/** the review-verdict check. opt-in, terminal-only, and deliberately separate from the above. */
|
|
31
|
+
export declare const APPROVAL_CHECK_NAME = "Pullfrog approval";
|
|
32
|
+
/**
|
|
33
|
+
* The terminal states we report. Exactly GitHub's check-run `conclusion` enum, which
|
|
34
|
+
* happens to be `WorkflowRunStatus` minus `running` — so the server can map a finished
|
|
35
|
+
* run's status straight across (`checkConclusionFromStatus` in utils/workflowRunStatus.ts).
|
|
36
|
+
*/
|
|
37
|
+
export type RunStatusCheckConclusion = "success" | "failure" | "cancelled" | "timed_out" | "action_required" | "neutral" | "skipped" | "stale";
|
|
38
|
+
/**
|
|
39
|
+
* Parse the on-the-wire `{ id: string }` shape (the form carried in `JsonPayload`) into
|
|
40
|
+
* a check-run id. Mirrors `parseProgressComment` — returns undefined when the id isn't a
|
|
41
|
+
* positive integer so callers can short-circuit cleanly.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseCheckRunId(raw: {
|
|
44
|
+
id: string;
|
|
45
|
+
} | null | undefined): number | undefined;
|
|
46
|
+
interface CheckRunResponse {
|
|
47
|
+
data: {
|
|
48
|
+
id: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
type CheckRunStatus = "queued" | "in_progress" | "completed";
|
|
52
|
+
type CheckRunOutput = {
|
|
53
|
+
title: string;
|
|
54
|
+
summary: string;
|
|
55
|
+
};
|
|
56
|
+
type CreateCheckRunParams = {
|
|
57
|
+
owner: string;
|
|
58
|
+
repo: string;
|
|
59
|
+
name: string;
|
|
60
|
+
head_sha: string;
|
|
61
|
+
status?: CheckRunStatus;
|
|
62
|
+
conclusion?: RunStatusCheckConclusion;
|
|
63
|
+
details_url?: string;
|
|
64
|
+
output?: CheckRunOutput;
|
|
65
|
+
};
|
|
66
|
+
type UpdateCheckRunParams = {
|
|
67
|
+
owner: string;
|
|
68
|
+
repo: string;
|
|
69
|
+
check_run_id: number;
|
|
70
|
+
status?: CheckRunStatus;
|
|
71
|
+
conclusion?: RunStatusCheckConclusion;
|
|
72
|
+
details_url?: string;
|
|
73
|
+
output?: CheckRunOutput;
|
|
74
|
+
};
|
|
75
|
+
export interface RunStatusCheckOctokit {
|
|
76
|
+
rest: {
|
|
77
|
+
checks: {
|
|
78
|
+
create: (params: CreateCheckRunParams) => Promise<CheckRunResponse>;
|
|
79
|
+
update: (params: UpdateCheckRunParams) => Promise<CheckRunResponse>;
|
|
80
|
+
get: (params: {
|
|
81
|
+
owner: string;
|
|
82
|
+
repo: string;
|
|
83
|
+
check_run_id: number;
|
|
84
|
+
}) => Promise<{
|
|
85
|
+
data: {
|
|
86
|
+
status: string;
|
|
87
|
+
};
|
|
88
|
+
}>;
|
|
89
|
+
listForRef: (params: {
|
|
90
|
+
owner: string;
|
|
91
|
+
repo: string;
|
|
92
|
+
ref: string;
|
|
93
|
+
check_name?: string;
|
|
94
|
+
status?: "queued" | "in_progress" | "completed";
|
|
95
|
+
}) => Promise<{
|
|
96
|
+
data: {
|
|
97
|
+
check_runs: {
|
|
98
|
+
id: number;
|
|
99
|
+
}[];
|
|
100
|
+
};
|
|
101
|
+
}>;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Post the `in_progress` check-run on `headSha` and return its id for the finalizers.
|
|
107
|
+
*
|
|
108
|
+
* Best-effort: a transient 5xx, a repo that revoked `checks: write`, or a PR whose head
|
|
109
|
+
* has already been deleted must never stop a run from dispatching. Returns undefined on
|
|
110
|
+
* failure, which every caller treats as "no check to finalize".
|
|
111
|
+
*/
|
|
112
|
+
export declare function createRunStatusCheck(params: {
|
|
113
|
+
octokit: RunStatusCheckOctokit;
|
|
114
|
+
owner: string;
|
|
115
|
+
repo: string;
|
|
116
|
+
headSha: string;
|
|
117
|
+
detailsUrl: string | undefined;
|
|
118
|
+
}): Promise<number | undefined>;
|
|
119
|
+
/**
|
|
120
|
+
* Move an existing check-run to its terminal conclusion.
|
|
121
|
+
*
|
|
122
|
+
* A PATCH, not a second create: `POST /check-runs` with the same name + sha creates a
|
|
123
|
+
* SECOND row rather than replacing the first, so creating twice would show the PR two
|
|
124
|
+
* contradictory `pullfrog` rows. (That is a real bug today — `finalizeSuccessRun` posts
|
|
125
|
+
* success and a later throw posts failure, both as fresh rows.)
|
|
126
|
+
*/
|
|
127
|
+
export declare function finalizeRunStatusCheck(params: {
|
|
128
|
+
octokit: RunStatusCheckOctokit;
|
|
129
|
+
owner: string;
|
|
130
|
+
repo: string;
|
|
131
|
+
checkRunId: number;
|
|
132
|
+
conclusion: RunStatusCheckConclusion;
|
|
133
|
+
detailsUrl: string | undefined;
|
|
134
|
+
reviewUrl?: string | undefined;
|
|
135
|
+
}): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Post an already-terminal check-run in one call.
|
|
138
|
+
*
|
|
139
|
+
* The fallback for runs that never got a server-created check to update: a rolling
|
|
140
|
+
* deploy where the dispatch payload predates `checkRun`, or a workflow invoked outside
|
|
141
|
+
* Pullfrog's own dispatch path (`prompt_file`, a hand-written step).
|
|
142
|
+
*/
|
|
143
|
+
export declare function createTerminalRunStatusCheck(params: {
|
|
144
|
+
octokit: RunStatusCheckOctokit;
|
|
145
|
+
owner: string;
|
|
146
|
+
repo: string;
|
|
147
|
+
headSha: string;
|
|
148
|
+
conclusion: RunStatusCheckConclusion;
|
|
149
|
+
detailsUrl: string | undefined;
|
|
150
|
+
reviewUrl?: string | undefined;
|
|
151
|
+
}): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Whether this check still needs finalizing.
|
|
154
|
+
*
|
|
155
|
+
* The server-side close-outs are BACKSTOPS: they exist for runs the action could not
|
|
156
|
+
* finalize itself. Firing them unconditionally is actively harmful, because the action
|
|
157
|
+
* writes a richer summary than they can — it knows the review URL, they do not — so a
|
|
158
|
+
* blind re-PATCH silently strips that link seconds after it appears. It also resets
|
|
159
|
+
* `completed_at`, discarding the duration GitHub renders as "Successful in 2m".
|
|
160
|
+
*
|
|
161
|
+
* Returns false when GitHub cannot be reached: a backstop that cannot confirm the check
|
|
162
|
+
* is unfinished must not overwrite a good one.
|
|
163
|
+
*/
|
|
164
|
+
export declare function runStatusCheckNeedsFinalizing(params: {
|
|
165
|
+
octokit: RunStatusCheckOctokit;
|
|
166
|
+
owner: string;
|
|
167
|
+
repo: string;
|
|
168
|
+
checkRunId: number;
|
|
169
|
+
}): Promise<boolean>;
|
|
170
|
+
export {};
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import type { ToolContext } from "../mcp/server.ts";
|
|
2
2
|
/**
|
|
3
|
-
* post the
|
|
4
|
-
*
|
|
5
|
-
* protection. no-op unless the `status_checks` input is enabled and the run is
|
|
6
|
-
* on a pull request.
|
|
3
|
+
* post the `Pullfrog` (run lifecycle) and `Pullfrog approval` (review verdict)
|
|
4
|
+
* commit-status check-runs.
|
|
7
5
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* - `Pullfrog` is on by default (`Repo.statusChecks`). the server already created it
|
|
7
|
+
* `in_progress` at dispatch, so the work here is a PATCH to its terminal conclusion —
|
|
8
|
+
* see `runStatusCheck.ts` for why a second create would leave two contradictory rows.
|
|
9
|
+
* the terminal-create fallback covers a payload with no `checkRun` (older server
|
|
10
|
+
* build mid-rolling-deploy, or a workflow driven outside Pullfrog's dispatch path).
|
|
11
|
+
* - `Pullfrog approval` stays opt-in (`status_checks: enabled`) and terminal-only:
|
|
12
|
+
* it asserts a review verdict, which only exists once a run produces one. anchored
|
|
13
|
+
* to the exact reviewed sha so a mid-run push leaves the new head unapproved until
|
|
14
|
+
* a follow-up re-review reports.
|
|
12
15
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* verdict (`toolState.approval`, set by create_pull_request_review),
|
|
17
|
-
* anchored to the reviewed sha so a mid-run push leaves the new head
|
|
18
|
-
* unapproved until the follow-up re-review reports.
|
|
19
|
-
*
|
|
20
|
-
* best-effort throughout: a check-post failure (fork PR head not in the base
|
|
21
|
-
* repo, transient 5xx, closed PR) must never flip the run's own outcome.
|
|
16
|
+
* best-effort throughout: a check-post failure (transient 5xx, closed PR, revoked
|
|
17
|
+
* permission) must never flip the run's own outcome. the `workflow_run.completed` webhook
|
|
18
|
+
* and both stuck-run reaper sweeps close out a check this function fails to finalize.
|
|
22
19
|
*/
|
|
23
20
|
export declare function reportStatusChecks(ctx: ToolContext, params: {
|
|
24
21
|
runSucceeded: boolean;
|