job51-gitlab-cr-node-jt-1 2.8.3 → 2.8.5
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/.claude/rules/code-review-rules.md +28 -34
- package/docs/GITLAB_CR_NODE_TECHNICAL_DOCS.md +420 -13
- package/index.js +42 -32
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
0. **「已安全处理」代码禁止报告**(关键规则):
|
|
8
8
|
> - **如果代码已正确处理潜在风险(如已判空、已捕获异常、已有边界检查),则绝对禁止报告该问题**
|
|
9
9
|
> - **如果分析结论包含"逻辑正确"、"无需修改"、"已有 XX 保护"、"符合安全编码规范"、"已正确处理该场景"等描述,必须省略该问题,不得输出报告**
|
|
10
|
-
> -
|
|
10
|
+
> - **示例**:判空检查后再进行值比较的逻辑(如:先检查对象非空,再访问其属性)— 已判空后再操作,是安全编码,**禁止报告任何问题**
|
|
11
11
|
> - **自检问题**:输出前问自己"如果这段代码是安全的,我为什么要报告它?"
|
|
12
12
|
|
|
13
13
|
1. **审查范围限制**(关键规则):
|
|
@@ -19,21 +19,21 @@
|
|
|
19
19
|
2. **同一问题只报告一次**:
|
|
20
20
|
> - 同一个空指针问题可能在多处出现(import 行、依赖注入行、方法调用行)
|
|
21
21
|
> - **只在真正会执行出错的代码行上报告一次**
|
|
22
|
-
> -
|
|
23
|
-
> -
|
|
22
|
+
> - 示例:依赖注入的字段声明和后续的方法调用行都存在空指针风险
|
|
23
|
+
> - **正确做法**:只在实际方法调用处报告(如调用 SDK 对象方法的位置),**禁止**在依赖注入行报告
|
|
24
24
|
|
|
25
25
|
3. **禁止报告问题的位置**:
|
|
26
26
|
> - import 导入语句行
|
|
27
27
|
> - 类定义、package 声明行
|
|
28
28
|
> - 方法签名行(除非签名本身有安全问题)
|
|
29
|
-
> -
|
|
29
|
+
> - 依赖注入/字段声明行(如带有依赖注入注解的字段声明)
|
|
30
30
|
> - 仅定义变量但未使用的行
|
|
31
31
|
> - 其他不会直接导致运行时错误的位置
|
|
32
32
|
|
|
33
33
|
4. **深度分析但精准报告**:
|
|
34
34
|
> - **报告运行时异常风险前,必须先用 Read 工具追踪读取相关方法/函数的实现代码**
|
|
35
35
|
> - 适用场景:空指针/空引用异常、类型转换异常、集合越界等所有运行时异常
|
|
36
|
-
> -
|
|
36
|
+
> - 示例:看到方法调用链式访问对象属性时(如:调用服务方法获取对象,再访问该对象属性),**必须先读取**该服务方法的源码,确认其返回值是否可能为 null
|
|
37
37
|
> - 如果方法/函数内部已有防护措施(如返回默认对象、空对象模式、边界检查等),则**禁止报告**该问题
|
|
38
38
|
> - **禁止仅凭代码表面形式判断运行时异常风险**
|
|
39
39
|
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
> - **⚠️ 风格一致性原则**:参数校验、异常处理、注解使用等应与项目原有风格匹配,**不得报告"建议添加 XX 注解/XX 校验/XX 异常处理"** 这类问题。
|
|
42
42
|
> - **⚠️ Controller/Client 接口参数校验放宽**:
|
|
43
43
|
> - Controller 接口方法、Client 接口方法的参数校验**以项目原有风格为准**
|
|
44
|
-
> -
|
|
44
|
+
> - 如果项目现有接口多数没有添加参数校验注解(如非空校验、格式校验等),**不得建议添加**
|
|
45
45
|
> - 如果项目现有接口多数没有显式参数判空逻辑,**不得建议添加**
|
|
46
46
|
> - 参数校验形式应参考同文件/同模块其他接口的写法,保持一致性
|
|
47
47
|
> - **仅在校验风格与同一文件中其他接口明显不一致时**,才需要提示
|
|
@@ -86,14 +86,14 @@
|
|
|
86
86
|
> - **必须读取完整方法上下文**:
|
|
87
87
|
> - 审查前必须使用 Read 工具读取**整个方法**的代码,不只是 diff 块
|
|
88
88
|
> - 分析方法开始处是否有判空保护、早期返回、断言等逻辑
|
|
89
|
-
> -
|
|
89
|
+
> - 示例:方法开头有判空检查并提前返回的逻辑,后续访问该对象属性的代码 **不应报告 NPE**
|
|
90
90
|
> - **必须跨 diff 块分析同一文件/方法的上下文**:
|
|
91
91
|
> - 同一个文件/方法可能被拆分成多个 diff 块,**必须合并所有块一起分析**
|
|
92
|
-
> - 示例:块 A
|
|
92
|
+
> - 示例:块 A 显示删除了对象属性赋值语句,块 B 显示新增了条件判断后的对象属性赋值语句
|
|
93
93
|
> - 这种情况下**不应报告**"删除了 set 值会影响数据",因为块 B 已有新的 set 逻辑
|
|
94
94
|
> - **必须分析方法内联上下文**:
|
|
95
95
|
> - 对于在同一方法内的代码,必须分析完整的上下文逻辑
|
|
96
|
-
> -
|
|
96
|
+
> - 示例:方法开始处已有判空检查并提前返回的逻辑,后续有访问对象属性的调用
|
|
97
97
|
> - **结论**:不应报告空指针问题,因为已有前置判空保护
|
|
98
98
|
> - **确认后再报告**:
|
|
99
99
|
> - 如果方法/函数内部已处理边界情况(如返回默认对象、空对象、默认值等),则**不应**标记为问题
|
|
@@ -105,21 +105,21 @@
|
|
|
105
105
|
|
|
106
106
|
> - **⚠️ 免报告场景识别(强制执行)**:
|
|
107
107
|
> - **工具类方法安全调用**:以下工具类方法内部已处理 null 检查,不应报告空指针问题:
|
|
108
|
-
> -
|
|
109
|
-
> -
|
|
110
|
-
> -
|
|
111
|
-
> -
|
|
108
|
+
> - 集合工具类的判空方法(Apache Commons、Spring 版本)
|
|
109
|
+
> - 字符串工具类的判空判白方法(Apache Commons Lang3)
|
|
110
|
+
> - 字符串判空工具方法(Guava)
|
|
111
|
+
> - 对象判空工具方法(JDK)
|
|
112
112
|
> - **框架校验逻辑**:框架/库自带的校验逻辑不应报告为代码缺陷:
|
|
113
|
-
> - Spring/Bean Validation:
|
|
113
|
+
> - Spring/Bean Validation: 参数非空校验注解、格式校验注解等
|
|
114
114
|
> - Feign Client 参数校验、MyBatis/JPA 实体字段约束
|
|
115
|
-
> - Lombok
|
|
115
|
+
> - Lombok 非空注解生成的代码
|
|
116
116
|
> - **返回类型确定性**:
|
|
117
117
|
> - 基本类型(int, boolean):不可能为 null
|
|
118
|
-
> -
|
|
119
|
-
> -
|
|
118
|
+
> - 明确返回空集合的方法(如返回空集合的工具方法)
|
|
119
|
+
> - 有非空注解或对象非空校验方法保护的方法
|
|
120
120
|
> - **早期返回模式**:
|
|
121
121
|
> - 方法开头已有判空/边界检查并提前返回的代码,后续逻辑**不应报告**空指针问题
|
|
122
|
-
> -
|
|
122
|
+
> - 示例:方法开头有判空或边界检查并提前返回空结果的逻辑,后续有正常业务逻辑,**不应报告**问题
|
|
123
123
|
> - **禁止报告"代码简化建议"类问题**:
|
|
124
124
|
> - **禁止**建议"移除变量声明,直接 return xxx.stream()..."
|
|
125
125
|
> - **禁止**建议"合并变量声明和返回语句"
|
|
@@ -146,9 +146,9 @@
|
|
|
146
146
|
> - 仅定义变量但未使用的行
|
|
147
147
|
> - 其他不会直接导致运行时错误的位置
|
|
148
148
|
> - **Feign Client 远程调用返回值校验**:
|
|
149
|
-
> - Feign Client
|
|
149
|
+
> - Feign Client 接口调用(如客户端接口的方法调用)的返回值**不纳入空指针审查范围**
|
|
150
150
|
> - Feign 框架会在调用失败时抛出异常,而不是返回 null
|
|
151
|
-
> -
|
|
151
|
+
> - 示例:调用远程服务接口获取结果对象,后续调用该结果对象的成功判断方法 **不应报告 NPE 问题**
|
|
152
152
|
5. 使用当前系统时间填充 `[当前时间]`,并根据实际变更内容计算 `[文件数量]`;
|
|
153
153
|
6. 所有占位符必须被真实内容替换;
|
|
154
154
|
> - **修改建议中的代码示例**:
|
|
@@ -158,13 +158,13 @@
|
|
|
158
158
|
> - **代码风格一致性**:建议代码应遵循项目现有风格(工具类方法、函数式编程、命名约定等)
|
|
159
159
|
> - **⚠️ 禁止报告不存在的代码**:
|
|
160
160
|
> - **错误代码示例必须是 diff 中实际存在的代码**(`+` 开头或空格开头的行)
|
|
161
|
-
> - **禁止编造 diff
|
|
161
|
+
> - **禁止编造 diff 中没有的代码**,如报告中出现某个条件判断但 diff 中根本没有这行代码
|
|
162
162
|
> - **禁止报告与 diff 无关的代码片段**,所有问题涉及的代码必须能在当前 diff 块中找到
|
|
163
163
|
> - **输出前验证**:检查错误代码示例中的每一行,确认都能在 diff 的 `+` 开头或空格开头的行中找到
|
|
164
164
|
7. 若无某类问题(如无严重问题),则**完全省略该部分**;
|
|
165
165
|
8. 若同一级别问题有多个,在对应标题下按原代码顺序依次展示;
|
|
166
166
|
> - **⚠️ 跨块去重规则**:**同一文件中由同一根本原因导致的问题,只报告一次**
|
|
167
|
-
> -
|
|
167
|
+
> - 示例:同一对象的同一方法在文件中多处被调用,若都存在未判空问题,**合并为一条报告**
|
|
168
168
|
> - 判断标准:**文件 + 问题类型 + 根本原因**三者相同即为重复问题
|
|
169
169
|
9. **严重问题(🔴)**:
|
|
170
170
|
> - 安全漏洞(SQL 注入、命令注入、敏感信息泄露)
|
|
@@ -181,8 +181,7 @@
|
|
|
181
181
|
> - 导致核心功能失效或产生错误业务结果
|
|
182
182
|
> - 引入构建失败、测试失败或高危依赖漏洞
|
|
183
183
|
> - **⚠️ 问题行号定位规则**:
|
|
184
|
-
> -
|
|
185
|
-
> - 示例:`UserTaskPop pop = sdk.method(); log.debug(pop.getId())` 问题应报告在 `pop.getId()` 行,不是 `sdk.method()` 或变量定义行
|
|
184
|
+
> - 空指针问题:报告在**实际访问对象属性/方法的行**(如访问对象的 ID 属性),不是变量定义行
|
|
186
185
|
> - **每个 diff 块只报告本块内实际会出错的代码**,不要在无关的 diff 块(如 package 行、import 行、类定义行)报告问题
|
|
187
186
|
|
|
188
187
|
11. **问题分级规则**:
|
|
@@ -255,10 +254,6 @@
|
|
|
255
254
|
14. `<REPORT>` 标签示例中的问题块数量仅用于展示格式,实际数量由 review 结果决定;
|
|
256
255
|
|
|
257
256
|
15. **输出前验证流程**:
|
|
258
|
-
> - **块内去重检查**:**同一 diff 块内由同一根本原因导致的问题,只报告一次**
|
|
259
|
-
> - 示例:同一个变量 `userTaskSDK` 在块内多处被调用,若都存在未判空问题,**合并为一条报告**
|
|
260
|
-
> - 方法:**按「变量名 + 问题类型 + 根本原因」进行去重**,相同组合的问题只保留第一个
|
|
261
|
-
> - **注意**:每个 diff 块是独立审查的,无法跨块去重,只需保证当前块内不重复
|
|
262
257
|
> - **代码示例验证**:确保错误代码示例不包含 `-` 开头的已删除代码
|
|
263
258
|
> - **删除代码验证**:**逐条检查问题涉及的代码行,确认不是 `-` 开头的已删除代码**
|
|
264
259
|
> - **安全问题验证**:确保不针对已删除代码报告安全问题
|
|
@@ -270,9 +265,8 @@
|
|
|
270
265
|
> - **错误代码选取**:必须从变更后实际存在的代码中选取(`+` 开头或空格开头)
|
|
271
266
|
> - **⚠️ 违例后果**:对 `-` 开头的代码报告问题是严重误报,必须避免
|
|
272
267
|
> - **⚠️ 问题报告位置规则**:
|
|
273
|
-
> -
|
|
274
|
-
> -
|
|
275
|
-
> - **依赖注入/字段声明**:如 `@Autowired UserTaskSDK userTaskSDK;`,**禁止**在此行报告空指针问题
|
|
268
|
+
> - **空指针/未判空问题**:只报告在**实际调用方法访问返回值的行**,而不是方法声明用或变量定义的行
|
|
269
|
+
> - **依赖注入/字段声明**:**禁止**在依赖注入/字段声明处报告空指针问题
|
|
276
270
|
> - **Import 语句**:**禁止**在 import 行报告任何问题
|
|
277
271
|
> - **同一变量多次使用**:只在第一次可能出错的地方报告一次
|
|
278
272
|
> - **禁止**在类定义、package、import、方法签名等位置报告与这些行无关的问题
|
|
@@ -294,7 +288,7 @@
|
|
|
294
288
|
> - 确认没有对已删除代码报告任何问题
|
|
295
289
|
> - **步骤 7:问题定位验证**
|
|
296
290
|
> - 确认问题报告在**真正会执行出错的行**上
|
|
297
|
-
> -
|
|
291
|
+
> - 空指针问题:报告在实际调用的行,不是变量定义行
|
|
298
292
|
> - 禁止在 package、import、类定义、方法签名等位置报告无关问题
|
|
299
293
|
|
|
300
294
|
18. **输出格式**:严格参照 SKILL.md 模板,无某类问题时省略对应部分;
|
|
@@ -366,7 +360,7 @@
|
|
|
366
360
|
> - [ ] 已追踪读取相关方法实现,确认可能返回危险值
|
|
367
361
|
> - [ ] 已跨 diff 块分析,确认不是已被新逻辑替代的删除代码
|
|
368
362
|
> - [ ] 已分析方法内联上下文,确认没有前置判空保护
|
|
369
|
-
> - [ ]
|
|
363
|
+
> - [ ] 已确认不是工具类方法的安全调用
|
|
370
364
|
> - [ ] 已确认不是框架校验逻辑覆盖的场景
|
|
371
365
|
> - [ ] 已确认不是返回空集合或有不返回 null 保证的方法
|
|
372
366
|
> - [ ] **已确认问题不是"风格偏好"类问题**(如建议添加项目惯例中不存在的注解/校验/异常处理)
|
|
@@ -374,7 +368,7 @@
|
|
|
374
368
|
> - [ ] **已执行跨块去重**:同一文件同一根本原因的问题只报告一次
|
|
375
369
|
> - [ ] **已验证问题位置**:问题报告在真正会执行出错的行上,而非 package/import/类定义/方法签名等位置
|
|
376
370
|
> - [ ] **已确认报告不自相矛盾**:
|
|
377
|
-
> -
|
|
371
|
+
> - 如果代码已有判空检查,**禁止**报告"未判空"问题
|
|
378
372
|
> - 如果分析结论包含"当前代码逻辑正确"、"无需修改"、"已有 XX 保护"等描述,**禁止**将该问题报告为严重问题
|
|
379
373
|
> - **报告前自检**:问题描述、错误代码、修改建议三者逻辑必须一致,不得出现"有判空但说未判空"的矛盾
|
|
380
374
|
> - **建议写法**:如果确实想提醒注意某行为,但代码已正确处理,应省略该问题,不输出报告
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# GitLab Code Review AI Tool 技术文档
|
|
2
2
|
|
|
3
3
|
**项目名称**: job51-gitlab-cr-node
|
|
4
|
-
**当前版本**: 2.
|
|
4
|
+
**当前版本**: 2.8.3
|
|
5
5
|
**作者**: tao.jing
|
|
6
|
-
**最后更新**: 2026-04-
|
|
6
|
+
**最后更新**: 2026-04-23
|
|
7
7
|
**项目地址**: https://gitdev.51job.com/51jobweb/ai-agent
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -27,9 +27,94 @@
|
|
|
27
27
|
|
|
28
28
|
## 版本历史
|
|
29
29
|
|
|
30
|
+
### v2.8.3 (2026-04-23)
|
|
31
|
+
|
|
32
|
+
**当前版本**: 评论发布功能修复
|
|
33
|
+
|
|
34
|
+
**Bug 修复**:
|
|
35
|
+
- **GitLab 评论 API 兼容性修复**:将汇总报告的评论发布从 Discussions API 改为 Notes API,避免权限问题
|
|
36
|
+
- 问题现象:使用 Discussions API 发布汇总报告时可能遇到权限限制或评论类型设置问题
|
|
37
|
+
- 修复方案:
|
|
38
|
+
- 在 `postSummaryCommentToGitLab` 方法中改用 `/projects/:id/merge_requests/:iid/notes` API 端点
|
|
39
|
+
- Notes API 发布的是普通注释(Note),不会显示 resolve 按钮
|
|
40
|
+
- 移除不必要的 `resolvable` 参数配置,简化评论发布流程
|
|
41
|
+
- 影响:
|
|
42
|
+
- 汇总报告评论不再显示 resolve 按钮,避免用户误操作
|
|
43
|
+
- 评论类型统一为普通注释,提高 API 兼容性
|
|
44
|
+
- 简化评论发布逻辑,降低出错概率
|
|
45
|
+
- 修复文件:
|
|
46
|
+
- `index.js:987-1011`:重构汇总报告发布方法,使用 Notes API
|
|
47
|
+
- 移除 `resolvable: false` 参数,Notes API 自动使用普通注释类型
|
|
48
|
+
|
|
49
|
+
### v2.8.2 (2026-04-22)
|
|
50
|
+
|
|
51
|
+
**更新**:
|
|
52
|
+
- **版本号同步**:更新 package.json 版本号到 2.8.2
|
|
53
|
+
|
|
54
|
+
### v2.8.1 (2026-04-22)
|
|
55
|
+
|
|
56
|
+
**Bug 修复**:
|
|
57
|
+
- **汇总报告评论 Resolve 问题修复**:为汇总报告评论设置 `resolvable: false`,避免用户误操作
|
|
58
|
+
- 问题现象:汇总报告作为 Discussion 评论发布时带有 resolve 按钮,用户可能误点 resolve 导致报告消失
|
|
59
|
+
- 修复方案:
|
|
60
|
+
- 在 `postSummaryCommentToGitLab` 方法中添加 `resolvable: false` 参数
|
|
61
|
+
- GitLab Discussion API 中设置 `resolvable: false` 后评论不会显示 resolve 按钮
|
|
62
|
+
- 汇总报告作为信息展示类评论,不应该被 resolve
|
|
63
|
+
- 影响:
|
|
64
|
+
- 汇总报告评论不再显示 resolve 按钮
|
|
65
|
+
- 报告永久保留在 MR 讨论区,方便用户随时查看
|
|
66
|
+
- 避免用户误操作导致报告消失
|
|
67
|
+
- 修复文件:
|
|
68
|
+
- `index.js:988-1010`:添加 `resolvable: false` 配置
|
|
69
|
+
|
|
70
|
+
### v2.8.0 (2026-04-22)
|
|
71
|
+
|
|
72
|
+
**重大功能更新**: AI 汇总报告生成功能
|
|
73
|
+
|
|
74
|
+
**新增功能**:
|
|
75
|
+
- **自动生成汇总报告**:在所有 diff 块审查完成后,自动调用 Claude AI 生成结构化的汇总报告
|
|
76
|
+
- 功能流程:
|
|
77
|
+
1. 收集所有 diff 块的审查报告内容(`collectAllReviewReports` 方法)
|
|
78
|
+
2. 为每个报告添加文件路径和 diff 块索引标识
|
|
79
|
+
3. 调用 Claude CLI 命令生成汇总报告(`callClaudeForSummary` 方法)
|
|
80
|
+
4. 提取 `<SUMMARY_REPORT>` 标签内容
|
|
81
|
+
5. 发布汇总报告到 GitLab MR(`postSummaryCommentToGitLab` 方法)
|
|
82
|
+
- 汇总报告结构:
|
|
83
|
+
- 审查概览:文件数量、diff 块数量、问题总数、严重问题数、警告数
|
|
84
|
+
- 无问题文件列表:列出所有没有问题的文件路径(完整路径)
|
|
85
|
+
- 严重问题汇总:按文件分组,完整展示每个问题的描述、位置、修改建议
|
|
86
|
+
- 警告汇总:按文件分组,完整展示每个问题的描述、位置、修改建议
|
|
87
|
+
- 建议:针对问题的处理建议
|
|
88
|
+
- Prompt 设计:
|
|
89
|
+
- 使用东八区时间(北京时间,UTC+8)生成时间戳
|
|
90
|
+
- 构造详细的汇总报告模板,要求 AI 严格按照模板格式输出
|
|
91
|
+
- 强制使用 `<SUMMARY_REPORT>` 标签包裹报告内容
|
|
92
|
+
- 要求统计数据准确(文件数、问题数)
|
|
93
|
+
- 要求完整展示每个问题的描述、位置、修改建议,不简化
|
|
94
|
+
- 重试机制:
|
|
95
|
+
- 最大重试次数:5 次
|
|
96
|
+
- 验证返回内容是否包含 `<SUMMARY_REPORT>` 标签
|
|
97
|
+
- 缺少标签时自动重试
|
|
98
|
+
- 新增方法:
|
|
99
|
+
- `collectAllReviewReports(results)`: 收集并拼接所有审查报告内容
|
|
100
|
+
- `generateSummaryReportWithAI(allReportsText)`: 调用 Claude AI 生成汇总报告
|
|
101
|
+
- `buildSummaryPrompt(allReportsText)`: 构造汇总报告生成的 Prompt
|
|
102
|
+
- `callClaudeForSummary(promptFile)`: 调用 Claude CLI 命令生成汇总报告
|
|
103
|
+
- `postSummaryCommentToGitLab(projectId, mergeRequestIid, summaryReport)`: 发布汇总报告到 GitLab MR
|
|
104
|
+
- 集成位置:
|
|
105
|
+
- 在 `reviewMergeRequest` 方法结束时自动调用(index.js:173-192)
|
|
106
|
+
- 即使生成失败也不影响主流程,确保已发布的单个评论不受影响
|
|
107
|
+
- 新增文件:
|
|
108
|
+
- `index.js:196-428`:汇总报告生成相关方法(约 232 行新增代码)
|
|
109
|
+
- 效果:
|
|
110
|
+
- 用户可以在 MR 讨论区看到一份完整的汇总报告,包含所有问题的统一视图
|
|
111
|
+
- 汇总报告按文件分组展示问题,方便用户快速定位和修复
|
|
112
|
+
- 提供无问题文件列表,让用户了解审查覆盖范围
|
|
113
|
+
- 自动生成统计数据和可视化标记(🔴 严重问题、🟡 警告、✅ 无问题)
|
|
114
|
+
|
|
30
115
|
### v2.7.4 (2026-04-20)
|
|
31
116
|
|
|
32
|
-
|
|
117
|
+
**优化**: 日志标识增强
|
|
33
118
|
|
|
34
119
|
**优化**:
|
|
35
120
|
- **日志追踪标识**:为每个 diff 块的 AI 调用添加唯一标识,解决 CI 环境中处理多个 diff 块重试时日志追踪困难的问题
|
|
@@ -218,6 +303,10 @@ GitLab Code Review AI Tool 是一个基于 Claude AI 的自动化代码审查工
|
|
|
218
303
|
│ 4. 发布评论 ←───────────────────────────────────── │
|
|
219
304
|
│ ↓ │
|
|
220
305
|
│ GitLab Discussion API (行级评论/一般讨论) │
|
|
306
|
+
│ ↓ │
|
|
307
|
+
│ 5. 收集所有报告 ──→ 6. AI生成汇总 ──→ 7. 发布汇总报告 │
|
|
308
|
+
│ ↓ ↓ ↓ │
|
|
309
|
+
│ 拼接报告内容 Claude CLI调用 GitLab Notes API │
|
|
221
310
|
└─────────────────────────────────────────────────────────────┘
|
|
222
311
|
```
|
|
223
312
|
|
|
@@ -239,9 +328,10 @@ GitLab Code Review AI Tool 是一个基于 Claude AI 的自动化代码审查工
|
|
|
239
328
|
│ │ GitLabAPIClient │ │ reviewDiffWith │ │ postCommentsTo │ │
|
|
240
329
|
│ │ (GitLab 通信) │ │ ClaudeUsingFile │ │ GitLab │ │
|
|
241
330
|
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
|
242
|
-
│ ┌─────────────────┐
|
|
243
|
-
│ │ MetricsCollector│
|
|
244
|
-
│
|
|
331
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
|
332
|
+
│ │ MetricsCollector│ │ generateSummary │ │ postSummaryTo │ │
|
|
333
|
+
│ │ (性能指标收集) │ │ ReportWithAI │ │ GitLab │ │
|
|
334
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
|
245
335
|
└─────────────────────────────────────────────────────────────────┘
|
|
246
336
|
↓
|
|
247
337
|
┌─────────────────────────────────────────────────────────────────┐
|
|
@@ -252,6 +342,11 @@ GitLab Code Review AI Tool 是一个基于 Claude AI 的自动化代码审查工
|
|
|
252
342
|
│ │ │ simple-code- │ │ code-review- │ │ SKILL.md │ │ │
|
|
253
343
|
│ │ │ review 技能 │ │ rules.md │ │ 模板 │ │ │
|
|
254
344
|
│ │ └───────────────┘ └───────────────┘ └─────────────┘ │ │
|
|
345
|
+
│ └─────────────────────────────────────────────────────────┐ │
|
|
346
|
+
│ │ Claude CLI (汇总报告生成) │ │
|
|
347
|
+
│ │ ┌─────────────────────────────────────────────────┐ │ │
|
|
348
|
+
│ │ │ buildSummaryPrompt → callClaudeForSummary │ │ │
|
|
349
|
+
│ │ └─────────────────────────────────────────────────┘ │ │
|
|
255
350
|
│ └─────────────────────────────────────────────────────────┘ │
|
|
256
351
|
└─────────────────────────────────────────────────────────────────┘
|
|
257
352
|
```
|
|
@@ -287,12 +382,18 @@ constructor(gitlabToken, gitlabUrl = null)
|
|
|
287
382
|
2. 获取 MR 的 diff 信息
|
|
288
383
|
3. 调用 AI 进行代码审查
|
|
289
384
|
4. 将审查结果发布到 GitLab
|
|
290
|
-
5.
|
|
385
|
+
5. 生成并发布 AI 汇总报告
|
|
386
|
+
6. 性能指标收集与统计
|
|
291
387
|
|
|
292
388
|
**新增功能** (v2.5.x):
|
|
293
389
|
- `_versionCache`: MR 版本信息缓存,避免重复 API 调用
|
|
294
390
|
- `metrics`: MetricsCollector 实例,收集性能指标
|
|
295
391
|
|
|
392
|
+
**新增功能** (v2.8.0):
|
|
393
|
+
- `collectAllReviewReports`: 收集所有审查报告内容
|
|
394
|
+
- `generateSummaryReportWithAI`: 调用 AI 生成汇总报告
|
|
395
|
+
- `postSummaryCommentToGitLab`: 发布汇总报告到 GitLab MR
|
|
396
|
+
|
|
296
397
|
### 3.2 GitLabAPIClient 类
|
|
297
398
|
|
|
298
399
|
**位置**: `utils.js:70-107`
|
|
@@ -327,7 +428,7 @@ class GitLabAPIClient {
|
|
|
327
428
|
5. 重试机制 (最多 5 次)
|
|
328
429
|
```
|
|
329
430
|
|
|
330
|
-
**重试策略** (`index.js:
|
|
431
|
+
**重试策略** (`index.js:457-533`):
|
|
331
432
|
- 最大重试次数:5 次
|
|
332
433
|
- 递增等待时间:`1000 * attempts` 毫秒
|
|
333
434
|
- 三级验证条件:
|
|
@@ -335,6 +436,85 @@ class GitLabAPIClient {
|
|
|
335
436
|
2. 包含"严重问题"关键词
|
|
336
437
|
3. 标题为"🤖 AI 代码审查结果"
|
|
337
438
|
|
|
439
|
+
### 3.4 AI 汇总报告生成模块
|
|
440
|
+
|
|
441
|
+
**位置**: `index.js:196-428`
|
|
442
|
+
|
|
443
|
+
**核心职责**:
|
|
444
|
+
1. 收集所有 diff 块的审查报告内容
|
|
445
|
+
2. 为每个报告添加文件路径和 diff 块索引标识
|
|
446
|
+
3. 构造汇总报告生成的 Prompt
|
|
447
|
+
4. 调用 Claude CLI 生成结构化的汇总报告
|
|
448
|
+
5. 提取 `<SUMMARY_REPORT>` 标签内容
|
|
449
|
+
6. 发布汇总报告到 GitLab MR
|
|
450
|
+
|
|
451
|
+
**汇总报告结构**:
|
|
452
|
+
```
|
|
453
|
+
<SUMMARY_REPORT>
|
|
454
|
+
## 🤖 AI 代码审查汇总报告
|
|
455
|
+
|
|
456
|
+
**生成时间**: [时间戳]
|
|
457
|
+
**审查范围**: [文件数量]个文件,[diff块数量]个变更块
|
|
458
|
+
**发现问题**: [总数]个,其中严重问题[数量]个
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
### 📊 审查概览
|
|
463
|
+
|
|
464
|
+
- ✅ 无问题文件:[数量]个(详见下方列表)
|
|
465
|
+
- ⚠️ 有问题文件:[数量]个
|
|
466
|
+
- 🔴 严重问题:[数量]个
|
|
467
|
+
- 🟡 一般警告:[数量]个
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
### ✅ 无问题文件列表
|
|
472
|
+
|
|
473
|
+
以下文件审查完成,未发现问题:
|
|
474
|
+
|
|
475
|
+
1. `[文件路径1]`
|
|
476
|
+
2. `[文件路径2]`
|
|
477
|
+
...
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### 🔴 严重问题汇总
|
|
482
|
+
|
|
483
|
+
以下文件包含严重问题,需要优先处理:
|
|
484
|
+
|
|
485
|
+
#### 1. [文件路径] ([问题数量]个问题)
|
|
486
|
+
|
|
487
|
+
**问题 1**:[完整问题描述]
|
|
488
|
+
- **位置**:[文件路径]:[行号]
|
|
489
|
+
- **修改建议**:[完整修改建议,包含示例代码]
|
|
490
|
+
|
|
491
|
+
**问题 2**:...
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
### 🟡 一般警告汇总
|
|
496
|
+
|
|
497
|
+
...
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
### 💡 建议
|
|
502
|
+
|
|
503
|
+
1. **优先处理严重问题**:这些问题可能导致运行时异常或数据错误
|
|
504
|
+
2. **测试验证**:建议对修改后的代码进行充分的单元测试和集成测试
|
|
505
|
+
3. **代码规范**:部分警告涉及代码风格,建议参考项目规范进行统一
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
*本报告由 AI 自动生成,建议结合人工审查确认问题准确性*
|
|
510
|
+
</SUMMARY_REPORT>
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**重试机制** (`index.js:372-428`):
|
|
514
|
+
- 最大重试次数:5 次
|
|
515
|
+
- 验证条件:返回内容必须包含 `<SUMMARY_REPORT>` 标签
|
|
516
|
+
- 失败时继续重试,达到最大次数后抛出错误
|
|
517
|
+
|
|
338
518
|
---
|
|
339
519
|
|
|
340
520
|
## 4. 关键算法与流程
|
|
@@ -525,6 +705,193 @@ export GITLAB_CR_CONCURRENCY=5 # 默认 3
|
|
|
525
705
|
### 4.6 行号解析算法
|
|
526
706
|
|
|
527
707
|
**解析函数**:
|
|
708
|
+
|
|
709
|
+
### 4.7 AI 汇总报告生成流程
|
|
710
|
+
|
|
711
|
+
**位置**: `index.js:173-192` (集成点), `index.js:196-428` (核心逻辑)
|
|
712
|
+
|
|
713
|
+
**完整流程**:
|
|
714
|
+
```
|
|
715
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
716
|
+
│ AI 汇总报告生成流程 │
|
|
717
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
718
|
+
│ │
|
|
719
|
+
│ 步骤 1: 所有 diff 块审查完成 │
|
|
720
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
721
|
+
│ │ reviewMergeRequest 方法中,所有 diff 块审查并发布评论完成 │ │
|
|
722
|
+
│ │ results 数组包含所有审查结果 │ │
|
|
723
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
724
|
+
│ ↓ │
|
|
725
|
+
│ 步骤 2: 收集所有审查报告内容 │
|
|
726
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
727
|
+
│ │ collectAllReviewReports(results) │ │
|
|
728
|
+
│ │ │ │
|
|
729
|
+
│ │ 遍历所有审查结果: │ │
|
|
730
|
+
│ │ - 为每个报告添加文件路径标识 │ │
|
|
731
|
+
│ │ - 为每个报告添加 diff 块索引标识 │ │
|
|
732
|
+
│ │ - 拼接所有报告内容为完整文本 │ │
|
|
733
|
+
│ │ │ │
|
|
734
|
+
│ │ 输出格式: │ │
|
|
735
|
+
│ │ ========== 审查报告 #1 ========== │ │
|
|
736
|
+
│ │ 文件:src/main/java/UserService.java │ │
|
|
737
|
+
│ │ Diff 块索引:#0 │ │
|
|
738
|
+
│ │ │ │
|
|
739
|
+
│ │ <REPORT>...</REPORT> │ │
|
|
740
|
+
│ │ │ │
|
|
741
|
+
│ │ ========== 审查报告 #2 ========== │ │
|
|
742
|
+
│ │ ... │ │
|
|
743
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
744
|
+
│ ↓ │
|
|
745
|
+
│ 步骤 3: 构造汇总报告生成 Prompt │
|
|
746
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
747
|
+
│ │ buildSummaryPrompt(allReportsText) │ │
|
|
748
|
+
│ │ │ │
|
|
749
|
+
│ │ Prompt 内容包含: │ │
|
|
750
|
+
│ │ - 角色定义:专业的代码审查汇总助手 │ │
|
|
751
|
+
│ │ - 输出要求: │ │
|
|
752
|
+
│ │ * 仅输出一份汇总报告 │ │
|
|
753
|
+
│ │ * 以 <SUMMARY_REPORT> 开始,以 </SUMMARY_REPORT> 结束 │ │
|
|
754
|
+
│ │ * 不得输出任何解释、问候或额外文本 │ │
|
|
755
|
+
│ │ - 汇总报告结构(详细模板): │ │
|
|
756
|
+
│ │ * 审查概览:文件数量、问题总数、严重问题数 │ │
|
|
757
|
+
│ │ * 无问题文件列表:完整路径列表 │ │
|
|
758
|
+
│ │ * 严重问题汇总:按文件分组,完整展示 │ │
|
|
759
|
+
│ │ * 警告汇总:按文件分组,完整展示 │ │
|
|
760
|
+
│ │ * 建议:针对问题的处理建议 │ │
|
|
761
|
+
│ │ - 统计数据准确要求 │ │
|
|
762
|
+
│ │ - 完整展示问题要求 │ │
|
|
763
|
+
│ │ - 问题位置格式要求 │ │
|
|
764
|
+
│ │ - 时间戳生成(东八区时间) │ │
|
|
765
|
+
│ │ - 输出格式模板(Markdown 格式) │ │
|
|
766
|
+
│ │ - 提供的审查报告内容 │ │
|
|
767
|
+
│ │ - 最后强调:必须严格按照模板格式输出 │ │
|
|
768
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
769
|
+
│ ↓ │
|
|
770
|
+
│ 步骤 4: 创建临时 Prompt 文件 │
|
|
771
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
772
|
+
│ │ tmpFileName = summary_prompt_${Date.now()}.txt │ │
|
|
773
|
+
│ │ fs.writeFileSync(tmpFileName, prompt, 'utf-8') │ │
|
|
774
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
775
|
+
│ ↓ │
|
|
776
|
+
│ 步骤 5: 调用 Claude CLI 生成汇总报告 │
|
|
777
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
778
|
+
│ │ callClaudeForSummary(tmpFileName) │ │
|
|
779
|
+
│ │ │ │
|
|
780
|
+
│ │ 最大重试次数:5 次 │ │
|
|
781
|
+
│ │ 重试循环: │ │
|
|
782
|
+
│ │ 1. 执行 Claude CLI 命令: │ │
|
|
783
|
+
│ │ spawn('claude', ['--tools', 'default', '-p', '--', tmpFileName])│
|
|
784
|
+
│ │ 2. 捕获 stdout 和 stderr 输出 │ │
|
|
785
|
+
│ │ 3. 等待进程完成(Promise 等待) │ │
|
|
786
|
+
│ │ 4. 验证返回内容是否包含 <SUMMARY_REPORT> 标签 │ │
|
|
787
|
+
│ │ 5. 如果包含 → 返回成功 │ │
|
|
788
|
+
│ │ 6. 如果不包含 → 重试 │ │
|
|
789
|
+
│ │ 7. 如果失败 → 等待后重试 │ │
|
|
790
|
+
│ │ │ │
|
|
791
|
+
│ │ 验证条件: │ │
|
|
792
|
+
│ │ stdout.includes('<SUMMARY_REPORT>') │ │
|
|
793
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
794
|
+
│ ↓ │
|
|
795
|
+
│ 步骤 6: 提取汇总报告内容 │
|
|
796
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
797
|
+
│ │ reportMatch = summaryReport.match( │ │
|
|
798
|
+
│ │ /<SUMMARY_REPORT>(.*?)<\/SUMMARY_REPORT>/s │ │
|
|
799
|
+
│ │ ) │ │
|
|
800
|
+
│ │ │ │
|
|
801
|
+
│ │ 如果有匹配 → 返回 reportMatch[1].trim() │ │
|
|
802
|
+
│ │ 如果无匹配 → 返回 summaryReport.trim() │ │
|
|
803
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
804
|
+
│ ↓ │
|
|
805
|
+
│ 步骤 7: 发布汇总报告到 GitLab MR │
|
|
806
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
807
|
+
│ │ postSummaryCommentToGitLab(projectId, mergeRequestIid, summaryReport)│
|
|
808
|
+
│ │ │ │
|
|
809
|
+
│ │ v2.8.3 版本(当前): │ │
|
|
810
|
+
│ │ 使用 GitLab Notes API 发布普通注释 │ │
|
|
811
|
+
│ │ API 端点:/projects/:id/merge_requests/:iid/notes │ │
|
|
812
|
+
│ │ Payload: │ │
|
|
813
|
+
│ │ { │ │
|
|
814
|
+
│ │ "body": summaryReport // Markdown 格式的汇总报告内容 │ │
|
|
815
|
+
│ │ } │ │
|
|
816
|
+
│ │ │ │
|
|
817
|
+
│ │ v2.8.0-v2.8.1 版本(已废弃): │ │
|
|
818
|
+
│ │ 使用 GitLab Discussions API │ │
|
|
819
|
+
│ │ API 端点:/projects/:id/merge_requests/:iid/discussions │ │
|
|
820
|
+
│ │ Payload: │ │
|
|
821
|
+
│ │ { │ │
|
|
822
|
+
│ │ "body": summaryReport, │ │
|
|
823
|
+
│ │ "resolvable": false // v2.8.1 新增,避免用户误操作 │ │
|
|
824
|
+
│ │ } │ │
|
|
825
|
+
│ │ │ │
|
|
826
|
+
│ │ 注意: │ │
|
|
827
|
+
│ │ - Notes API 发布的是普通注释(Note),不会显示 resolve 按钮 │ │
|
|
828
|
+
│ │ - Discussions API 发布的是讨论(Discussion),会显示 resolve 按钮│ │
|
|
829
|
+
│ │ - v2.8.3 使用 Notes API 提高兼容性 │ │
|
|
830
|
+
│ │ - 发布失败不影响主流程,确保已发布的单个评论不受影响 │ │
|
|
831
|
+
│ │ - 记录评论发布指标:this.metrics.recordCommentPublished() │ │
|
|
832
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
833
|
+
│ ↓ │
|
|
834
|
+
│ 步骤 8: 清理临时 Prompt 文件 │
|
|
835
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
836
|
+
│ │ finally { │ │
|
|
837
|
+
│ │ if (fs.existsSync(tmpFileName)) { │ │
|
|
838
|
+
│ │ fs.unlinkSync(tmpFileName); │ │
|
|
839
|
+
│ │ } │ │
|
|
840
|
+
│ │ } │ │
|
|
841
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
842
|
+
│ ↓ │
|
|
843
|
+
│ 步骤 9: 汇总报告发布完成 │
|
|
844
|
+
│ ┌───────────────────────────────────────────────────────────────────┐ │
|
|
845
|
+
│ │ 汇总报告已成功发布到 GitLab MR 讨论区 │ │
|
|
846
|
+
│ │ 用户可以在 MR 页面看到完整的汇总报告 │ │
|
|
847
|
+
│ │ │ │
|
|
848
|
+
│ │ 报告包含: │ │
|
|
849
|
+
│ │ - 审查概览和统计数据 │ │
|
|
850
|
+
│ │ - 无问题文件列表 │ │
|
|
851
|
+
│ │ - 按文件分组的严重问题汇总 │ │
|
|
852
|
+
│ │ - 按文件分组的警告汇总 │ │
|
|
853
|
+
│ │ - 处理建议 │ │
|
|
854
|
+
│ │ │ │
|
|
855
|
+
│ │ 特点: │ │
|
|
856
|
+
│ │ - 普通注释类型(v2.8.3),不显示 resolve 按钮 │ │
|
|
857
|
+
│ │ - 永久保留在 MR 讨论区 │ │
|
|
858
|
+
│ │ - Markdown 格式,可视化标记 │ │
|
|
859
|
+
│ │ - AI 自动生成,统计数据准确 │ │
|
|
860
|
+
│ └───────────────────────────────────────────────────────────────────┘ │
|
|
861
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
**关键设计决策**:
|
|
865
|
+
|
|
866
|
+
| 设计点 | 决策内容 | 理由 |
|
|
867
|
+
|--------|----------|------|
|
|
868
|
+
| **集成时机** | 所有 diff 块审查完成后 | 确保汇总报告包含完整的审查结果 |
|
|
869
|
+
| **失败处理** | 不抛出错误,允许主流程继续 | 确保已发布的单个评论不受影响 |
|
|
870
|
+
| **重试机制** | 最大 5 次,验证 `<SUMMARY_REPORT>` 标签 | 确保生成成功率,避免格式错误 |
|
|
871
|
+
| **时间戳生成** | 使用东八区时间(北京时间,UTC+8) | 符合中国用户习惯 |
|
|
872
|
+
| **API 选择** | v2.8.3 使用 Notes API(普通注释) | 提高兼容性,避免权限问题 |
|
|
873
|
+
| **评论类型** | 普通注释(Note),无 resolve 按钮 | 避免用户误操作,报告永久保留 |
|
|
874
|
+
| **数据完整性** | 完整展示每个问题的描述、位置、修改建议 | 不简化,方便用户理解问题详情 |
|
|
875
|
+
| **文件分组** | 按文件分组展示问题 | 方便用户快速定位和修复 |
|
|
876
|
+
|
|
877
|
+
**Prompt 设计特点**:
|
|
878
|
+
|
|
879
|
+
1. **角色定义明确**:专业的代码审查汇总助手
|
|
880
|
+
2. **输出格式强制**:必须使用 `<SUMMARY_REPORT>` 标签包裹
|
|
881
|
+
3. **结构化模板**:提供详细的 Markdown 格式模板
|
|
882
|
+
4. **统计准确性**:要求根据提供的报告内容准确统计
|
|
883
|
+
5. **完整展示**:每个问题都要完整展示,不简化
|
|
884
|
+
6. **可视化标记**:使用 emoji 标记(🔴 严重问题、🟡 警告、✅ 无问题)
|
|
885
|
+
7. **问题位置格式**:统一使用"文件路径:行号"格式
|
|
886
|
+
8. **无问题处理**:即使无问题也生成报告说明审查完成
|
|
887
|
+
9. **最后强调**:必须严格按照模板格式输出,不得输出其他文本
|
|
888
|
+
|
|
889
|
+
**v2.8.3 版本改进**:
|
|
890
|
+
|
|
891
|
+
- **API 兼容性**:从 Discussions API 改为 Notes API,避免权限问题
|
|
892
|
+
- **评论类型简化**:使用普通注释(Note),移除不必要的 `resolvable` 参数
|
|
893
|
+
- **用户体验优化**:汇总报告不显示 resolve 按钮,避免用户误操作
|
|
894
|
+
- **代码简化**:移除 Discussions API 的复杂配置,降低出错概率
|
|
528
895
|
```javascript
|
|
529
896
|
// 解析所有问题行号 (v2.4.6)
|
|
530
897
|
parseAllLineInfoFromReviewResult(lineInfoTag) {
|
|
@@ -589,7 +956,32 @@ extractSingleProblemReport(fullReport, problemIndex) {
|
|
|
589
956
|
}
|
|
590
957
|
```
|
|
591
958
|
|
|
592
|
-
### 5.3
|
|
959
|
+
### 5.3 汇总报告请求结构
|
|
960
|
+
|
|
961
|
+
```javascript
|
|
962
|
+
{
|
|
963
|
+
prompt: string, // 汇总报告生成的 Prompt 内容
|
|
964
|
+
tmpFileName: string // 临时 Prompt 文件路径
|
|
965
|
+
}
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
### 5.4 汇总报告响应结构
|
|
969
|
+
|
|
970
|
+
```javascript
|
|
971
|
+
{
|
|
972
|
+
summaryReport: string, // <SUMMARY_REPORT>...</SUMMARY_REPORT> 内容
|
|
973
|
+
timestamp: string, // 生成时间戳(东八区时间)
|
|
974
|
+
stats: {
|
|
975
|
+
totalFiles: number, // 审查文件总数
|
|
976
|
+
totalBlocks: number, // 审查 diff 块总数
|
|
977
|
+
totalProblems: number, // 发现问题总数
|
|
978
|
+
seriousProblems: number, // 严重问题数量
|
|
979
|
+
warnings: number // 一般警告数量
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
### 5.5 LINE_INFO 格式
|
|
593
985
|
|
|
594
986
|
```json
|
|
595
987
|
[
|
|
@@ -746,6 +1138,11 @@ curl --request POST \
|
|
|
746
1138
|
| `postSingleCommentToGitLab` | projectId, mergeRequestIid, result | `Promise<void>` | 发布单条评论 |
|
|
747
1139
|
| `getMergeRequestVersions` | projectId, mergeRequestIid | `Promise<Object>` | 获取 MR 版本信息 |
|
|
748
1140
|
| `getVersionInfo` | projectId, mergeRequestIid | `Promise<Object>` | 获取 MR 版本信息 (带缓存) |
|
|
1141
|
+
| `collectAllReviewReports` | results | `string` | 收集所有审查报告内容 |
|
|
1142
|
+
| `generateSummaryReportWithAI` | allReportsText | `Promise<string>` | 调用 AI 生成汇总报告 |
|
|
1143
|
+
| `buildSummaryPrompt` | allReportsText | `string` | 构造汇总报告 Prompt |
|
|
1144
|
+
| `callClaudeForSummary` | promptFile | `Promise<string>` | 调用 Claude CLI 生成汇总报告 |
|
|
1145
|
+
| `postSummaryCommentToGitLab` | projectId, mergeRequestIid, summaryReport | `Promise<void>` | 发布汇总报告到 GitLab MR |
|
|
749
1146
|
|
|
750
1147
|
### 8.2 GitLab API 端点
|
|
751
1148
|
|
|
@@ -756,7 +1153,7 @@ GET /projects/{projectId}/merge_requests/{iid}/diffs?per_page=20&page=1
|
|
|
756
1153
|
// 获取 Versions
|
|
757
1154
|
GET /projects/{projectId}/merge_requests/{iid}/versions
|
|
758
1155
|
|
|
759
|
-
// 发布 Discussion
|
|
1156
|
+
// 发布 Discussion (单个问题评论)
|
|
760
1157
|
POST /projects/{projectId}/merge_requests/{iid}/discussions
|
|
761
1158
|
{
|
|
762
1159
|
"body": "评论内容",
|
|
@@ -769,6 +1166,12 @@ POST /projects/{projectId}/merge_requests/{iid}/discussions
|
|
|
769
1166
|
"new_path": "file.java"
|
|
770
1167
|
}
|
|
771
1168
|
}
|
|
1169
|
+
|
|
1170
|
+
// 发布 Note (汇总报告评论,v2.8.3 新增)
|
|
1171
|
+
POST /projects/{projectId}/merge_requests/{iid}/notes
|
|
1172
|
+
{
|
|
1173
|
+
"body": "汇总报告内容(Markdown 格式)"
|
|
1174
|
+
}
|
|
772
1175
|
```
|
|
773
1176
|
|
|
774
1177
|
---
|
|
@@ -1008,6 +1411,10 @@ npm run dev
|
|
|
1008
1411
|
|
|
1009
1412
|
| 版本 | 日期 | 变更说明 |
|
|
1010
1413
|
|------|------|----------|
|
|
1414
|
+
| **2.8.3** | 2026-04-23 | **GitLab 评论 API 兼容性修复**:将汇总报告发布从 Discussions API 改为 Notes API,避免权限问题;移除 `resolvable` 参数,使用普通注释类型发布;影响:汇总报告不再显示 resolve 按钮,评论类型统一为普通注释,提高 API 兼容性;修复文件:`index.js:987-1011` |
|
|
1415
|
+
| **2.8.2** | 2026-04-22 | **版本号同步**:更新 package.json 版本号到 2.8.2 |
|
|
1416
|
+
| **2.8.1** | 2026-04-22 | **汇总报告评论 Resolve 问题修复**:为汇总报告评论设置 `resolvable: false`,避免用户误操作导致报告消失;影响:汇总报告永久保留在 MR 讨论区;修复文件:`index.js:988-1010` |
|
|
1417
|
+
| **2.8.0** | 2026-04-22 | **重大功能更新**:新增 AI 汇总报告生成功能;新增方法:`collectAllReviewReports`、`generateSummaryReportWithAI`、`buildSummaryPrompt`、`callClaudeForSummary`、`postSummaryCommentToGitLab`;汇总报告结构:审查概览、无问题文件列表、严重问题汇总、警告汇总、建议;新增代码:约 232 行;集成位置:`reviewMergeRequest` 方法结束时自动调用;效果:用户可看到完整的汇总报告,包含所有问题的统一视图 |
|
|
1011
1418
|
| **2.6.2** | 2026-04-16 | **行号计算示例增强**:添加临时文件完整格式示例,明确展示元数据行和 `@@` 行不编号。问题根因:尽管规则已明确"从 `@@` 之后开始计数",但 AI 仍然错误地将元数据行和 `@@` 行算入编号,导致行号系统性偏差(如正确行号 29 返回 43、31 返回 45 等)。修复方案:(1) 在 `code-review-rules.md` 第 13 条添加**示例 0:临时文件完整格式**,逐行标注哪些行忽略、哪些行编号、编号如何计算;(2) 在 `SKILL.md` 第 3 步添加**临时文件格式示例**,展示完整的计数过程;(3) 示例中明确标注 `=== File Information ===` 等 7 行元数据 + `@@` 行共 8 行都必须忽略,从 `@@` 之后的第一行才开始编号为 1 |
|
|
1012
1419
|
| **2.6.1** | 2026-04-16 | 行号计数起点明确修复 - 补充示例 |
|
|
1013
1420
|
| **2.6.0** | 2026-04-16 | **行号计数起点明确修复**:修复 AI 返回的行号系统性偏差 +8 的问题。问题根因:AI 在计数时把 `@@ ... @@` 这一行也算进去了,导致所有行号都 +8(如正确行号 30 返回 38、34 返回 42、38 返回 46、48 返回 56、54 返回 62)。修复方案:(1) 更新 `SKILL.md` 第 3 步,明确"`@@ ... @@`这一行本身也不编号,从它**之后**的第一行才开始编号";(2) 更新 `code-review-rules.md` 第 13 条,明确"`@@ ... @@`这一行本身**不编号**,从它**之后**的第一行才开始编号";(3) 在计数步骤中细化为 6 步,第 1 步"找到 `@@ ... @@` 行",第 2 步"从`@@ ... @@`**之后**的第一行开始编号" |
|
|
@@ -1026,12 +1433,12 @@ npm run dev
|
|
|
1026
1433
|
|
|
1027
1434
|
| 文件 | 行数 | 职责 |
|
|
1028
1435
|
|------|------|------|
|
|
1029
|
-
| `index.js` |
|
|
1436
|
+
| `index.js` | 1095 | 主入口,审查逻辑,汇总报告生成逻辑 |
|
|
1030
1437
|
| `utils.js` | 354 | 工具函数,GitLab 客户端,指标收集器 |
|
|
1031
1438
|
| `package.json` | 28 | 项目配置 |
|
|
1032
1439
|
| `.claude/rules/code-review-rules.md` | 200+ | 审查规则 |
|
|
1033
1440
|
| `.claude/skills/simple-code-review/SKILL.md` | 91 | 技能定义 |
|
|
1034
|
-
| `docs/GITLAB_CR_NODE_TECHNICAL_DOCS.md` |
|
|
1441
|
+
| `docs/GITLAB_CR_NODE_TECHNICAL_DOCS.md` | 1100+ | 技术文档 |
|
|
1035
1442
|
|
|
1036
1443
|
---
|
|
1037
1444
|
|
|
@@ -1070,4 +1477,4 @@ export LOG_LEVEL=0 # DEBUG 级别
|
|
|
1070
1477
|
|
|
1071
1478
|
---
|
|
1072
1479
|
|
|
1073
|
-
*文档生成时间:2026-04-
|
|
1480
|
+
*文档生成时间:2026-04-23*
|
package/index.js
CHANGED
|
@@ -856,43 +856,53 @@ ${allReportsText}
|
|
|
856
856
|
let targetLine = null;
|
|
857
857
|
let skipReason = null;
|
|
858
858
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
859
|
+
// 验证文件路径是否匹配当前 diff 块
|
|
860
|
+
if (problemInfo.new_path && diff_info.new_path &&
|
|
861
|
+
problemInfo.new_path !== diff_info.new_path) {
|
|
862
|
+
skipReason = `AI 返回的文件路径 ${problemInfo.new_path} 与当前 diff 块文件 ${diff_info.new_path} 不匹配,可能存在AI幻觉`;
|
|
863
|
+
debugLog(`第 ${i + 1} 个问题 ${skipReason}`);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// 只有文件路径匹配时,才继续验证行号
|
|
867
|
+
if (!skipReason) {
|
|
868
|
+
if (problemInfo.old_line && !problemInfo.new_line) {
|
|
869
|
+
// 删除代码,使用 old_line
|
|
870
|
+
if (oldCount === 0) {
|
|
871
|
+
skipReason = `删除文件的 diff 块 (old_count=${oldCount}),无法使用 old_line`;
|
|
872
|
+
} else if (problemInfo.old_line < oldStart || problemInfo.old_line > oldEnd) {
|
|
873
|
+
skipReason = `old_line=${problemInfo.old_line} 超出 diff 块范围 [${oldStart}, ${oldEnd}]`;
|
|
874
|
+
} else {
|
|
875
|
+
targetLine = {
|
|
876
|
+
old_path: problemInfo.old_path || diff_info.old_path,
|
|
877
|
+
old_line: problemInfo.old_line
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
} else if (problemInfo.new_line) {
|
|
881
|
+
// 新增代码或修改代码,使用 new_line
|
|
882
|
+
// 对于删除文件(new_count=0),AI 可能返回 new_line 但实际应该用 old_line
|
|
883
|
+
if (isDeleteFile) {
|
|
884
|
+
// 删除文件:将 AI 返回的 new_line 视为原文件行号,使用 old_path + old_line
|
|
885
|
+
if (problemInfo.new_line < oldStart || problemInfo.new_line > oldEnd) {
|
|
886
|
+
skipReason = `删除文件中 new_line=${problemInfo.new_line} 超出原文件范围 [${oldStart}, ${oldEnd}]`;
|
|
887
|
+
} else {
|
|
888
|
+
targetLine = {
|
|
889
|
+
old_path: problemInfo.new_path || diff_info.old_path,
|
|
890
|
+
old_line: problemInfo.new_line
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
} else if (newCount === 0) {
|
|
894
|
+
skipReason = `new_count=0,无法使用 new_line`;
|
|
895
|
+
} else if (problemInfo.new_line < newStart || problemInfo.new_line > newEnd) {
|
|
896
|
+
skipReason = `new_line=${problemInfo.new_line} 超出 diff 块范围 [${newStart}, ${newEnd}]`;
|
|
878
897
|
} else {
|
|
898
|
+
// 新增文件/新增行:使用 new_path + new_line
|
|
879
899
|
targetLine = {
|
|
880
|
-
|
|
881
|
-
|
|
900
|
+
new_path: problemInfo.new_path || diff_info.new_path,
|
|
901
|
+
new_line: problemInfo.new_line
|
|
882
902
|
};
|
|
883
903
|
}
|
|
884
|
-
} else if (newCount === 0) {
|
|
885
|
-
skipReason = `new_count=0,无法使用 new_line`;
|
|
886
|
-
} else if (problemInfo.new_line < newStart || problemInfo.new_line > newEnd) {
|
|
887
|
-
skipReason = `new_line=${problemInfo.new_line} 超出 diff 块范围 [${newStart}, ${newEnd}]`;
|
|
888
|
-
} else {
|
|
889
|
-
// 新增文件/新增行:使用 new_path + new_line
|
|
890
|
-
targetLine = {
|
|
891
|
-
new_path: problemInfo.new_path || diff_info.new_path,
|
|
892
|
-
new_line: problemInfo.new_line
|
|
893
|
-
};
|
|
894
904
|
}
|
|
895
|
-
}
|
|
905
|
+
} // 文件路径验证条件块结束
|
|
896
906
|
|
|
897
907
|
if (!targetLine) {
|
|
898
908
|
// 无法解析行号或行号超出范围,使用一般讨论
|