pr-shepherd 0.35.0 → 0.36.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.
Files changed (80) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +32 -12
  3. package/bin/checks/triage.mjs +11 -3
  4. package/bin/cli/args.mjs +1 -0
  5. package/bin/cli/default-poll.mjs +1 -0
  6. package/bin/cli/help-command-pages.d.mts +1 -1
  7. package/bin/cli/help-iterate-poll-pages.d.mts +1 -1
  8. package/bin/cli/help-iterate-poll-pages.mjs +10 -5
  9. package/bin/cli/help-top-page.d.mts +1 -1
  10. package/bin/cli/help-top-page.mjs +2 -1
  11. package/bin/cli/help.d.mts +2 -2
  12. package/bin/cli/iterate-formatter.mjs +11 -2
  13. package/bin/cli/iterate-lean.mjs +1 -0
  14. package/bin/cli/poll-handler.mjs +7 -0
  15. package/bin/commands/check.d.mts +1 -0
  16. package/bin/commands/check.mjs +26 -22
  17. package/bin/commands/commit-suggestion.mjs +11 -5
  18. package/bin/commands/iterate/fix-code.mjs +1 -1
  19. package/bin/commands/iterate/helpers.d.mts +1 -0
  20. package/bin/commands/iterate/helpers.mjs +15 -6
  21. package/bin/commands/iterate/index.mjs +3 -10
  22. package/bin/commands/poll.d.mts +2 -0
  23. package/bin/commands/poll.mjs +51 -17
  24. package/bin/commands/ready-delay.mjs +3 -13
  25. package/bin/config/load.mjs +67 -25
  26. package/bin/github/batch-page-helpers.d.mts +45 -0
  27. package/bin/github/batch-page-helpers.mjs +63 -0
  28. package/bin/github/batch-page.d.mts +14 -0
  29. package/bin/github/batch-page.mjs +62 -0
  30. package/bin/github/batch-parse-suites.d.mts +4 -0
  31. package/bin/github/batch-parse-suites.mjs +25 -0
  32. package/bin/github/batch-parsers-rules.d.mts +6 -0
  33. package/bin/github/batch-parsers-rules.mjs +122 -0
  34. package/bin/github/batch-parsers.mjs +6 -0
  35. package/bin/github/batch-raw-rules.d.mts +59 -0
  36. package/bin/github/batch-raw-rules.mjs +1 -0
  37. package/bin/github/batch-raw-types.d.mts +20 -11
  38. package/bin/github/batch.d.mts +2 -0
  39. package/bin/github/batch.mjs +14 -120
  40. package/bin/github/gql/batch-pr-page.gql +189 -0
  41. package/bin/github/gql/batch-pr.gql +74 -21
  42. package/bin/github/gql/commit-suggestion-thread.gql +40 -0
  43. package/bin/github/http.d.mts +2 -1
  44. package/bin/github/http.mjs +2 -1
  45. package/bin/github/pagination.d.mts +3 -2
  46. package/bin/github/pagination.mjs +3 -2
  47. package/bin/github/queries.d.mts +4 -0
  48. package/bin/github/queries.mjs +4 -0
  49. package/bin/github/rest-http.d.mts +6 -1
  50. package/bin/github/rest-http.mjs +25 -86
  51. package/bin/github/rest-text.d.mts +1 -0
  52. package/bin/github/rest-text.mjs +88 -0
  53. package/bin/github/suggestion-thread.d.mts +9 -0
  54. package/bin/github/suggestion-thread.mjs +45 -0
  55. package/bin/github/thread-comments.mjs +12 -8
  56. package/bin/merge-status/derive.mjs +2 -0
  57. package/bin/merge-status/requirements-format.d.mts +3 -0
  58. package/bin/merge-status/requirements-format.mjs +88 -0
  59. package/bin/merge-status/requirements.d.mts +2 -0
  60. package/bin/merge-status/requirements.mjs +51 -0
  61. package/bin/state/base.d.mts +9 -0
  62. package/bin/state/base.mjs +23 -0
  63. package/bin/state/bot-cr-seen.mjs +3 -13
  64. package/bin/state/fix-attempts.mjs +3 -13
  65. package/bin/state/iterate-stall.mjs +3 -13
  66. package/bin/state/seen-comments.mjs +6 -13
  67. package/bin/types/github.d.mts +4 -7
  68. package/bin/types/iterate.d.mts +6 -7
  69. package/bin/types/merge-requirements.d.mts +82 -0
  70. package/bin/types/merge-requirements.mjs +2 -0
  71. package/bin/types.d.mts +1 -0
  72. package/bin/types.mjs +1 -0
  73. package/bin/util/path-segment.d.mts +2 -0
  74. package/bin/util/path-segment.mjs +2 -0
  75. package/bin/util/pool.d.mts +2 -0
  76. package/bin/util/pool.mjs +18 -0
  77. package/package.json +1 -1
  78. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  79. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  80. package/plugins/pr-shepherd/.mcp.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { mapAuthorType, parseCreatedAt, mapStatusContextState, latestApprovedLogins, isReviewStale, mapCheckRunNode, } from "./batch-parser-helpers.mjs";
