job51-gitlab-cr-node-jt-1 3.0.5 → 3.0.6
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/index.js +84 -1
- package/package.json +1 -1
- package/.cr-config-templates/rules/code-review-rules.md +0 -191
package/index.js
CHANGED
|
@@ -15,6 +15,74 @@ class GitLabCodeReviewer {
|
|
|
15
15
|
this.metrics = new MetricsCollector();
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* 判断文件是否是测试文件(需要跳过审查)
|
|
20
|
+
* @param {string} filePath 文件路径
|
|
21
|
+
* @returns {boolean} 是否是测试文件
|
|
22
|
+
*/
|
|
23
|
+
isTestFile(filePath) {
|
|
24
|
+
if (!filePath) return false;
|
|
25
|
+
|
|
26
|
+
// 标准化路径(统一使用 / 分隔符)
|
|
27
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
28
|
+
|
|
29
|
+
// 测试目录模式列表(包含中间路径和路径开头两种情况)
|
|
30
|
+
const testDirPatterns = [
|
|
31
|
+
'/test/', // Java/Maven: src/test/java, Node: test/
|
|
32
|
+
'/tests/', // Node: tests/
|
|
33
|
+
'/__tests__/', // Jest: __tests__/
|
|
34
|
+
'/spec/', // Ruby/Node: spec/
|
|
35
|
+
'/specs/', // specs/
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
// 检查是否包含测试目录路径(中间路径)
|
|
39
|
+
for (const pattern of testDirPatterns) {
|
|
40
|
+
if (normalizedPath.includes(pattern)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 检查是否以测试目录开头(路径开头情况)
|
|
46
|
+
const testDirStartPatterns = [
|
|
47
|
+
'test/', // 根目录下的 test/
|
|
48
|
+
'tests/', // 根目录下的 tests/
|
|
49
|
+
'__tests__/', // 根目录下的 __tests__/
|
|
50
|
+
'spec/', // 根目录下的 spec/ (Ruby RSpec 常见)
|
|
51
|
+
'specs/', // 根目录下的 specs/
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const pattern of testDirStartPatterns) {
|
|
55
|
+
if (normalizedPath.startsWith(pattern)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 测试文件命名模式(文件名包含 .test. 或 .spec.)
|
|
61
|
+
const testFilePatterns = [
|
|
62
|
+
'.test.', // JavaScript: xxx.test.js
|
|
63
|
+
'.spec.', // JavaScript: xxx.spec.js
|
|
64
|
+
'_test.', // Python: xxx_test.py
|
|
65
|
+
'Test.', // Java: XxxTest.java (类名以 Test 结尾)
|
|
66
|
+
'Tests.', // Java: XxxTests.java
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
// 提取文件名(不含扩展名)
|
|
70
|
+
const fileName = normalizedPath.split('/').pop() || '';
|
|
71
|
+
|
|
72
|
+
for (const pattern of testFilePatterns) {
|
|
73
|
+
if (fileName.includes(pattern)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Java 特殊处理:文件名以 Test.java 或 Tests.java 结尾
|
|
79
|
+
if (fileName.endsWith('Test.java') || fileName.endsWith('Tests.java')) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
18
86
|
/**
|
|
19
87
|
* 获取合并请求的diff信息
|
|
20
88
|
* @param {number} projectId GitLab项目ID
|
|
@@ -275,9 +343,19 @@ class GitLabCodeReviewer {
|
|
|
275
343
|
}
|
|
276
344
|
};
|
|
277
345
|
|
|
278
|
-
//
|
|
346
|
+
// 收集所有需要处理的块(排除测试文件)
|
|
279
347
|
const allBlocks = [];
|
|
348
|
+
const skippedTestFiles = []; // 记录跳过的测试文件
|
|
280
349
|
for (const diff of diffs) {
|
|
350
|
+
const filePath = diff.new_path || diff.old_path;
|
|
351
|
+
|
|
352
|
+
// 检查是否是测试文件
|
|
353
|
+
if (this.isTestFile(filePath)) {
|
|
354
|
+
debugLog(`跳过测试文件: ${filePath}`);
|
|
355
|
+
skippedTestFiles.push(filePath);
|
|
356
|
+
continue; // 跳过测试文件
|
|
357
|
+
}
|
|
358
|
+
|
|
281
359
|
const diffObjects = this.getDiffBlocks(diff);
|
|
282
360
|
for (let i = 0; i < diffObjects.length; i++) {
|
|
283
361
|
// 更新块索引
|
|
@@ -286,6 +364,11 @@ class GitLabCodeReviewer {
|
|
|
286
364
|
}
|
|
287
365
|
}
|
|
288
366
|
|
|
367
|
+
// 输出跳过的测试文件统计
|
|
368
|
+
if (skippedTestFiles.length > 0) {
|
|
369
|
+
infoLog(`已跳过 ${skippedTestFiles.length} 个测试文件: ${skippedTestFiles.join(', ')}`);
|
|
370
|
+
}
|
|
371
|
+
|
|
289
372
|
// 使用线程池控制并发数量
|
|
290
373
|
const results = await this.processWithThreadPool(allBlocks, processBlock, maxConcurrency);
|
|
291
374
|
|
package/package.json
CHANGED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
# 代码审查规则模板
|
|
2
|
-
|
|
3
|
-
> **说明**:这是自定义审查规则的模板示例。将此文件复制到项目根目录的 `.cr-config/rules/code-review-rules.md` 并根据团队需求修改。
|
|
4
|
-
|
|
5
|
-
**核心原则:高准确率、低误报、深度上下文分析、风格一致性**
|
|
6
|
-
|
|
7
|
-
**⚠️ 最高优先级强制规则(违反将导致严重误报)**:
|
|
8
|
-
|
|
9
|
-
0. **文件路径必须保持原样**(关键规则,防止AI幻觉):
|
|
10
|
-
> - **LINE_INFO 中的 `new_path` 和 `old_path` 必须与 diff 块的实际路径完全一致,不得修改任何字符**
|
|
11
|
-
> - **严禁AI"纠正"或"规范化"文件路径命名**:连字符、下划线、点号等所有字符必须保持原样
|
|
12
|
-
> - **路径格式错误将导致评论无法发布到正确位置,被判定为AI幻觉并跳过发布**
|
|
13
|
-
|
|
14
|
-
1. **「已安全处理」代码禁止报告**(关键规则):
|
|
15
|
-
> - **如果代码已正确处理潜在风险(如已判空、已捕获异常、已有边界检查),则绝对禁止报告该问题**
|
|
16
|
-
> - **如果分析结论包含"逻辑正确"、"无需修改"、"已有 XX 保护"等描述,必须省略该问题**
|
|
17
|
-
|
|
18
|
-
2. **审查范围限制**(关键规则):
|
|
19
|
-
> - **只审查当前 diff 块内的新增代码**(+ 开头的行)
|
|
20
|
-
> - **只报告当前 diff 块内能直接发现的问题**
|
|
21
|
-
> - **禁止对上下文行(空格开头的行)报告问题**
|
|
22
|
-
|
|
23
|
-
3. **同一问题只报告一次**:
|
|
24
|
-
> - 同一个空指针问题可能在多处出现,**只在真正会执行出错的代码行上报告一次**
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## ⛔ 空指针/空引用问题特别规则
|
|
29
|
-
|
|
30
|
-
### 一、外部依赖调用的安全假设(禁止报告场景)
|
|
31
|
-
|
|
32
|
-
**调用外部库、框架、工具类的方法时,应假设返回值已做安全处理,禁止报告空指针问题:**
|
|
33
|
-
|
|
34
|
-
> 1. **外部库/框架方法的返回值安全假设**:
|
|
35
|
-
> - 成熟框架/库返回集合的方法通常返回空集合而非 null
|
|
36
|
-
> - 依赖注入对象由容器管理,注入失败会在启动时报错
|
|
37
|
-
> - **禁止对这些外部依赖的返回值报告"未判空直接使用"类问题**
|
|
38
|
-
|
|
39
|
-
> 2. **识别外部依赖的标准**:
|
|
40
|
-
> - 来自第三方库/框架的方法(非项目代码)
|
|
41
|
-
> - 标准库/语言内置方法
|
|
42
|
-
> - 如果方法定义不在当前项目代码中,视为外部依赖
|
|
43
|
-
|
|
44
|
-
### 二、必须深度分析才能报告空指针的场景
|
|
45
|
-
|
|
46
|
-
**真正的空指针问题通常只出现在人工手写的新代码中,需完整追踪调用链路确认:**
|
|
47
|
-
|
|
48
|
-
> 1. **人工手写的新方法返回值**:
|
|
49
|
-
> - 需完整读取方法实现代码,分析所有返回分支
|
|
50
|
-
> - **只有确认调用方确实未处理且会导致运行时异常时,才可报告**
|
|
51
|
-
|
|
52
|
-
> 2. **跨方法/跨文件上下文分析**:
|
|
53
|
-
> - 如果调用的是项目内其他方法,必须读取该方法源码分析
|
|
54
|
-
> - **禁止仅凭方法名/调用形式推断返回值可能为空**
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## ⛔ 资源泄漏问题特别规则
|
|
59
|
-
|
|
60
|
-
**资源泄漏会导致系统不稳定、连接池耗尽,必须严格检测**
|
|
61
|
-
|
|
62
|
-
### 一、必须检测的资源类型
|
|
63
|
-
|
|
64
|
-
> 1. **JDBC 资源**:数据库连接对象、语句对象、结果集对象
|
|
65
|
-
> 2. **文件流**:文件输入流、文件输出流
|
|
66
|
-
> 3. **网络资源**:套接字、HTTP连接对象
|
|
67
|
-
|
|
68
|
-
### 二、危险代码模式(必须报告为严重问题)
|
|
69
|
-
|
|
70
|
-
> **模式1:直接创建资源但未关闭** → **必须报告为严重问题**
|
|
71
|
-
> **模式2:try 块中创建资源但未在 finally 关闭** → **必须报告为严重问题**
|
|
72
|
-
> **模式3:循环内创建资源但未关闭** → **必须报告为严重问题**
|
|
73
|
-
|
|
74
|
-
### 三、安全代码模式(禁止报告)
|
|
75
|
-
|
|
76
|
-
> - 使用自动关闭语法块(try-with-resources)
|
|
77
|
-
> - 使用 try-finally 块,在 finally 中显式调用关闭方法
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## ⛔ 框架特性问题特别规则
|
|
82
|
-
|
|
83
|
-
### 一、Spring 框架问题
|
|
84
|
-
|
|
85
|
-
> **异步方法返回值问题**:
|
|
86
|
-
> > - 检测带有 @Async 注解的方法,检查其返回类型
|
|
87
|
-
> > - 如果返回具体类型(非 Void、非 Future),调用方拿到的将是 null
|
|
88
|
-
> > - **返回具体类型 → 必须报告为严重问题**
|
|
89
|
-
|
|
90
|
-
> **事务注解问题**:
|
|
91
|
-
> > - @Transactional 在私有方法上无效
|
|
92
|
-
> > - 同类内部直接调用事务方法不生效
|
|
93
|
-
> > - **检测到此类用法 → 必须报告**
|
|
94
|
-
|
|
95
|
-
### 二、MyBatis-Plus 框架问题
|
|
96
|
-
|
|
97
|
-
> **更新实体字段设置问题**:
|
|
98
|
-
> > - 更新操作会把实体对象的所有非空字段都加入 SET 语句
|
|
99
|
-
> > - **检测方法**:检查更新实体是否设置了与查询条件重复的非主键字段
|
|
100
|
-
> > - **存在字段重复 → 必须报告为严重问题**
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## ⛔ 循环逻辑问题特别规则
|
|
105
|
-
|
|
106
|
-
### 一、循环内状态失效问题
|
|
107
|
-
|
|
108
|
-
> **问题描述**:循环中使用的外部变量/对象,如果其状态会被循环内的操作修改,后续迭代继续使用该对象的状态值时,状态已过期
|
|
109
|
-
|
|
110
|
-
> **检测方法**:
|
|
111
|
-
> 1. 找到循环结构
|
|
112
|
-
> 2. 检查循环内是否调用了外部对象的方法
|
|
113
|
-
> 3. 分析该方法是否会修改该对象的状态
|
|
114
|
-
> 4. **状态会过期且未重新获取 → 必须报告为严重问题**
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## ⛔ 异常处理问题特别规则
|
|
119
|
-
|
|
120
|
-
### 一、异常吞没问题
|
|
121
|
-
|
|
122
|
-
> **问题描述**:
|
|
123
|
-
> > - catch 块中仅记录日志但不做任何处理,异常被吞没
|
|
124
|
-
> > - catch 块为空实现,异常完全被忽略
|
|
125
|
-
|
|
126
|
-
> **检测方法**:
|
|
127
|
-
> > - 检查 catch 块的内容
|
|
128
|
-
> > - **异常被吞没且无恢复机制 → 必须报告为严重问题**
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## ⛔ 并发安全问题特别规则
|
|
133
|
-
|
|
134
|
-
### 一、线程安全问题
|
|
135
|
-
|
|
136
|
-
> **问题描述**:
|
|
137
|
-
> > - 共享变量在多线程环境下未正确同步
|
|
138
|
-
> > - 非线程安全类被多个线程共享使用
|
|
139
|
-
|
|
140
|
-
> **检测方法**:
|
|
141
|
-
> > - 检查共享变量的使用场景
|
|
142
|
-
> > - **存在并发访问且无同步机制 → 必须报告**
|
|
143
|
-
|
|
144
|
-
### 二、分布式锁问题
|
|
145
|
-
|
|
146
|
-
> **问题描述**:分布式环境使用本地锁(如 synchronized)无效
|
|
147
|
-
|
|
148
|
-
> **检测方法**:
|
|
149
|
-
> > - 检查锁的使用场景
|
|
150
|
-
> > - **分布式场景使用本地锁 → 必须报告**
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## ⛔ 性能问题特别规则
|
|
155
|
-
|
|
156
|
-
### 一、循环内重复查询问题
|
|
157
|
-
|
|
158
|
-
> **问题描述**:循环内每次迭代都执行数据库查询或远程调用,应批量获取后再处理
|
|
159
|
-
|
|
160
|
-
> **检测方法**:
|
|
161
|
-
> > - 检查循环内是否有数据库查询或远程调用
|
|
162
|
-
> > - **循环内重复查询 → 建议报告为警告级别**
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## 团队自定义规则示例
|
|
167
|
-
|
|
168
|
-
> **在此添加团队特定的审查规则**
|
|
169
|
-
|
|
170
|
-
### 一、[团队规则 1:日志规范]
|
|
171
|
-
|
|
172
|
-
> - 所有 public 方法必须有日志记录
|
|
173
|
-
> - 异常日志必须包含完整的错误信息和上下文
|
|
174
|
-
> - **不符合规范 → 建议报告为警告级别**
|
|
175
|
-
|
|
176
|
-
### 二、[团队规则 2:API 设计规范]
|
|
177
|
-
|
|
178
|
-
> - Controller 方法必须有 @ApiOperation 注解
|
|
179
|
-
> - 请求参数必须有 @Validated 校验
|
|
180
|
-
> - **不符合规范 → 建议报告为警告级别**
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## 输出格式要求
|
|
185
|
-
|
|
186
|
-
1. **报告开头必须包含 `## 🤖 AI 代码审查结果`**
|
|
187
|
-
2. **每个问题必须以 `**问题 N**:` 开头**
|
|
188
|
-
3. **每个问题块只能有一个 `**文件及行号**:` 行**
|
|
189
|
-
4. **LINE_INFO 必须与问题一一对应**
|
|
190
|
-
5. **禁止在报告中输出错误代码示例(已有行号定位)**
|
|
191
|
-
6. **无问题时 LINE_INFO 必须输出空数组 `[]`**
|