@jphutchins/code-review 0.1.0-alpha.32 → 0.1.0-alpha.33
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/index.js +225 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1068,9 +1068,9 @@ var formatErrors = (errors) => errors.map(describeValidationError);
|
|
|
1068
1068
|
var declaredVersion = (raw) => typeof raw === "object" && raw !== null && "schema_version" in raw ? typeof raw.schema_version === "string" ? raw.schema_version : void 0 : void 0;
|
|
1069
1069
|
var supportedVersions = (kind) => tableFor(kind).map((entry) => entry.minor);
|
|
1070
1070
|
var defaultVersion = (kind) => {
|
|
1071
|
-
const
|
|
1072
|
-
if (!
|
|
1073
|
-
return
|
|
1071
|
+
const latest2 = tableFor(kind).find((entry) => entry.latest);
|
|
1072
|
+
if (!latest2) throw new Error(`Registry invariant violated \u2014 no latest entry for "${kind}"`);
|
|
1073
|
+
return latest2.defaultVersion;
|
|
1074
1074
|
};
|
|
1075
1075
|
var bundledSchemaPath = (relativePath) => resolve$1(import.meta.dirname, "..", "schema", relativePath);
|
|
1076
1076
|
var schemaPathFor = (kind, version) => {
|
|
@@ -1759,6 +1759,134 @@ var announce = async (input, ghApi = runGhApi) => {
|
|
|
1759
1759
|
ghApi
|
|
1760
1760
|
);
|
|
1761
1761
|
};
|
|
1762
|
+
var incompleteBody = (headSha, runUrl, existingBody) => {
|
|
1763
|
+
const notice = `${DEFAULT_MARKER}
|
|
1764
|
+
|
|
1765
|
+
\u26A0\uFE0F **Code review did not complete** for \`${headSha.slice(0, 7)}\` \u2014 the review job failed ([run](${runUrl})). Re-request the review; do not treat this round as spent.`;
|
|
1766
|
+
const carried = existingBody ? carryForwardMarkers(existingBody) : "";
|
|
1767
|
+
return carried ? `${notice}
|
|
1768
|
+
|
|
1769
|
+
${carried}` : notice;
|
|
1770
|
+
};
|
|
1771
|
+
var reportIncomplete = async (input, ghApi = runGhApi) => {
|
|
1772
|
+
const candidates = await fetchPrCandidates(input.repo, input.headSha, ghApi);
|
|
1773
|
+
const resolution = resolvePr(candidates, input.headBranch);
|
|
1774
|
+
if (resolution.kind !== "open") {
|
|
1775
|
+
process.stderr.write(
|
|
1776
|
+
`No open PR for ${input.headSha} \u2014 nothing to report (${resolution.kind})
|
|
1777
|
+
`
|
|
1778
|
+
);
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const existing = await findBotComment(
|
|
1782
|
+
input.repo,
|
|
1783
|
+
resolution.prNumber,
|
|
1784
|
+
input.botLogin,
|
|
1785
|
+
DEFAULT_MARKER,
|
|
1786
|
+
ghApi
|
|
1787
|
+
);
|
|
1788
|
+
if (existing !== null && parseReviewComplete(existing.body)) {
|
|
1789
|
+
process.stderr.write(`Sticky already reflects a completed review \u2014 leaving it in place
|
|
1790
|
+
`);
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
if (existing !== null && !existing.body.includes(input.runUrl)) {
|
|
1794
|
+
process.stderr.write(`Sticky belongs to another run \u2014 leaving it in place
|
|
1795
|
+
`);
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
await upsertSticky(
|
|
1799
|
+
input.repo,
|
|
1800
|
+
resolution.prNumber,
|
|
1801
|
+
existing,
|
|
1802
|
+
incompleteBody(input.headSha, input.runUrl, existing?.body),
|
|
1803
|
+
ghApi
|
|
1804
|
+
);
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1807
|
+
// src/checkrun.ts
|
|
1808
|
+
var CHECK_RUN_NAME = "Code review";
|
|
1809
|
+
var latest = (checks) => checks.reduce(
|
|
1810
|
+
(best, c) => best === null || c.id > best.id ? c : best,
|
|
1811
|
+
null
|
|
1812
|
+
);
|
|
1813
|
+
var isOpen = (status) => status === "in_progress" || status === "queued";
|
|
1814
|
+
var settled = /* @__PURE__ */ new Set(["success", "neutral", "skipped"]);
|
|
1815
|
+
var decideCheckAction = (checks, intent) => {
|
|
1816
|
+
const head = latest(checks);
|
|
1817
|
+
switch (intent) {
|
|
1818
|
+
case "in_progress":
|
|
1819
|
+
return head !== null && isOpen(head.status) ? { kind: "noop", reason: "a check is already in progress for this head" } : { kind: "create", status: "in_progress" };
|
|
1820
|
+
case "neutral":
|
|
1821
|
+
if (head === null) return { kind: "create", status: "completed", conclusion: "neutral" };
|
|
1822
|
+
return head.status === "completed" && head.conclusion === "neutral" ? { kind: "noop", reason: "the check already records this completed review" } : { kind: "patch", id: head.id, status: "completed", conclusion: "neutral" };
|
|
1823
|
+
case "failure":
|
|
1824
|
+
if (head === null) return { kind: "create", status: "completed", conclusion: "failure" };
|
|
1825
|
+
if (head.status === "completed" && head.conclusion !== null && settled.has(head.conclusion))
|
|
1826
|
+
return { kind: "noop", reason: "a completed review already recorded this head" };
|
|
1827
|
+
return head.status === "completed" && head.conclusion === "failure" ? { kind: "noop", reason: "the check already records this failure" } : { kind: "patch", id: head.id, status: "completed", conclusion: "failure" };
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1830
|
+
var CHECK_JQ = ".check_runs[] | {id: .id, status: .status, conclusion: .conclusion}";
|
|
1831
|
+
var fetchChecks = async (repo, headSha, ghApi) => parseJsonl(
|
|
1832
|
+
await ghApi([
|
|
1833
|
+
`repos/${repo}/commits/${headSha}/check-runs?check_name=${encodeURIComponent(CHECK_RUN_NAME)}&per_page=100`,
|
|
1834
|
+
"--paginate",
|
|
1835
|
+
"--jq",
|
|
1836
|
+
CHECK_JQ
|
|
1837
|
+
])
|
|
1838
|
+
);
|
|
1839
|
+
var output = (intent, runUrl) => {
|
|
1840
|
+
switch (intent) {
|
|
1841
|
+
case "in_progress":
|
|
1842
|
+
return {
|
|
1843
|
+
title: "Code review in progress",
|
|
1844
|
+
summary: `The review is running \u2014 [see the run](${runUrl}).`
|
|
1845
|
+
};
|
|
1846
|
+
case "neutral":
|
|
1847
|
+
return {
|
|
1848
|
+
title: "Code review complete",
|
|
1849
|
+
summary: `The review was posted \u2014 [see the run](${runUrl}).`
|
|
1850
|
+
};
|
|
1851
|
+
case "failure":
|
|
1852
|
+
return {
|
|
1853
|
+
title: "Code review did not complete",
|
|
1854
|
+
summary: `The review job failed \u2014 [see the run](${runUrl}). Re-request the review; do not treat this round as spent.`
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
var checkRun = async (input, ghApi = runGhApi) => {
|
|
1859
|
+
const action = decideCheckAction(
|
|
1860
|
+
await fetchChecks(input.repo, input.headSha, ghApi),
|
|
1861
|
+
input.intent
|
|
1862
|
+
);
|
|
1863
|
+
if (action.kind === "noop") {
|
|
1864
|
+
process.stderr.write(`code-review check-run: ${action.reason} \u2014 leaving it
|
|
1865
|
+
`);
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
const body = action.kind === "create" ? {
|
|
1869
|
+
name: CHECK_RUN_NAME,
|
|
1870
|
+
head_sha: input.headSha,
|
|
1871
|
+
status: action.status,
|
|
1872
|
+
details_url: input.runUrl,
|
|
1873
|
+
...action.conclusion ? { conclusion: action.conclusion } : {},
|
|
1874
|
+
output: output(input.intent, input.runUrl)
|
|
1875
|
+
} : {
|
|
1876
|
+
status: action.status,
|
|
1877
|
+
conclusion: action.conclusion,
|
|
1878
|
+
details_url: input.runUrl,
|
|
1879
|
+
output: output(input.intent, input.runUrl)
|
|
1880
|
+
};
|
|
1881
|
+
const endpoint = action.kind === "create" ? [`--method`, `POST`, `repos/${input.repo}/check-runs`, `--input`, `-`] : [
|
|
1882
|
+
`--method`,
|
|
1883
|
+
`PATCH`,
|
|
1884
|
+
`repos/${input.repo}/check-runs/${String(action.id)}`,
|
|
1885
|
+
`--input`,
|
|
1886
|
+
`-`
|
|
1887
|
+
];
|
|
1888
|
+
await ghApi(endpoint, JSON.stringify(body));
|
|
1889
|
+
};
|
|
1762
1890
|
var DURATION_RE = /^(\d+)(h|m|s)$/;
|
|
1763
1891
|
var USD_RE = /^\$(\d+(?:\.\d+)?)$/;
|
|
1764
1892
|
var toSeconds = (n, unit) => unit === "h" ? n * 3600 : unit === "m" ? n * 60 : n;
|
|
@@ -1965,12 +2093,12 @@ var resolveCiRun = async (repo, headSha, workflowName, ghApi) => {
|
|
|
1965
2093
|
`
|
|
1966
2094
|
);
|
|
1967
2095
|
}
|
|
1968
|
-
const
|
|
2096
|
+
const latest2 = runs.filter((r) => r.name === workflowName).reduce(
|
|
1969
2097
|
(best, r) => best === null || r.run_number > best.run_number ? r : best,
|
|
1970
2098
|
null
|
|
1971
2099
|
);
|
|
1972
2100
|
return {
|
|
1973
|
-
run:
|
|
2101
|
+
run: latest2 === null ? null : { id: latest2.id, status: latest2.status ?? "unknown", conclusion: latest2.conclusion },
|
|
1974
2102
|
seenNames: [...new Set(runs.flatMap((r) => r.name === null ? [] : [r.name]))]
|
|
1975
2103
|
};
|
|
1976
2104
|
};
|
|
@@ -2722,7 +2850,7 @@ var renderCmd = defineCommand({
|
|
|
2722
2850
|
const prices = decode(PriceMapCodec.decode(readJSON(priceResolution.path)), "prices");
|
|
2723
2851
|
const template = readFileSync(templatePath, "utf-8");
|
|
2724
2852
|
const testReport = args["test-report"] ? decode(TestSummaryCodec.decode(readJSON(args["test-report"])), "test report") : void 0;
|
|
2725
|
-
const
|
|
2853
|
+
const output2 = render({
|
|
2726
2854
|
findings,
|
|
2727
2855
|
envelope,
|
|
2728
2856
|
prices,
|
|
@@ -2734,7 +2862,7 @@ var renderCmd = defineCommand({
|
|
|
2734
2862
|
testReport,
|
|
2735
2863
|
postedAt: formatUtc(/* @__PURE__ */ new Date())
|
|
2736
2864
|
});
|
|
2737
|
-
process.stdout.write(
|
|
2865
|
+
process.stdout.write(output2);
|
|
2738
2866
|
}
|
|
2739
2867
|
});
|
|
2740
2868
|
var inlineCmd = defineCommand({
|
|
@@ -2924,7 +3052,7 @@ var budgetHookCmd = defineCommand({
|
|
|
2924
3052
|
const prices = args.prices ? tryReadPrices(args.prices) : null;
|
|
2925
3053
|
const spentUsd = prices !== null && usage ? computeCost(usage.models, prices).totalCostUSD : null;
|
|
2926
3054
|
const wallMs = args.wall ? parseWallMs(args.wall) : null;
|
|
2927
|
-
const
|
|
3055
|
+
const output2 = evaluateBudgetHook(input, {
|
|
2928
3056
|
spentUsd,
|
|
2929
3057
|
budgetUsd: parseBudgetUsd(args["budget-usd"]),
|
|
2930
3058
|
elapsedMs: anchoredElapsedMs({
|
|
@@ -2948,7 +3076,7 @@ var budgetHookCmd = defineCommand({
|
|
|
2948
3076
|
});
|
|
2949
3077
|
if (asRecord(input)?.["hook_event_name"] === "PostToolBatch" && !isSubagentHookInput(input))
|
|
2950
3078
|
snapshotIfValid(draftPath);
|
|
2951
|
-
process.stdout.write(`${JSON.stringify(
|
|
3079
|
+
process.stdout.write(`${JSON.stringify(output2)}
|
|
2952
3080
|
`);
|
|
2953
3081
|
} catch (err) {
|
|
2954
3082
|
process.stderr.write(`code-review budget-hook: degrading to no-op \u2014 ${errMsg(err)}
|
|
@@ -3762,6 +3890,92 @@ var announceCmd = defineCommand({
|
|
|
3762
3890
|
);
|
|
3763
3891
|
}
|
|
3764
3892
|
});
|
|
3893
|
+
var isCheckIntent = (s) => s === "in_progress" || s === "neutral" || s === "failure";
|
|
3894
|
+
var checkRunCmd = defineCommand({
|
|
3895
|
+
meta: {
|
|
3896
|
+
name: "check-run",
|
|
3897
|
+
description: "Upsert the native 'Code review' check-run on the head SHA \u2014 the attribution surface that appears in the PR's own checks list and (writing to the base repo) works for fork PRs too. `in_progress` at review start, `neutral` when the review completes, `failure` when it didn't. Forward-only: `failure` never overwrites a completed review."
|
|
3898
|
+
},
|
|
3899
|
+
args: {
|
|
3900
|
+
repo: { type: "string", description: "Repository (owner/name)", required: true },
|
|
3901
|
+
"head-sha": {
|
|
3902
|
+
type: "string",
|
|
3903
|
+
description: "Head SHA the check-run is anchored to",
|
|
3904
|
+
required: true
|
|
3905
|
+
},
|
|
3906
|
+
status: {
|
|
3907
|
+
type: "positional",
|
|
3908
|
+
description: "One of: in_progress, neutral, failure",
|
|
3909
|
+
required: true
|
|
3910
|
+
},
|
|
3911
|
+
"run-url": {
|
|
3912
|
+
type: "string",
|
|
3913
|
+
description: "Workflow run URL the check-run's details link to",
|
|
3914
|
+
required: true
|
|
3915
|
+
}
|
|
3916
|
+
},
|
|
3917
|
+
run: async ({ args }) => {
|
|
3918
|
+
if (!isCheckIntent(args.status)) {
|
|
3919
|
+
process.stderr.write(
|
|
3920
|
+
`::warning::code-review check-run: unrecognized status "${annotationSafe(args.status)}" \u2014 expected in_progress, neutral, or failure; skipping
|
|
3921
|
+
`
|
|
3922
|
+
);
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
await checkRun({
|
|
3926
|
+
repo: args.repo,
|
|
3927
|
+
headSha: args["head-sha"],
|
|
3928
|
+
intent: args.status,
|
|
3929
|
+
runUrl: args["run-url"]
|
|
3930
|
+
}).catch(
|
|
3931
|
+
(err) => process.stderr.write(
|
|
3932
|
+
`::warning::code-review check-run: could not upsert the check-run (${annotationSafe(errMsg(err))}) \u2014 continuing (attribution aid)
|
|
3933
|
+
`
|
|
3934
|
+
)
|
|
3935
|
+
);
|
|
3936
|
+
}
|
|
3937
|
+
});
|
|
3938
|
+
var reportIncompleteCmd = defineCommand({
|
|
3939
|
+
meta: {
|
|
3940
|
+
name: "report-incomplete",
|
|
3941
|
+
description: "Post (or update) the sticky when a review job hard-failed and posted nothing \u2014 an attributed 'did not complete' notice linking the run, telling the reader to re-request. Never buries a completed review, and never overwrites a superseding run's live in-progress placeholder. (A cancelled review is left to the superseding run that took over.)"
|
|
3942
|
+
},
|
|
3943
|
+
args: {
|
|
3944
|
+
repo: { type: "string", description: "Repository (owner/name)", required: true },
|
|
3945
|
+
"head-sha": {
|
|
3946
|
+
type: "string",
|
|
3947
|
+
description: "Trusted head SHA to resolve the PR (from workflow_run.head_sha)",
|
|
3948
|
+
required: true
|
|
3949
|
+
},
|
|
3950
|
+
"run-url": {
|
|
3951
|
+
type: "string",
|
|
3952
|
+
description: "Workflow run URL the notice links to",
|
|
3953
|
+
required: true
|
|
3954
|
+
},
|
|
3955
|
+
"bot-login": {
|
|
3956
|
+
type: "string",
|
|
3957
|
+
description: "Bot login to trust for the sticky comment upsert (default: github-actions[bot])"
|
|
3958
|
+
},
|
|
3959
|
+
"head-branch": {
|
|
3960
|
+
type: "string",
|
|
3961
|
+
description: "Head branch to disambiguate the PR when multiple share a commit"
|
|
3962
|
+
}
|
|
3963
|
+
},
|
|
3964
|
+
run: async ({ args }) => {
|
|
3965
|
+
await reportIncomplete({
|
|
3966
|
+
repo: args.repo,
|
|
3967
|
+
headSha: args["head-sha"],
|
|
3968
|
+
botLogin: args["bot-login"] || "github-actions[bot]",
|
|
3969
|
+
runUrl: args["run-url"],
|
|
3970
|
+
headBranch: args["head-branch"]
|
|
3971
|
+
}).catch(
|
|
3972
|
+
(err) => process.stderr.write(
|
|
3973
|
+
`::warning::code-review report-incomplete: could not post the failure notice (${annotationSafe(errMsg(err))}) \u2014 continuing
|
|
3974
|
+
`
|
|
3975
|
+
)
|
|
3976
|
+
);
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3765
3979
|
var requireCeilingSec = (raw) => {
|
|
3766
3980
|
if (raw === void 0) return null;
|
|
3767
3981
|
const ms = parseWallMs(raw);
|
|
@@ -3935,6 +4149,8 @@ var main = defineCommand({
|
|
|
3935
4149
|
inline: inlineCmd,
|
|
3936
4150
|
post: postCmd,
|
|
3937
4151
|
announce: announceCmd,
|
|
4152
|
+
"check-run": checkRunCmd,
|
|
4153
|
+
"report-incomplete": reportIncompleteCmd,
|
|
3938
4154
|
cost: costCmd,
|
|
3939
4155
|
"check-cost": checkCostCmd,
|
|
3940
4156
|
validate: validateCmd,
|