@reneturcios/greenlight 0.3.9 → 0.3.11
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 +9 -2
- package/dist/ci-triage.d.ts +20 -0
- package/dist/ci-triage.js +47 -10
- package/dist/ci-triage.js.map +1 -1
- package/dist/claims.js +33 -0
- package/dist/claims.js.map +1 -1
- package/dist/cli.js +23 -2
- package/dist/cli.js.map +1 -1
- package/dist/digest.d.ts +212 -0
- package/dist/digest.js +541 -0
- package/dist/digest.js.map +1 -0
- package/dist/guard.d.ts +29 -1
- package/dist/guard.js +110 -23
- package/dist/guard.js.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/integrations/README.md +2 -1
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/digest.js
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo-level maintainer digest. The guard answers "what is wrong with THIS
|
|
3
|
+
* PR"; the digest answers "what needs my attention across my whole repo":
|
|
4
|
+
* PR races (two open PRs fixing one issue), claimed-by-other conflicts,
|
|
5
|
+
* stale claims, and assignment-gate conflicts.
|
|
6
|
+
*
|
|
7
|
+
* Four sections, all evidence-carrying, all degradable. A section that
|
|
8
|
+
* cannot be computed says so and why, never silently empty.
|
|
9
|
+
*
|
|
10
|
+
* API budget discipline (unauthenticated: 60 calls/hr): the digest is
|
|
11
|
+
* front-loaded with cheap list calls. Issue comments — the expensive part
|
|
12
|
+
* — are fetched ONLY for linked issues whose issue metadata shows
|
|
13
|
+
* comments > 0, and full timeline walks only happen for candidate stale
|
|
14
|
+
* claims, never for every issue. Each fetch step below names its own
|
|
15
|
+
* budget behavior.
|
|
16
|
+
*/
|
|
17
|
+
import { apiGet, fetchComments, fetchLinkedPRs, fetchContributing } from "./github.js";
|
|
18
|
+
import { parseGates } from "./gates.js";
|
|
19
|
+
import { detectClaims, isBotAuthor } from "./claims.js";
|
|
20
|
+
import { extractLinkedIssueNumbers, extractCrossRepoIssues, splitIssueClaims } from "./guard.js";
|
|
21
|
+
export const DIGEST_VERSION = "0.3.11";
|
|
22
|
+
/** Default cap for list fetches; --limit overrides. The true total is always reported. */
|
|
23
|
+
export const DEFAULT_DIGEST_LIMIT = 50;
|
|
24
|
+
/** A claim on an open issue with no open PR after this many days is stale. */
|
|
25
|
+
export const STALE_CLAIM_DAYS = 14;
|
|
26
|
+
/** At this age the suggested action flips from "nudge" to "release". */
|
|
27
|
+
export const RELEASE_CLAIM_DAYS = 30;
|
|
28
|
+
/* ------------------------------------------------------------------ */
|
|
29
|
+
/* Pure section builders */
|
|
30
|
+
/* ------------------------------------------------------------------ */
|
|
31
|
+
/**
|
|
32
|
+
* Issue keys a PR links to: same-repo closing links plus cross-repo
|
|
33
|
+
* closing references (guard's extractors, reused exactly).
|
|
34
|
+
*/
|
|
35
|
+
export function extractPRIssueKeys(pull, prOwner, prRepo) {
|
|
36
|
+
const out = [];
|
|
37
|
+
const seen = new Set();
|
|
38
|
+
for (const n of extractLinkedIssueNumbers(pull.title, pull.body, pull.headRef)) {
|
|
39
|
+
const label = `#${n}`;
|
|
40
|
+
if (!seen.has(label)) {
|
|
41
|
+
seen.add(label);
|
|
42
|
+
out.push({ owner: prOwner, repo: prRepo, number: n, label });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const r of extractCrossRepoIssues(pull.title, pull.body, prOwner, prRepo)) {
|
|
46
|
+
const label = `${r.owner}/${r.repo}#${r.number}`;
|
|
47
|
+
if (!seen.has(label.toLowerCase())) {
|
|
48
|
+
seen.add(label.toLowerCase());
|
|
49
|
+
out.push({ owner: r.owner, repo: r.repo, number: r.number, label });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/** Group open PRs by issue key; groups of 2+ are races. */
|
|
55
|
+
export function groupPRsByIssue(prs, prOwner, prRepo) {
|
|
56
|
+
const groups = new Map();
|
|
57
|
+
for (const pr of prs) {
|
|
58
|
+
for (const key of extractPRIssueKeys(pr, prOwner, prRepo)) {
|
|
59
|
+
const mapKey = `${key.owner.toLowerCase()}/${key.repo.toLowerCase()}#${key.number}`;
|
|
60
|
+
const g = groups.get(mapKey);
|
|
61
|
+
if (g) {
|
|
62
|
+
if (!g.prs.some((p) => p.number === pr.number))
|
|
63
|
+
g.prs.push(pr);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
groups.set(mapKey, { key, prs: [pr] });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return groups;
|
|
71
|
+
}
|
|
72
|
+
function earliestOf(items, by) {
|
|
73
|
+
let best = null;
|
|
74
|
+
for (const item of items) {
|
|
75
|
+
if (!best || by(item) < by(best))
|
|
76
|
+
best = item;
|
|
77
|
+
}
|
|
78
|
+
return best;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* One race: earliest claim (author + date) and earliest PR opened, with a
|
|
82
|
+
* one-line arbitration summary. Pure: issue comments and PR groups are
|
|
83
|
+
* injected.
|
|
84
|
+
*/
|
|
85
|
+
export function buildRace(group, issueTitle, issueUrl, comments, now = new Date()) {
|
|
86
|
+
const claims = detectClaims("", comments, now).filter((c) => !isBotAuthor(c.author));
|
|
87
|
+
claims.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
88
|
+
const first = claims[0] ?? null;
|
|
89
|
+
const firstPr = earliestOf(group.prs, (p) => p.createdAt) ?? group.prs[0];
|
|
90
|
+
const otherPrs = group.prs.filter((p) => p.number !== firstPr.number);
|
|
91
|
+
const arbitration = [
|
|
92
|
+
first
|
|
93
|
+
? `first claim: @${first.author} on ${first.createdAt.slice(0, 10)}`
|
|
94
|
+
: "no claim comments on this issue",
|
|
95
|
+
`first PR opened: #${firstPr.number} by @${firstPr.author} on ${firstPr.createdAt.slice(0, 10)}`,
|
|
96
|
+
otherPrs.length > 0
|
|
97
|
+
? `the other PR(s) duplicate effort: ${otherPrs.map((p) => `#${p.number} by @${p.author}`).join(", ")}`
|
|
98
|
+
: "no other PRs",
|
|
99
|
+
].join("; ");
|
|
100
|
+
return {
|
|
101
|
+
issue: group.key,
|
|
102
|
+
issueTitle,
|
|
103
|
+
issueUrl,
|
|
104
|
+
prs: [...group.prs].sort((a, b) => a.number - b.number),
|
|
105
|
+
earliestClaim: first
|
|
106
|
+
? { author: first.author, createdAt: first.createdAt, strength: first.strength, phrase: first.phrase }
|
|
107
|
+
: null,
|
|
108
|
+
arbitration,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Claimed-by-other conflicts: open PRs whose linked issue carries a claim
|
|
113
|
+
* by someone other than the PR author that predates the PR. Pure: per-issue
|
|
114
|
+
* comments and author are injected; splitIssueClaims (guard) does the
|
|
115
|
+
* actual matching.
|
|
116
|
+
*/
|
|
117
|
+
export function buildClaimConflicts(args) {
|
|
118
|
+
const conflicts = [];
|
|
119
|
+
for (const pr of args.prs) {
|
|
120
|
+
for (const key of extractPRIssueKeys(pr, args.prOwner, args.prRepo)) {
|
|
121
|
+
const mapKey = `${key.owner.toLowerCase()}/${key.repo.toLowerCase()}#${key.number}`;
|
|
122
|
+
const data = args.issueData.get(mapKey);
|
|
123
|
+
if (!data)
|
|
124
|
+
continue;
|
|
125
|
+
const { foreign } = splitIssueClaims(data.author, data.comments, pr.author, pr.createdAt, key.number);
|
|
126
|
+
if (foreign.length > 0) {
|
|
127
|
+
conflicts.push({ pr, issue: key, issueTitle: data.title, issueUrl: data.url, foreignClaims: foreign });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return conflicts;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Stale claims: open issues with a claim older than STALE_CLAIM_DAYS and
|
|
135
|
+
* NO open PR linked in the issue's timeline. Pure: claims come from
|
|
136
|
+
* injected comments; the timeline result is injected as LinkedPR[].
|
|
137
|
+
*/
|
|
138
|
+
export function buildStaleClaims(candidates, now = new Date()) {
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const c of candidates) {
|
|
141
|
+
const claims = detectClaims("", c.comments, now).filter((x) => !isBotAuthor(x.author));
|
|
142
|
+
const hasOpenPR = c.linkedPRs.some((pr) => pr.state === "open");
|
|
143
|
+
if (hasOpenPR)
|
|
144
|
+
continue;
|
|
145
|
+
for (const claim of claims) {
|
|
146
|
+
if (claim.ageDays >= STALE_CLAIM_DAYS) {
|
|
147
|
+
out.push({
|
|
148
|
+
issue: c.key,
|
|
149
|
+
issueTitle: c.title,
|
|
150
|
+
issueUrl: c.url,
|
|
151
|
+
claimant: claim.author,
|
|
152
|
+
claimDate: claim.createdAt,
|
|
153
|
+
ageDays: claim.ageDays,
|
|
154
|
+
action: claim.ageDays >= RELEASE_CLAIM_DAYS ? "release the claim" : `nudge @${claim.author}`,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
out.sort((a, b) => b.ageDays - a.ageDays);
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Assignment-gate conflicts: only runs when the repo's gates say
|
|
164
|
+
* assignment is required. A PR whose author is not among the issue's
|
|
165
|
+
* assignees is flagged; "assigned to nobody" is its own flavor.
|
|
166
|
+
*/
|
|
167
|
+
export function buildAssignmentConflicts(args) {
|
|
168
|
+
if (!args.assignmentRequired)
|
|
169
|
+
return [];
|
|
170
|
+
const conflicts = [];
|
|
171
|
+
for (const pr of args.prs) {
|
|
172
|
+
for (const key of extractPRIssueKeys(pr, args.prOwner, args.prRepo)) {
|
|
173
|
+
const mapKey = `${key.owner.toLowerCase()}/${key.repo.toLowerCase()}#${key.number}`;
|
|
174
|
+
const data = args.assigneesByIssue.get(mapKey);
|
|
175
|
+
if (!data)
|
|
176
|
+
continue;
|
|
177
|
+
const mine = data.assignees.some((a) => a.toLowerCase() === pr.author.toLowerCase());
|
|
178
|
+
if (!mine) {
|
|
179
|
+
conflicts.push({ pr, issue: key, issueTitle: data.title, issueUrl: data.url, assignees: data.assignees });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return conflicts;
|
|
184
|
+
}
|
|
185
|
+
/* ------------------------------------------------------------------ */
|
|
186
|
+
/* Rendering */
|
|
187
|
+
/* ------------------------------------------------------------------ */
|
|
188
|
+
function plural(n, one, many) {
|
|
189
|
+
return n === 1 ? one : many;
|
|
190
|
+
}
|
|
191
|
+
export function buildDigestSummary(args) {
|
|
192
|
+
const capped = args.trueOpenPRs !== null && args.trueOpenPRs > args.prCap
|
|
193
|
+
? ` (showing ${args.prCap} of ${args.trueOpenPRs} open PRs)`
|
|
194
|
+
: "";
|
|
195
|
+
return `Digest for ${args.repo}${capped}: ${args.races} ${plural(args.races, "race", "races")}, ${args.claimConflicts} claimed-by-other ${plural(args.claimConflicts, "conflict", "conflicts")}, ${args.staleClaims} stale ${plural(args.staleClaims, "claim", "claims")}, ${args.assignmentConflicts} assignment ${plural(args.assignmentConflicts, "conflict", "conflicts")}`;
|
|
196
|
+
}
|
|
197
|
+
export function renderDigestMarkdown(result) {
|
|
198
|
+
const lines = [`# ${result.summary}`, ""];
|
|
199
|
+
if (result.races.length > 0) {
|
|
200
|
+
lines.push(`## PR races (${result.races.length})`);
|
|
201
|
+
for (const race of result.races) {
|
|
202
|
+
lines.push(`### ${race.issue.label}: ${race.issueTitle}`);
|
|
203
|
+
lines.push(`- ${race.issueUrl}`);
|
|
204
|
+
lines.push(`- open PRs: ${race.prs.map((p) => `#${p.number} by @${p.author} ("${p.title.slice(0, 60)}")`).join("; ")}`);
|
|
205
|
+
lines.push(`- arbitration: ${race.arbitration}`);
|
|
206
|
+
lines.push("");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Conflicts are strong foreign claims (someone actually claimed the work).
|
|
210
|
+
// Soft foreign claims ("happy to help", "interested in this") render as
|
|
211
|
+
// "possible interest", not conflicts: live runs showed soft patterns
|
|
212
|
+
// matching polite offers that are not claims of work.
|
|
213
|
+
const strongConflicts = result.claimConflicts.filter((c) => c.foreignClaims.some((f) => f.strength === "strong"));
|
|
214
|
+
const softOnly = result.claimConflicts.filter((c) => !c.foreignClaims.some((f) => f.strength === "strong"));
|
|
215
|
+
if (result.claimConflicts.length > 0) {
|
|
216
|
+
lines.push(`## Claimed-by-other conflicts (${strongConflicts.length})`);
|
|
217
|
+
for (const c of strongConflicts) {
|
|
218
|
+
lines.push(`- PR #${c.pr.number} by @${c.pr.author} fixes ${c.issue.label} ("${c.issueTitle.slice(0, 60)}") but ${c.foreignClaims
|
|
219
|
+
.filter((f) => f.strength === "strong")
|
|
220
|
+
.map((f) => `@${f.author} claimed it on ${f.createdAt.slice(0, 10)}`)
|
|
221
|
+
.join("; ")}`);
|
|
222
|
+
lines.push(` ${c.issueUrl}`);
|
|
223
|
+
}
|
|
224
|
+
if (softOnly.length > 0) {
|
|
225
|
+
lines.push("");
|
|
226
|
+
lines.push(`Possible interest (soft claims, not firm):`);
|
|
227
|
+
for (const c of softOnly) {
|
|
228
|
+
lines.push(`- PR #${c.pr.number} by @${c.pr.author} fixes ${c.issue.label}: ${c.foreignClaims
|
|
229
|
+
.map((f) => `@${f.author} on ${f.createdAt.slice(0, 10)} ("${f.phrase}")`)
|
|
230
|
+
.join("; ")}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
lines.push("");
|
|
234
|
+
}
|
|
235
|
+
if (result.staleClaims.length > 0) {
|
|
236
|
+
lines.push(`## Stale claims (${result.staleClaims.length})`);
|
|
237
|
+
for (const s of result.staleClaims) {
|
|
238
|
+
lines.push(`- ${s.issue.label} "${s.issueTitle.slice(0, 60)}": @${s.claimant} claimed on ${s.claimDate.slice(0, 10)} (${s.ageDays} days ago), no open PR — suggested action: ${s.action}`);
|
|
239
|
+
lines.push(` ${s.issueUrl}`);
|
|
240
|
+
}
|
|
241
|
+
lines.push("");
|
|
242
|
+
}
|
|
243
|
+
if (result.assignmentConflicts.length > 0) {
|
|
244
|
+
lines.push(`## Assignment-gate conflicts (${result.assignmentConflicts.length})`);
|
|
245
|
+
for (const a of result.assignmentConflicts) {
|
|
246
|
+
const assigneeText = a.assignees.length > 0 ? `assigned to ${a.assignees.map((x) => `@${x}`).join(", ")}` : "assigned to nobody";
|
|
247
|
+
lines.push(`- PR #${a.pr.number} by @${a.pr.author} fixes ${a.issue.label} which is ${assigneeText} (repo requires assignment before a PR)`);
|
|
248
|
+
lines.push(` ${a.issueUrl}`);
|
|
249
|
+
}
|
|
250
|
+
lines.push("");
|
|
251
|
+
}
|
|
252
|
+
if (result.degraded.length > 0) {
|
|
253
|
+
lines.push(`## Could not compute`);
|
|
254
|
+
for (const d of result.degraded)
|
|
255
|
+
lines.push(`- ${d.section}: ${d.note}`);
|
|
256
|
+
lines.push("");
|
|
257
|
+
}
|
|
258
|
+
const zero = result.races.length === 0 && result.claimConflicts.length === 0 && result.staleClaims.length === 0 && result.assignmentConflicts.length === 0;
|
|
259
|
+
if (zero && result.degraded.length === 0) {
|
|
260
|
+
lines.push("_Nothing needs attention:_ no PR races, no claimed-by-other conflicts, no stale claims, no assignment conflicts.");
|
|
261
|
+
lines.push("");
|
|
262
|
+
}
|
|
263
|
+
lines.push("---");
|
|
264
|
+
lines.push(`_Generated with [Greenlight digest](https://github.com/CloudCorpRecords/greenlight) v${DIGEST_VERSION}; findings are signals, verify before acting._`);
|
|
265
|
+
return lines.join("\n");
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Budget notes (the live layer):
|
|
269
|
+
* - listOpenPRs: 1 pulls call (+ up to 5 pages at limit 50); the true total
|
|
270
|
+
* comes from one search call. Cached per repo for the 6h CLI window.
|
|
271
|
+
* - listOpenIssues: same shape against the issues endpoint (PRs filtered
|
|
272
|
+
* out via the pull_request key). Same true-total treatment.
|
|
273
|
+
* - fetchIssueMeta: 1 call per distinct linked issue (title, author,
|
|
274
|
+
* assignees, comments count). NOT called for issues with no PR linked.
|
|
275
|
+
* - fetchIssueComments: called only when meta.commentsCount > 0 AND the
|
|
276
|
+
* section needs claims. Never for comment-less issues.
|
|
277
|
+
* - fetchLinkedPRs (timeline + search): called only for candidate stale
|
|
278
|
+
* claims, never for every issue.
|
|
279
|
+
*/
|
|
280
|
+
async function defaultListOpenPRs(owner, repo, limit) {
|
|
281
|
+
const prs = [];
|
|
282
|
+
let total = null;
|
|
283
|
+
try {
|
|
284
|
+
// Newest first: the cap keeps the most recent open PRs, which is what a
|
|
285
|
+
// maintainer triages. The summary always states the cap and the true
|
|
286
|
+
// total, so nothing is silently dropped.
|
|
287
|
+
const data = (await apiGet(`/repos/${owner}/${repo}/pulls?state=open&sort=created&direction=desc&per_page=${Math.min(limit, 100)}&page=1`));
|
|
288
|
+
for (const p of data ?? []) {
|
|
289
|
+
prs.push({
|
|
290
|
+
number: Number(p.number),
|
|
291
|
+
title: String(p.title ?? ""),
|
|
292
|
+
body: String(p.body ?? ""),
|
|
293
|
+
author: String(p.user?.login ?? ""),
|
|
294
|
+
headRef: String(p.head?.ref ?? ""),
|
|
295
|
+
createdAt: String(p.created_at ?? ""),
|
|
296
|
+
url: String(p.html_url ?? `https://github.com/${owner}/${repo}/pull/${p.number}`),
|
|
297
|
+
});
|
|
298
|
+
if (prs.length >= limit)
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return { prs: [], total: null };
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const q = encodeURIComponent(`repo:${owner}/${repo} type:pr state:open`);
|
|
307
|
+
const search = (await apiGet(`/search/issues?q=${q}&per_page=1`));
|
|
308
|
+
total = typeof search.total_count === "number" ? search.total_count : null;
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
// total stays null: the summary states the cap without the true total
|
|
312
|
+
}
|
|
313
|
+
return { prs, total };
|
|
314
|
+
}
|
|
315
|
+
async function defaultListOpenIssues(owner, repo, limit) {
|
|
316
|
+
let data = [];
|
|
317
|
+
let total = null;
|
|
318
|
+
try {
|
|
319
|
+
data = (await apiGet(`/repos/${owner}/${repo}/issues?state=open&per_page=${Math.min(limit, 100)}&page=1`));
|
|
320
|
+
// The issues endpoint returns PRs too; the digest only wants issues.
|
|
321
|
+
data = (data ?? []).filter((i) => !i.pull_request);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
return { issues: [], total: null };
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const q = encodeURIComponent(`repo:${owner}/${repo} type:issue state:open`);
|
|
328
|
+
const search = (await apiGet(`/search/issues?q=${q}&per_page=1`));
|
|
329
|
+
total = typeof search.total_count === "number" ? search.total_count : null;
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
// total stays null
|
|
333
|
+
}
|
|
334
|
+
return { issues: data.slice(0, limit), total };
|
|
335
|
+
}
|
|
336
|
+
async function defaultFetchIssueMeta(owner, repo, number) {
|
|
337
|
+
const issue = (await apiGet(`/repos/${owner}/${repo}/issues/${number}`));
|
|
338
|
+
return {
|
|
339
|
+
number,
|
|
340
|
+
title: String(issue.title ?? ""),
|
|
341
|
+
state: String(issue.state ?? ""),
|
|
342
|
+
author: String(issue.user?.login ?? ""),
|
|
343
|
+
url: String(issue.html_url ?? `https://github.com/${owner}/${repo}/issues/${number}`),
|
|
344
|
+
commentsCount: typeof issue.comments === "number" ? issue.comments : 0,
|
|
345
|
+
assignees: (issue.assignees ?? []).map((a) => String(a.login ?? "")),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Full digest for owner/repo. Best-effort throughout: a section whose
|
|
350
|
+
* data cannot be read is recorded in `degraded` with the reason, never
|
|
351
|
+
* presented as a clean zero.
|
|
352
|
+
*/
|
|
353
|
+
export async function digestRepo(owner, repo, limit, deps = {}, opts = {}) {
|
|
354
|
+
const now = opts.now ?? new Date();
|
|
355
|
+
const listOpenPRs = deps.listOpenPRs ?? defaultListOpenPRs;
|
|
356
|
+
const listOpenIssues = deps.listOpenIssues ?? defaultListOpenIssues;
|
|
357
|
+
const fetchIssueMeta = deps.fetchIssueMeta ?? defaultFetchIssueMeta;
|
|
358
|
+
const fetchIssueComments = deps.fetchIssueComments ?? fetchComments;
|
|
359
|
+
const fetchRepoLinkedPRs = deps.fetchLinkedPRs ?? fetchLinkedPRs;
|
|
360
|
+
const fetchRepoContributing = deps.fetchContributing ?? fetchContributing;
|
|
361
|
+
const degraded = [];
|
|
362
|
+
// 1. The cheap lists first (2-3 calls total).
|
|
363
|
+
const { prs, total: trueOpenPRs } = await listOpenPRs(owner, repo, limit);
|
|
364
|
+
const { issues: openIssues, total: trueOpenIssues } = await listOpenIssues(owner, repo, limit);
|
|
365
|
+
let contributing;
|
|
366
|
+
try {
|
|
367
|
+
contributing = await fetchRepoContributing(owner, repo);
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
contributing = undefined;
|
|
371
|
+
}
|
|
372
|
+
const races = [];
|
|
373
|
+
const claimConflicts = [];
|
|
374
|
+
const staleClaims = [];
|
|
375
|
+
const assignmentConflicts = [];
|
|
376
|
+
// 2. Linked issues across open PRs. One meta call per DISTINCT linked
|
|
377
|
+
// issue (not per PR): budget discipline for race/conflict sections.
|
|
378
|
+
const groups = groupPRsByIssue(prs, owner, repo);
|
|
379
|
+
const metaByKey = new Map();
|
|
380
|
+
const metaKey = (k) => `${k.owner.toLowerCase()}/${k.repo.toLowerCase()}#${k.number}`;
|
|
381
|
+
const fetchMeta = async (key) => {
|
|
382
|
+
const m = metaKey(key);
|
|
383
|
+
const cached = metaByKey.get(m);
|
|
384
|
+
if (cached)
|
|
385
|
+
return cached;
|
|
386
|
+
try {
|
|
387
|
+
const meta = await fetchIssueMeta(key.owner, key.repo, key.number);
|
|
388
|
+
metaByKey.set(m, meta);
|
|
389
|
+
return meta;
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
degraded.push({ section: `issue ${key.label}`, note: "issue metadata could not be read" });
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
const fetchCommentsIfAny = async (key, meta) => {
|
|
397
|
+
// Comments are the expensive part: skip entirely when the issue has none.
|
|
398
|
+
if (meta.commentsCount <= 0)
|
|
399
|
+
return [];
|
|
400
|
+
try {
|
|
401
|
+
return await fetchIssueComments(key.owner, key.repo, key.number);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
degraded.push({ section: `issue ${key.label}`, note: "comments could not be read; claim checks skipped for this issue" });
|
|
405
|
+
return [];
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
// 3. Races: only groups of 2+ open PRs need issue data.
|
|
409
|
+
// A group keyed on a number that resolves to a PR (not an issue) is not
|
|
410
|
+
// a race: skip it with a note instead of reporting a phantom race.
|
|
411
|
+
const raceGroups = [...groups.values()].filter((g) => g.prs.length >= 2);
|
|
412
|
+
// Group keys that resolve to PRs, not issues, are skipped in every
|
|
413
|
+
// section that treats them as issues (races, claimed-by-other,
|
|
414
|
+
// assignment). Stale claims come from the issues endpoint, which is
|
|
415
|
+
// already PR-filtered.
|
|
416
|
+
const notIssueKeys = new Set();
|
|
417
|
+
for (const group of raceGroups) {
|
|
418
|
+
const meta = await fetchMeta(group.key);
|
|
419
|
+
if (meta && meta.url.includes("/pull/")) {
|
|
420
|
+
degraded.push({ section: `race ${group.key.label}`, note: "skipped: resolves to a PR, not an issue" });
|
|
421
|
+
notIssueKeys.add(metaKey(group.key));
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const comments = meta ? await fetchCommentsIfAny(group.key, meta) : [];
|
|
425
|
+
races.push(buildRace(group, meta?.title ?? "(title unavailable)", meta?.url ?? `https://github.com/${group.key.owner}/${group.key.repo}/issues/${group.key.number}`, comments, now));
|
|
426
|
+
}
|
|
427
|
+
// 4. Claimed-by-other conflicts: meta + comments only for distinct
|
|
428
|
+
// linked issues that have comments. Claim-free issues cost one meta
|
|
429
|
+
// call and no comment call.
|
|
430
|
+
{
|
|
431
|
+
const issueData = new Map();
|
|
432
|
+
for (const { key } of groups.values()) {
|
|
433
|
+
if (notIssueKeys.has(metaKey(key)))
|
|
434
|
+
continue;
|
|
435
|
+
const meta = await fetchMeta(key);
|
|
436
|
+
if (!meta)
|
|
437
|
+
continue;
|
|
438
|
+
const comments = await fetchCommentsIfAny(key, meta);
|
|
439
|
+
issueData.set(metaKey(key), { key, title: meta.title, url: meta.url, author: meta.author, comments });
|
|
440
|
+
}
|
|
441
|
+
for (const c of buildClaimConflicts({ prs, prOwner: owner, prRepo: repo, issueData })) {
|
|
442
|
+
claimConflicts.push(c);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
// 5. Stale claims: comments fetched only for open issues with
|
|
446
|
+
// commentsCount > 0; the timeline walk (fetchLinkedPRs) only for
|
|
447
|
+
// candidates that actually carry a claim older than 14 days.
|
|
448
|
+
{
|
|
449
|
+
const candidates = [];
|
|
450
|
+
for (const item of openIssues) {
|
|
451
|
+
const number = Number(item.number);
|
|
452
|
+
const commentsCount = typeof item.comments === "number" ? item.comments : 0;
|
|
453
|
+
if (commentsCount <= 0)
|
|
454
|
+
continue;
|
|
455
|
+
let comments;
|
|
456
|
+
try {
|
|
457
|
+
comments = await fetchIssueComments(owner, repo, number);
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
degraded.push({ section: `stale-claims #${number}`, note: "comments could not be read; this issue was skipped" });
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
const claims = detectClaims(String(item.user?.login ?? ""), comments).filter((c) => !isBotAuthor(c.author));
|
|
464
|
+
if (!claims.some((c) => c.ageDays >= STALE_CLAIM_DAYS))
|
|
465
|
+
continue;
|
|
466
|
+
let linked = [];
|
|
467
|
+
try {
|
|
468
|
+
linked = await fetchRepoLinkedPRs(owner, repo, number);
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
linked = [];
|
|
472
|
+
degraded.push({ section: `stale-claims #${number}`, note: "timeline could not be read; assuming no linked PRs" });
|
|
473
|
+
}
|
|
474
|
+
candidates.push({
|
|
475
|
+
key: { owner, repo, number, label: `#${number}` },
|
|
476
|
+
title: String(item.title ?? ""),
|
|
477
|
+
url: String(item.html_url ?? `https://github.com/${owner}/${repo}/issues/${number}`),
|
|
478
|
+
comments,
|
|
479
|
+
linkedPRs: linked,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
for (const s of buildStaleClaims(candidates, now))
|
|
483
|
+
staleClaims.push(s);
|
|
484
|
+
}
|
|
485
|
+
// 6. Assignment-gate conflicts: only when the repo's gates require
|
|
486
|
+
// assignment. Assignees come from the meta already fetched above;
|
|
487
|
+
// no new calls beyond those.
|
|
488
|
+
{
|
|
489
|
+
let assignmentRequired = false;
|
|
490
|
+
try {
|
|
491
|
+
const gates = parseGates(contributing, { collaboratorsOnlyPolicy: false });
|
|
492
|
+
assignmentRequired = gates.some((g) => g.kind === "assignment_required" && g.detected);
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
degraded.push({ section: "assignment conflicts", note: "repo gates could not be parsed" });
|
|
496
|
+
}
|
|
497
|
+
if (assignmentRequired) {
|
|
498
|
+
const assigneesByIssue = new Map();
|
|
499
|
+
for (const { key } of groups.values()) {
|
|
500
|
+
if (notIssueKeys.has(metaKey(key)))
|
|
501
|
+
continue;
|
|
502
|
+
const meta = metaByKey.get(metaKey(key));
|
|
503
|
+
if (!meta)
|
|
504
|
+
continue;
|
|
505
|
+
assigneesByIssue.set(metaKey(key), { key, title: meta.title, url: meta.url, assignees: meta.assignees });
|
|
506
|
+
}
|
|
507
|
+
for (const c of buildAssignmentConflicts({ prs, prOwner: owner, prRepo: repo, assignmentRequired, assigneesByIssue })) {
|
|
508
|
+
assignmentConflicts.push(c);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const summary = buildDigestSummary({
|
|
513
|
+
repo: `${owner}/${repo}`,
|
|
514
|
+
races: races.length,
|
|
515
|
+
// The header counts strong-claim conflicts; soft interest is noted in
|
|
516
|
+
// the section body, not counted as a conflict.
|
|
517
|
+
claimConflicts: claimConflicts.filter((c) => c.foreignClaims.some((f) => f.strength === "strong")).length,
|
|
518
|
+
staleClaims: staleClaims.length,
|
|
519
|
+
assignmentConflicts: assignmentConflicts.length,
|
|
520
|
+
prCap: limit,
|
|
521
|
+
trueOpenPRs,
|
|
522
|
+
});
|
|
523
|
+
const result = {
|
|
524
|
+
repo: `${owner}/${repo}`,
|
|
525
|
+
races,
|
|
526
|
+
claimConflicts,
|
|
527
|
+
staleClaims,
|
|
528
|
+
assignmentConflicts,
|
|
529
|
+
degraded,
|
|
530
|
+
summary,
|
|
531
|
+
prCap: limit,
|
|
532
|
+
trueOpenPRs,
|
|
533
|
+
issueCap: limit,
|
|
534
|
+
trueOpenIssues,
|
|
535
|
+
hasRaces: races.length > 0,
|
|
536
|
+
markdown: "",
|
|
537
|
+
};
|
|
538
|
+
result.markdown = renderDigestMarkdown(result);
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"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"}
|
package/dist/guard.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommentSignal, LinkedPR } from "./types.js";
|
|
2
|
-
export declare const GUARD_VERSION = "0.3.
|
|
2
|
+
export declare const GUARD_VERSION = "0.3.11";
|
|
3
3
|
/** The hidden marker the GitHub Action uses to find its own comment and update it. */
|
|
4
4
|
export declare const GUARD_COMMENT_MARKER = "<!-- greenlight-guard -->";
|
|
5
5
|
/** Check ids, also the keys of .greenlight-guard.json. */
|
|
@@ -24,6 +24,8 @@ export interface GuardCompetingPR {
|
|
|
24
24
|
state: string;
|
|
25
25
|
linkStrength: "closing" | "mention";
|
|
26
26
|
via?: string;
|
|
27
|
+
/** "owner/repo#N" when the issue lives in another repo; undefined for same-repo. */
|
|
28
|
+
issueRef?: string;
|
|
27
29
|
}
|
|
28
30
|
export interface GuardClaim {
|
|
29
31
|
issueNumber: number;
|
|
@@ -33,6 +35,8 @@ export interface GuardClaim {
|
|
|
33
35
|
strength: "strong" | "soft";
|
|
34
36
|
phrase: string;
|
|
35
37
|
claimedByAuthor: boolean;
|
|
38
|
+
/** "owner/repo#N" when the issue lives in another repo; undefined for same-repo. */
|
|
39
|
+
issueRef?: string;
|
|
36
40
|
}
|
|
37
41
|
export interface GuardFinding {
|
|
38
42
|
/** Machine key, e.g. "competing-fix" / "changeset-missing" / "dco-missing" / "cla-status" / "first-time". */
|
|
@@ -93,6 +97,30 @@ export interface GuardRepoConventions {
|
|
|
93
97
|
* matches the race-detection behavior exactly.
|
|
94
98
|
*/
|
|
95
99
|
export declare function extractLinkedIssueNumbers(title: string, body: string, branch: string): number[];
|
|
100
|
+
/**
|
|
101
|
+
* A cross-repo issue reference this PR claims to fix, e.g. "acme/widgets#123".
|
|
102
|
+
* The PR's own repo is tracked separately (same-repo #N machinery); the
|
|
103
|
+
* issue lives in another repo, so the guard must fetch THAT repo's issue
|
|
104
|
+
* (comments for claims, timeline for competing PRs).
|
|
105
|
+
*/
|
|
106
|
+
export interface GuardIssueRef {
|
|
107
|
+
owner: string;
|
|
108
|
+
repo: string;
|
|
109
|
+
number: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Cross-repo issue references this PR claims to fix:
|
|
113
|
+
* - "Fixes acme/widgets#123" (closing keyword + owner/repo#N)
|
|
114
|
+
* - "Closes https://github.com/acme/widgets/issues/123" (closing keyword + issue URL)
|
|
115
|
+
* - an issue URL in the PR title (author intent, mirroring the
|
|
116
|
+
* "#N in the title is closing" rule for same-repo links)
|
|
117
|
+
*
|
|
118
|
+
* Only closing intent counts: "see acme/widgets#123" or "related to
|
|
119
|
+
* acme/widgets#123" never count, exactly as for same-repo mentions.
|
|
120
|
+
* References pointing back at the PR's own repo are skipped; the
|
|
121
|
+
* same-repo machinery already handles those.
|
|
122
|
+
*/
|
|
123
|
+
export declare function extractCrossRepoIssues(title: string, body: string, prOwner: string, prRepo: string): GuardIssueRef[];
|
|
96
124
|
/** Other OPEN PRs already fixing the same issue, excluding this PR. Only "closing"-strength links count. */
|
|
97
125
|
export declare function findCompetingPRs(issueNumber: number, linkedPRs: LinkedPR[], prNumber: number, authorsByNumber?: Map<number, string>): GuardCompetingPR[];
|
|
98
126
|
/**
|