@clearlydev/nx-archweave 0.3.2 → 0.4.0
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/bin/review-verdict.js +8 -249
- package/dist/eslint/index.js +28 -321
- package/dist/generators/_chunks/chunk-2WSX5YNB.js +274 -0
- package/dist/generators/_chunks/chunk-34V6HAJT.js +55 -0
- package/dist/generators/_chunks/chunk-3A6RZUCZ.js +114 -0
- package/dist/generators/_chunks/chunk-47T7NOPP.js +30 -0
- package/dist/generators/_chunks/chunk-4FJ7CLEU.js +189 -0
- package/dist/generators/_chunks/chunk-5MI3O4VZ.js +99 -0
- package/dist/generators/_chunks/chunk-6ZTIUBB2.js +139 -0
- package/dist/generators/_chunks/chunk-AIJCJ7JK.js +203 -0
- package/dist/generators/_chunks/chunk-ALSXKTLM.js +1098 -0
- package/dist/generators/_chunks/chunk-AQHV7DJS.js +656 -0
- package/dist/generators/_chunks/chunk-C2VVUWBA.js +386 -0
- package/dist/generators/_chunks/chunk-EXYZLL7A.js +234 -0
- package/dist/generators/_chunks/chunk-FQHFT5IH.js +50 -0
- package/dist/generators/_chunks/chunk-H222FPLK.js +80 -0
- package/dist/generators/_chunks/chunk-IIDOBI42.js +616 -0
- package/dist/generators/_chunks/chunk-L2RZ2LBO.js +132 -0
- package/dist/generators/_chunks/chunk-MQNQJOWA.js +217 -0
- package/dist/generators/_chunks/chunk-QQNDYJTR.js +243 -0
- package/dist/generators/_chunks/chunk-SFXU6IUS.js +0 -0
- package/dist/generators/_chunks/chunk-SNBIVIMI.js +89 -0
- package/dist/generators/_chunks/chunk-TUN34LAQ.js +8 -0
- package/dist/generators/_chunks/chunk-TXAQ2GJC.js +20 -0
- package/dist/generators/_chunks/chunk-U6LAFHSF.js +49 -0
- package/dist/generators/_chunks/chunk-URV6FLUH.js +73 -0
- package/dist/generators/_chunks/chunk-YNMLB4DL.js +25 -0
- package/dist/generators/_chunks/chunk-YY2UESLM.js +282 -0
- package/dist/generators/add-agent-rules/generator.js +11 -842
- package/dist/generators/add-backend/generator.js +11 -906
- package/dist/generators/add-fsd-lite/generator.js +12 -801
- package/dist/generators/add-github-templates/generator.js +13 -116
- package/dist/generators/add-integration/generator.js +15 -743
- package/dist/generators/add-review/generator.js +12 -1231
- package/dist/generators/allow-builds/generator.js +7 -71
- package/dist/generators/doctor/generator.js +106 -2044
- package/dist/generators/entity/generator.js +15 -604
- package/dist/generators/feature/generator.js +15 -604
- package/dist/generators/init/generator.js +68 -3376
- package/dist/generators/install-integration/generator.js +35 -871
- package/dist/generators/page/generator.js +15 -604
- package/dist/generators/record-integration/generator.js +12 -778
- package/dist/generators/shared/generator.js +15 -604
- package/dist/generators/widget/generator.js +15 -604
- package/dist/index.js +5 -663
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -209,7 +209,7 @@ Review is fully optional and isn't tied to one provider.
|
|
|
209
209
|
|
|
210
210
|
- If review is disabled, zero review artifacts are generated.
|
|
211
211
|
- If review is enabled, the workflow **green-skips** (it never fails) until you register the provider's secret.
|
|
212
|
-
- A round marker stops the workflow after `--maxRounds` reviews per PR (1–5, default 3).
|
|
212
|
+
- A round marker stops the workflow after `--maxRounds` reviews per PR (1–5, default 3). A later commit has no AI verdict, so the `review` check fails on it; merge it with your branch ruleset's bypass.
|
|
213
213
|
|
|
214
214
|
| `--provider` | Workflow file | Required secret |
|
|
215
215
|
| --- | --- | --- |
|
|
@@ -1,257 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import "../generators/_chunks/chunk-SFXU6IUS.js";
|
|
3
|
+
import {
|
|
4
|
+
VERDICT_MARKER,
|
|
5
|
+
runVerdictGate
|
|
6
|
+
} from "../generators/_chunks/chunk-ALSXKTLM.js";
|
|
2
7
|
|
|
3
8
|
// src/bin/review-verdict.ts
|
|
4
9
|
import { spawnSync } from "node:child_process";
|
|
5
10
|
import { randomBytes } from "node:crypto";
|
|
6
11
|
import { appendFileSync, realpathSync } from "node:fs";
|
|
7
|
-
|
|
8
|
-
// ../review-policy/dist/schema/review-finding.js
|
|
9
|
-
function computeVerdict(findings) {
|
|
10
|
-
if (findings.some((f) => f.priority === "P0" || f.priority === "P1"))
|
|
11
|
-
return "BLOCK";
|
|
12
|
-
if (findings.some((f) => f.priority === "P2"))
|
|
13
|
-
return "CHANGES_RECOMMENDED";
|
|
14
|
-
if (findings.length > 0)
|
|
15
|
-
return "APPROVE_WITH_NOTES";
|
|
16
|
-
return "APPROVE";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// ../review-policy/dist/verdict-gate/findings-block.js
|
|
20
|
-
var FINDINGS_MARKER = "<!-- archweave-findings-v1 -->";
|
|
21
|
-
var FINDINGS_SCHEMA_ID = "archweave/findings@1";
|
|
22
|
-
var PRIORITIES = ["P0", "P1", "P2", "P3", "Nit"];
|
|
23
|
-
function findingKey(f) {
|
|
24
|
-
return `${f.file}:${f.lineRange.start}:${f.category}`;
|
|
25
|
-
}
|
|
26
|
-
function extractFindingsBlock(commentBody) {
|
|
27
|
-
const markerIndex = commentBody.lastIndexOf(FINDINGS_MARKER);
|
|
28
|
-
if (markerIndex === -1)
|
|
29
|
-
return { status: "missing" };
|
|
30
|
-
const after = commentBody.slice(markerIndex + FINDINGS_MARKER.length);
|
|
31
|
-
const open = /```json[ \t]*\r?\n/.exec(after);
|
|
32
|
-
if (!open)
|
|
33
|
-
return { status: "invalid" };
|
|
34
|
-
const contentStart = open.index + open[0].length;
|
|
35
|
-
let parsed;
|
|
36
|
-
let found = false;
|
|
37
|
-
for (let close = after.indexOf("```", contentStart); close !== -1; close = after.indexOf("```", close + 3)) {
|
|
38
|
-
try {
|
|
39
|
-
parsed = JSON.parse(after.slice(contentStart, close));
|
|
40
|
-
found = true;
|
|
41
|
-
break;
|
|
42
|
-
} catch {
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (!found)
|
|
46
|
-
return { status: "invalid" };
|
|
47
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
48
|
-
return { status: "invalid" };
|
|
49
|
-
const obj = parsed;
|
|
50
|
-
if (obj.schema !== FINDINGS_SCHEMA_ID || !Array.isArray(obj.findings))
|
|
51
|
-
return { status: "invalid" };
|
|
52
|
-
const findings = [];
|
|
53
|
-
for (const raw of obj.findings) {
|
|
54
|
-
const finding = normalizeFinding(raw);
|
|
55
|
-
if (finding === null)
|
|
56
|
-
return { status: "invalid" };
|
|
57
|
-
findings.push(finding);
|
|
58
|
-
}
|
|
59
|
-
return { status: "ok", findings };
|
|
60
|
-
}
|
|
61
|
-
function normalizeFinding(raw) {
|
|
62
|
-
if (raw === null || typeof raw !== "object")
|
|
63
|
-
return null;
|
|
64
|
-
const r = raw;
|
|
65
|
-
const lineRange = r["lineRange"];
|
|
66
|
-
if (!PRIORITIES.includes(r["priority"]) || typeof r["category"] !== "string" || typeof r["title"] !== "string" || typeof r["file"] !== "string" || lineRange === null || lineRange === void 0 || typeof lineRange !== "object" || typeof lineRange.start !== "number" || !Number.isInteger(lineRange.start) || lineRange.start < 1) {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
const str = (value) => typeof value === "string" ? value : "";
|
|
70
|
-
return {
|
|
71
|
-
priority: r["priority"],
|
|
72
|
-
category: r["category"],
|
|
73
|
-
title: r["title"],
|
|
74
|
-
file: r["file"],
|
|
75
|
-
lineRange: { start: lineRange.start, ...typeof lineRange.end === "number" ? { end: lineRange.end } : {} },
|
|
76
|
-
evidence: str(r["evidence"]),
|
|
77
|
-
impact: str(r["impact"]),
|
|
78
|
-
reproductionCondition: str(r["reproductionCondition"]),
|
|
79
|
-
recommendation: str(r["recommendation"]),
|
|
80
|
-
confidence: r["confidence"] === "plausible" ? "plausible" : "confirmed"
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ../review-policy/dist/renderers/render-review-comment.js
|
|
85
|
-
var COPY = {
|
|
86
|
-
en: {
|
|
87
|
-
terminationBanner: (maxRounds) => `> \u26A0\uFE0F **Automated review ended.** The maximum of ${maxRounds} review rounds has been reached with blocking findings (P0/P1) still open. Later pushes aren't reviewed by AI, so review them yourself before merging.`,
|
|
88
|
-
verdictLines: {
|
|
89
|
-
BLOCK: "**Verdict: BLOCK** \u2014 P0/P1 findings must be resolved before this change can merge.",
|
|
90
|
-
CHANGES_RECOMMENDED: "**Verdict: CHANGES_RECOMMENDED** \u2014 P2 findings should be addressed.",
|
|
91
|
-
APPROVE_WITH_NOTES: "**Verdict: APPROVE_WITH_NOTES** \u2014 only advisory notes below; safe to merge.",
|
|
92
|
-
APPROVE: "**Verdict: APPROVE** \u2014 no findings."
|
|
93
|
-
},
|
|
94
|
-
mainSection: "## Correctness & Security",
|
|
95
|
-
overEngineeringSection: "## Over-engineering",
|
|
96
|
-
nitSection: "## Nits",
|
|
97
|
-
roundHistoryHeading: "**Round history:**",
|
|
98
|
-
roundLine: (round, fixed, remaining) => `- round ${round}: ${fixed} fixed, ${remaining} remaining`,
|
|
99
|
-
fieldLabels: {
|
|
100
|
-
file: "File",
|
|
101
|
-
evidence: "Evidence",
|
|
102
|
-
impact: "Impact",
|
|
103
|
-
reproduction: "Reproduction",
|
|
104
|
-
recommendation: "Recommendation",
|
|
105
|
-
confidence: "Confidence"
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
ko: {
|
|
109
|
-
terminationBanner: (maxRounds) => `> \u26A0\uFE0F **\uC790\uB3D9 \uB9AC\uBDF0 \uC885\uB8CC.** \uCD5C\uB300 ${maxRounds}\uD68C\uC758 \uB9AC\uBDF0 \uB77C\uC6B4\uB4DC\uC5D0 \uB3C4\uB2EC\uD588\uC9C0\uB9CC \uBCD1\uD569\uC744 \uB9C9\uB294 finding(P0/P1)\uC774 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4. \uC774\uD6C4 push\uB294 AI\uAC00 \uB9AC\uBDF0\uD558\uC9C0 \uC54A\uC73C\uB2C8, \uBCD1\uD569 \uC804\uC5D0 \uC9C1\uC811 \uB9AC\uBDF0\uD558\uC138\uC694.`,
|
|
110
|
-
verdictLines: {
|
|
111
|
-
BLOCK: "**\uD310\uC815: BLOCK** \u2014 \uBCD1\uD569 \uC804\uC5D0 P0/P1 finding\uC744 \uD574\uACB0\uD574\uC57C \uD569\uB2C8\uB2E4.",
|
|
112
|
-
CHANGES_RECOMMENDED: "**\uD310\uC815: CHANGES_RECOMMENDED** \u2014 P2 finding\uC744 \uD574\uACB0\uD558\uB294 \uAC83\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
113
|
-
APPROVE_WITH_NOTES: "**\uD310\uC815: APPROVE_WITH_NOTES** \u2014 \uCC38\uACE0\uC6A9 \uB178\uD2B8\uB9CC \uC788\uC2B5\uB2C8\uB2E4. \uBCD1\uD569\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4.",
|
|
114
|
-
APPROVE: "**\uD310\uC815: APPROVE** \u2014 finding\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
115
|
-
},
|
|
116
|
-
mainSection: "## \uC815\uD655\uC131 & \uBCF4\uC548",
|
|
117
|
-
overEngineeringSection: "## \uACFC\uC789 \uC124\uACC4",
|
|
118
|
-
nitSection: "## \uC0AC\uC18C\uD55C \uC9C0\uC801 (Nit)",
|
|
119
|
-
roundHistoryHeading: "**\uB77C\uC6B4\uB4DC \uC774\uB825:**",
|
|
120
|
-
roundLine: (round, fixed, remaining) => `- ${round}\uB77C\uC6B4\uB4DC: \uD574\uACB0 ${fixed}\uAC74, \uBBF8\uD574\uACB0 ${remaining}\uAC74`,
|
|
121
|
-
fieldLabels: {
|
|
122
|
-
file: "\uD30C\uC77C",
|
|
123
|
-
evidence: "\uADFC\uAC70",
|
|
124
|
-
impact: "\uC601\uD5A5",
|
|
125
|
-
reproduction: "\uC7AC\uD604 \uC870\uAC74",
|
|
126
|
-
recommendation: "\uAD8C\uC7A5 \uC870\uCE58",
|
|
127
|
-
confidence: "\uD655\uC2E0\uB3C4"
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
function verdictLine(verdict, locale) {
|
|
132
|
-
return COPY[locale].verdictLines[verdict];
|
|
133
|
-
}
|
|
134
|
-
function terminationBannerLine(maxRounds, locale) {
|
|
135
|
-
return COPY[locale].terminationBanner(maxRounds);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ../review-policy/dist/verdict-gate/verdict-comment.js
|
|
139
|
-
var VERDICT_MARKER = "<!-- archweave-verdict -->";
|
|
140
|
-
var HISTORY_HEADING = { en: "**Round history:**", ko: "**\uB77C\uC6B4\uB4DC \uC774\uB825:**" };
|
|
141
|
-
var ROUND_LINE = {
|
|
142
|
-
en: (round, fixed, remaining) => `- round ${round}: ${fixed} fixed, ${remaining} remaining`,
|
|
143
|
-
ko: (round, fixed, remaining) => `- ${round}\uCC28: ${fixed}\uAC74 \uD574\uACB0, ${remaining}\uAC74 \uC794\uC874`
|
|
144
|
-
};
|
|
145
|
-
var UNPARSEABLE_NOTICE = {
|
|
146
|
-
en: "\u26A0\uFE0F The review comment could not be machine-read (missing or invalid findings block). The verdict gate stays green; please review this PR manually.",
|
|
147
|
-
ko: "\u26A0\uFE0F \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uAE30\uACC4 \uD310\uB3C5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(findings \uBE14\uB85D \uB204\uB77D \uB610\uB294 \uC190\uC0C1). verdict \uAC8C\uC774\uD2B8\uB294 \uB179\uC0C9\uC73C\uB85C \uB450\uB2C8 \uC774 PR\uC740 \uC0AC\uB78C\uC774 \uC9C1\uC811 \uB9AC\uBDF0\uD574 \uC8FC\uC138\uC694."
|
|
148
|
-
};
|
|
149
|
-
var NO_ROUND_NOTICE = {
|
|
150
|
-
en: "\u26A0\uFE0F This run of the review posted no summary comment for the current commit, so there is no verdict for it (an earlier round is never reused). The verdict gate stays green; please review this PR manually.",
|
|
151
|
-
ko: "\u26A0\uFE0F \uC774\uBC88 \uB9AC\uBDF0 \uC2E4\uD589\uC774 \uD604\uC7AC \uCEE4\uBC0B\uC5D0 \uB300\uD55C \uC694\uC57D \uCF54\uBA58\uD2B8\uB97C \uAC8C\uC2DC\uD558\uC9C0 \uC54A\uC544 verdict\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(\uC774\uC804 \uB77C\uC6B4\uB4DC\uB294 \uC7AC\uC0AC\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4). verdict \uAC8C\uC774\uD2B8\uB294 \uB179\uC0C9\uC73C\uB85C \uB450\uB2C8 \uC774 PR\uC740 \uC0AC\uB78C\uC774 \uC9C1\uC811 \uB9AC\uBDF0\uD574 \uC8FC\uC138\uC694."
|
|
152
|
-
};
|
|
153
|
-
var NO_SUMMARY_NOTICE = {
|
|
154
|
-
en: "\u26D4 AI review posted no summary for this commit, so there is no verdict for it and the review check fails. Review this PR manually, or re-run all jobs to review it again.",
|
|
155
|
-
ko: "\u26D4 AI \uB9AC\uBDF0\uAC00 \uC774 \uCEE4\uBC0B\uC5D0 \uB300\uD55C \uC694\uC57D\uC744 \uAC8C\uC2DC\uD558\uC9C0 \uC54A\uC544 verdict\uAC00 \uC5C6\uACE0, review \uCCB4\uD06C\uB294 \uC2E4\uD328\uD569\uB2C8\uB2E4. \uC774 PR\uC744 \uC9C1\uC811 \uB9AC\uBDF0\uD558\uAC70\uB098, \uBAA8\uB4E0 \uC7A1\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uB2E4\uC2DC \uB9AC\uBDF0\uBC1B\uC73C\uC138\uC694."
|
|
156
|
-
};
|
|
157
|
-
var UNREADABLE_SUMMARY_NOTICE = {
|
|
158
|
-
en: "\u26D4 AI review posted a summary whose findings block could not be machine-read (missing or invalid), so there is no verdict for this commit and the review check fails. Review this PR manually, or re-run all jobs to review it again.",
|
|
159
|
-
ko: "\u26D4 AI \uB9AC\uBDF0 \uC694\uC57D\uC758 findings \uBE14\uB85D\uC744 \uAE30\uACC4 \uD310\uB3C5\uD558\uC9C0 \uBABB\uD574(\uB204\uB77D \uB610\uB294 \uC190\uC0C1) \uC774 \uCEE4\uBC0B\uC758 verdict\uAC00 \uC5C6\uACE0, review \uCCB4\uD06C\uB294 \uC2E4\uD328\uD569\uB2C8\uB2E4. \uC774 PR\uC744 \uC9C1\uC811 \uB9AC\uBDF0\uD558\uAC70\uB098, \uBAA8\uB4E0 \uC7A1\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uB2E4\uC2DC \uB9AC\uBDF0\uBC1B\uC73C\uC138\uC694."
|
|
160
|
-
};
|
|
161
|
-
function renderCommitLine(locale, shortSha) {
|
|
162
|
-
return locale === "en" ? `<sub>Commit \`${shortSha}\` \xB7 this comment is updated on every review round.</sub>` : `<sub>\uCEE4\uBC0B \`${shortSha}\` \xB7 \uC774 \uCF54\uBA58\uD2B8\uB294 \uB9AC\uBDF0 \uB77C\uC6B4\uB4DC\uB9C8\uB2E4 \uAC31\uC2E0\uB429\uB2C8\uB2E4.</sub>`;
|
|
163
|
-
}
|
|
164
|
-
var HEAD_LINE = {
|
|
165
|
-
en: (sha) => renderCommitLine("en", sha.slice(0, 7)),
|
|
166
|
-
ko: (sha) => renderCommitLine("ko", sha.slice(0, 7))
|
|
167
|
-
};
|
|
168
|
-
function withHead(lines, locale, headSha) {
|
|
169
|
-
return (headSha === void 0 ? lines : [...lines, "", HEAD_LINE[locale](headSha)]).join("\n");
|
|
170
|
-
}
|
|
171
|
-
function renderUnparseableNotice(locale, headSha, failClosed = false) {
|
|
172
|
-
return withHead([VERDICT_MARKER, (failClosed ? UNREADABLE_SUMMARY_NOTICE : UNPARSEABLE_NOTICE)[locale]], locale, headSha);
|
|
173
|
-
}
|
|
174
|
-
function renderNoSummaryNotice(locale, headSha) {
|
|
175
|
-
return withHead([VERDICT_MARKER, NO_SUMMARY_NOTICE[locale]], locale, headSha);
|
|
176
|
-
}
|
|
177
|
-
function renderNoRoundNotice(locale, headSha) {
|
|
178
|
-
return withHead([VERDICT_MARKER, NO_ROUND_NOTICE[locale]], locale, headSha);
|
|
179
|
-
}
|
|
180
|
-
function renderVerdictComment(input) {
|
|
181
|
-
const lines = [VERDICT_MARKER];
|
|
182
|
-
if (input.isFinalRound && input.verdict === "BLOCK") {
|
|
183
|
-
lines.push(terminationBannerLine(input.maxRounds, input.locale), "");
|
|
184
|
-
}
|
|
185
|
-
lines.push(verdictLine(input.verdict, input.locale));
|
|
186
|
-
if (input.history.length > 1) {
|
|
187
|
-
lines.push("", HISTORY_HEADING[input.locale]);
|
|
188
|
-
for (let i = 0; i < input.history.length; i++) {
|
|
189
|
-
if (i === 0)
|
|
190
|
-
continue;
|
|
191
|
-
const entry = input.history[i];
|
|
192
|
-
lines.push(ROUND_LINE[input.locale](entry.round, entry.fixedFindingKeys.length, entry.remainingFindingKeys.length));
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return withHead(lines, input.locale, input.headSha);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// ../review-policy/dist/verdict-gate/verdict-gate.js
|
|
199
|
-
var ROUND_MARKER = "<!-- archweave-review-round -->";
|
|
200
|
-
function collectRounds(comments) {
|
|
201
|
-
return comments.filter((c) => c.body.includes(ROUND_MARKER) && !c.body.includes(VERDICT_MARKER)).map((c, index) => ({ round: index + 1, id: c.id, extraction: extractFindingsBlock(c.body) }));
|
|
202
|
-
}
|
|
203
|
-
var LINE_DRIFT = 3;
|
|
204
|
-
function sameDefect(a, b) {
|
|
205
|
-
if (a.file !== b.file)
|
|
206
|
-
return false;
|
|
207
|
-
const aEnd = a.lineRange.end ?? a.lineRange.start;
|
|
208
|
-
const bEnd = b.lineRange.end ?? b.lineRange.start;
|
|
209
|
-
return a.lineRange.start <= bEnd + LINE_DRIFT && b.lineRange.start <= aEnd + LINE_DRIFT;
|
|
210
|
-
}
|
|
211
|
-
function computeRoundHistory(rounds) {
|
|
212
|
-
const parsed = rounds.filter((r) => r.extraction.status === "ok");
|
|
213
|
-
const history = [];
|
|
214
|
-
for (let i = 0; i < parsed.length; i++) {
|
|
215
|
-
const keys = new Set(parsed[i].extraction.findings.map(findingKey));
|
|
216
|
-
if (i === 0) {
|
|
217
|
-
history.push({ round: parsed[i].round, fixedFindingKeys: [], remainingFindingKeys: [...keys] });
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
const current = parsed[i].extraction.findings;
|
|
221
|
-
history.push({
|
|
222
|
-
round: parsed[i].round,
|
|
223
|
-
fixedFindingKeys: parsed[i - 1].extraction.findings.filter((finding) => !current.some((now) => sameDefect(finding, now))).map(findingKey),
|
|
224
|
-
remainingFindingKeys: [...keys]
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
return history;
|
|
228
|
-
}
|
|
229
|
-
function runVerdictGate(input) {
|
|
230
|
-
const rounds = collectRounds(input.comments);
|
|
231
|
-
const reviewRan = input.reviewRan === true;
|
|
232
|
-
if (rounds.length === 0) {
|
|
233
|
-
return reviewRan ? { kind: "no-summary", commentBody: renderNoSummaryNotice(input.locale, input.headSha) } : { kind: "no-review" };
|
|
234
|
-
}
|
|
235
|
-
const latest = rounds[rounds.length - 1];
|
|
236
|
-
if (input.roundAfterId !== void 0 && (latest.id === void 0 || latest.id <= input.roundAfterId)) {
|
|
237
|
-
return reviewRan ? { kind: "no-summary", commentBody: renderNoSummaryNotice(input.locale, input.headSha) } : { kind: "no-round", commentBody: renderNoRoundNotice(input.locale, input.headSha) };
|
|
238
|
-
}
|
|
239
|
-
if (latest.extraction.status !== "ok") {
|
|
240
|
-
return { kind: "unparseable", commentBody: renderUnparseableNotice(input.locale, input.headSha, reviewRan), failClosed: reviewRan };
|
|
241
|
-
}
|
|
242
|
-
const verdict = computeVerdict(latest.extraction.findings);
|
|
243
|
-
const commentBody = renderVerdictComment({
|
|
244
|
-
verdict,
|
|
245
|
-
history: computeRoundHistory(rounds),
|
|
246
|
-
maxRounds: input.maxRounds,
|
|
247
|
-
locale: input.locale,
|
|
248
|
-
isFinalRound: rounds.length >= input.maxRounds,
|
|
249
|
-
headSha: input.headSha
|
|
250
|
-
});
|
|
251
|
-
return { kind: "verdict", verdict, commentBody, exitCode: verdict === "BLOCK" ? 1 : 0 };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// src/bin/review-verdict.ts
|
|
255
12
|
var realExec = (command, args, stdin) => {
|
|
256
13
|
const result = spawnSync(command, args, { encoding: "utf-8", input: stdin });
|
|
257
14
|
return { status: result.status ?? null, stdout: result.stdout ?? "" };
|
|
@@ -276,13 +33,16 @@ function renderStepOutputs(commentBody, previousId, blocked, reason) {
|
|
|
276
33
|
].join("\n");
|
|
277
34
|
}
|
|
278
35
|
var UNREAD_COMMENTS_ERROR = "::error title=Review verdict not computed::Could not read PR comments, so the verdict could not be computed. Re-run the failed jobs to retry. If it fails again, check that the review job has pull-requests: read.";
|
|
36
|
+
var MISCONFIGURED_ERROR = "::error title=Review verdict not computed::The verdict gate is missing GITHUB_REPOSITORY or ARCHWEAVE_PR_NUMBER, or ARCHWEAVE_MAX_ROUNDS is not a whole number from 1, so no verdict was computed. Regenerate the workflow with add-review --onConflict=overwrite if it was edited by hand.";
|
|
279
37
|
function runReviewVerdictBin(env, exec, writeOutput = realWriteOutput) {
|
|
280
38
|
const logs = [];
|
|
281
39
|
const repo = env["GITHUB_REPOSITORY"];
|
|
282
40
|
const pr = env["ARCHWEAVE_PR_NUMBER"];
|
|
283
41
|
const maxRounds = Number(env["ARCHWEAVE_MAX_ROUNDS"]);
|
|
284
42
|
const locale = env["ARCHWEAVE_LOCALE"] === "ko" ? "ko" : "en";
|
|
43
|
+
const outputPath = outputModePath(env);
|
|
285
44
|
if (!repo || !pr || !Number.isInteger(maxRounds) || maxRounds < 1) {
|
|
45
|
+
if (outputPath !== void 0) return { exitCode: 1, logs: [MISCONFIGURED_ERROR] };
|
|
286
46
|
logs.push("verdict gate: required environment missing or malformed \u2014 skipping (check stays green).");
|
|
287
47
|
return { exitCode: 0, logs };
|
|
288
48
|
}
|
|
@@ -290,7 +50,6 @@ function runReviewVerdictBin(env, exec, writeOutput = realWriteOutput) {
|
|
|
290
50
|
const roundAfterId = watermark !== void 0 && /^\d+$/.test(watermark) ? Number(watermark) : void 0;
|
|
291
51
|
const sha = env["ARCHWEAVE_HEAD_SHA"];
|
|
292
52
|
const headSha = sha !== void 0 && /^[0-9a-f]{7,40}$/i.test(sha) ? sha : void 0;
|
|
293
|
-
const outputPath = outputModePath(env);
|
|
294
53
|
const fetched = exec("gh", ["api", `repos/${repo}/issues/${pr}/comments`, "--paginate"]);
|
|
295
54
|
const pages = fetched.status === 0 ? splitConcatenatedJson(fetched.stdout) : null;
|
|
296
55
|
if (pages === null) {
|