@jphutchins/code-review 0.1.0-alpha.58 → 0.1.0-alpha.59
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/index.js +171 -192
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ npx @jphutchins/code-review <subcommand>
|
|
|
38
38
|
| Subcommand | What it does |
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| `post` | Post a complete review from findings + envelope + diff — the one-call path. The findings are listed in the sticky summary; `--inline` renders the in-diff ones as comments on the diff instead. Also renders the review into `$GITHUB_STEP_SUMMARY`: the sticky is overwritten each round, the run summary keeps each round as it stood |
|
|
41
|
-
| `gather` | Resolve the PR from the CI head SHA and gather the review inputs (diff with git-diff fallback, PR context, prior bot review, the prior review's answered-findings registry, failing-job logs) into the
|
|
41
|
+
| `gather` | Resolve the PR from the CI head SHA and gather the review inputs (diff with git-diff fallback, PR context, prior bot review, the prior review's answered-findings registry, failing-job logs) into the directory named by `--out-dir` (default: the current directory; the shipped workflows use `$RUNNER_TEMP/gather`) |
|
|
42
42
|
| `parse-command` | Resolve a PR's head from its number and parse a ChatOps trigger comment (`/code-review [24m] [$1.00] <instructions>`) into review overrides — the on-demand comment trigger |
|
|
43
43
|
| `react` | Add/remove a GitHub comment reaction — the ChatOps acknowledgement (👀 on receipt, 🚀 on completion) |
|
|
44
44
|
| `await-ci` | Wait for a PR head's CI run to conclude and emit its real conclusion + run id — so an on-demand comment review routes on the CI result (success → full, failure → mechanic) instead of reviewing blind |
|
package/dist/index.js
CHANGED
|
@@ -76,11 +76,16 @@ var UriString = t.refinement(
|
|
|
76
76
|
(s) => !/\s/.test(s) && URL.canParse(s),
|
|
77
77
|
"UriString"
|
|
78
78
|
);
|
|
79
|
+
var strictExact = (name, shape, members) => {
|
|
80
|
+
const keys = new Set(members.flatMap((m) => Object.keys(m.props)));
|
|
81
|
+
return t.exact(
|
|
82
|
+
t.refinement(shape, (x) => Object.keys(x).every((k) => keys.has(k)), name)
|
|
83
|
+
);
|
|
84
|
+
};
|
|
79
85
|
var RuleUrlCodec = t.partial({
|
|
80
86
|
code_url: UriString
|
|
81
87
|
});
|
|
82
|
-
var
|
|
83
|
-
id: t.string,
|
|
88
|
+
var FindingCoreRequired = t.type({
|
|
84
89
|
path: t.string,
|
|
85
90
|
start_line: LineNumber,
|
|
86
91
|
end_line: LineNumber,
|
|
@@ -91,28 +96,25 @@ var FindingRequired = t.type({
|
|
|
91
96
|
confidence: Confidence,
|
|
92
97
|
likelihood: Likelihood
|
|
93
98
|
});
|
|
99
|
+
var FindingIdRequired = t.type({ id: t.string });
|
|
94
100
|
var FindingOptional = t.partial({
|
|
95
101
|
side: SideCodec,
|
|
96
102
|
recommendation: t.string,
|
|
97
103
|
patch: t.string
|
|
98
104
|
});
|
|
99
|
-
var
|
|
100
|
-
var
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
var EndGeStart = (shape) => t.refinement(shape, (f) => f.end_line >= f.start_line, "EndGeStart");
|
|
106
|
+
var FindingShape = t.intersection([
|
|
107
|
+
FindingCoreRequired,
|
|
108
|
+
FindingIdRequired,
|
|
109
|
+
RuleUrlCodec,
|
|
110
|
+
FindingOptional
|
|
111
|
+
]);
|
|
112
|
+
var FindingCodec = strictExact("FindingStrict", EndGeStart(FindingShape), [
|
|
113
|
+
FindingCoreRequired,
|
|
114
|
+
FindingIdRequired,
|
|
115
|
+
RuleUrlCodec,
|
|
116
|
+
FindingOptional
|
|
109
117
|
]);
|
|
110
|
-
var FindingStrict = t.refinement(
|
|
111
|
-
EndGeStart,
|
|
112
|
-
(f) => Object.keys(f).every((k) => FINDING_KEYS.has(k)),
|
|
113
|
-
"FindingStrict"
|
|
114
|
-
);
|
|
115
|
-
var FindingCodec = t.exact(FindingStrict);
|
|
116
118
|
var SystemicRequired = t.type({
|
|
117
119
|
title: t.string,
|
|
118
120
|
description: t.string,
|
|
@@ -127,47 +129,34 @@ var SystemicOptional = t.partial({
|
|
|
127
129
|
paths: t.array(t.string)
|
|
128
130
|
});
|
|
129
131
|
var SystemicProblemShape = t.intersection([SystemicRequired, RuleUrlCodec, SystemicOptional]);
|
|
130
|
-
var
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
var SystemicProblemCodec = strictExact("SystemicProblemStrict", SystemicProblemShape, [
|
|
133
|
+
SystemicRequired,
|
|
134
|
+
RuleUrlCodec,
|
|
135
|
+
SystemicOptional
|
|
134
136
|
]);
|
|
135
|
-
var
|
|
136
|
-
|
|
137
|
-
(
|
|
138
|
-
"
|
|
137
|
+
var ConsecutiveRounds = t.refinement(
|
|
138
|
+
t.number,
|
|
139
|
+
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
140
|
+
"ConsecutiveRounds"
|
|
141
|
+
);
|
|
142
|
+
var StartRound = t.refinement(
|
|
143
|
+
t.number,
|
|
144
|
+
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
145
|
+
"StartRound"
|
|
139
146
|
);
|
|
140
|
-
var SystemicProblemCodec = t.exact(SystemicProblemStrict);
|
|
141
147
|
var RecurringShape = t.type({
|
|
142
148
|
id: t.string,
|
|
143
|
-
consecutive_rounds:
|
|
144
|
-
|
|
145
|
-
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
146
|
-
"ConsecutiveRounds"
|
|
147
|
-
),
|
|
148
|
-
start_round: t.refinement(
|
|
149
|
-
t.number,
|
|
150
|
-
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
151
|
-
"StartRound"
|
|
152
|
-
)
|
|
149
|
+
consecutive_rounds: ConsecutiveRounds,
|
|
150
|
+
start_round: StartRound
|
|
153
151
|
});
|
|
154
|
-
var
|
|
155
|
-
var RecurringCodec = t.refinement(
|
|
156
|
-
RecurringShape,
|
|
157
|
-
(r) => Object.keys(r).every((k) => RECURRING_KEYS.has(k)),
|
|
158
|
-
"RecurringStrict"
|
|
159
|
-
);
|
|
152
|
+
var RecurringCodec = strictExact("RecurringStrict", RecurringShape, [RecurringShape]);
|
|
160
153
|
var ScopeMetastasisShape = t.type({
|
|
161
154
|
decision_prompt: t.string,
|
|
162
155
|
recurring: t.array(RecurringCodec)
|
|
163
156
|
});
|
|
164
|
-
var
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
(s) => Object.keys(s).every((k) => SCOPE_METASTASIS_KEYS.has(k)),
|
|
168
|
-
"ScopeMetastasisStrict"
|
|
169
|
-
);
|
|
170
|
-
var ScopeMetastasisCodec = t.exact(ScopeMetastasisStrict);
|
|
157
|
+
var ScopeMetastasisCodec = strictExact("ScopeMetastasisStrict", ScopeMetastasisShape, [
|
|
158
|
+
ScopeMetastasisShape
|
|
159
|
+
]);
|
|
171
160
|
var RoundNumber = t.refinement(
|
|
172
161
|
t.number,
|
|
173
162
|
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
@@ -181,6 +170,7 @@ var idFrequencyCodec = (name) => new t.Type(
|
|
|
181
170
|
const entries = [];
|
|
182
171
|
for (const [k, v] of Object.entries(u)) {
|
|
183
172
|
if (typeof v !== "number" || !Number.isSafeInteger(v) || v < 0) return t.failure(v, c);
|
|
173
|
+
if (v === 0) continue;
|
|
184
174
|
entries.push([k, v]);
|
|
185
175
|
}
|
|
186
176
|
return t.success(Object.fromEntries(entries));
|
|
@@ -195,16 +185,10 @@ var ConvergenceRoundOptional = t.partial({
|
|
|
195
185
|
sha: t.string
|
|
196
186
|
});
|
|
197
187
|
var ConvergenceRoundShape = t.intersection([ConvergenceRoundRequired, ConvergenceRoundOptional]);
|
|
198
|
-
var
|
|
199
|
-
|
|
200
|
-
|
|
188
|
+
var ConvergenceRoundCodec = strictExact("ConvergenceRoundStrict", ConvergenceRoundShape, [
|
|
189
|
+
ConvergenceRoundRequired,
|
|
190
|
+
ConvergenceRoundOptional
|
|
201
191
|
]);
|
|
202
|
-
var ConvergenceRoundStrict = t.refinement(
|
|
203
|
-
ConvergenceRoundShape,
|
|
204
|
-
(r) => Object.keys(r).every((k) => CONVERGENCE_ROUND_KEYS.has(k)),
|
|
205
|
-
"ConvergenceRoundStrict"
|
|
206
|
-
);
|
|
207
|
-
var ConvergenceRoundCodec = t.exact(ConvergenceRoundStrict);
|
|
208
192
|
var ConvergenceCoreShape = t.type({
|
|
209
193
|
score: FiniteNumber,
|
|
210
194
|
threshold: FiniteNumber,
|
|
@@ -212,16 +196,10 @@ var ConvergenceCoreShape = t.type({
|
|
|
212
196
|
});
|
|
213
197
|
var ConvergenceOptional = t.partial({ rounds: t.array(ConvergenceRoundCodec) });
|
|
214
198
|
var ConvergenceShape = t.intersection([ConvergenceCoreShape, ConvergenceOptional]);
|
|
215
|
-
var
|
|
216
|
-
|
|
217
|
-
|
|
199
|
+
var ConvergenceCodec = strictExact("ConvergenceStrict", ConvergenceShape, [
|
|
200
|
+
ConvergenceCoreShape,
|
|
201
|
+
ConvergenceOptional
|
|
218
202
|
]);
|
|
219
|
-
var ConvergenceStrict = t.refinement(
|
|
220
|
-
ConvergenceShape,
|
|
221
|
-
(c) => Object.keys(c).every((k) => CONVERGENCE_KEYS.has(k)),
|
|
222
|
-
"ConvergenceStrict"
|
|
223
|
-
);
|
|
224
|
-
var ConvergenceCodec = t.exact(ConvergenceStrict);
|
|
225
203
|
var LineDelta = t.refinement(
|
|
226
204
|
t.number,
|
|
227
205
|
(n) => Number.isInteger(n) && n >= 0,
|
|
@@ -271,102 +249,66 @@ var usableCountsMap = (v) => {
|
|
|
271
249
|
);
|
|
272
250
|
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
273
251
|
};
|
|
252
|
+
var mergedCountsMaps = (ids, codes) => {
|
|
253
|
+
const idsMap = usableCountsMap(ids);
|
|
254
|
+
const codesMap = usableCountsMap(codes);
|
|
255
|
+
if (idsMap === void 0) return codesMap;
|
|
256
|
+
if (codesMap === void 0) return idsMap;
|
|
257
|
+
return { ...codesMap, ...idsMap };
|
|
258
|
+
};
|
|
274
259
|
var LegacyRuleCodec = t.partial({
|
|
275
260
|
code: t.string,
|
|
276
261
|
id: t.string,
|
|
277
262
|
code_url: UriString
|
|
278
263
|
});
|
|
279
|
-
var FindingShapeV09 = t.intersection([
|
|
280
|
-
|
|
281
|
-
path: t.string,
|
|
282
|
-
start_line: LineNumber,
|
|
283
|
-
end_line: LineNumber,
|
|
284
|
-
severity: SeverityCodec,
|
|
285
|
-
title: t.string,
|
|
286
|
-
description: t.string,
|
|
287
|
-
reasoning: t.string,
|
|
288
|
-
confidence: Confidence,
|
|
289
|
-
likelihood: Likelihood
|
|
290
|
-
}),
|
|
291
|
-
LegacyRuleCodec,
|
|
292
|
-
t.partial({
|
|
293
|
-
side: SideCodec,
|
|
294
|
-
recommendation: t.string,
|
|
295
|
-
patch: t.string
|
|
296
|
-
})
|
|
297
|
-
]);
|
|
298
|
-
var EndGeStartV09 = t.refinement(
|
|
299
|
-
FindingShapeV09,
|
|
300
|
-
(f) => f.end_line >= f.start_line,
|
|
301
|
-
"EndGeStartV09"
|
|
302
|
-
);
|
|
303
|
-
var FindingCodecV09 = t.exact(EndGeStartV09);
|
|
264
|
+
var FindingShapeV09 = t.intersection([FindingCoreRequired, LegacyRuleCodec, FindingOptional]);
|
|
265
|
+
var FindingCodecV09 = t.exact(EndGeStart(FindingShapeV09));
|
|
304
266
|
var SystemicV09Optional = t.partial({
|
|
305
267
|
finding_codes: t.array(t.string),
|
|
306
268
|
finding_ids: t.array(t.string),
|
|
307
269
|
paths: t.array(t.string)
|
|
308
270
|
});
|
|
309
271
|
var SystemicV09Shape = t.intersection([SystemicRequired, LegacyRuleCodec, SystemicV09Optional]);
|
|
310
|
-
var
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
]);
|
|
315
|
-
var SystemicV09Strict = t.refinement(
|
|
316
|
-
SystemicV09Shape,
|
|
317
|
-
(s) => Object.keys(s).every((k) => SYSTEMIC_V09_KEYS.has(k)),
|
|
318
|
-
"SystemicV09Strict"
|
|
319
|
-
);
|
|
320
|
-
var SystemicProblemCodecV09 = t.exact(SystemicV09Strict);
|
|
321
|
-
var RecurringV09Shape = t.intersection([
|
|
322
|
-
t.partial({ code: t.string, id: t.string }),
|
|
323
|
-
t.type({
|
|
324
|
-
consecutive_rounds: t.refinement(
|
|
325
|
-
t.number,
|
|
326
|
-
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
327
|
-
"ConsecutiveRoundsV09"
|
|
328
|
-
),
|
|
329
|
-
start_round: t.refinement(
|
|
330
|
-
t.number,
|
|
331
|
-
(n) => Number.isSafeInteger(n) && n >= 1,
|
|
332
|
-
"StartRoundV09"
|
|
333
|
-
)
|
|
334
|
-
})
|
|
272
|
+
var SystemicProblemCodecV09 = strictExact("SystemicV09Strict", SystemicV09Shape, [
|
|
273
|
+
SystemicRequired,
|
|
274
|
+
LegacyRuleCodec,
|
|
275
|
+
SystemicV09Optional
|
|
335
276
|
]);
|
|
277
|
+
var RecurringV09Identity = t.partial({ code: t.string, id: t.string });
|
|
278
|
+
var RecurringV09Counts = t.type({
|
|
279
|
+
consecutive_rounds: ConsecutiveRounds,
|
|
280
|
+
start_round: StartRound
|
|
281
|
+
});
|
|
282
|
+
var RecurringV09Shape = t.intersection([RecurringV09Identity, RecurringV09Counts]);
|
|
336
283
|
var ScopeMetastasisV09Shape = t.type({
|
|
337
284
|
decision_prompt: t.string,
|
|
338
285
|
recurring: t.array(RecurringV09Shape)
|
|
339
286
|
});
|
|
340
|
-
var
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
(s) => Object.keys(s).every((k) => SCOPE_METASTASIS_V09_KEYS.has(k)),
|
|
344
|
-
"ScopeMetastasisV09Strict"
|
|
345
|
-
);
|
|
346
|
-
var ScopeMetastasisCodecV09 = t.exact(ScopeMetastasisV09Strict);
|
|
287
|
+
var ScopeMetastasisCodecV09 = strictExact("ScopeMetastasisV09Strict", ScopeMetastasisV09Shape, [
|
|
288
|
+
ScopeMetastasisV09Shape
|
|
289
|
+
]);
|
|
347
290
|
var CodeFrequencyV09 = idFrequencyCodec("CodeFrequencyV09");
|
|
291
|
+
var ConvergenceRoundV09Optional = t.partial({
|
|
292
|
+
score: FiniteNumber,
|
|
293
|
+
codes: CodeFrequencyV09,
|
|
294
|
+
ids: CodeFrequencyV09,
|
|
295
|
+
sha: t.string
|
|
296
|
+
});
|
|
348
297
|
var ConvergenceRoundV09Shape = t.intersection([
|
|
349
|
-
|
|
350
|
-
|
|
298
|
+
ConvergenceRoundRequired,
|
|
299
|
+
ConvergenceRoundV09Optional
|
|
351
300
|
]);
|
|
352
|
-
var
|
|
353
|
-
|
|
301
|
+
var ConvergenceRoundCodecV09 = strictExact(
|
|
302
|
+
"ConvergenceRoundV09Strict",
|
|
354
303
|
ConvergenceRoundV09Shape,
|
|
355
|
-
|
|
356
|
-
"ConvergenceRoundV09Strict"
|
|
304
|
+
[ConvergenceRoundRequired, ConvergenceRoundV09Optional]
|
|
357
305
|
);
|
|
358
|
-
var
|
|
359
|
-
var ConvergenceV09Shape = t.intersection([
|
|
306
|
+
var ConvergenceV09Optional = t.partial({ rounds: t.array(ConvergenceRoundCodecV09) });
|
|
307
|
+
var ConvergenceV09Shape = t.intersection([ConvergenceCoreShape, ConvergenceV09Optional]);
|
|
308
|
+
var ConvergenceCodecV09 = strictExact("ConvergenceV09Strict", ConvergenceV09Shape, [
|
|
360
309
|
ConvergenceCoreShape,
|
|
361
|
-
|
|
310
|
+
ConvergenceV09Optional
|
|
362
311
|
]);
|
|
363
|
-
var CONVERGENCE_V09_KEYS = /* @__PURE__ */ new Set([...Object.keys(ConvergenceCoreShape.props), "rounds"]);
|
|
364
|
-
var ConvergenceV09Strict = t.refinement(
|
|
365
|
-
ConvergenceV09Shape,
|
|
366
|
-
(c) => Object.keys(c).every((k) => CONVERGENCE_V09_KEYS.has(k)),
|
|
367
|
-
"ConvergenceV09Strict"
|
|
368
|
-
);
|
|
369
|
-
var ConvergenceCodecV09 = t.exact(ConvergenceV09Strict);
|
|
370
312
|
var FindingsV09Shape = t.intersection([
|
|
371
313
|
t.type({
|
|
372
314
|
// Any pre-0.10 minor — the registry dispatches on major.minor before decoding, so the codec
|
|
@@ -419,7 +361,7 @@ var normalizeV09 = (doc) => {
|
|
|
419
361
|
converged: doc.convergence.converged,
|
|
420
362
|
...doc.convergence.rounds !== void 0 ? {
|
|
421
363
|
rounds: doc.convergence.rounds.map((r) => {
|
|
422
|
-
const ids =
|
|
364
|
+
const ids = mergedCountsMaps(r.ids, r.codes);
|
|
423
365
|
return {
|
|
424
366
|
round: r.round,
|
|
425
367
|
...r.score !== void 0 ? { score: r.score } : {},
|
|
@@ -490,26 +432,17 @@ var FlatModelPricesShape = t.type({
|
|
|
490
432
|
cache_read: NonNegativePrice,
|
|
491
433
|
cache_write: NonNegativePrice
|
|
492
434
|
});
|
|
493
|
-
var
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
(p) => Object.keys(p).every((k) => FLAT_PRICE_KEYS.has(k)),
|
|
497
|
-
"FlatModelPricesStrict"
|
|
498
|
-
);
|
|
499
|
-
var FlatModelPricesCodec = t.exact(FlatModelPricesStrict);
|
|
435
|
+
var FlatModelPricesCodec = strictExact("FlatModelPricesStrict", FlatModelPricesShape, [
|
|
436
|
+
FlatModelPricesShape
|
|
437
|
+
]);
|
|
500
438
|
var UTC_HHMM_RE = /^([01][0-9]|2[0-3]):[0-5][0-9]$/;
|
|
501
439
|
var UtcHHMM = t.refinement(t.string, (s) => UTC_HHMM_RE.test(s), "UtcHHMM");
|
|
502
|
-
var
|
|
503
|
-
|
|
440
|
+
var PriceSlotAnchor = t.type({ utc_from: UtcHHMM, utc_to: UtcHHMM });
|
|
441
|
+
var PriceSlotShape = t.intersection([PriceSlotAnchor, FlatModelPricesShape]);
|
|
442
|
+
var PriceSlotCodec = strictExact("PriceSlotStrict", PriceSlotShape, [
|
|
443
|
+
PriceSlotAnchor,
|
|
504
444
|
FlatModelPricesShape
|
|
505
445
|
]);
|
|
506
|
-
var PRICE_SLOT_KEYS = /* @__PURE__ */ new Set(["utc_from", "utc_to", ...Object.keys(FlatModelPricesShape.props)]);
|
|
507
|
-
var PriceSlotStrict = t.refinement(
|
|
508
|
-
PriceSlotShape,
|
|
509
|
-
(s) => Object.keys(s).every((k) => PRICE_SLOT_KEYS.has(k)),
|
|
510
|
-
"PriceSlotStrict"
|
|
511
|
-
);
|
|
512
|
-
var PriceSlotCodec = t.exact(PriceSlotStrict);
|
|
513
446
|
var NonEmptyPriceSlots = t.refinement(
|
|
514
447
|
t.array(PriceSlotCodec),
|
|
515
448
|
(a) => a.length >= 1,
|
|
@@ -518,16 +451,10 @@ var NonEmptyPriceSlots = t.refinement(
|
|
|
518
451
|
var SlottedRequired = t.type({ slots: NonEmptyPriceSlots });
|
|
519
452
|
var SlottedOptional = t.partial({ weekend_slots: NonEmptyPriceSlots });
|
|
520
453
|
var SlottedShape = t.intersection([SlottedRequired, SlottedOptional]);
|
|
521
|
-
var
|
|
522
|
-
|
|
523
|
-
|
|
454
|
+
var SlottedModelPricesCodec = strictExact("SlottedModelPricesStrict", SlottedShape, [
|
|
455
|
+
SlottedRequired,
|
|
456
|
+
SlottedOptional
|
|
524
457
|
]);
|
|
525
|
-
var SlottedModelPricesStrict = t.refinement(
|
|
526
|
-
SlottedShape,
|
|
527
|
-
(s) => Object.keys(s).every((k) => SLOTTED_KEYS.has(k)),
|
|
528
|
-
"SlottedModelPricesStrict"
|
|
529
|
-
);
|
|
530
|
-
var SlottedModelPricesCodec = t.exact(SlottedModelPricesStrict);
|
|
531
458
|
var ModelPricesCodec = t.union([FlatModelPricesCodec, SlottedModelPricesCodec]);
|
|
532
459
|
var PriceMapCodec = t.type({
|
|
533
460
|
_updated: t.string,
|
|
@@ -830,10 +757,13 @@ var isSeverityCounts = (u) => typeof u === "object" && u !== null && SEVERITIES.
|
|
|
830
757
|
var MAX_IDS_PER_ROUND = 8;
|
|
831
758
|
var hasId = (ids, code) => ids !== void 0 && Object.prototype.hasOwnProperty.call(ids, code);
|
|
832
759
|
var escapeCodeBackticks = (code) => code.replace(/`/g, "-").replace(/\r?\n/g, " ");
|
|
833
|
-
var normalizeIdCounts = (ids, priorCodes) => {
|
|
834
|
-
const entries = Object.entries(usableCountsMap(ids) ?? {});
|
|
760
|
+
var normalizeIdCounts = (ids, priorCodes, preferredKeys, preValidated = false) => {
|
|
761
|
+
const entries = Object.entries((preValidated ? ids : usableCountsMap(ids)) ?? {});
|
|
835
762
|
if (entries.length === 0) return void 0;
|
|
836
763
|
const sorted = entries.sort((a, b) => {
|
|
764
|
+
const aPreferred = preferredKeys?.has(a[0]) === true ? 1 : 0;
|
|
765
|
+
const bPreferred = preferredKeys?.has(b[0]) === true ? 1 : 0;
|
|
766
|
+
if (aPreferred !== bPreferred) return bPreferred - aPreferred;
|
|
837
767
|
if (b[1] !== a[1]) return b[1] - a[1];
|
|
838
768
|
const aPrior = hasId(priorCodes, a[0]) ? 1 : 0;
|
|
839
769
|
const bPrior = hasId(priorCodes, b[0]) ? 1 : 0;
|
|
@@ -853,7 +783,12 @@ var parseRounds = (body) => {
|
|
|
853
783
|
let priorCodes;
|
|
854
784
|
for (const u of decoded.filter(isSeverityCounts)) {
|
|
855
785
|
const rec = u;
|
|
856
|
-
const codes = normalizeIdCounts(
|
|
786
|
+
const codes = normalizeIdCounts(
|
|
787
|
+
mergedCountsMaps(rec["ids"], rec["codes"]),
|
|
788
|
+
priorCodes,
|
|
789
|
+
new Set(Object.keys(usableCountsMap(rec["ids"]) ?? {})),
|
|
790
|
+
true
|
|
791
|
+
);
|
|
857
792
|
priorCodes = codes;
|
|
858
793
|
const sha = rec["sha"];
|
|
859
794
|
const shaStr = typeof sha === "string" && sha !== "" ? sha : void 0;
|
|
@@ -1086,7 +1021,7 @@ var withLegacyConvergenceIds = (raw) => {
|
|
|
1086
1021
|
const mapped = rounds.map((r) => {
|
|
1087
1022
|
if (typeof r !== "object" || r === null) return r;
|
|
1088
1023
|
const round = r;
|
|
1089
|
-
const ids =
|
|
1024
|
+
const ids = mergedCountsMaps(round["ids"], round["codes"]);
|
|
1090
1025
|
if (ids === void 0) {
|
|
1091
1026
|
return round["ids"] !== void 0 || round["codes"] !== void 0 ? Object.fromEntries(Object.entries(round).filter(([k]) => k !== "ids" && k !== "codes")) : round;
|
|
1092
1027
|
}
|
|
@@ -1448,10 +1383,29 @@ var answeredRegistryFrom = (comments, botLogin) => {
|
|
|
1448
1383
|
}
|
|
1449
1384
|
return [...byKey.values()];
|
|
1450
1385
|
};
|
|
1451
|
-
var
|
|
1452
|
-
var
|
|
1453
|
-
var
|
|
1386
|
+
var isSynthesizedTitleMatch = (f, e) => isSynthesizedFindingId(e.code) && e.title === f.title;
|
|
1387
|
+
var matches = (resolvedId, f, e) => e.code === resolvedId || isSynthesizedTitleMatch(f, e);
|
|
1388
|
+
var VERBATIM_FIELDS = ["title", "description", "reasoning", "severity", "path", "patch"];
|
|
1389
|
+
var verbatimFieldEqual = (f, e, field) => field === "patch" ? (f.patch ?? null) === e.patch : f[field] === e[field];
|
|
1390
|
+
var isVerbatimReRaise = (f, e) => VERBATIM_FIELDS.every((field) => verbatimFieldEqual(f, e, field));
|
|
1391
|
+
var isAnsweredDrop = (resolvedId, f, e) => matches(resolvedId, f, e) && isVerbatimReRaise(f, e) && f.severity !== "critical";
|
|
1392
|
+
var verbatimMatchCount = (f, e) => VERBATIM_FIELDS.reduce((count, field) => count + (verbatimFieldEqual(f, e, field) ? 1 : 0), 0);
|
|
1454
1393
|
var answeredNoteKey = (f) => f.id !== "" ? f.id : `title:${f.title}`;
|
|
1394
|
+
var NO_TITLE_MATCH = { entry: void 0, score: -1 };
|
|
1395
|
+
var bestTitleMatch = (f, registry) => {
|
|
1396
|
+
let best;
|
|
1397
|
+
let bestScore = -1;
|
|
1398
|
+
for (const e of registry) {
|
|
1399
|
+
if (!isSynthesizedTitleMatch(f, e)) continue;
|
|
1400
|
+
const score = verbatimMatchCount(f, e);
|
|
1401
|
+
if (score > bestScore) {
|
|
1402
|
+
best = e;
|
|
1403
|
+
bestScore = score;
|
|
1404
|
+
if (score === VERBATIM_FIELDS.length) break;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return { entry: best, score: bestScore };
|
|
1408
|
+
};
|
|
1455
1409
|
var answeredNote = (e) => `Re-raised; prior answer at ${e.replyUrl} by ${e.replyAuthor} \u2014 cite the new evidence that invalidates it.`;
|
|
1456
1410
|
var applyAnswered = (findings, registry) => {
|
|
1457
1411
|
const kept = [];
|
|
@@ -1460,14 +1414,18 @@ var applyAnswered = (findings, registry) => {
|
|
|
1460
1414
|
const droppedFindingIds = [];
|
|
1461
1415
|
let droppedCount = 0;
|
|
1462
1416
|
for (const f of findings) {
|
|
1463
|
-
const
|
|
1417
|
+
const resolvedId = resolveFindingId(f);
|
|
1418
|
+
const idMatch = registry.find((e) => e.code === resolvedId);
|
|
1419
|
+
const { entry: titleMatch, score: titleScore } = idMatch === void 0 ? bestTitleMatch(f, registry) : NO_TITLE_MATCH;
|
|
1420
|
+
const entry = idMatch ?? titleMatch;
|
|
1464
1421
|
if (entry === void 0) {
|
|
1465
1422
|
kept.push(f);
|
|
1466
1423
|
continue;
|
|
1467
1424
|
}
|
|
1468
|
-
|
|
1425
|
+
const dropped = (idMatch !== void 0 ? isVerbatimReRaise(f, entry) : titleScore === VERBATIM_FIELDS.length) && f.severity !== "critical";
|
|
1426
|
+
if (dropped) {
|
|
1469
1427
|
droppedByEntry.set(entry.replyId, entry);
|
|
1470
|
-
droppedFindingIds.push(
|
|
1428
|
+
droppedFindingIds.push(resolvedId);
|
|
1471
1429
|
droppedCount += 1;
|
|
1472
1430
|
} else {
|
|
1473
1431
|
kept.push(f);
|
|
@@ -3181,30 +3139,44 @@ var priorIdsFrom = (doc) => {
|
|
|
3181
3139
|
});
|
|
3182
3140
|
return [...idsOf("findings", false), ...idsOf("systemic_problems", true)];
|
|
3183
3141
|
};
|
|
3142
|
+
var appendBestEffort = (path, label, body) => {
|
|
3143
|
+
if (path === void 0 || path === "") return;
|
|
3144
|
+
try {
|
|
3145
|
+
appendFileSync(path, body);
|
|
3146
|
+
} catch (err) {
|
|
3147
|
+
process.stderr.write(`Warning: could not write ${label}: ${errMsg(err)}
|
|
3148
|
+
`);
|
|
3149
|
+
}
|
|
3150
|
+
};
|
|
3151
|
+
var writePostedSignal = (value) => {
|
|
3152
|
+
appendBestEffort(
|
|
3153
|
+
process.env["GITHUB_OUTPUT"],
|
|
3154
|
+
"the posted signal to GITHUB_OUTPUT",
|
|
3155
|
+
`posted=${value ? "true" : "false"}
|
|
3156
|
+
`
|
|
3157
|
+
);
|
|
3158
|
+
};
|
|
3184
3159
|
var appendRunSummary = (summaryPath, body) => {
|
|
3185
3160
|
if (summaryPath === void 0 || summaryPath === "") return;
|
|
3186
3161
|
const rendered = body();
|
|
3187
|
-
|
|
3188
|
-
appendFileSync(summaryPath, `
|
|
3162
|
+
appendBestEffort(summaryPath, "the run summary", `
|
|
3189
3163
|
${rendered}
|
|
3190
3164
|
`);
|
|
3191
|
-
} catch (err) {
|
|
3192
|
-
process.stderr.write(`Warning: could not write the run summary: ${errMsg(err)}
|
|
3193
|
-
`);
|
|
3194
|
-
}
|
|
3195
3165
|
};
|
|
3196
|
-
var upsertSticky = async (repo, prNumber, existing, body, ghApi) => {
|
|
3166
|
+
var upsertSticky = async (repo, prNumber, existing, body, ghApi, signal = false) => {
|
|
3197
3167
|
if (existing !== null) {
|
|
3198
3168
|
const patched = await patchComment(repo, existing.id, body, ghApi);
|
|
3199
3169
|
process.stderr.write(
|
|
3200
3170
|
`Updated sticky comment #${String(existing.id)} on PR #${String(prNumber)}
|
|
3201
3171
|
`
|
|
3202
3172
|
);
|
|
3173
|
+
if (signal) writePostedSignal(true);
|
|
3203
3174
|
return { id: existing.id, url: patched?.html_url };
|
|
3204
3175
|
}
|
|
3205
3176
|
const posted = await postComment(repo, prNumber, body, ghApi);
|
|
3206
3177
|
process.stderr.write(`Posted new sticky comment on PR #${String(prNumber)}
|
|
3207
3178
|
`);
|
|
3179
|
+
if (signal && posted !== null) writePostedSignal(true);
|
|
3208
3180
|
return posted ? { id: posted.id, url: posted.html_url } : null;
|
|
3209
3181
|
};
|
|
3210
3182
|
var isBotReview = (r) => typeof r === "object" && r !== null && typeof r.id === "number" && typeof r.state === "string" && typeof r.user?.login === "string";
|
|
@@ -3327,6 +3299,7 @@ var post = async (input, ghApi = runGhApi, readArtifact = ghArtifactReader) => {
|
|
|
3327
3299
|
if (resolution.kind === "none") {
|
|
3328
3300
|
process.stderr.write(`No open PR for ${input.headSha} \u2014 nothing to post
|
|
3329
3301
|
`);
|
|
3302
|
+
writePostedSignal(false);
|
|
3330
3303
|
process.exit(0);
|
|
3331
3304
|
}
|
|
3332
3305
|
if (resolution.kind === "not-open") {
|
|
@@ -3334,6 +3307,7 @@ var post = async (input, ghApi = runGhApi, readArtifact = ghArtifactReader) => {
|
|
|
3334
3307
|
`PR #${String(resolution.prNumber)} for ${input.headSha} is not open (state: ${resolution.state}) \u2014 nothing to post
|
|
3335
3308
|
`
|
|
3336
3309
|
);
|
|
3310
|
+
writePostedSignal(false);
|
|
3337
3311
|
process.exit(0);
|
|
3338
3312
|
}
|
|
3339
3313
|
const prNumber = resolution.prNumber;
|
|
@@ -3374,6 +3348,7 @@ var post = async (input, ghApi = runGhApi, readArtifact = ghArtifactReader) => {
|
|
|
3374
3348
|
process.stderr.write(
|
|
3375
3349
|
message ?? "Review did not complete and the sticky already reflects a completed review \u2014 leaving it in place\n"
|
|
3376
3350
|
);
|
|
3351
|
+
writePostedSignal(true);
|
|
3377
3352
|
process.exit(0);
|
|
3378
3353
|
};
|
|
3379
3354
|
const logAnsweredDrops = () => {
|
|
@@ -3401,7 +3376,7 @@ ${dropNote}` : ""}`,
|
|
|
3401
3376
|
sticky.body
|
|
3402
3377
|
)
|
|
3403
3378
|
);
|
|
3404
|
-
await upsertSticky(input.repo, prNumber, sticky, body, ghApi);
|
|
3379
|
+
await upsertSticky(input.repo, prNumber, sticky, body, ghApi, true);
|
|
3405
3380
|
process.exit(0);
|
|
3406
3381
|
};
|
|
3407
3382
|
const prices = JSON.parse(readFileSync(input.pricesPath, "utf-8"));
|
|
@@ -3479,7 +3454,8 @@ ${dropNote}` : ""}`,
|
|
|
3479
3454
|
prNumber,
|
|
3480
3455
|
existingSticky,
|
|
3481
3456
|
renderNotice("The diff for this PR is empty \u2014 nothing to review.", discussion),
|
|
3482
|
-
ghApi
|
|
3457
|
+
ghApi,
|
|
3458
|
+
true
|
|
3483
3459
|
);
|
|
3484
3460
|
process.exit(0);
|
|
3485
3461
|
}
|
|
@@ -3492,7 +3468,8 @@ ${dropNote}` : ""}`,
|
|
|
3492
3468
|
prNumber,
|
|
3493
3469
|
existingSticky,
|
|
3494
3470
|
renderNotice(noticeMessageFor(findingsResult), discussion),
|
|
3495
|
-
ghApi
|
|
3471
|
+
ghApi,
|
|
3472
|
+
true
|
|
3496
3473
|
);
|
|
3497
3474
|
process.exit(0);
|
|
3498
3475
|
}
|
|
@@ -3617,7 +3594,7 @@ ${dropNote}` : ""}`,
|
|
|
3617
3594
|
orphanedUnresolvable: orphanResolveFailed
|
|
3618
3595
|
})
|
|
3619
3596
|
);
|
|
3620
|
-
await upsertSticky(input.repo, prNumber, existingSticky, body, ghApi);
|
|
3597
|
+
await upsertSticky(input.repo, prNumber, existingSticky, body, ghApi, true);
|
|
3621
3598
|
appendRunSummary(process.env["GITHUB_STEP_SUMMARY"], () => body);
|
|
3622
3599
|
if (inlineRequested) {
|
|
3623
3600
|
process.stderr.write(
|
|
@@ -3743,7 +3720,8 @@ ${dropNote}` : ""}`,
|
|
|
3743
3720
|
prNumber,
|
|
3744
3721
|
existingSticky,
|
|
3745
3722
|
renderBody(initialDisposition),
|
|
3746
|
-
ghApi
|
|
3723
|
+
ghApi,
|
|
3724
|
+
true
|
|
3747
3725
|
);
|
|
3748
3726
|
const priorInlineComments = await listPriorBotCommentIds(
|
|
3749
3727
|
input.repo,
|
|
@@ -5683,9 +5661,10 @@ var seedDraftCmd = defineCommand({
|
|
|
5683
5661
|
const resolved = resolvedPriorValue(strippedPrior);
|
|
5684
5662
|
const doc = resolved === null ? strippedPrior : {
|
|
5685
5663
|
...resolved,
|
|
5686
|
-
findings: answeredRegistry !== null && answeredRegistry.length > 0 ? resolved.findings.filter(
|
|
5687
|
-
|
|
5688
|
-
|
|
5664
|
+
findings: answeredRegistry !== null && answeredRegistry.length > 0 ? resolved.findings.filter((f) => {
|
|
5665
|
+
const resolvedId = resolveFindingId(f);
|
|
5666
|
+
return !answeredRegistry.some((e) => isAnsweredDrop(resolvedId, f, e));
|
|
5667
|
+
}) : resolved.findings
|
|
5689
5668
|
};
|
|
5690
5669
|
const carried = doc["scope_metastasis"];
|
|
5691
5670
|
if (ScopeMetastasisCodec.decode(carried)._tag === "Right") return doc;
|