gitlab-ai-review 2.5.4 → 3.0.1

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/README.md CHANGED
@@ -9,6 +9,13 @@ GitLab AI Review SDK - 支持 CI/CD 自动配置和手动配置
9
9
  - ✅ 支持手动传递配置
10
10
  - ✅ 获取项目和 MR 信息
11
11
  - ✅ 添加 MR 评论
12
+ - ✅ **全面影响分析** 🆕
13
+ - 检测删除符号的影响
14
+ - 检查文件内部冲突
15
+ - 追踪跨文件依赖关系
16
+ - 完整上下文分析
17
+ - ✅ 行级 AI 代码审查
18
+ - ✅ 批量审查和评论
12
19
 
13
20
  ## 安装
14
21
 
@@ -135,44 +142,221 @@ changes.forEach(change => {
135
142
  await sdk.addComment('✅ 代码审查通过!');
136
143
  ```
137
144
 
145
+ #### `reviewWithImpactAnalysis(options)` 🆕
146
+ AI 审查 MR 的所有变更(包含影响分析)
147
+
148
+ ```javascript
149
+ // 使用默认配置(启用影响分析)
150
+ const results = await sdk.reviewWithImpactAnalysis();
151
+
152
+ // 自定义配置
153
+ const results = await sdk.reviewWithImpactAnalysis({
154
+ maxFiles: 5, // 最多审查 5 个文件
155
+ maxAffectedFiles: 10, // 每个文件最多分析 10 个受影响的文件
156
+ enableImpactAnalysis: true // 启用影响分析(默认)
157
+ });
158
+
159
+ console.log(`审查完成,共添加 ${results.length} 条评论`);
160
+ ```
161
+
162
+ **参数:**
163
+ - `options.maxFiles` - 最大审查文件数量(默认不限制)
164
+ - `options.maxAffectedFiles` - 每个文件最多分析的受影响文件数量(默认 10)
165
+ - `options.enableImpactAnalysis` - 是否启用影响分析(默认 true)
166
+
167
+ **返回值:**
168
+ 返回评论结果数组,每个元素包含:
169
+ - `status` - 'success' 或 'error'
170
+ - `fileName` - 文件名
171
+ - `lineNumber` - 行号
172
+ - `comment` - 评论内容
173
+ - `error` - 错误信息(如果失败)
174
+
175
+ #### `reviewAndCommentOnLines(options)`
176
+ AI 审查 MR 的所有变更(不包含影响分析)
177
+
178
+ ```javascript
179
+ const results = await sdk.reviewAndCommentOnLines({
180
+ maxFiles: 10 // 最多审查 10 个文件
181
+ });
182
+ ```
183
+
138
184
  ## 在 GitLab CI/CD 中使用
139
185
 
140
- `.gitlab-ci.yml` 示例:
186
+ ### 推荐配置:使用 npx 直接运行
187
+
188
+ 在 GitLab 项目根目录创建 `.gitlab-ci.yml` 文件:
141
189
 
142
190
  ```yaml
191
+ # GitLab CI/CD 配置
192
+ # 使用 gitlab-ai-review CLI (npx 方式)
193
+
143
194
  stages:
144
195
  - review
145
196
 
146
- ai-review:
197
+ # gitlab-ai-review CLI 执行任务(推荐)
198
+ ai-code-review:
147
199
  stage: review
148
- image: node:18
200
+ image: node:18-alpine
201
+ tags:
202
+ - docker
203
+ timeout: 30m
149
204
  only:
150
- - merge_requests
205
+ - merge_requests # 只在 MR 时运行
206
+ variables:
207
+ # 🔑 手动传递 GitLab Token
208
+ # 注意:在生产环境中,应该在 GitLab CI/CD Settings > Variables 中配置
209
+ GITLAB_TOKEN: $GITLAB_TOKEN
210
+
211
+ # 🤖 ARK API Key(用于 AI Review)
212
+ ARK_API_KEY: $ARK_API_KEY
213
+
214
+ # GitLab CI 自动提供的环境变量(无需配置):
215
+ # - CI_JOB_TOKEN (自动生成的临时 Token)
216
+ # - CI_SERVER_URL (GitLab 地址)
217
+ # - CI_PROJECT_ID (项目 ID)
218
+ # - CI_MERGE_REQUEST_IID (MR 编号)
219
+
151
220
  script:
152
- - npm install gitlab-ai-review
153
- - node review.js
221
+ - echo ""
222
+ - echo "🔑 环境变量检查..."
223
+ - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
224
+ - echo "ARK_API_KEY = ${ARK_API_KEY}"
225
+ - echo "GITLAB_TOKEN = ${GITLAB_TOKEN:0:10}..."
226
+ - echo "CI_JOB_TOKEN = ${CI_JOB_TOKEN:0:10}..."
227
+ - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
228
+ - echo ""
229
+ - echo "🚀 使用 npx 执行 gitlab-ai-review CLI..."
230
+ - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
231
+ - npx gitlab-ai-review
232
+
233
+ allow_failure: true # 不阻塞 MR 合并
234
+ timeout: 10m # 超时时间
154
235
  ```
155
236
 
156
- `review.js` 示例:
237
+ ### 环境变量配置
238
+
239
+ 在 GitLab 项目的 **Settings > CI/CD > Variables** 中配置:
240
+
241
+ | 变量名 | 说明 | 是否必需 |
242
+ |-------|------|---------|
243
+ | `ARK_API_KEY` | 火山引擎 ARK API 密钥 | ✅ 必需 |
244
+ | `GITLAB_TOKEN` | GitLab 访问令牌 | ⚠️ 建议配置(可用 `CI_JOB_TOKEN` 替代) |
245
+
246
+ ### AI 模型信息
247
+
248
+ 本项目使用**火山引擎豆包大模型**进行代码审查:
249
+
250
+ - **模型**: `doubao-seed-1-6-251015`
251
+ - **申请地址**: [火山引擎 ARK 平台](https://console.volcengine.com/ark/region:ark+cn-beijing/model/detail?Id=doubao-seed-1-6)
252
+
253
+ **如何申请 ARK API Key:**
254
+ 1. 访问 [火山引擎 ARK 控制台](https://console.volcengine.com/ark/region:ark+cn-beijing/model/detail?Id=doubao-seed-1-6)
255
+ 2. 注册/登录账号
256
+ 3. 创建 API Key
257
+ 4. 将 API Key 配置到 GitLab CI/CD Variables 中
258
+
259
+ ---
260
+
261
+ ## 🎯 影响分析示例
262
+
263
+ ### 场景 1:删除被使用的函数
157
264
 
158
265
  ```javascript
159
- import GitLabAIReview from 'gitlab-ai-review';
266
+ // 变更:删除了 utils/api.js 中的 fetchData
267
+ - export function fetchData(url) { ... }
160
268
 
161
- const sdk = new GitLabAIReview();
269
+ // AI 审查结果:
270
+ 🤖 AI 代码审查
162
271
 
163
- // 获取 MR 信息
164
- const mr = await sdk.getMergeRequest();
165
- console.log('正在审查 MR:', mr.title);
272
+ ⚠️ 严重问题:函数 fetchData 已被删除
166
273
 
167
- // 获取代码变更
168
- const changes = await sdk.getMergeRequestChanges();
169
- console.log(`共有 ${changes.length} 个文件变更`);
274
+ 影响分析显示:
275
+ - components/UserList.vue (第 45 ) 在使用此函数
276
+ - pages/Dashboard.vue ( 78 ) 在使用此函数
277
+ - services/data.js (第 12 行) 在使用此函数
170
278
 
171
- // 添加评论
172
- await sdk.addComment('🤖 AI 代码审查已完成!');
279
+ 3 个文件将无法正常工作,建议:
280
+ 1. 恢复此函数,或
281
+ 2. 提供替代方案并更新所有调用处
173
282
  ```
174
283
 
175
- ## 版本
284
+ ### 场景 2:文件内部冲突
285
+
286
+ ```javascript
287
+ // 变更:删除了辅助函数
288
+ - function calculateTotal(items) { ... }
289
+
290
+ export function checkout() {
291
+ const total = calculateTotal(cart.items) // 💥 这里会报错
292
+ // ...
293
+ }
294
+
295
+ // AI 审查结果:
296
+ 🤖 AI 代码审查
297
+
298
+ 🚨 严重错误:文件内部冲突
299
+
300
+ 函数 calculateTotal 在第 5 行被删除,但在第 12 行仍被调用。
301
+ 这将导致运行时错误:ReferenceError: calculateTotal is not defined
302
+
303
+ 必须修复:
304
+ 1. 恢复 calculateTotal 函数,或
305
+ 2. 修改第 12 行的调用逻辑
306
+ ```
307
+
308
+ ### 场景 3:函数签名变更
309
+
310
+ ```javascript
311
+ // 变更:修改了函数参数
312
+ - export function process(data) { ... }
313
+ + export function process(data, options = {}) { ... }
314
+
315
+ // AI 审查结果:
316
+ 🤖 AI 代码审查
317
+
318
+ ⚠️ 函数签名已改变,新增了 options 参数
319
+
320
+ 影响分析显示有 8 个文件在使用此函数,但都未传递新参数。
321
+ 虽然有默认值,但建议检查是否需要在关键场景中传递 options。
322
+
323
+ 受影响的文件:
324
+ - components/Processor.vue
325
+ - services/processor.js
326
+ ...
327
+ ```
328
+
329
+ ## 版本历史
330
+
331
+ ### 3.0.0 - 全面影响分析 🆕
332
+
333
+ **重大更新**:从简单的 diff 审查升级为全面的影响分析系统
334
+
335
+ - ✨ 删除符号检测:自动检测被删除的函数/类/组件,并分析影响范围
336
+ - ✨ 文件内部冲突检查:检测文件内部是否使用了被删除的符号
337
+ - ✨ 完整文件上下文:AI 审查时提供完整文件内容,而非仅 diff
338
+ - ✨ 跨文件依赖追踪:使用 GitLab Search API 搜索符号使用情况
339
+ - ✨ 修改符号识别:识别被修改的函数签名,检查 API 兼容性
340
+ - ⚡ 使用火山引擎豆包大模型 `doubao-seed-1-6-251015`
341
+
342
+ ### 2.4.0
343
+
344
+ - ✅ 行级 AI 代码审查
345
+ - ✅ 批量审查和评论
346
+ - ✅ 基础影响分析
347
+
348
+ ### 2.3.0
349
+
350
+ - ✅ 支持 `reviewguard.md` 配置文件
351
+ - ✅ 项目特定审查规则
352
+
353
+ ### 2.0.0
354
+
355
+ - ✅ CI/CD 自动配置
356
+ - ✅ 手动配置支持
357
+ - ✅ GitLab API 客户端封装
358
+
359
+ ### 1.0.0
176
360
 
177
- - 1.0.1 - 添加 GitLab 客户端封装和自动配置
178
- - 1.0.0 - 初始测试版本
361
+ - 初始版本发布
362
+ - 基础 GitLab 集成
package/cli.js CHANGED
@@ -7,7 +7,68 @@
7
7
 
8
8
  import { GitLabAIReview } from './index.js';
9
9
 
10
+ // 解析命令行参数
11
+ function parseArgs() {
12
+ const args = process.argv.slice(2);
13
+ const options = {
14
+ enableImpactAnalysis: true, // 默认启用影响分析
15
+ maxAffectedFiles: 10,
16
+ maxFiles: Infinity,
17
+ };
18
+
19
+ for (let i = 0; i < args.length; i++) {
20
+ const arg = args[i];
21
+
22
+ if (arg === '--no-impact' || arg === '--disable-impact') {
23
+ options.enableImpactAnalysis = false;
24
+ } else if (arg === '--max-affected-files' && args[i + 1]) {
25
+ options.maxAffectedFiles = parseInt(args[i + 1], 10);
26
+ i++;
27
+ } else if (arg === '--max-files' && args[i + 1]) {
28
+ options.maxFiles = parseInt(args[i + 1], 10);
29
+ i++;
30
+ } else if (arg === '--help' || arg === '-h') {
31
+ console.log(`
32
+ GitLab AI Review CLI
33
+
34
+ 用法:
35
+ npx gitlab-ai-review [选项]
36
+
37
+ 选项:
38
+ --no-impact, --disable-impact 禁用影响分析(默认启用)
39
+ --max-affected-files <数量> 每个文件最多分析的受影响文件数量(默认 10)
40
+ --max-files <数量> 最大审查文件数量(默认不限制)
41
+ --help, -h 显示帮助信息
42
+
43
+ 环境变量:
44
+ GITLAB_TOKEN GitLab 访问令牌
45
+ CI_PROJECT_ID 项目 ID
46
+ CI_MERGE_REQUEST_IID MR IID
47
+ ARK_API_KEY AI API 密钥
48
+
49
+ 示例:
50
+ # 默认模式(启用影响分析)
51
+ npx gitlab-ai-review
52
+
53
+ # 禁用影响分析
54
+ npx gitlab-ai-review --no-impact
55
+
56
+ # 自定义受影响文件数量
57
+ npx gitlab-ai-review --max-affected-files 5
58
+
59
+ # 限制审查文件数量
60
+ npx gitlab-ai-review --max-files 3
61
+ `);
62
+ process.exit(0);
63
+ }
64
+ }
65
+
66
+ return options;
67
+ }
68
+
10
69
  async function main() {
70
+ const cliOptions = parseArgs();
71
+
11
72
  console.log('🚀 GitLab AI Review CLI 启动...\n');
12
73
 
13
74
  try {
@@ -16,11 +77,15 @@ async function main() {
16
77
 
17
78
  // 2. 验证配置
18
79
  console.log('📋 配置信息:');
19
- console.log(` - GitLab Host: ${sdk.config.gitlab.host}`);
80
+ console.log(` - GitLab Host: ${sdk.config.gitlab.url}`);
20
81
  console.log(` - Project ID: ${sdk.config.project.projectId}`);
21
82
  console.log(` - MR IID: ${sdk.config.project.mergeRequestIid}`);
22
83
  console.log(` - AI API Key: ${sdk.config.ai?.arkApiKey ? '✅ 已配置' : '❌ 未配置'}`);
23
84
  console.log(` - Review Guard: ${sdk.config.ai?.guardConfig?.content ? '✅ 已加载' : '⚠️ 未找到'}`);
85
+ console.log(` - 影响分析: ${cliOptions.enableImpactAnalysis ? '✅ 已启用' : '⚠️ 已禁用'}`);
86
+ if (cliOptions.enableImpactAnalysis) {
87
+ console.log(` - 最多分析受影响文件: ${cliOptions.maxAffectedFiles} 个`);
88
+ }
24
89
  console.log();
25
90
 
26
91
  // 3. 获取 MR 变更信息
@@ -28,105 +93,19 @@ async function main() {
28
93
  const changes = await sdk.getMergeRequestChanges();
29
94
  console.log(`✅ 共发现 ${changes.length} 个文件变更\n`);
30
95
 
31
- // 3.1 输出详细的变更列表
32
- if (changes.length > 0) {
33
- console.log('📝 变更文件列表:');
34
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
35
-
36
- changes.forEach((change, index) => {
37
- const fileName = change.new_path || change.old_path;
38
- let status = '';
39
- let statusIcon = '';
40
-
41
- // 判断文件状态
42
- if (change.new_file) {
43
- status = '新增';
44
- statusIcon = '✨';
45
- } else if (change.deleted_file) {
46
- status = '删除';
47
- statusIcon = '🗑️';
48
- } else if (change.renamed_file) {
49
- status = '重命名';
50
- statusIcon = '📝';
51
- } else {
52
- status = '修改';
53
- statusIcon = '✏️';
54
- }
55
-
56
- // 计算变更行数
57
- const diff = change.diff || '';
58
- const addedLines = (diff.match(/^\+[^+]/gm) || []).length;
59
- const deletedLines = (diff.match(/^-[^-]/gm) || []).length;
60
-
61
- console.log(`${index + 1}. ${statusIcon} ${status} - ${fileName}`);
62
- if (addedLines > 0 || deletedLines > 0) {
63
- console.log(` 📊 +${addedLines} -${deletedLines} 行`);
64
- }
65
-
66
- // 如果是重命名,显示旧路径
67
- if (change.renamed_file && change.old_path !== change.new_path) {
68
- console.log(` 📂 ${change.old_path} → ${change.new_path}`);
69
- }
70
-
71
- // 输出具体的 diff 内容
72
- if (diff) {
73
- console.log(`\n 📄 Diff 内容:`);
74
- console.log(' ┌─────────────────────────────────────────────────────');
75
-
76
- // 分行显示 diff,并添加颜色标记
77
- const diffLines = diff.split('\n');
78
- diffLines.forEach((line, lineIndex) => {
79
- // 限制显示最多 100 行 diff
80
- if (lineIndex >= 100) {
81
- if (lineIndex === 100) {
82
- console.log(' │ ... (diff 内容过长,已截断)');
83
- }
84
- return;
85
- }
86
-
87
- // 为不同类型的行添加标记
88
- let prefix = ' │ ';
89
- if (line.startsWith('+++') || line.startsWith('---')) {
90
- prefix = ' │ 📁 '; // 文件路径
91
- } else if (line.startsWith('@@')) {
92
- prefix = ' │ 🔵 '; // hunk 标记
93
- } else if (line.startsWith('+') && !line.startsWith('+++')) {
94
- prefix = ' │ ➕ '; // 新增行
95
- } else if (line.startsWith('-') && !line.startsWith('---')) {
96
- prefix = ' │ ➖ '; // 删除行
97
- }
98
-
99
- console.log(prefix + line);
100
- });
101
-
102
- console.log(' └─────────────────────────────────────────────────────\n');
103
- }
104
- });
105
-
106
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
107
- }
108
-
109
96
  // 4. 执行 AI 代码审查
110
97
  if (sdk.config.ai?.arkApiKey && changes.length > 0) {
111
98
  console.log('🤖 开始 AI 代码审查...\n');
112
99
 
113
- const results = await sdk.reviewAndCommentOnLines();
100
+ // 使用新的影响分析方法
101
+ const results = await sdk.reviewWithImpactAnalysis(cliOptions);
114
102
 
115
- // 统计结果
116
- const fileNames = new Set(results.map(r => r.fileName));
103
+ console.log('\n📊 审查结果汇总:');
117
104
  const successCount = results.filter(r => r.status === 'success').length;
118
105
  const errorCount = results.filter(r => r.status === 'error').length;
119
- const skippedCount = results.filter(r => r.status === 'skipped').length;
120
-
121
- console.log('\n📊 审查结果汇总:');
122
- console.log(` - 审查文件数: ${fileNames.size}`);
123
- console.log(` - 成功添加评论: ${successCount} 条`);
124
- if (errorCount > 0) {
125
- console.log(` - 失败: ${errorCount} 条`);
126
- }
127
- if (skippedCount > 0) {
128
- console.log(` - 跳过: ${skippedCount} 条`);
129
- }
106
+ console.log(` - 总评论数: ${results.length}`);
107
+ console.log(` - 成功: ${successCount}`);
108
+ console.log(` - 失败: ${errorCount}`);
130
109
 
131
110
  if (errorCount > 0) {
132
111
  console.log('\n⚠️ 部分评论添加失败,请检查上方日志');