pr-shepherd 0.16.2 → 0.16.3

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
3
  "description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
4
- "version": "0.16.2",
4
+ "version": "0.16.3",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",
7
7
  "email": "jonathanrichardong@gmail.com"
@@ -1,5 +1,5 @@
1
1
  import { fetchPrBatch } from "../github/batch.mjs";
2
- import { getRepoInfo, getCurrentPrNumber, getMergeableState } from "../github/client.mjs";
2
+ import { getRepoInfo, getCurrentPrNumber } from "../github/client.mjs";
3
3
  import { classifyChecks, getCiVerdict } from "../checks/classify.mjs";
4
4
  import { mergeStartupFailureChecks } from "../checks/startup-failures.mjs";
5
5
  import { fetchStartupFailureChecks, triageFailingChecks } from "../checks/triage.mjs";
@@ -10,6 +10,7 @@ import { loadConfig } from "../config/load.mjs";
10
10
  import { classifyVisibleComments } from "../comments/visible-comments.mjs";
11
11
  import { computeStatus } from "./check-status.mjs";
12
12
  import { buildTerminalReport } from "./check-terminal-report.mjs";
13
+ import { isBlockedByFilteredCheck, refreshReadyMergeability, refreshUnknownMergeability, } from "./ready-mergeability.mjs";
13
14
  import { loadSeenMap, markSeen, classifyItem } from "../state/seen-comments.mjs";
14
15
  export async function runCheck(opts) {
15
16
  const repo = await getRepoInfo();
@@ -21,17 +22,10 @@ export async function runCheck(opts) {
21
22
  const paginateApprovedReviews = config.iterate.minimizeApprovals;
22
23
  const result = await fetchPrBatch(prNumber, repo, { paginateApprovedReviews });
23
24
  let batchData = result.data;
24
- // Fall back to REST when GraphQL returns UNKNOWN — skip for non-OPEN PRs.
25
- if ((batchData.state ?? "OPEN") === "OPEN" &&
26
- (batchData.mergeable === "UNKNOWN" || batchData.mergeStateStatus === "UNKNOWN")) {
27
- const restState = await getMergeableState(prNumber, repo.owner, repo.name);
28
- batchData = {
29
- ...batchData,
30
- mergeable: restState.mergeable ?? batchData.mergeable,
31
- mergeStateStatus: restState.mergeStateStatus ?? batchData.mergeStateStatus,
32
- };
33
- }
34
- const mergeStatus = deriveMergeStatus(batchData);
25
+ const unknownRefresh = await refreshUnknownMergeability(prNumber, repo, batchData);
26
+ batchData = unknownRefresh.batchData;
27
+ const didRefreshMergeability = unknownRefresh.didRefresh;
28
+ let mergeStatus = deriveMergeStatus(batchData);
35
29
  if (mergeStatus.state === "MERGED" || mergeStatus.state === "CLOSED") {
36
30
  return buildTerminalReport(prNumber, repo, batchData, mergeStatus, mergeStatus.state);
37
31
  }
@@ -116,11 +110,14 @@ export async function runCheck(opts) {
116
110
  ...[...firstLookSummaries, ...editedSummaries].map((r) => markSeen(stateKey, r.id, r.body)),
117
111
  ]);
118
112
  const resolutionOnlyThreads = unresolvedThreads.filter((t) => !autoResolvedIds.has(t.id) && (t.isOutdated || t.isMinimized));
119
- const blockedByFilteredCheck = mergeStatus.status === "BLOCKED" &&
120
- !verdict.anyFailing &&
121
- !verdict.anyInProgress &&
122
- verdict.filteredNames.length > 0;
123
- const status = computeStatus(verdict, activeThreads.length + resolutionOnlyThreads.length, visibleCommentClassification.actionable.length, mergeStatus, batchData.changesRequestedReviews.length);
113
+ let status = computeStatus(verdict, activeThreads.length + resolutionOnlyThreads.length, visibleCommentClassification.actionable.length, mergeStatus, batchData.changesRequestedReviews.length);
114
+ if (status === "READY" && !didRefreshMergeability) {
115
+ const refreshed = await refreshReadyMergeability(prNumber, repo, batchData, verdict, activeThreads.length + resolutionOnlyThreads.length, visibleCommentClassification.actionable.length);
116
+ batchData = refreshed.batchData;
117
+ mergeStatus = refreshed.mergeStatus;
118
+ status = refreshed.status;
119
+ }
120
+ const blockedByFilteredCheck = isBlockedByFilteredCheck(mergeStatus, verdict);
124
121
  return {
125
122
  pr: prNumber,
126
123
  nodeId: batchData.nodeId,
@@ -29,6 +29,7 @@ export async function runIterate(opts) {
29
29
  const stallKey = { owner: repoOwner, repo: repoName, pr: prNumber };
30
30
  if (report.mergeStatus.state !== "OPEN") {
31
31
  const state = report.mergeStatus.state.toLowerCase();
32
+ await updateReadyDelay(report.pr, false, readyDelaySeconds, repoOwner, repoName);
32
33
  await clearStallState(stallKey);
33
34
  return {
34
35
  pr: report.pr,
@@ -0,0 +1,30 @@
1
+ import { getMergeableState } from "../github/client.mjs";
2
+ import { deriveMergeStatus } from "../merge-status/derive.mjs";
3
+ import { computeStatus } from "./check-status.mjs";
4
+ export async function refreshUnknownMergeability(prNumber, repo, batchData) {
5
+ if ((batchData.state ?? "OPEN") !== "OPEN" ||
6
+ (batchData.mergeable !== "UNKNOWN" && batchData.mergeStateStatus !== "UNKNOWN")) {
7
+ return { batchData, didRefresh: false };
8
+ }
9
+ return { batchData: await readMergeability(prNumber, repo, batchData), didRefresh: true };
10
+ }
11
+ export async function refreshReadyMergeability(prNumber, repo, batchData, verdict, unresolvedThreads, unresolvedComments) {
12
+ const refreshedBatchData = await readMergeability(prNumber, repo, batchData);
13
+ const mergeStatus = deriveMergeStatus(refreshedBatchData);
14
+ const status = computeStatus(verdict, unresolvedThreads, unresolvedComments, mergeStatus, refreshedBatchData.changesRequestedReviews.length);
15
+ return { batchData: refreshedBatchData, mergeStatus, status };
16
+ }
17
+ export function isBlockedByFilteredCheck(mergeStatus, verdict) {
18
+ return (mergeStatus.status === "BLOCKED" &&
19
+ !verdict.anyFailing &&
20
+ !verdict.anyInProgress &&
21
+ verdict.filteredNames.length > 0);
22
+ }
23
+ async function readMergeability(prNumber, repo, batchData) {
24
+ const restState = await getMergeableState(prNumber, repo.owner, repo.name);
25
+ return {
26
+ ...batchData,
27
+ mergeable: restState.mergeable ?? batchData.mergeable,
28
+ mergeStateStatus: restState.mergeStateStatus ?? batchData.mergeStateStatus,
29
+ };
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
- "version": "0.16.2",
3
+ "version": "0.16.3",
4
4
  "description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
5
5
  "license": "MIT",
6
6
  "author": "Jonathan Ong",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
- "version": "0.16.2",
3
+ "version": "0.16.3",
4
4
  "description": "Autonomous PR CI monitor and review-comment resolver for Codex.",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",