2
2
  import { buildPrActivitySummary } from "./activity.mjs";
3
3
  import { parseBranchProtection } from "./branch-protection.mjs";
4
+ import { parseBranchRules, parseMergeQueueEntry, parseStack } from "./batch-parsers-rules.mjs";
4
5
  function parseReviewNode(r) {
5
6
  const base = {
6
7
  id: r.id,
@@ -130,6 +131,11 @@ export function parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes,
130
131
  approvedReviews,
131
132
  checks,
132
133
  branchProtection: parseBranchProtection(raw),
134
+ branchRules: parseBranchRules(raw.baseRef),
135
+ isInMergeQueue: raw.isInMergeQueue ?? false,
136
+ isMergeQueueEnabled: raw.isMergeQueueEnabled ?? false,
137
+ mergeQueueEntry: parseMergeQueueEntry(raw.mergeQueueEntry),
138
+ stack: parseStack(raw),
133
139
  activity: buildPrActivitySummary(raw, comments, reviewThreads, reviewSummaries, allChangesRequestedReviews, approvedReviews),
134
140
  };
135
141
  }
@@ -0,0 +1,59 @@
1
+ export interface RawBranchProtectionRule {
2
+ requiresApprovingReviews: boolean;
3
+ requiredApprovingReviewCount: number;
4
+ requiresConversationResolution: boolean;
5
+ requiresStatusChecks: boolean;
6
+ requiredStatusCheckContexts: string[] | null;
7
+ requiresCodeOwnerReviews?: boolean;
8
+ requireLastPushApproval?: boolean;
9
+ requiresCommitSignatures?: boolean;
10
+ requiresLinearHistory?: boolean;
11
+ requiresStrictStatusChecks?: boolean;
12
+ requiresDeployments?: boolean;
13
+ requiredDeploymentEnvironments?: string[] | null;
14
+ }
15
+ interface RawMergeQueueEntry {
16
+ position: number;
17
+ state: string;
18
+ estimatedTimeToMerge: number | null;
19
+ }
20
+ interface RawStack {
21
+ number: number;
22
+ size: number;
23
+ baseRefName: string;
24
+ }
25
+ export interface RawRepositoryRule {
26
+ type: string;
27
+ parameters: RawRuleParameters | null;
28
+ }
29
+ interface RawRuleParameters {
30
+ requiredApprovingReviewCount?: number;
31
+ requiredReviewThreadResolution?: boolean;
32
+ requireCodeOwnerReview?: boolean;
33
+ requireLastPushApproval?: boolean;
34
+ strictRequiredStatusChecksPolicy?: boolean;
35
+ requiredStatusChecks?: Array<{
36
+ context: string;
37
+ }>;
38
+ requiredDeploymentEnvironments?: string[];
39
+ codeScanningTools?: Array<{
40
+ tool: string;
41
+ }>;
42
+ }
43
+ export interface RawBaseRef {
44
+ branchProtectionRule: RawBranchProtectionRule | null;
45
+ rules: {
46
+ nodes: RawRepositoryRule[];
47
+ } | null;
48
+ }
49
+ export interface RawPrMergeFields {
50
+ isInMergeQueue?: boolean;
51
+ isMergeQueueEnabled?: boolean;
52
+ mergeQueueEntry?: RawMergeQueueEntry | null;
53
+ stack?: RawStack | null;
54
+ stackEntry?: {
55
+ position: number;
56
+ } | null;
57
+ baseRef?: RawBaseRef | null;
58
+ }
59
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,11 @@
1
1
  import type { CommentAuthorAssociation } from "../types/github.mts";
