@jphutchins/code-review 0.1.0-alpha.28 → 0.1.0-alpha.29
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 +83 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/comment.eta +5 -2
package/dist/index.js
CHANGED
|
@@ -186,6 +186,8 @@ var parseReviewedSha = (body) => {
|
|
|
186
186
|
const sha = /<!-- reviewed-sha: ([0-9a-fA-F]{40}) -->/.exec(body)?.[1]?.toLowerCase();
|
|
187
187
|
return sha && sha !== ZERO_SHA ? sha : null;
|
|
188
188
|
};
|
|
189
|
+
var REVIEW_COMPLETE_MARKER = "<!-- review-complete -->";
|
|
190
|
+
var parseReviewComplete = (body) => body.includes(REVIEW_COMPLETE_MARKER);
|
|
189
191
|
var parseFindingsMarker = (body) => {
|
|
190
192
|
const match = /<!-- code-review:findings-json;base64 ([A-Za-z0-9+/=]+) -->/.exec(body);
|
|
191
193
|
const b64 = match?.[1];
|
|
@@ -240,6 +242,8 @@ var computeSeverityCounts = (findings) => findings.reduce(
|
|
|
240
242
|
var render = (input) => {
|
|
241
243
|
const eta = new Eta({ autoTrim: false });
|
|
242
244
|
const usageAvailable = input.envelope !== null;
|
|
245
|
+
const hasUsage = input.envelope !== null && input.envelope.models.length > 0;
|
|
246
|
+
const incomplete = input.incomplete ?? input.envelope?.incomplete ?? false;
|
|
243
247
|
const costReport = input.envelope ? computeCost(input.envelope.models, input.prices) : null;
|
|
244
248
|
const pricesProvided = input.pricesProvided ?? true;
|
|
245
249
|
const route = input.route ?? input.envelope?.route ?? null;
|
|
@@ -249,6 +253,8 @@ var render = (input) => {
|
|
|
249
253
|
findings: input.findings,
|
|
250
254
|
envelope: input.envelope,
|
|
251
255
|
usageAvailable,
|
|
256
|
+
hasUsage,
|
|
257
|
+
incomplete,
|
|
252
258
|
costReport,
|
|
253
259
|
pricesProvided,
|
|
254
260
|
route,
|
|
@@ -602,7 +608,12 @@ var ResultEnvelopeCodec = t.intersection([
|
|
|
602
608
|
t.partial({
|
|
603
609
|
vendor_cost_usd: t.union([t.number, t.null]),
|
|
604
610
|
route: t.string,
|
|
605
|
-
effort: t.string
|
|
611
|
+
effort: t.string,
|
|
612
|
+
// The run produced a notice rather than a completed review (security-gate block, agent kill, no
|
|
613
|
+
// recoverable findings). An empty `findings` array alone can't say this — a genuine clean review
|
|
614
|
+
// is also empty — so the render suppresses "clean review" and the sticky precedence guard refuses
|
|
615
|
+
// to bury a completed review under it. Absent ⇒ a completed review.
|
|
616
|
+
incomplete: t.boolean
|
|
606
617
|
})
|
|
607
618
|
]);
|
|
608
619
|
var ModelPricesCodec = t.type({
|
|
@@ -959,6 +970,35 @@ var formatMarkdown = (md) => {
|
|
|
959
970
|
};
|
|
960
971
|
var pad2 = (n) => String(n).padStart(2, "0");
|
|
961
972
|
var formatUtc = (d) => `${String(d.getUTCFullYear())}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())} ${pad2(d.getUTCHours())}:${pad2(d.getUTCMinutes())} UTC`;
|
|
973
|
+
|
|
974
|
+
// src/notice.ts
|
|
975
|
+
var isNoticeKind = (s) => s === "security-blocked" || s === "setup-failed" || s === "diff-apply-failed" || s === "no-output";
|
|
976
|
+
var blockquote = (text) => text.replaceAll("\n", "\n> ");
|
|
977
|
+
var noticeSummary = (kind, reasons) => {
|
|
978
|
+
switch (kind) {
|
|
979
|
+
case "security-blocked":
|
|
980
|
+
return reasons !== void 0 && reasons.trim() !== "" ? `### \u{1F6D1} Code review skipped by the security gate
|
|
981
|
+
|
|
982
|
+
The diff was flagged as unsafe to apply and execute:
|
|
983
|
+
|
|
984
|
+
> ${blockquote(reasons)}` : "### \u{1F6D1} Code review skipped by the security gate\n\nThe security triage returned an unsafe verdict without a reason. See workflow logs.";
|
|
985
|
+
case "setup-failed":
|
|
986
|
+
return "### \u{1F6E0}\uFE0F Review did not run\n\nThe review job failed before the security triage could run (e.g. dependency install or environment setup). See the workflow logs \u2014 this is an infrastructure failure, not a security verdict.";
|
|
987
|
+
case "diff-apply-failed":
|
|
988
|
+
return "### \u26A0\uFE0F Could not apply the diff\n\nThe PR diff could not be applied to the checked-out base commit, so the review was skipped rather than run against an unmodified tree. See workflow logs.";
|
|
989
|
+
case "no-output":
|
|
990
|
+
return "### \u26A0\uFE0F Review did not complete\n\nThe diff passed triage but the review produced no output. See workflow logs.";
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
var buildNoticeEnvelope = (kind, reasons) => ({
|
|
994
|
+
schema_version: DEFAULT_SCHEMA_VERSION,
|
|
995
|
+
findings: noticeFindings(noticeSummary(kind, reasons)),
|
|
996
|
+
models: [],
|
|
997
|
+
turns: 0,
|
|
998
|
+
duration_ms: 0,
|
|
999
|
+
vendor_cost_usd: null,
|
|
1000
|
+
incomplete: true
|
|
1001
|
+
});
|
|
962
1002
|
var identity = (decoded) => decoded;
|
|
963
1003
|
var findingsTable = [
|
|
964
1004
|
{
|
|
@@ -1417,6 +1457,15 @@ var post = async (input, ghApi = runGhApi) => {
|
|
|
1417
1457
|
DEFAULT_MARKER,
|
|
1418
1458
|
ghApi
|
|
1419
1459
|
);
|
|
1460
|
+
const existingComplete = existingSticky !== null && parseReviewComplete(existingSticky.body);
|
|
1461
|
+
const wouldBuryCompleted = (incomplete) => incomplete && existingComplete;
|
|
1462
|
+
const leaveInPlace = () => {
|
|
1463
|
+
process.stderr.write(
|
|
1464
|
+
`Review did not complete and the sticky already reflects a completed review \u2014 leaving it in place
|
|
1465
|
+
`
|
|
1466
|
+
);
|
|
1467
|
+
process.exit(0);
|
|
1468
|
+
};
|
|
1420
1469
|
const prices = JSON.parse(readFileSync(input.pricesPath, "utf-8"));
|
|
1421
1470
|
const decodedPrices = PriceMapCodec.decode(prices);
|
|
1422
1471
|
if (decodedPrices._tag === "Left") {
|
|
@@ -1428,6 +1477,7 @@ var post = async (input, ghApi = runGhApi) => {
|
|
|
1428
1477
|
render({
|
|
1429
1478
|
findings: noticeFindings(`### \u26A0\uFE0F ${message}`),
|
|
1430
1479
|
envelope: null,
|
|
1480
|
+
incomplete: true,
|
|
1431
1481
|
prices: decodedPrices.right,
|
|
1432
1482
|
pricesProvided: input.pricesProvided,
|
|
1433
1483
|
template,
|
|
@@ -1440,6 +1490,7 @@ var post = async (input, ghApi = runGhApi) => {
|
|
|
1440
1490
|
})
|
|
1441
1491
|
);
|
|
1442
1492
|
if (isEmptyDiff(diff)) {
|
|
1493
|
+
if (wouldBuryCompleted(true)) leaveInPlace();
|
|
1443
1494
|
await upsertSticky(
|
|
1444
1495
|
input.repo,
|
|
1445
1496
|
prNumber,
|
|
@@ -1451,6 +1502,7 @@ var post = async (input, ghApi = runGhApi) => {
|
|
|
1451
1502
|
}
|
|
1452
1503
|
const findingsResult = loadFindings(input.findingsPath);
|
|
1453
1504
|
if (findingsResult.kind !== "ok") {
|
|
1505
|
+
if (wouldBuryCompleted(true)) leaveInPlace();
|
|
1454
1506
|
await upsertSticky(
|
|
1455
1507
|
input.repo,
|
|
1456
1508
|
prNumber,
|
|
@@ -1487,6 +1539,8 @@ var post = async (input, ghApi = runGhApi) => {
|
|
|
1487
1539
|
);
|
|
1488
1540
|
process.exit(0);
|
|
1489
1541
|
}
|
|
1542
|
+
const thisIncomplete = envelope.incomplete === true;
|
|
1543
|
+
if (wouldBuryCompleted(thisIncomplete)) leaveInPlace();
|
|
1490
1544
|
const findingsMarker = findingsPointer(findings, input.jsonUrl);
|
|
1491
1545
|
const {
|
|
1492
1546
|
comments: rawComments,
|
|
@@ -1510,6 +1564,7 @@ var post = async (input, ghApi = runGhApi) => {
|
|
|
1510
1564
|
const commonRenderInput = {
|
|
1511
1565
|
findings,
|
|
1512
1566
|
envelope,
|
|
1567
|
+
incomplete: thisIncomplete,
|
|
1513
1568
|
prices: decodedPrices.right,
|
|
1514
1569
|
pricesProvided: input.pricesProvided,
|
|
1515
1570
|
template,
|
|
@@ -1624,7 +1679,7 @@ var announce = async (input, ghApi = runGhApi) => {
|
|
|
1624
1679
|
DEFAULT_MARKER,
|
|
1625
1680
|
ghApi
|
|
1626
1681
|
);
|
|
1627
|
-
if (existing !== null && parseReviewedSha(existing.body) === input.headSha.toLowerCase()) {
|
|
1682
|
+
if (existing !== null && parseReviewComplete(existing.body) && parseReviewedSha(existing.body) === input.headSha.toLowerCase()) {
|
|
1628
1683
|
process.stderr.write(
|
|
1629
1684
|
`Sticky already reflects a completed review of ${input.headSha} \u2014 leaving it in place
|
|
1630
1685
|
`
|
|
@@ -2365,6 +2420,7 @@ var buildEnvelope = (telemetry, native, agentFilePath, agentFileFallbackPath) =>
|
|
|
2365
2420
|
findings: noticeFindings(`### \u26A0\uFE0F Review did not complete
|
|
2366
2421
|
|
|
2367
2422
|
${outcome.reason}`),
|
|
2423
|
+
incomplete: true,
|
|
2368
2424
|
...telemetry
|
|
2369
2425
|
};
|
|
2370
2426
|
}
|
|
@@ -3125,6 +3181,30 @@ var adaptCmd = defineCommand({
|
|
|
3125
3181
|
`);
|
|
3126
3182
|
}
|
|
3127
3183
|
});
|
|
3184
|
+
var noticeCmd = defineCommand({
|
|
3185
|
+
meta: {
|
|
3186
|
+
name: "notice",
|
|
3187
|
+
description: "Emit an abstract envelope for a run that produced no completed review (security block, setup failure, unapplied diff, or empty run) \u2014 flagged incomplete so the commenter renders it honestly and won't bury a real review"
|
|
3188
|
+
},
|
|
3189
|
+
args: {
|
|
3190
|
+
kind: {
|
|
3191
|
+
type: "positional",
|
|
3192
|
+
description: "One of: security-blocked, setup-failed, diff-apply-failed, no-output",
|
|
3193
|
+
required: true
|
|
3194
|
+
},
|
|
3195
|
+
reasons: {
|
|
3196
|
+
type: "string",
|
|
3197
|
+
description: "security-blocked only: the triage's fail-closed reason string (empty/omitted \u21D2 the no-reason wording)"
|
|
3198
|
+
}
|
|
3199
|
+
},
|
|
3200
|
+
run: ({ args }) => {
|
|
3201
|
+
const kind = isNoticeKind(args.kind) ? args.kind : fail(
|
|
3202
|
+
`Unknown notice kind "${args.kind}" \u2014 expected one of: security-blocked, setup-failed, diff-apply-failed, no-output`
|
|
3203
|
+
);
|
|
3204
|
+
process.stdout.write(`${JSON.stringify(buildNoticeEnvelope(kind, args.reasons), null, 2)}
|
|
3205
|
+
`);
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3128
3208
|
var isExtractSchemaKind = (s) => s === "findings" || s === "triage";
|
|
3129
3209
|
var requireExtractSchemaKind = (name) => isExtractSchemaKind(name) ? name : fail(`Unknown kind "${name}" for extract \u2014 expected one of: findings, triage`);
|
|
3130
3210
|
var failClosedTriage = (outcome) => ({
|
|
@@ -3728,6 +3808,7 @@ var main = defineCommand({
|
|
|
3728
3808
|
validate: validateCmd,
|
|
3729
3809
|
"seed-draft": seedDraftCmd,
|
|
3730
3810
|
adapt: adaptCmd,
|
|
3811
|
+
notice: noticeCmd,
|
|
3731
3812
|
extract: extractCmd,
|
|
3732
3813
|
"validate-patches": validatePatchesCmd,
|
|
3733
3814
|
"print-schema": printSchemaCmd,
|