co-maintainer 0.4.7 → 0.4.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "co-maintainer",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Analyzes a GitHub repository and writes repository-specific contribution guidance.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -52,6 +52,7 @@ export async function parseArgs(args) {
52
52
  console.log("Options: --include-codebase --include-pull-requests --include-pull-request-changes");
53
53
  console.log(" --include-commit-history --include-how-repo-works");
54
54
  console.log(" --max-commits=N --max-pr-months=N --max-pull-request-change-lines=N --max-comment=N");
55
+ console.log(" --only-request-changed-pr");
55
56
  console.log(" --auth=gh|pat --github-pat=... --ai=none|openrouter|hetzner --token=... --low-model=... --high-model=...");
56
57
  process.exit(0);
57
58
  }
@@ -145,7 +146,8 @@ export async function parseArgs(args) {
145
146
  if (arg === "--debug" ||
146
147
  arg === "--log-time" ||
147
148
  arg === "--review-upstream" ||
148
- arg === "--disable-codegraph")
149
+ arg === "--disable-codegraph" ||
150
+ arg === "--only-request-changed-pr")
149
151
  continue;
150
152
  if (arg.startsWith("--") && !known)
151
153
  die(`Unknown option: ${arg}`);
@@ -241,6 +243,8 @@ export async function parseArgs(args) {
241
243
  includePullRequestChanges: enabled("include-pull-request-changes"),
242
244
  includeCommitHistory: enabled("include-commit-history"),
243
245
  includeHowRepoWorks: enabled("include-how-repo-works"),
246
+ onlyRequestChangedPr: rest.includes("--only-request-changed-pr") ||
247
+ repoConfig.onlyRequestChangedPr === true,
244
248
  maxCommits: value("max-commits") ?? repoConfig.maxCommits ?? configDefault.maxCommits,
245
249
  maxPrMonths: value("max-pr-months") ??
246
250
  repoConfig.maxPrMonths ??
@@ -17,6 +17,7 @@ export type RepoConfig = {
17
17
  includePullRequestChanges?: boolean;
18
18
  includeCommitHistory?: boolean;
19
19
  includeHowRepoWorks?: boolean;
20
+ onlyRequestChangedPr?: boolean;
20
21
  /** Five field cron in UTC, checked by `serve` to queue a remake. */
21
22
  remakeCron?: string;
22
23
  };
@@ -10,6 +10,12 @@ function percent(done, total) {
10
10
  return "0%";
11
11
  return `${Math.round((done / total) * 100)}%`;
12
12
  }
13
+ function changesRequested(reviews) {
14
+ return reviews.some((review) => review.state === "CHANGES_REQUESTED");
15
+ }
16
+ function reviewBodies(reviews) {
17
+ return reviews.map((review) => String(review.body ?? "")).filter(Boolean);
18
+ }
13
19
  function withinPrWindow(updatedAt, months) {
14
20
  if (months === undefined || months === 0)
15
21
  return true;
@@ -258,13 +264,47 @@ async function pullRequests(client, options, previous, phase, progress) {
258
264
  changedFiles: cached?.changedFiles ?? [],
259
265
  diff: cached?.diff ?? "",
260
266
  };
267
+ if (typeof cached?.changesRequested === "boolean") {
268
+ current.changesRequested = cached.changesRequested;
269
+ }
270
+ const only = options.onlyRequestChangedPr;
261
271
  const discussionUnchanged = cached?.updatedAt === current.updatedAt;
272
+ const decisionKnown = typeof cached?.changesRequested === "boolean";
262
273
  const diffUnchanged = cached?.headSha === current.headSha && Boolean(cached?.diff);
263
- const discussionStatus = discussionUnchanged
264
- ? "comments/reviews cache"
265
- : "download comments/reviews";
274
+ let droppedFromCache = only && discussionUnchanged && cached?.changesRequested === false;
275
+ let dropped = droppedFromCache;
276
+ const loadComments = async () => {
277
+ const comments = await client.pages(`repos/${options.repo}/issues/${number}/comments`);
278
+ current.comments = comments
279
+ .map((comment) => String(comment.body ?? ""))
280
+ .filter(Boolean)
281
+ .slice(0, options.maxComments);
282
+ };
283
+ const loadReviews = async () => {
284
+ const reviews = await client.pages(`repos/${options.repo}/pulls/${number}/reviews`);
285
+ current.reviews = reviewBodies(reviews);
286
+ current.changesRequested = changesRequested(reviews);
287
+ };
288
+ if (!dropped && only && (!discussionUnchanged || !decisionKnown)) {
289
+ await loadReviews();
290
+ if (!current.changesRequested)
291
+ dropped = true;
292
+ else if (!discussionUnchanged)
293
+ await loadComments();
294
+ }
295
+ else if (!dropped && !discussionUnchanged) {
296
+ await loadComments();
297
+ await loadReviews();
298
+ }
299
+ const discussionStatus = dropped
300
+ ? droppedFromCache
301
+ ? "dropped cache"
302
+ : "dropped download"
303
+ : discussionUnchanged
304
+ ? "comments/reviews cache"
305
+ : "download comments/reviews";
266
306
  let diffStatus = "diff disabled";
267
- if (options.includePullRequestChanges) {
307
+ if (!dropped && options.includePullRequestChanges) {
268
308
  const lines = current.additions + current.deletions;
269
309
  diffStatus = diffUnchanged
270
310
  ? "diff cache"
@@ -278,18 +318,10 @@ async function pullRequests(client, options, previous, phase, progress) {
278
318
  if (phase) {
279
319
  phase.text = `PR #${number} · ${discussionStatus} · ${diffStatus} · ${completed}/${selected.length} · ${percent(completed, selected.length)}`;
280
320
  }
281
- if (!discussionUnchanged) {
282
- const comments = await client.pages(`repos/${options.repo}/issues/${number}/comments`);
283
- const reviews = await client.pages(`repos/${options.repo}/pulls/${number}/reviews`);
284
- current.comments = comments
285
- .map((comment) => String(comment.body ?? ""))
286
- .filter(Boolean)
287
- .slice(0, options.maxComments);
288
- current.reviews = reviews
289
- .map((review) => String(review.body ?? ""))
290
- .filter(Boolean);
291
- }
292
- if (options.includePullRequestChanges && !diffUnchanged && detail) {
321
+ if (!dropped &&
322
+ options.includePullRequestChanges &&
323
+ !diffUnchanged &&
324
+ detail) {
293
325
  const lines = current.additions + current.deletions;
294
326
  if (options.maxPullRequestChangeLines === undefined ||
295
327
  lines <= options.maxPullRequestChangeLines) {
@@ -311,7 +343,8 @@ async function pullRequests(client, options, previous, phase, progress) {
311
343
  current.diff = "";
312
344
  }
313
345
  }
314
- result[index] = current;
346
+ if (!dropped)
347
+ result[index] = current;
315
348
  completed++;
316
349
  if (phase) {
317
350
  phase.text = `pull requests ${completed}/${selected.length} · ${percent(completed, selected.length)}`;
@@ -322,7 +355,11 @@ async function pullRequests(client, options, previous, phase, progress) {
322
355
  await save;
323
356
  }
324
357
  });
325
- return result;
358
+ const kept = result.filter((item) => !!item);
359
+ if (options.onlyRequestChangedPr) {
360
+ log("fetch", `only request-changed pr · kept ${kept.length} · dropped ${selected.length - kept.length}`);
361
+ }
362
+ return kept;
326
363
  }
327
364
  async function commits(client, options, meta, phase) {
328
365
  const branch = String(meta.default_branch ?? "main");
@@ -12,6 +12,9 @@ export type PullRequest = {
12
12
  deletions: number;
13
13
  comments: string[];
14
14
  reviews: string[];
15
+ /** Set once reviews have been read. Missing means an older checkpoint
16
+ * never stored the review state. */
17
+ changesRequested?: boolean;
15
18
  changedFiles: string[];
16
19
  diff: string;
17
20
  };
@@ -44,6 +44,7 @@ function reviewOptionsForRepo(repo, useCodegraph) {
44
44
  includePullRequestChanges: true,
45
45
  includeCommitHistory: true,
46
46
  includeHowRepoWorks: true,
47
+ onlyRequestChangedPr: false,
47
48
  };
48
49
  }
49
50
  function supersedeActiveRemoteJobs(queueKey, supersededBy) {
@@ -130,6 +130,7 @@ export function reviewOptions(repo, prNumber) {
130
130
  includePullRequestChanges: true,
131
131
  includeCommitHistory: true,
132
132
  includeHowRepoWorks: true,
133
+ onlyRequestChangedPr: false,
133
134
  useCodegraph: getRepo(repo)?.use_codegraph === 1,
134
135
  };
135
136
  }
@@ -259,6 +259,7 @@ export async function runInitOrRemake(options) {
259
259
  includePullRequestChanges: options.includePullRequestChanges,
260
260
  includeCommitHistory: options.includeCommitHistory,
261
261
  includeHowRepoWorks: options.includeHowRepoWorks,
262
+ onlyRequestChangedPr: options.onlyRequestChangedPr,
262
263
  });
263
264
  });
264
265
  log("write", `${path} · ${result.changed.length
@@ -306,6 +307,7 @@ export function optionsFromConfig(repo, command) {
306
307
  includePullRequestChanges: repoConfig.includePullRequestChanges ?? true,
307
308
  includeCommitHistory: repoConfig.includeCommitHistory ?? true,
308
309
  includeHowRepoWorks: repoConfig.includeHowRepoWorks ?? true,
310
+ onlyRequestChangedPr: repoConfig.onlyRequestChangedPr === true,
309
311
  maxCommits: repoConfig.maxCommits ?? config.defaults?.maxCommits,
310
312
  maxPrMonths: repoConfig.maxPrMonths ?? config.defaults?.maxPrMonths,
311
313
  maxPullRequestChangeLines: repoConfig.maxPullRequestChangeLines ??
@@ -34,6 +34,9 @@ export type Options = {
34
34
  includePullRequestChanges: boolean;
35
35
  includeCommitHistory: boolean;
36
36
  includeHowRepoWorks: boolean;
37
+ /** Keep only pull requests in the window that have at least one
38
+ * `CHANGES_REQUESTED` review. Off by default, so the window is unchanged. */
39
+ onlyRequestChangedPr: boolean;
37
40
  maxCommits?: number;
38
41
  maxPrMonths?: number;
39
42
  maxPullRequestChangeLines?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "co-maintainer",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Analyzes a GitHub repository and writes repository-specific contribution guidance.",
5
5
  "license": "MIT",
6
6
  "repository": {