2
+ import type { RawPrMergeFields } from "./batch-raw-rules.mts";
2
3
  export interface RawBatchResponse {
3
4
  repository: {
4
5
  pullRequest: RawPr | null;
5
6
  } | null;
6
7
  }
7
- export interface RawPr {
8
+ export interface RawPr extends RawPrMergeFields {
8
9
  id: string;
9
10
  number: number;
10
11
  state: string;
@@ -18,9 +19,7 @@ export interface RawPr {
18
19
  nameWithOwner: string;
19
20
  } | null;
20
21
  baseRefName: string;
21
- baseRef: {
22
- branchProtectionRule: RawBranchProtectionRule | null;
23
- } | null;
22
+ baseRef: import("./batch-raw-rules.mts").RawBaseRef | null;
24
23
  reviewRequests: {
25
24
  nodes: Array<{
26
25
  requestedReviewer: {
@@ -79,6 +78,7 @@ export interface RawPr {
79
78
  commit: {
80
79
  oid: string;
81
80
  committedDate?: string;
81
+ checkSuites?: RawCheckSuites;
82
82
  statusCheckRollup: {
83
83
  contexts: {
84
84
  pageInfo: {
@@ -92,6 +92,22 @@ export interface RawPr {
92
92
  }>;
93
93
  };
94
94
  }
95
+ interface RawCheckSuites {
96
+ pageInfo: {
97
+ hasNextPage: boolean;
98
+ };
99
+ nodes: Array<{
100
+ conclusion: string | null;
101
+ workflowRun: {
102
+ databaseId: number | null;
103
+ event: string | null;
104
+ url: string | null;
105
+ workflow: {
106
+ name: string | null;
107
+ } | null;
108
+ } | null;
109
+ }>;
110
+ }
95
111
  interface RawAuthor {
96
112
  __typename?: string;
97
113
  login: string;
@@ -165,13 +181,6 @@ export interface RawReviewSummary {
165
181
  body: string;
166
182
  createdAt?: string;
167
183
  }
168
- interface RawBranchProtectionRule {
169
- requiresApprovingReviews: boolean;
170
- requiredApprovingReviewCount: number;
171
- requiresConversationResolution: boolean;
172
- requiresStatusChecks: boolean;
173
- requiredStatusCheckContexts: string[] | null;
174
- }
175
184
  export type RawContextNode = {
176
185
  __typename: "CheckRun";
177
186
  id: string;
@@ -3,6 +3,8 @@ import type { BatchPrData } from "../types.mts";
3
3
  interface BatchResult {
4
4
  data: BatchPrData;
5
5
  rateLimit?: RateLimitInfo;
6
+ /** True when GraphQL returned a complete CheckSuite page; skip REST startup-failure fetch. */
7
+ checkSuitesComplete?: boolean;
6
8
  }
7
9
  interface FetchPrBatchOptions {
8
10
  /**
@@ -1,134 +1,28 @@
1
- import { graphql, graphqlWithRateLimit } from "./client.mjs";
2
- import { paginateForward, paginateBackward } from "./pagination.mjs";
1
+ import { graphqlWithRateLimit } from "./client.mjs";
3
2
  import { hydrateThreadCommentPages } from "./thread-comments.mjs";
4
3
  import { BATCH_PR_QUERY } from "./queries.mjs";
5
4
  import { parseRawPr } from "./batch-parsers.mjs";
6
- import { requireContextNodes, requireRawPr } from "./batch-response.mjs";
5
+ import { parseCheckSuitesComplete, parseSuiteStartupFailures } from "./batch-parse-suites.mjs";
6
+ import { mergeStartupFailureChecks } from "../checks/startup-failures.mjs";
7
+ import { paginateBatchConnections } from "./batch-page.mjs";
8
+ import { requireRawPr } from "./batch-response.mjs";
7
9
  /**
8
10
  * Fetch all PR data needed for a `shepherd check` in one (or a few, if paginating) GraphQL requests.
9
11
  */
10
12
  export async function fetchPrBatch(pr, repo, opts = {}) {
11
- // First page: no cursor variables.
12
13
  const result = await graphqlWithRateLimit(BATCH_PR_QUERY, {
13
14
  owner: repo.owner,
14
15
  repo: repo.name,
15
16
  pr,
16
17
  });
17
18
  const raw = requireRawPr(result.data, pr, repo);
18
- // Paginate reviewThreads backward if the first page is incomplete.
19
- let rawThreadPages = raw.reviewThreads.nodes;
20
- if (raw.reviewThreads.pageInfo.hasPreviousPage && raw.reviewThreads.pageInfo.startCursor) {
21
- // Pass startCursor so paginateBackward fetches pages *before* the already-
22
- // fetched first page instead of re-fetching it from the start.
23
- const extra = await paginateBackward(async (cursor) => {
24
- const res = await graphql(BATCH_PR_QUERY, {
25
- owner: repo.owner,
26
- repo: repo.name,
27
- pr,
28
- ...(cursor ? { threadsCursor: cursor } : {}),
29
- });
30
- const pr2 = requireRawPr(res.data, pr, repo);
31
- return pr2.reviewThreads;
32
- }, raw.reviewThreads.pageInfo.startCursor);
33
- // extra contains pages before the first page.
34
- rawThreadPages = [...extra, ...rawThreadPages];
35
- }
36
- rawThreadPages = await hydrateThreadCommentPages(rawThreadPages);
37
- // Paginate comments backward if the first page is incomplete.
38
- let rawCommentNodes = raw.comments.nodes;
39
- if (raw.comments.pageInfo.hasPreviousPage && raw.comments.pageInfo.startCursor) {
40
- const extra = await paginateBackward(async (cursor) => {
41
- const res = await graphql(BATCH_PR_QUERY, {
42
- owner: repo.owner,
43
- repo: repo.name,
44
- pr,
45
- ...(cursor ? { commentsCursor: cursor } : {}),
46
- });
47
- const pr2 = requireRawPr(res.data, pr, repo);
48
- return pr2.comments;
49
- }, raw.comments.pageInfo.startCursor);
50
- rawCommentNodes = [...extra, ...rawCommentNodes];
51
- }
52
- // Paginate CHANGES_REQUESTED reviews backward if the first page is incomplete.
53
- let rawReviewNodes = raw.changesRequestedReviews.nodes;
54
- if (raw.changesRequestedReviews.pageInfo.hasPreviousPage &&
55
- raw.changesRequestedReviews.pageInfo.startCursor) {
56
- const extra = await paginateBackward(async (cursor) => {
57
- const res = await graphql(BATCH_PR_QUERY, {
58
- owner: repo.owner,
59
- repo: repo.name,
60
- pr,
61
- ...(cursor ? { changesRequestedCursor: cursor } : {}),
62
- });
63
- const pr2 = requireRawPr(res.data, pr, repo);
64
- return pr2.changesRequestedReviews;
65
- }, raw.changesRequestedReviews.pageInfo.startCursor);
66
- rawReviewNodes = [...extra, ...rawReviewNodes];
67
- }
68
- // Paginate COMMENTED review summaries backward if the first page is incomplete.
69
- let rawReviewSummaryNodes = raw.reviewSummaries.nodes;
70
- if (raw.reviewSummaries.pageInfo.hasPreviousPage && raw.reviewSummaries.pageInfo.startCursor) {
71
- const extra = await paginateBackward(async (cursor) => {
72
- const res = await graphql(BATCH_PR_QUERY, {
73
- owner: repo.owner,
74
- repo: repo.name,
75
- pr,
76
- ...(cursor ? { reviewSummariesCursor: cursor } : {}),
77
- });
78
- const pr2 = requireRawPr(res.data, pr, repo);
79
- return pr2.reviewSummaries;
80
- }, raw.reviewSummaries.pageInfo.startCursor);
81
- rawReviewSummaryNodes = [...extra, ...rawReviewSummaryNodes];
82
- }
83
- // Paginate APPROVED reviews backward if the first page is incomplete — gated behind
84
- // `paginateApprovedReviews` because approvals minimization is opt-in. See FetchPrBatchOptions.
85
- let rawApprovedReviewNodes = raw.approvedReviews.nodes;
86
- if (opts.paginateApprovedReviews &&
87
- raw.approvedReviews.pageInfo.hasPreviousPage &&
88
- raw.approvedReviews.pageInfo.startCursor) {
89
- const extra = await paginateBackward(async (cursor) => {
90
- const res = await graphql(BATCH_PR_QUERY, {
91
- owner: repo.owner,
92
- repo: repo.name,
93
- pr,
94
- ...(cursor ? { approvedReviewsCursor: cursor } : {}),
95
- });
96
- const pr2 = requireRawPr(res.data, pr, repo);
97
- return pr2.approvedReviews;
98
- }, raw.approvedReviews.pageInfo.startCursor);
99
- rawApprovedReviewNodes = [...extra, ...rawApprovedReviewNodes];
100
- }
101
- // Paginate check contexts forward if the first page is incomplete.
102
- let rawCheckNodes = requireContextNodes(raw.commits.nodes[0]?.commit.statusCheckRollup?.contexts.nodes ?? []);
103
- const checksPageInfo = raw.commits.nodes[0]?.commit.statusCheckRollup?.contexts.pageInfo;
104
- const firstOid = raw.commits.nodes[0]?.commit.oid;
105
- if (checksPageInfo?.hasNextPage && checksPageInfo.endCursor) {
106
- // Pass endCursor so paginateForward fetches pages *after* the already-
107
- // fetched first page instead of re-fetching it from the start.
108
- let pageCount = 0;
109
- const extra = await paginateForward(async (cursor) => {
110
- const res = await graphql(BATCH_PR_QUERY, {
111
- owner: repo.owner,
112
- repo: repo.name,
113
- pr,
114
- ...(cursor ? { checksCursor: cursor } : {}),
115
- });
116
- const pr2 = requireRawPr(res.data, pr, repo);
117
- if (!pr2?.commits.nodes[0]?.commit.statusCheckRollup) {
118
- throw new Error(`Check-context pagination interrupted: statusCheckRollup disappeared on page ${pageCount + 2} (possible force-push race). Retry after the push stabilizes.`);
119
- }
120
- const currentOid = pr2.commits.nodes[0]?.commit.oid;
121
- if (firstOid !== undefined && currentOid !== undefined && currentOid !== firstOid) {
122
- throw new Error(`Check-context pagination interrupted: head commit changed from ${firstOid} to ${currentOid} between pages (force-push race). Retry.`);
123
- }
124
- pageCount++;
125
- const ctxs = pr2.commits.nodes[0]?.commit.statusCheckRollup?.contexts;
126
- if (!ctxs)
127
- return { pageInfo: { hasNextPage: false, endCursor: null }, nodes: [] };
128
- return { ...ctxs, nodes: requireContextNodes(ctxs.nodes) };
129
- }, checksPageInfo.endCursor);
130
- rawCheckNodes = [...rawCheckNodes, ...extra];
131
- }
132
- const data = parseRawPr(raw, rawThreadPages, rawCommentNodes, rawReviewNodes, rawReviewSummaryNodes, rawApprovedReviewNodes, rawCheckNodes);
133
- return { data, rateLimit: result.rateLimit };
19
+ const paged = await paginateBatchConnections(pr, repo, raw, opts, result.rateLimit);
20
+ const rawThreadPages = await hydrateThreadCommentPages(paged.threads);
21
+ const data = parseRawPr(raw, rawThreadPages, paged.comments, paged.changesRequested, paged.reviewSummaries, paged.approvedReviews, paged.checks);
22
+ data.checks = mergeStartupFailureChecks(data.checks, parseSuiteStartupFailures(raw));
23
+ return {
24
+ data,
25
+ rateLimit: paged.rateLimit ?? result.rateLimit,
26
+ ...(parseCheckSuitesComplete(raw) && { checkSuitesComplete: true }),
27
+ };
134
28
  }
@@ -0,0 +1,189 @@
1
+ # Follow-up pages only — skipped connections are omitted via @include so extra
2
+ # pages do not re-pay the full batch-pr.gql node cost. Outstanding cursors are
3
+ # sent together in one request.
4
+ query BatchPrPage(
5
+ $owner: String!
6
+ $repo: String!
7
+ $pr: Int!
8
+ $includeThreads: Boolean!
9
+ $threadsCursor: String
10
+ $includeComments: Boolean!
11
+ $commentsCursor: String
12
+ $includeChangesRequested: Boolean!
13
+ $changesRequestedCursor: String
14
+ $includeReviewSummaries: Boolean!
15
+ $reviewSummariesCursor: String
16
+ $includeApprovedReviews: Boolean!
17
+ $approvedReviewsCursor: String
18
+ $includeChecks: Boolean!
19
+ $checksCursor: String
20
+ ) {
21
+ repository(owner: $owner, name: $repo) {
22
+ pullRequest(number: $pr) {
23
+ reviewThreads(last: 100, before: $threadsCursor) @include(if: $includeThreads) {
24
+ pageInfo {
25
+ hasPreviousPage
26
+ startCursor
27
+ }
28
+ nodes {
29
+ id
30
+ isResolved
31
+ isOutdated
32
+ path
33
+ line
34
+ startLine
35
+ comments(first: 100) {
36
+ pageInfo {
37
+ hasNextPage
38
+ endCursor
39
+ }
40
+ nodes {
41
+ id
42
+ isMinimized
43
+ url
44
+ authorAssociation
45
+ author {
46
+ __typename
47
+ login
48
+ }
49
+ pullRequestReview {
50
+ id
51
+ }
52
+ body
53
+ path
54
+ line
55
+ startLine
56
+ createdAt
57
+ }
58
+ }
59
+ }
60
+ }
61
+ comments(last: 100, before: $commentsCursor) @include(if: $includeComments) {
62
+ pageInfo {
63
+ hasPreviousPage
64
+ startCursor
65
+ }
66
+ nodes {
67
+ id
68
+ isMinimized
69
+ url
70
+ authorAssociation
71
+ author {
72
+ __typename
73
+ login
74
+ }
75
+ body
76
+ createdAt
77
+ }
78
+ }
79
+ changesRequestedReviews: reviews(
80
+ states: CHANGES_REQUESTED
81
+ last: 50
82
+ before: $changesRequestedCursor
83
+ ) @include(if: $includeChangesRequested) {
84
+ pageInfo {
85
+ hasPreviousPage
86
+ startCursor
87
+ }
88
+ nodes {
89
+ id
90
+ authorAssociation
91
+ author {
92
+ __typename
93
+ login
94
+ }
95
+ body
96
+ createdAt
97
+ commit {
98
+ oid
99
+ }
100
+ }
101
+ }
102
+ reviewSummaries: reviews(states: COMMENTED, last: 50, before: $reviewSummariesCursor)
103
+ @include(if: $includeReviewSummaries) {
104
+ pageInfo {
105
+ hasPreviousPage
106
+ startCursor
107
+ }
108
+ nodes {
109
+ id
110
+ isMinimized
111
+ authorAssociation
112
+ author {
113
+ __typename
114
+ login
115
+ }
116
+ body
117
+ createdAt
118
+ }
119
+ }
120
+ approvedReviews: reviews(states: APPROVED, last: 50, before: $approvedReviewsCursor)
121
+ @include(if: $includeApprovedReviews) {
122
+ pageInfo {
123
+ hasPreviousPage
124
+ startCursor
125
+ }
126
+ nodes {
127
+ id
128
+ isMinimized
129
+ authorAssociation
130
+ author {
131
+ __typename
132
+ login
133
+ }
134
+ body
135
+ createdAt
136
+ }
137
+ }
138
+ commits(last: 1) @include(if: $includeChecks) {
139
+ nodes {
140
+ commit {
141
+ oid
142
+ statusCheckRollup {
143
+ contexts(first: 100, after: $checksCursor) {
144
+ pageInfo {
145
+ hasNextPage
146
+ endCursor
147
+ }
148
+ nodes {
149
+ __typename
150
+ ... on CheckRun {
151
+ id
152
+ name
153
+ status
154
+ conclusion
155
+ detailsUrl
156
+ completedAt
157
+ startedAt
158
+ title
159
+ summary
160
+ checkSuite {
161
+ createdAt
162
+ updatedAt
163
+ workflowRun {
164
+ event
165
+ createdAt
166
+ updatedAt
167
+ workflow {
168
+ name
169
+ databaseId
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ... on StatusContext {
175
+ context
176
+ state
177
+ createdAt
178
+ targetUrl
179
+ description
180
+ }
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
@@ -1,14 +1,6 @@
1
- query BatchPr(
2
- $owner: String!
3
- $repo: String!
4
- $pr: Int!
5
- $threadsCursor: String
6
- $checksCursor: String
7
- $commentsCursor: String
8
- $changesRequestedCursor: String
9
- $reviewSummariesCursor: String
10
- $approvedReviewsCursor: String
11
- ) {
1
+ # First page only. Extra pages use batch-pr-page.gql so follow-ups do not
2
+ # re-select every connection (GraphQL points scale with possible nodes).
3
+ query BatchPr($owner: String!, $repo: String!, $pr: Int!) {
12
4
  repository(owner: $owner, name: $repo) {
13
5
  pullRequest(number: $pr) {
14
6
  id
@@ -24,13 +16,62 @@ query BatchPr(
24
16
  nameWithOwner
25
17
  }
26
18
  baseRefName
19
+ isInMergeQueue
20
+ isMergeQueueEnabled
21
+ mergeQueueEntry {
22
+ position
23
+ state
24
+ estimatedTimeToMerge
25
+ }
26
+ stack {
27
+ number
28
+ size
29
+ baseRefName
30
+ }
31
+ stackEntry {
32
+ position
33
+ }
27
34
  baseRef {
28
35
  branchProtectionRule {
29
36
  requiresApprovingReviews
30
37
  requiredApprovingReviewCount
31
38
  requiresConversationResolution
39
+ requiresCodeOwnerReviews
40
+ requireLastPushApproval
41
+ requiresCommitSignatures
42
+ requiresLinearHistory
32
43
  requiresStatusChecks
33
44
  requiredStatusCheckContexts
45
+ requiresStrictStatusChecks
46
+ requiresDeployments
47
+ requiredDeploymentEnvironments
48
+ }
49
+ rules(first: 100) {
50
+ nodes {
51
+ type
52
+ parameters {
53
+ ... on PullRequestParameters {
54
+ requiredApprovingReviewCount
55
+ requiredReviewThreadResolution
56
+ requireCodeOwnerReview
57
+ requireLastPushApproval
58
+ }
59
+ ... on RequiredStatusChecksParameters {
60
+ strictRequiredStatusChecksPolicy
61
+ requiredStatusChecks {
62
+ context
63
+ }
64
+ }
65
+ ... on RequiredDeploymentsParameters {
66
+ requiredDeploymentEnvironments
67
+ }
68
+ ... on CodeScanningParameters {
69
+ codeScanningTools {
70
+ tool
71
+ }
72
+ }
73
+ }
74
+ }
34
75
  }
35
76
  }
36
77
  # Not paginated — capped at 50; PRs with more pending reviewers truncate silently.
@@ -61,7 +102,7 @@ query BatchPr(
61
102
  state
62
103
  }
63
104
  }
64
- reviewThreads(last: 100, before: $threadsCursor) {
105
+ reviewThreads(last: 100) {
65
106
  pageInfo {
66
107
  hasPreviousPage
67
108
  startCursor
@@ -99,7 +140,7 @@ query BatchPr(
99
140
  }
100
141
  }
101
142
  }
102
- comments(last: 100, before: $commentsCursor) {
143
+ comments(last: 100) {
103
144
  pageInfo {
104
145
  hasPreviousPage
105
146
  startCursor
@@ -117,11 +158,7 @@ query BatchPr(
117
158
  createdAt
118
159
  }
119
160
  }
120
- changesRequestedReviews: reviews(
121
- states: CHANGES_REQUESTED
122
- last: 50
123
- before: $changesRequestedCursor
124
- ) {
161
+ changesRequestedReviews: reviews(states: CHANGES_REQUESTED, last: 50) {
125
162
  pageInfo {
126
163
  hasPreviousPage
127
164
  startCursor
@@ -140,7 +177,7 @@ query BatchPr(
140
177
  }
141
178
  }
142
179
  }
143
- reviewSummaries: reviews(states: COMMENTED, last: 50, before: $reviewSummariesCursor) {
180
+ reviewSummaries: reviews(states: COMMENTED, last: 50) {
144
181
  pageInfo {
145
182
  hasPreviousPage
146
183
  startCursor
@@ -160,7 +197,7 @@ query BatchPr(
160
197
  allReviews: reviews(last: 1) {
161
198
  totalCount
162
199
  }
163
- approvedReviews: reviews(states: APPROVED, last: 50, before: $approvedReviewsCursor) {
200
+ approvedReviews: reviews(states: APPROVED, last: 50) {
164
201
  pageInfo {
165
202
  hasPreviousPage
166
203
  startCursor
@@ -183,8 +220,24 @@ query BatchPr(
183
220
  commit {
184
221
  oid
185
222
  committedDate
223
+ checkSuites(first: 50) {
224
+ pageInfo {
225
+ hasNextPage
226
+ }
227
+ nodes {
228
+ conclusion
229
+ workflowRun {
230
+ databaseId
231
+ event
232
+ url
233
+ workflow {
234
+ name
235
+ }
236
+ }
237
+ }
238
+ }
186
239
  statusCheckRollup {
187
- contexts(first: 100, after: $checksCursor) {
240
+ contexts(first: 100) {
188
241
  pageInfo {
189
242
  hasNextPage
190
243
  endCursor
@@ -0,0 +1,40 @@
1
+ query CommitSuggestionThread($owner: String!, $repo: String!, $pr: Int!, $threadId: ID!) {
2
+ repository(owner: $owner, name: $repo) {
3
+ pullRequest(number: $pr) {
4
+ headRefOid
5
+ headRefName
6
+ headRepository {
7
+ nameWithOwner
8
+ }
9
+ }
10
+ }
11
+ node(id: $threadId) {
12
+ ... on PullRequestReviewThread {
13
+ id
14
+ isResolved
15
+ isOutdated
16
+ path
17
+ line
18
+ startLine
19
+ pullRequest {
20
+ number
21
+ }
22
+ comments(first: 1) {
23
+ nodes {
24
+ isMinimized
25
+ url
26
+ authorAssociation
27
+ author {
28
+ __typename
29
+ login
30
+ }
31
+ body
32
+ path
33
+ line
34
+ startLine
35
+ createdAt
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }