@wuyanbin/ai-code-review-cli-remote 1.0.13-canary.0 → 1.0.15-canary.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.
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -6
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +8 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +16 -3
- package/dist/constants.js.map +1 -1
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/diff.d.ts +14 -0
- package/dist/core/diff.d.ts.map +1 -0
- package/dist/core/diff.js +179 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/core/model.d.ts +6 -0
- package/dist/core/model.d.ts.map +1 -0
- package/dist/core/model.js +120 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/output.d.ts +4 -0
- package/dist/core/output.d.ts.map +1 -0
- package/dist/core/output.js +31 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/prompt.d.ts +17 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +92 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/reviewer.d.ts +6 -0
- package/dist/core/reviewer.d.ts.map +1 -0
- package/dist/core/reviewer.js +112 -0
- package/dist/core/reviewer.js.map +1 -0
- package/dist/core/summarizer.d.ts +3 -0
- package/dist/core/summarizer.d.ts.map +1 -0
- package/dist/core/summarizer.js +48 -0
- package/dist/core/summarizer.js.map +1 -0
- package/dist/diff.d.ts +0 -10
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +0 -54
- package/dist/diff.js.map +1 -1
- package/dist/gitlab/api.d.ts +52 -0
- package/dist/gitlab/api.d.ts.map +1 -0
- package/dist/gitlab/api.js +356 -0
- package/dist/gitlab/api.js.map +1 -0
- package/dist/gitlab.d.ts +0 -5
- package/dist/gitlab.d.ts.map +1 -1
- package/dist/gitlab.js +34 -155
- package/dist/gitlab.js.map +1 -1
- package/dist/http.d.ts +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +13 -0
- package/dist/http.js.map +1 -1
- package/dist/index.js +2 -18
- package/dist/index.js.map +1 -1
- package/dist/platform/config.d.ts +10 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/config.js +156 -0
- package/dist/platform/config.js.map +1 -0
- package/dist/platform/report.d.ts +9 -0
- package/dist/platform/report.d.ts.map +1 -0
- package/dist/platform/report.js +32 -0
- package/dist/platform/report.js.map +1 -0
- package/dist/reviewer.d.ts +1 -4
- package/dist/reviewer.d.ts.map +1 -1
- package/dist/reviewer.js +14 -61
- package/dist/reviewer.js.map +1 -1
- package/dist/runner.d.ts +0 -5
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +33 -64
- package/dist/runner.js.map +1 -1
- package/dist/shared/concurrency.d.ts +2 -0
- package/dist/shared/concurrency.d.ts.map +1 -0
- package/dist/shared/concurrency.js +16 -0
- package/dist/shared/concurrency.js.map +1 -0
- package/dist/shared/http.d.ts +18 -0
- package/dist/shared/http.d.ts.map +1 -0
- package/dist/shared/http.js +54 -0
- package/dist/shared/http.js.map +1 -0
- package/dist/{identity.d.ts → shared/identity.d.ts} +1 -1
- package/dist/shared/identity.d.ts.map +1 -0
- package/dist/{identity.js → shared/identity.js} +1 -1
- package/dist/shared/identity.js.map +1 -0
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -2
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/identity.d.ts.map +0 -1
- package/dist/identity.js.map +0 -1
- /package/dist/{context.d.ts → core/context.d.ts} +0 -0
- /package/dist/{context.js → core/context.js} +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchGitlabContext = fetchGitlabContext;
|
|
4
|
+
exports.postGitlabDiscussions = postGitlabDiscussions;
|
|
5
|
+
exports.postGitlabSummary = postGitlabSummary;
|
|
6
|
+
const constants_1 = require("../constants");
|
|
7
|
+
const diff_1 = require("../core/diff");
|
|
8
|
+
const http_1 = require("../shared/http");
|
|
9
|
+
const identity_1 = require("../shared/identity");
|
|
10
|
+
/**
|
|
11
|
+
* Facade: encapsulates all low-level GitLab REST API interactions.
|
|
12
|
+
* Consumers use high-level methods without knowing pagination, URL construction, or auth headers.
|
|
13
|
+
*/
|
|
14
|
+
class GitlabApiFacade {
|
|
15
|
+
constructor(token, env) {
|
|
16
|
+
this.token = token;
|
|
17
|
+
this.env = env;
|
|
18
|
+
}
|
|
19
|
+
buildApiUrl(suffix) {
|
|
20
|
+
if (!this.env.CI_API_V4_URL ||
|
|
21
|
+
!this.env.CI_PROJECT_ID ||
|
|
22
|
+
!this.env.CI_MERGE_REQUEST_IID) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const apiBase = this.env.CI_API_V4_URL.replace(/\/+$/, "");
|
|
26
|
+
const projectId = encodeURIComponent(this.env.CI_PROJECT_ID);
|
|
27
|
+
const mrIid = encodeURIComponent(this.env.CI_MERGE_REQUEST_IID);
|
|
28
|
+
return `${apiBase}/projects/${projectId}/merge_requests/${mrIid}${suffix}`;
|
|
29
|
+
}
|
|
30
|
+
fetch(url, init = {}) {
|
|
31
|
+
return (0, http_1.fetchWithTimeout)(url, init, constants_1.API_TIMEOUT_MS);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* For idempotent requests (GET/PUT/DELETE): gentle 429/5xx backoff.
|
|
35
|
+
* POST stays on plain fetch to avoid creating duplicate notes on retry.
|
|
36
|
+
*/
|
|
37
|
+
fetchIdempotent(url, init = {}) {
|
|
38
|
+
return (0, http_1.fetchWithRetry)(url, init, constants_1.API_TIMEOUT_MS);
|
|
39
|
+
}
|
|
40
|
+
authHeaders() {
|
|
41
|
+
return { Authorization: `Bearer ${this.token}` };
|
|
42
|
+
}
|
|
43
|
+
get discussionUrl() {
|
|
44
|
+
return this.buildApiUrl("/discussions");
|
|
45
|
+
}
|
|
46
|
+
get noteUrl() {
|
|
47
|
+
return this.buildApiUrl("/notes");
|
|
48
|
+
}
|
|
49
|
+
async fetchCurrentUser() {
|
|
50
|
+
const apiBase = this.env.CI_API_V4_URL?.replace(/\/+$/, "");
|
|
51
|
+
if (!apiBase)
|
|
52
|
+
return null;
|
|
53
|
+
try {
|
|
54
|
+
const resp = await this.fetchIdempotent(`${apiBase}/user`, {
|
|
55
|
+
headers: this.authHeaders(),
|
|
56
|
+
});
|
|
57
|
+
if (!resp.ok) {
|
|
58
|
+
console.error(`[gitlab] fetch current user failed status=${resp.status}`);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return await (0, http_1.parseJsonSafe)(resp);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error(`[gitlab] fetch current user error: ${err instanceof Error ? err.message : err}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async fetchMergeRequest() {
|
|
69
|
+
const url = this.buildApiUrl("");
|
|
70
|
+
if (!url)
|
|
71
|
+
return null;
|
|
72
|
+
try {
|
|
73
|
+
const resp = await this.fetchIdempotent(url, {
|
|
74
|
+
headers: this.authHeaders(),
|
|
75
|
+
});
|
|
76
|
+
if (!resp.ok) {
|
|
77
|
+
console.error(`[gitlab] merge request fetch failed status=${resp.status}`);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return await (0, http_1.parseJsonSafe)(resp);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.error(`[gitlab] merge request fetch error: ${err instanceof Error ? err.message : err}`);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async fetchAllPages(url) {
|
|
88
|
+
const results = [];
|
|
89
|
+
const maxPages = (0, constants_1.resolveMaxPaginationPages)(this.env);
|
|
90
|
+
let page = 1;
|
|
91
|
+
while (page <= maxPages) {
|
|
92
|
+
const sep = url.includes("?") ? "&" : "?";
|
|
93
|
+
let resp;
|
|
94
|
+
try {
|
|
95
|
+
resp = await this.fetchIdempotent(`${url}${sep}per_page=100&page=${page}`, { headers: this.authHeaders() });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
console.error(`[gitlab] pagination request failed page=${page}`);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (!resp.ok)
|
|
102
|
+
break;
|
|
103
|
+
const items = await (0, http_1.parseJsonSafe)(resp);
|
|
104
|
+
if (!items?.length)
|
|
105
|
+
break;
|
|
106
|
+
results.push(...items);
|
|
107
|
+
if (items.length < 100)
|
|
108
|
+
break;
|
|
109
|
+
page += 1;
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
async postDiscussion(body) {
|
|
114
|
+
const url = this.discussionUrl;
|
|
115
|
+
if (!url)
|
|
116
|
+
return null;
|
|
117
|
+
return this.fetch(url, {
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: { "Content-Type": "application/json", ...this.authHeaders() },
|
|
120
|
+
body: JSON.stringify(body),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async postNote(body) {
|
|
124
|
+
const url = this.noteUrl;
|
|
125
|
+
if (!url)
|
|
126
|
+
return null;
|
|
127
|
+
return this.fetch(url, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: { "Content-Type": "application/json", ...this.authHeaders() },
|
|
130
|
+
body: JSON.stringify(body),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async updateNote(discussionId, noteId, body) {
|
|
134
|
+
const baseUrl = this.discussionUrl;
|
|
135
|
+
if (!baseUrl)
|
|
136
|
+
return false;
|
|
137
|
+
const resp = await this.fetchIdempotent(`${baseUrl}/${discussionId}/notes/${noteId}`, {
|
|
138
|
+
method: "PUT",
|
|
139
|
+
headers: { "Content-Type": "application/json", ...this.authHeaders() },
|
|
140
|
+
body: JSON.stringify({ body }),
|
|
141
|
+
});
|
|
142
|
+
return resp.ok;
|
|
143
|
+
}
|
|
144
|
+
async deleteNote(discussionId, noteId) {
|
|
145
|
+
const baseUrl = this.discussionUrl;
|
|
146
|
+
if (!baseUrl)
|
|
147
|
+
return false;
|
|
148
|
+
const resp = await this.fetchIdempotent(`${baseUrl}/${discussionId}/notes/${noteId}`, {
|
|
149
|
+
method: "DELETE",
|
|
150
|
+
headers: this.authHeaders(),
|
|
151
|
+
});
|
|
152
|
+
return resp.ok || resp.status === 204;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function buildCommentBody(comment) {
|
|
156
|
+
const message = comment.message || constants_1.DEFAULT_COMMENT_MESSAGE;
|
|
157
|
+
const body = comment.suggestion
|
|
158
|
+
? `${message}\n\n建议:${comment.suggestion}`
|
|
159
|
+
: message;
|
|
160
|
+
return `${body}\n\n${(0, identity_1.buildHiddenMarker)(identity_1.COMMENT_MARKER_PREFIX, (0, identity_1.buildCommentFingerprint)(comment))}`;
|
|
161
|
+
}
|
|
162
|
+
function collectBotNotesByMarker(discussions, userId, markerKind) {
|
|
163
|
+
const notes = new Map();
|
|
164
|
+
for (const discussion of discussions) {
|
|
165
|
+
for (const note of discussion.notes) {
|
|
166
|
+
if (note.author.id !== userId || note.system || !note.body)
|
|
167
|
+
continue;
|
|
168
|
+
const fingerprint = (0, identity_1.extractHiddenMarker)(note.body, markerKind);
|
|
169
|
+
if (!fingerprint)
|
|
170
|
+
continue;
|
|
171
|
+
const current = notes.get(fingerprint) ?? [];
|
|
172
|
+
current.push({
|
|
173
|
+
discussionId: discussion.id,
|
|
174
|
+
noteId: note.id,
|
|
175
|
+
body: note.body,
|
|
176
|
+
});
|
|
177
|
+
notes.set(fingerprint, current);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return notes;
|
|
181
|
+
}
|
|
182
|
+
function buildValidLineSet(diff) {
|
|
183
|
+
const set = new Set();
|
|
184
|
+
for (const [file, lines] of (0, diff_1.collectAddedLines)(diff)) {
|
|
185
|
+
for (const { line } of lines) {
|
|
186
|
+
set.add(`${file}:${line}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return set;
|
|
190
|
+
}
|
|
191
|
+
function isLineValid(validLines, file, line) {
|
|
192
|
+
if (!validLines)
|
|
193
|
+
return true;
|
|
194
|
+
return validLines.has(`${(0, diff_1.normalizePath)(file)}:${line}`);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Fetch the per-run shared read context (current user + all discussions) once.
|
|
198
|
+
* Returns null when there is no token or no GitLab CI context, in which case the
|
|
199
|
+
* writers fall back to their own (also short-circuiting) fetch logic.
|
|
200
|
+
*/
|
|
201
|
+
async function fetchGitlabContext(options) {
|
|
202
|
+
const env = options.env ?? process.env;
|
|
203
|
+
if (!options.token)
|
|
204
|
+
return null;
|
|
205
|
+
const facade = new GitlabApiFacade(options.token, env);
|
|
206
|
+
const discussionUrl = facade.discussionUrl;
|
|
207
|
+
if (!discussionUrl)
|
|
208
|
+
return null;
|
|
209
|
+
const user = await facade.fetchCurrentUser();
|
|
210
|
+
const discussions = user
|
|
211
|
+
? await facade.fetchAllPages(discussionUrl)
|
|
212
|
+
: [];
|
|
213
|
+
return { user, discussions };
|
|
214
|
+
}
|
|
215
|
+
async function postGitlabDiscussions(options) {
|
|
216
|
+
const env = options.env ?? process.env;
|
|
217
|
+
if (!options.token) {
|
|
218
|
+
console.error("[gitlab] MR discussions skipped: missing GitLab token");
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
const facade = new GitlabApiFacade(options.token, env);
|
|
222
|
+
const discussionUrl = facade.discussionUrl;
|
|
223
|
+
if (!discussionUrl) {
|
|
224
|
+
console.error("[gitlab] MR discussions skipped: missing GitLab CI context");
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
const validLines = options.diff ? buildValidLineSet(options.diff) : null;
|
|
228
|
+
const user = options.context
|
|
229
|
+
? options.context.user
|
|
230
|
+
: await facade.fetchCurrentUser();
|
|
231
|
+
const discussions = options.context
|
|
232
|
+
? options.context.discussions
|
|
233
|
+
: user
|
|
234
|
+
? await facade.fetchAllPages(discussionUrl)
|
|
235
|
+
: [];
|
|
236
|
+
const existing = user
|
|
237
|
+
? collectBotNotesByMarker(discussions, user.id, identity_1.COMMENT_MARKER_PREFIX)
|
|
238
|
+
: new Map();
|
|
239
|
+
const activeFingerprints = new Set();
|
|
240
|
+
const mr = options.comments.length ? await facade.fetchMergeRequest() : null;
|
|
241
|
+
const refs = mr?.diff_refs;
|
|
242
|
+
if (options.comments.length &&
|
|
243
|
+
(!refs?.base_sha || !refs.start_sha || !refs.head_sha)) {
|
|
244
|
+
console.error("[gitlab] MR discussions skipped: missing diff refs");
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
let posted = 0;
|
|
248
|
+
let updated = 0;
|
|
249
|
+
let skippedInvalid = 0;
|
|
250
|
+
for (const comment of options.comments) {
|
|
251
|
+
if (!comment.file || !comment.line)
|
|
252
|
+
continue;
|
|
253
|
+
if (!isLineValid(validLines, comment.file, comment.line)) {
|
|
254
|
+
skippedInvalid += 1;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const fingerprint = (0, identity_1.buildCommentFingerprint)(comment);
|
|
258
|
+
const body = buildCommentBody(comment);
|
|
259
|
+
activeFingerprints.add(fingerprint);
|
|
260
|
+
const old = existing.get(fingerprint)?.[0];
|
|
261
|
+
try {
|
|
262
|
+
if (old) {
|
|
263
|
+
const ok = await facade.updateNote(old.discussionId, old.noteId, body);
|
|
264
|
+
if (ok) {
|
|
265
|
+
updated += 1;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
console.error(`[gitlab] MR discussion update failed file=${comment.file} line=${comment.line}`);
|
|
269
|
+
}
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const resp = await facade.postDiscussion({
|
|
273
|
+
body,
|
|
274
|
+
position: {
|
|
275
|
+
base_sha: refs.base_sha,
|
|
276
|
+
start_sha: refs.start_sha,
|
|
277
|
+
head_sha: refs.head_sha,
|
|
278
|
+
position_type: "text",
|
|
279
|
+
new_path: comment.file,
|
|
280
|
+
new_line: Number(comment.line),
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
if (!resp || !resp.ok) {
|
|
284
|
+
console.error(`[gitlab] MR discussion failed file=${comment.file} line=${comment.line} status=${resp?.status}`);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
posted += 1;
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
console.error(`[gitlab] MR discussion error file=${comment.file} line=${comment.line}: ${err instanceof Error ? err.message : err}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
let deleted = 0;
|
|
294
|
+
for (const [fingerprint, oldNotes] of existing) {
|
|
295
|
+
const staleNotes = activeFingerprints.has(fingerprint)
|
|
296
|
+
? oldNotes.slice(1)
|
|
297
|
+
: oldNotes;
|
|
298
|
+
for (const old of staleNotes) {
|
|
299
|
+
try {
|
|
300
|
+
if (await facade.deleteNote(old.discussionId, old.noteId)) {
|
|
301
|
+
deleted += 1;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
console.error(`[gitlab] stale discussion delete error discussion=${old.discussionId} note=${old.noteId}: ${err instanceof Error ? err.message : err}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
console.error(`[gitlab] MR discussions lifecycle posted=${posted} updated=${updated} deleted=${deleted} skippedInvalid=${skippedInvalid}`);
|
|
310
|
+
return posted + updated + deleted > 0;
|
|
311
|
+
}
|
|
312
|
+
async function postGitlabSummary(options) {
|
|
313
|
+
const env = options.env ?? process.env;
|
|
314
|
+
const markdown = options.markdown.trim();
|
|
315
|
+
if (!markdown) {
|
|
316
|
+
console.error("[gitlab] summary skipped: empty markdown");
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
if (!options.token) {
|
|
320
|
+
console.error("[gitlab] summary skipped: missing GitLab token");
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
const facade = new GitlabApiFacade(options.token, env);
|
|
324
|
+
const discussionUrl = facade.discussionUrl;
|
|
325
|
+
const noteUrl = facade.noteUrl;
|
|
326
|
+
if (!discussionUrl || !noteUrl) {
|
|
327
|
+
console.error("[gitlab] summary skipped: missing GitLab CI context");
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
const user = options.context
|
|
331
|
+
? options.context.user
|
|
332
|
+
: await facade.fetchCurrentUser();
|
|
333
|
+
const summaryFingerprint = (0, identity_1.stableHash)(identity_1.SUMMARY_MARKER);
|
|
334
|
+
const body = `${markdown}\n\n${(0, identity_1.buildHiddenMarker)(identity_1.SUMMARY_MARKER, summaryFingerprint)}`;
|
|
335
|
+
if (user) {
|
|
336
|
+
const discussions = options.context
|
|
337
|
+
? options.context.discussions
|
|
338
|
+
: await facade.fetchAllPages(discussionUrl);
|
|
339
|
+
const existing = collectBotNotesByMarker(discussions, user.id, identity_1.SUMMARY_MARKER).get(summaryFingerprint)?.[0];
|
|
340
|
+
if (existing) {
|
|
341
|
+
const ok = await facade.updateNote(existing.discussionId, existing.noteId, body);
|
|
342
|
+
console.error(ok
|
|
343
|
+
? "[gitlab] summary note updated"
|
|
344
|
+
: "[gitlab] summary note update failed");
|
|
345
|
+
return ok;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const resp = await facade.postNote({ body });
|
|
349
|
+
if (!resp || !resp.ok) {
|
|
350
|
+
console.error(`[gitlab] summary note post failed status=${resp?.status}`);
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
console.error("[gitlab] summary note posted");
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/gitlab/api.ts"],"names":[],"mappings":"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"}
|
package/dist/gitlab.d.ts
CHANGED
|
@@ -8,9 +8,4 @@ export declare function postGitlabDiscussions(options: {
|
|
|
8
8
|
token?: string;
|
|
9
9
|
env?: NodeJS.ProcessEnv;
|
|
10
10
|
}): Promise<boolean>;
|
|
11
|
-
export declare function postGitlabSummary(options: {
|
|
12
|
-
markdown: string;
|
|
13
|
-
token?: string;
|
|
14
|
-
env?: NodeJS.ProcessEnv;
|
|
15
|
-
}): Promise<boolean>;
|
|
16
11
|
//# sourceMappingURL=gitlab.d.ts.map
|
package/dist/gitlab.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../src/gitlab.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../src/gitlab.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAsIzC,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DlB;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE;IACnD,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgEnB"}
|
package/dist/gitlab.js
CHANGED
|
@@ -2,19 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.cleanupBotComments = cleanupBotComments;
|
|
4
4
|
exports.postGitlabDiscussions = postGitlabDiscussions;
|
|
5
|
-
exports.postGitlabSummary = postGitlabSummary;
|
|
6
5
|
const constants_1 = require("./constants");
|
|
7
6
|
const http_1 = require("./http");
|
|
8
|
-
const
|
|
7
|
+
const GITLAB_API_CONCURRENCY = 5;
|
|
9
8
|
function gitlabFetch(url, init = {}) {
|
|
10
9
|
return (0, http_1.fetchWithTimeout)(url, init, constants_1.API_TIMEOUT_MS);
|
|
11
10
|
}
|
|
12
11
|
function buildCommentBody(comment) {
|
|
13
12
|
const message = comment.message || constants_1.DEFAULT_COMMENT_MESSAGE;
|
|
14
|
-
|
|
13
|
+
return comment.suggestion
|
|
15
14
|
? `${message}\n\n建议:${comment.suggestion}`
|
|
16
15
|
: message;
|
|
17
|
-
return `${body}\n\n${(0, identity_1.buildHiddenMarker)(identity_1.COMMENT_MARKER_PREFIX, (0, identity_1.buildCommentFingerprint)(comment))}`;
|
|
18
16
|
}
|
|
19
17
|
function buildApiUrl(env, suffix) {
|
|
20
18
|
if (!env.CI_API_V4_URL || !env.CI_PROJECT_ID || !env.CI_MERGE_REQUEST_IID) {
|
|
@@ -25,9 +23,6 @@ function buildApiUrl(env, suffix) {
|
|
|
25
23
|
const mrIid = encodeURIComponent(env.CI_MERGE_REQUEST_IID);
|
|
26
24
|
return `${apiBase}/projects/${projectId}/merge_requests/${mrIid}${suffix}`;
|
|
27
25
|
}
|
|
28
|
-
function buildMrNoteUrl(env) {
|
|
29
|
-
return buildApiUrl(env, "/notes");
|
|
30
|
-
}
|
|
31
26
|
async function fetchMergeRequest(token, env) {
|
|
32
27
|
const url = buildApiUrl(env, "");
|
|
33
28
|
if (!url)
|
|
@@ -91,44 +86,6 @@ async function fetchAllPages(url, token) {
|
|
|
91
86
|
}
|
|
92
87
|
return results;
|
|
93
88
|
}
|
|
94
|
-
function collectBotNotesByMarker(discussions, userId, markerKind) {
|
|
95
|
-
const notes = new Map();
|
|
96
|
-
for (const discussion of discussions) {
|
|
97
|
-
for (const note of discussion.notes) {
|
|
98
|
-
if (note.author.id !== userId || note.system || !note.body)
|
|
99
|
-
continue;
|
|
100
|
-
const fingerprint = (0, identity_1.extractHiddenMarker)(note.body, markerKind);
|
|
101
|
-
if (!fingerprint)
|
|
102
|
-
continue;
|
|
103
|
-
const current = notes.get(fingerprint) ?? [];
|
|
104
|
-
current.push({
|
|
105
|
-
discussionId: discussion.id,
|
|
106
|
-
noteId: note.id,
|
|
107
|
-
body: note.body,
|
|
108
|
-
});
|
|
109
|
-
notes.set(fingerprint, current);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return notes;
|
|
113
|
-
}
|
|
114
|
-
async function updateDiscussionNote(discussionUrl, token, discussionId, noteId, body) {
|
|
115
|
-
const resp = await gitlabFetch(`${discussionUrl}/${discussionId}/notes/${noteId}`, {
|
|
116
|
-
method: "PUT",
|
|
117
|
-
headers: {
|
|
118
|
-
"Content-Type": "application/json",
|
|
119
|
-
Authorization: `Bearer ${token}`,
|
|
120
|
-
},
|
|
121
|
-
body: JSON.stringify({ body }),
|
|
122
|
-
});
|
|
123
|
-
return resp.ok;
|
|
124
|
-
}
|
|
125
|
-
async function deleteDiscussionNote(discussionUrl, token, discussionId, noteId) {
|
|
126
|
-
const resp = await gitlabFetch(`${discussionUrl}/${discussionId}/notes/${noteId}`, {
|
|
127
|
-
method: "DELETE",
|
|
128
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
129
|
-
});
|
|
130
|
-
return resp.ok || resp.status === 204;
|
|
131
|
-
}
|
|
132
89
|
async function cleanupBotComments(options) {
|
|
133
90
|
const env = options.env ?? process.env;
|
|
134
91
|
if (!options.token) {
|
|
@@ -147,34 +104,42 @@ async function cleanupBotComments(options) {
|
|
|
147
104
|
}
|
|
148
105
|
console.error(`[gitlab] cleanup bot user=${user.username} (id=${user.id})`);
|
|
149
106
|
const discussions = await fetchAllPages(discussionUrl, options.token);
|
|
150
|
-
|
|
107
|
+
const toDelete = [];
|
|
151
108
|
for (const discussion of discussions) {
|
|
152
109
|
for (const note of discussion.notes) {
|
|
153
110
|
if (note.author.id !== user.id || note.system)
|
|
154
111
|
continue;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
112
|
+
toDelete.push({ discussionId: discussion.id, noteId: note.id });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
let deleted = 0;
|
|
116
|
+
await (0, http_1.mapConcurrent)(toDelete, GITLAB_API_CONCURRENCY, async ({ discussionId, noteId }) => {
|
|
117
|
+
const deleteUrl = `${discussionUrl}/${discussionId}/notes/${noteId}`;
|
|
118
|
+
try {
|
|
119
|
+
const resp = await gitlabFetch(deleteUrl, {
|
|
120
|
+
method: "DELETE",
|
|
121
|
+
headers: { Authorization: `Bearer ${options.token}` },
|
|
122
|
+
});
|
|
123
|
+
if (resp.ok || resp.status === 204) {
|
|
124
|
+
deleted += 1;
|
|
167
125
|
}
|
|
168
|
-
|
|
169
|
-
console.error(`[gitlab] delete note
|
|
126
|
+
else {
|
|
127
|
+
console.error(`[gitlab] delete note failed discussion=${discussionId} note=${noteId} status=${resp.status}`);
|
|
170
128
|
}
|
|
171
129
|
}
|
|
172
|
-
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.error(`[gitlab] delete note error discussion=${discussionId} note=${noteId}: ${err instanceof Error ? err.message : err}`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
173
134
|
console.error(`[gitlab] cleanup complete deleted=${deleted}`);
|
|
174
135
|
return deleted;
|
|
175
136
|
}
|
|
176
137
|
async function postGitlabDiscussions(options) {
|
|
177
138
|
const env = options.env ?? process.env;
|
|
139
|
+
if (options.comments.length === 0) {
|
|
140
|
+
console.error("[gitlab] MR discussions skipped: no diagnostics");
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
178
143
|
if (!options.token) {
|
|
179
144
|
console.error("[gitlab] MR discussions skipped: missing GitLab token");
|
|
180
145
|
return false;
|
|
@@ -184,42 +149,16 @@ async function postGitlabDiscussions(options) {
|
|
|
184
149
|
console.error("[gitlab] MR discussions skipped: missing GitLab CI context");
|
|
185
150
|
return false;
|
|
186
151
|
}
|
|
187
|
-
const
|
|
188
|
-
const discussions = user
|
|
189
|
-
? await fetchAllPages(discussionUrl, options.token)
|
|
190
|
-
: [];
|
|
191
|
-
const existing = user
|
|
192
|
-
? collectBotNotesByMarker(discussions, user.id, identity_1.COMMENT_MARKER_PREFIX)
|
|
193
|
-
: new Map();
|
|
194
|
-
const activeFingerprints = new Set();
|
|
195
|
-
const mr = options.comments.length
|
|
196
|
-
? await fetchMergeRequest(options.token, env)
|
|
197
|
-
: null;
|
|
152
|
+
const mr = await fetchMergeRequest(options.token, env);
|
|
198
153
|
const refs = mr?.diff_refs;
|
|
199
|
-
if (
|
|
154
|
+
if (!refs?.base_sha || !refs.start_sha || !refs.head_sha) {
|
|
200
155
|
console.error("[gitlab] MR discussions skipped: missing diff refs");
|
|
201
156
|
return false;
|
|
202
157
|
}
|
|
158
|
+
const validComments = options.comments.filter((c) => c.file && c.line);
|
|
203
159
|
let posted = 0;
|
|
204
|
-
|
|
205
|
-
for (const comment of options.comments) {
|
|
206
|
-
if (!comment.file || !comment.line)
|
|
207
|
-
continue;
|
|
208
|
-
const fingerprint = (0, identity_1.buildCommentFingerprint)(comment);
|
|
209
|
-
const body = buildCommentBody(comment);
|
|
210
|
-
activeFingerprints.add(fingerprint);
|
|
211
|
-
const old = existing.get(fingerprint)?.[0];
|
|
160
|
+
await (0, http_1.mapConcurrent)(validComments, GITLAB_API_CONCURRENCY, async (comment) => {
|
|
212
161
|
try {
|
|
213
|
-
if (old) {
|
|
214
|
-
const ok = await updateDiscussionNote(discussionUrl, options.token, old.discussionId, old.noteId, body);
|
|
215
|
-
if (ok) {
|
|
216
|
-
updated += 1;
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
console.error(`[gitlab] MR discussion update failed file=${comment.file} line=${comment.line}`);
|
|
220
|
-
}
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
162
|
const resp = await gitlabFetch(discussionUrl, {
|
|
224
163
|
method: "POST",
|
|
225
164
|
headers: {
|
|
@@ -227,7 +166,7 @@ async function postGitlabDiscussions(options) {
|
|
|
227
166
|
Authorization: `Bearer ${options.token}`,
|
|
228
167
|
},
|
|
229
168
|
body: JSON.stringify({
|
|
230
|
-
body,
|
|
169
|
+
body: buildCommentBody(comment),
|
|
231
170
|
position: {
|
|
232
171
|
base_sha: refs.base_sha,
|
|
233
172
|
start_sha: refs.start_sha,
|
|
@@ -240,75 +179,15 @@ async function postGitlabDiscussions(options) {
|
|
|
240
179
|
});
|
|
241
180
|
if (!resp.ok) {
|
|
242
181
|
console.error(`[gitlab] MR discussion failed file=${comment.file} line=${comment.line} status=${resp.status}`);
|
|
243
|
-
|
|
182
|
+
return;
|
|
244
183
|
}
|
|
245
184
|
posted += 1;
|
|
246
185
|
}
|
|
247
186
|
catch (err) {
|
|
248
187
|
console.error(`[gitlab] MR discussion error file=${comment.file} line=${comment.line}: ${err instanceof Error ? err.message : err}`);
|
|
249
188
|
}
|
|
250
|
-
}
|
|
251
|
-
let deleted = 0;
|
|
252
|
-
for (const [fingerprint, oldNotes] of existing) {
|
|
253
|
-
const staleNotes = activeFingerprints.has(fingerprint)
|
|
254
|
-
? oldNotes.slice(1)
|
|
255
|
-
: oldNotes;
|
|
256
|
-
for (const old of staleNotes) {
|
|
257
|
-
try {
|
|
258
|
-
if (await deleteDiscussionNote(discussionUrl, options.token, old.discussionId, old.noteId)) {
|
|
259
|
-
deleted += 1;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
catch (err) {
|
|
263
|
-
console.error(`[gitlab] stale discussion delete error discussion=${old.discussionId} note=${old.noteId}: ${err instanceof Error ? err.message : err}`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
console.error(`[gitlab] MR discussions lifecycle posted=${posted} updated=${updated} deleted=${deleted}`);
|
|
268
|
-
return posted + updated + deleted > 0;
|
|
269
|
-
}
|
|
270
|
-
async function postGitlabSummary(options) {
|
|
271
|
-
const env = options.env ?? process.env;
|
|
272
|
-
const markdown = options.markdown.trim();
|
|
273
|
-
if (!markdown) {
|
|
274
|
-
console.error("[gitlab] summary skipped: empty markdown");
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
if (!options.token) {
|
|
278
|
-
console.error("[gitlab] summary skipped: missing GitLab token");
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
const discussionUrl = buildApiUrl(env, "/discussions");
|
|
282
|
-
const noteUrl = buildMrNoteUrl(env);
|
|
283
|
-
if (!discussionUrl || !noteUrl) {
|
|
284
|
-
console.error("[gitlab] summary skipped: missing GitLab CI context");
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
const user = await fetchCurrentUser(options.token, env);
|
|
288
|
-
const summaryFingerprint = (0, identity_1.stableHash)(identity_1.SUMMARY_MARKER);
|
|
289
|
-
const body = `${markdown}\n\n${(0, identity_1.buildHiddenMarker)(identity_1.SUMMARY_MARKER, summaryFingerprint)}`;
|
|
290
|
-
if (user) {
|
|
291
|
-
const discussions = await fetchAllPages(discussionUrl, options.token);
|
|
292
|
-
const existing = collectBotNotesByMarker(discussions, user.id, identity_1.SUMMARY_MARKER).get(summaryFingerprint)?.[0];
|
|
293
|
-
if (existing) {
|
|
294
|
-
const ok = await updateDiscussionNote(discussionUrl, options.token, existing.discussionId, existing.noteId, body);
|
|
295
|
-
console.error(ok ? "[gitlab] summary note updated" : "[gitlab] summary note update failed");
|
|
296
|
-
return ok;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const resp = await gitlabFetch(noteUrl, {
|
|
300
|
-
method: "POST",
|
|
301
|
-
headers: {
|
|
302
|
-
"Content-Type": "application/json",
|
|
303
|
-
Authorization: `Bearer ${options.token}`,
|
|
304
|
-
},
|
|
305
|
-
body: JSON.stringify({ body }),
|
|
306
189
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
console.error("[gitlab] summary note posted");
|
|
312
|
-
return true;
|
|
190
|
+
console.error(`[gitlab] MR discussions posted count=${posted}`);
|
|
191
|
+
return posted > 0;
|
|
313
192
|
}
|
|
314
193
|
//# sourceMappingURL=gitlab.js.map
|