edsger 0.49.0 โ 0.50.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.
|
@@ -21,11 +21,27 @@ export declare function fetchFileContent(opts: FetchFileContentOptions): Promise
|
|
|
21
21
|
* Fetch PR file changes (diff information and full content)
|
|
22
22
|
*/
|
|
23
23
|
export declare function fetchPRFileChanges(octokit: Octokit, owner: string, repo: string, prNumber: number, verbose?: boolean): Promise<PRFileChange[]>;
|
|
24
|
+
export interface GraphQLClient {
|
|
25
|
+
graphql: <ResponseData>(query: string, variables?: Record<string, unknown>) => Promise<ResponseData>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Page through every `reviewThreads` connection, following `pageInfo.endCursor`
|
|
29
|
+
* until GitHub reports `hasNextPage: false`. Exported for tests.
|
|
30
|
+
*/
|
|
31
|
+
export declare function fetchAllReviewThreads(octokit: GraphQLClient, owner: string, repo: string, prNumber: number, verbose?: boolean): Promise<ReviewThread[]>;
|
|
24
32
|
/**
|
|
25
33
|
* Fetch unresolved review threads using GitHub GraphQL API
|
|
26
34
|
* This provides accurate resolution status unlike REST API
|
|
27
35
|
*/
|
|
28
36
|
export declare function fetchUnresolvedReviewThreads(octokit: Octokit, owner: string, repo: string, prNumber: number, verbose?: boolean): Promise<ReviewThread[]>;
|
|
37
|
+
/**
|
|
38
|
+
* For any thread whose `comments` connection was truncated (>100 comments),
|
|
39
|
+
* page through the remaining comments and append them to the thread in place.
|
|
40
|
+
* Each thread is hydrated concurrently; the per-thread loop is still
|
|
41
|
+
* sequential because each page depends on the previous cursor. Exported for
|
|
42
|
+
* tests.
|
|
43
|
+
*/
|
|
44
|
+
export declare function hydrateThreadComments(octokit: GraphQLClient, threads: ReviewThread[], verbose?: boolean): Promise<void>;
|
|
29
45
|
/**
|
|
30
46
|
* Mark review threads as resolved using GraphQL API
|
|
31
47
|
*/
|
|
@@ -87,50 +87,108 @@ export async function fetchPRFileChanges(octokit, owner, repo, prNumber, verbose
|
|
|
87
87
|
return [];
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
const REVIEW_THREADS_QUERY = `
|
|
91
|
+
query($owner: String!, $repo: String!, $prNumber: Int!, $threadCursor: String) {
|
|
92
|
+
repository(owner: $owner, name: $repo) {
|
|
93
|
+
pullRequest(number: $prNumber) {
|
|
94
|
+
reviewThreads(first: 100, after: $threadCursor) {
|
|
95
|
+
pageInfo {
|
|
96
|
+
hasNextPage
|
|
97
|
+
endCursor
|
|
98
|
+
}
|
|
99
|
+
nodes {
|
|
100
|
+
id
|
|
101
|
+
isResolved
|
|
102
|
+
isOutdated
|
|
103
|
+
comments(first: 100) {
|
|
104
|
+
totalCount
|
|
105
|
+
pageInfo {
|
|
106
|
+
hasNextPage
|
|
107
|
+
endCursor
|
|
108
|
+
}
|
|
104
109
|
nodes {
|
|
105
110
|
id
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
comments(first: 100) {
|
|
109
|
-
totalCount
|
|
110
|
-
nodes {
|
|
111
|
-
id
|
|
112
|
-
author {
|
|
113
|
-
login
|
|
114
|
-
}
|
|
115
|
-
body
|
|
116
|
-
path
|
|
117
|
-
line
|
|
118
|
-
url
|
|
119
|
-
}
|
|
111
|
+
author {
|
|
112
|
+
login
|
|
120
113
|
}
|
|
114
|
+
body
|
|
115
|
+
path
|
|
116
|
+
line
|
|
117
|
+
url
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
const THREAD_COMMENTS_QUERY = `
|
|
127
|
+
query($threadId: ID!, $cursor: String) {
|
|
128
|
+
node(id: $threadId) {
|
|
129
|
+
... on PullRequestReviewThread {
|
|
130
|
+
comments(first: 100, after: $cursor) {
|
|
131
|
+
pageInfo {
|
|
132
|
+
hasNextPage
|
|
133
|
+
endCursor
|
|
134
|
+
}
|
|
135
|
+
nodes {
|
|
136
|
+
id
|
|
137
|
+
author {
|
|
138
|
+
login
|
|
139
|
+
}
|
|
140
|
+
body
|
|
141
|
+
path
|
|
142
|
+
line
|
|
143
|
+
url
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
/**
|
|
151
|
+
* Page through every `reviewThreads` connection, following `pageInfo.endCursor`
|
|
152
|
+
* until GitHub reports `hasNextPage: false`. Exported for tests.
|
|
153
|
+
*/
|
|
154
|
+
export async function fetchAllReviewThreads(octokit, owner, repo, prNumber, verbose) {
|
|
155
|
+
const allThreads = [];
|
|
156
|
+
let threadCursor = null;
|
|
157
|
+
let threadPage = 0;
|
|
158
|
+
while (true) {
|
|
159
|
+
threadPage += 1;
|
|
160
|
+
const result = await octokit.graphql(REVIEW_THREADS_QUERY, {
|
|
128
161
|
owner,
|
|
129
162
|
repo,
|
|
130
163
|
prNumber,
|
|
164
|
+
threadCursor,
|
|
131
165
|
});
|
|
132
|
-
const
|
|
133
|
-
|
|
166
|
+
const page = result.repository?.pullRequest?.reviewThreads;
|
|
167
|
+
const pageThreads = page?.nodes ?? [];
|
|
168
|
+
allThreads.push(...pageThreads);
|
|
169
|
+
if (verbose) {
|
|
170
|
+
logInfo(` ยท page ${threadPage}: fetched ${pageThreads.length} thread(s) (total so far: ${allThreads.length})`);
|
|
171
|
+
}
|
|
172
|
+
const pageInfo = page?.pageInfo;
|
|
173
|
+
if (!pageInfo?.hasNextPage || !pageInfo.endCursor) {
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
threadCursor = pageInfo.endCursor;
|
|
177
|
+
}
|
|
178
|
+
return allThreads;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Fetch unresolved review threads using GitHub GraphQL API
|
|
182
|
+
* This provides accurate resolution status unlike REST API
|
|
183
|
+
*/
|
|
184
|
+
export async function fetchUnresolvedReviewThreads(octokit, owner, repo, prNumber, verbose) {
|
|
185
|
+
try {
|
|
186
|
+
if (verbose) {
|
|
187
|
+
logInfo('๐ Fetching review threads via GraphQL API...');
|
|
188
|
+
}
|
|
189
|
+
const allThreads = await fetchAllReviewThreads(octokit, owner, repo, prNumber, verbose);
|
|
190
|
+
// Fill in any threads whose comments were truncated at 100
|
|
191
|
+
await hydrateThreadComments(octokit, allThreads, verbose);
|
|
134
192
|
// Filter for truly unresolved threads
|
|
135
193
|
// - Exclude resolved threads (isResolved = true)
|
|
136
194
|
// - Exclude outdated threads (isOutdated = true) - these mean code has changed, should auto-resolve
|
|
@@ -158,6 +216,34 @@ export async function fetchUnresolvedReviewThreads(octokit, owner, repo, prNumbe
|
|
|
158
216
|
return [];
|
|
159
217
|
}
|
|
160
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* For any thread whose `comments` connection was truncated (>100 comments),
|
|
221
|
+
* page through the remaining comments and append them to the thread in place.
|
|
222
|
+
* Each thread is hydrated concurrently; the per-thread loop is still
|
|
223
|
+
* sequential because each page depends on the previous cursor. Exported for
|
|
224
|
+
* tests.
|
|
225
|
+
*/
|
|
226
|
+
export async function hydrateThreadComments(octokit, threads, verbose) {
|
|
227
|
+
await Promise.all(threads.map((thread) => hydrateOneThreadComments(octokit, thread, verbose)));
|
|
228
|
+
}
|
|
229
|
+
async function hydrateOneThreadComments(octokit, thread, verbose) {
|
|
230
|
+
let { pageInfo } = thread.comments;
|
|
231
|
+
let cursor = pageInfo?.endCursor ?? null;
|
|
232
|
+
while (pageInfo?.hasNextPage && cursor) {
|
|
233
|
+
const result = await octokit.graphql(THREAD_COMMENTS_QUERY, {
|
|
234
|
+
threadId: thread.id,
|
|
235
|
+
cursor,
|
|
236
|
+
});
|
|
237
|
+
const page = result.node?.comments;
|
|
238
|
+
const pageComments = page?.nodes ?? [];
|
|
239
|
+
thread.comments.nodes.push(...pageComments);
|
|
240
|
+
if (verbose) {
|
|
241
|
+
logInfo(` ยท thread ${thread.id}: fetched ${pageComments.length} extra comment(s)`);
|
|
242
|
+
}
|
|
243
|
+
pageInfo = page?.pageInfo;
|
|
244
|
+
cursor = pageInfo?.endCursor ?? null;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
161
247
|
/**
|
|
162
248
|
* Mark review threads as resolved using GraphQL API
|
|
163
249
|
*/
|
|
@@ -2,22 +2,27 @@
|
|
|
2
2
|
* Type definitions for Code Refine Verification
|
|
3
3
|
*/
|
|
4
4
|
import { type EdsgerConfig } from '../../types/index.js';
|
|
5
|
+
export interface ReviewThreadComment {
|
|
6
|
+
id: string;
|
|
7
|
+
author: {
|
|
8
|
+
login: string;
|
|
9
|
+
};
|
|
10
|
+
body: string;
|
|
11
|
+
path: string;
|
|
12
|
+
line: number | null;
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
5
15
|
export interface ReviewThread {
|
|
6
16
|
id: string;
|
|
7
17
|
isResolved: boolean;
|
|
8
18
|
isOutdated: boolean;
|
|
9
19
|
comments: {
|
|
10
20
|
totalCount: number;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
body: string;
|
|
17
|
-
path: string;
|
|
18
|
-
line: number | null;
|
|
19
|
-
url: string;
|
|
20
|
-
}[];
|
|
21
|
+
pageInfo?: {
|
|
22
|
+
hasNextPage: boolean;
|
|
23
|
+
endCursor: string | null;
|
|
24
|
+
};
|
|
25
|
+
nodes: ReviewThreadComment[];
|
|
21
26
|
};
|
|
22
27
|
}
|
|
23
28
|
export interface PRFileChange {
|
package/package.json
CHANGED
package/vitest.config.ts
CHANGED
|
@@ -2,10 +2,14 @@ import { defineConfig } from 'vitest/config'
|
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
test: {
|
|
5
|
-
//
|
|
6
|
-
// (assert + node --test), not vitest.
|
|
7
|
-
//
|
|
8
|
-
|
|
5
|
+
// Most other __tests__ folders in this package use the node:test API
|
|
6
|
+
// (assert + node --test), not vitest. Scope vitest to the folders whose
|
|
7
|
+
// tests are written against `vitest`; migrating the rest can happen
|
|
8
|
+
// separately.
|
|
9
|
+
include: [
|
|
10
|
+
'src/phases/run-sheet/__tests__/**/*.test.ts',
|
|
11
|
+
'src/phases/code-refine-verification/__tests__/**/*.test.ts',
|
|
12
|
+
],
|
|
9
13
|
exclude: ['dist/**', 'node_modules/**'],
|
|
10
14
|
environment: 'node',
|
|
11
15
|
},
|