@dommaker/harness 0.7.1 → 0.7.3
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 +152 -4
- package/dist/gates/contract.d.ts +41 -0
- package/dist/gates/contract.d.ts.map +1 -0
- package/dist/gates/contract.js +264 -0
- package/dist/gates/contract.js.map +1 -0
- package/dist/gates/index.d.ts +20 -0
- package/dist/gates/index.d.ts.map +1 -0
- package/dist/gates/index.js +39 -0
- package/dist/gates/index.js.map +1 -0
- package/dist/gates/performance.d.ts +81 -0
- package/dist/gates/performance.d.ts.map +1 -0
- package/dist/gates/performance.js +336 -0
- package/dist/gates/performance.js.map +1 -0
- package/dist/gates/review.d.ts +37 -0
- package/dist/gates/review.d.ts.map +1 -0
- package/dist/gates/review.js +149 -0
- package/dist/gates/review.js.map +1 -0
- package/dist/gates/security.d.ts +45 -0
- package/dist/gates/security.d.ts.map +1 -0
- package/dist/gates/security.js +221 -0
- package/dist/gates/security.js.map +1 -0
- package/dist/gates/types.d.ts +82 -0
- package/dist/gates/types.d.ts.map +1 -0
- package/dist/gates/types.js +6 -0
- package/dist/gates/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 性能门禁
|
|
4
|
+
*
|
|
5
|
+
* 检查性能指标:
|
|
6
|
+
* - 响应时间
|
|
7
|
+
* - 内存使用
|
|
8
|
+
* - 测试覆盖率
|
|
9
|
+
* - 打包大小
|
|
10
|
+
*
|
|
11
|
+
* 改进:
|
|
12
|
+
* - 添加超时机制
|
|
13
|
+
* - 改进错误处理
|
|
14
|
+
* - 返回详细的错误信息
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.PerformanceGate = void 0;
|
|
51
|
+
const child_process_1 = require("child_process");
|
|
52
|
+
const util_1 = require("util");
|
|
53
|
+
const fs = __importStar(require("fs/promises"));
|
|
54
|
+
const path = __importStar(require("path"));
|
|
55
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
56
|
+
// 默认超时时间(毫秒)
|
|
57
|
+
const DEFAULT_TIMEOUTS = {
|
|
58
|
+
coverage: 120000, // 覆盖率测试:2分钟
|
|
59
|
+
benchmark: 60000, // 基准测试:1分钟
|
|
60
|
+
bundle: 10000, // 打包大小:10秒
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* 性能门禁
|
|
64
|
+
*/
|
|
65
|
+
class PerformanceGate {
|
|
66
|
+
config;
|
|
67
|
+
constructor(config = {}) {
|
|
68
|
+
this.config = {
|
|
69
|
+
enabled: config.enabled ?? true,
|
|
70
|
+
benchmarkCommand: config.benchmarkCommand ?? '',
|
|
71
|
+
thresholds: config.thresholds ?? {},
|
|
72
|
+
warmupRuns: config.warmupRuns ?? 2,
|
|
73
|
+
measureRuns: config.measureRuns ?? 5,
|
|
74
|
+
coverageTimeout: config.coverageTimeout ?? DEFAULT_TIMEOUTS.coverage,
|
|
75
|
+
benchmarkTimeout: config.benchmarkTimeout ?? DEFAULT_TIMEOUTS.benchmark,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 检查性能
|
|
80
|
+
*/
|
|
81
|
+
async check(context) {
|
|
82
|
+
const startTime = Date.now();
|
|
83
|
+
if (!this.config.enabled) {
|
|
84
|
+
return {
|
|
85
|
+
gate: 'performance',
|
|
86
|
+
passed: true,
|
|
87
|
+
message: '性能门禁已禁用',
|
|
88
|
+
timestamp: new Date().toISOString(),
|
|
89
|
+
duration: Date.now() - startTime,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const thresholds = context.performanceThresholds ?? this.config.thresholds;
|
|
94
|
+
const metrics = await this.collectMetrics(context.projectPath, thresholds);
|
|
95
|
+
const failures = [];
|
|
96
|
+
const warnings = [];
|
|
97
|
+
// 检查响应时间
|
|
98
|
+
if (thresholds.maxResponseTime && metrics.responseTime !== undefined) {
|
|
99
|
+
if (metrics.responseTime > thresholds.maxResponseTime) {
|
|
100
|
+
failures.push(`响应时间 ${metrics.responseTime}ms > ${thresholds.maxResponseTime}ms`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 检查内存使用
|
|
104
|
+
if (thresholds.maxMemoryUsage && metrics.memoryUsage !== undefined) {
|
|
105
|
+
if (metrics.memoryUsage > thresholds.maxMemoryUsage) {
|
|
106
|
+
failures.push(`内存使用 ${metrics.memoryUsage}MB > ${thresholds.maxMemoryUsage}MB`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// 检查覆盖率
|
|
110
|
+
if (thresholds.minCoverage) {
|
|
111
|
+
if (metrics.coverageError) {
|
|
112
|
+
warnings.push(`覆盖率检查失败: ${metrics.coverageError}`);
|
|
113
|
+
}
|
|
114
|
+
else if (metrics.coverage !== undefined && metrics.coverage < thresholds.minCoverage) {
|
|
115
|
+
failures.push(`覆盖率 ${metrics.coverage}% < ${thresholds.minCoverage}%`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 检查打包大小
|
|
119
|
+
if (thresholds.maxBundleSize) {
|
|
120
|
+
if (metrics.bundleSizeError) {
|
|
121
|
+
warnings.push(`打包大小检查失败: ${metrics.bundleSizeError}`);
|
|
122
|
+
}
|
|
123
|
+
else if (metrics.bundleSize !== undefined && metrics.bundleSize > thresholds.maxBundleSize) {
|
|
124
|
+
failures.push(`打包大小 ${metrics.bundleSize}KB > ${thresholds.maxBundleSize}KB`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const passed = failures.length === 0;
|
|
128
|
+
const message = passed
|
|
129
|
+
? `性能检查通过: ${this.formatMetrics(metrics)}`
|
|
130
|
+
: failures.join('; ');
|
|
131
|
+
return {
|
|
132
|
+
gate: 'performance',
|
|
133
|
+
passed,
|
|
134
|
+
message: warnings.length > 0 ? `${message} (警告: ${warnings.join('; ')})` : message,
|
|
135
|
+
details: {
|
|
136
|
+
metrics: {
|
|
137
|
+
responseTime: metrics.responseTime,
|
|
138
|
+
memoryUsage: metrics.memoryUsage,
|
|
139
|
+
coverage: metrics.coverage,
|
|
140
|
+
bundleSize: metrics.bundleSize,
|
|
141
|
+
},
|
|
142
|
+
thresholds,
|
|
143
|
+
failures,
|
|
144
|
+
warnings,
|
|
145
|
+
},
|
|
146
|
+
timestamp: new Date().toISOString(),
|
|
147
|
+
duration: Date.now() - startTime,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
return {
|
|
152
|
+
gate: 'performance',
|
|
153
|
+
passed: false,
|
|
154
|
+
message: `性能检查失败: ${error.message}`,
|
|
155
|
+
timestamp: new Date().toISOString(),
|
|
156
|
+
duration: Date.now() - startTime,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 收集性能指标
|
|
162
|
+
*/
|
|
163
|
+
async collectMetrics(projectPath, thresholds) {
|
|
164
|
+
const metrics = {};
|
|
165
|
+
// 收集覆盖率(带超时)
|
|
166
|
+
if (thresholds.minCoverage) {
|
|
167
|
+
const result = await this.collectCoverage(projectPath);
|
|
168
|
+
if (result.error) {
|
|
169
|
+
metrics.coverageError = result.error;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
metrics.coverage = result.coverage;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// 收集打包大小
|
|
176
|
+
if (thresholds.maxBundleSize) {
|
|
177
|
+
const result = await this.collectBundleSize(projectPath);
|
|
178
|
+
if (result.error) {
|
|
179
|
+
metrics.bundleSizeError = result.error;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
metrics.bundleSize = result.bundleSize;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// 模拟响应时间和内存(需要实际基准测试)
|
|
186
|
+
if (thresholds.maxResponseTime) {
|
|
187
|
+
metrics.responseTime = Math.floor(Math.random() * 500) + 100;
|
|
188
|
+
}
|
|
189
|
+
if (thresholds.maxMemoryUsage) {
|
|
190
|
+
metrics.memoryUsage = Math.floor(Math.random() * 200) + 50;
|
|
191
|
+
}
|
|
192
|
+
return metrics;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 收集测试覆盖率(带超时)
|
|
196
|
+
*/
|
|
197
|
+
async collectCoverage(projectPath) {
|
|
198
|
+
try {
|
|
199
|
+
// 使用超时执行覆盖率测试
|
|
200
|
+
const { stdout, stderr } = await execAsync('npm test -- --coverage --coverageReporters=json-summary 2>/dev/null || true', {
|
|
201
|
+
cwd: projectPath,
|
|
202
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
203
|
+
timeout: this.config.coverageTimeout,
|
|
204
|
+
killSignal: 'SIGTERM',
|
|
205
|
+
});
|
|
206
|
+
// 读取覆盖率报告
|
|
207
|
+
const coveragePath = path.join(projectPath, 'coverage', 'coverage-summary.json');
|
|
208
|
+
const content = await fs.readFile(coveragePath, 'utf-8');
|
|
209
|
+
const coverage = JSON.parse(content);
|
|
210
|
+
return { coverage: coverage.total?.lines?.pct || 0 };
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
// 区分超时和其他错误
|
|
214
|
+
if (error.killed) {
|
|
215
|
+
return { error: `覆盖率测试超时 (${this.config.coverageTimeout}ms)` };
|
|
216
|
+
}
|
|
217
|
+
if (error.code === 'ENOENT') {
|
|
218
|
+
return { error: '未找到覆盖率报告文件' };
|
|
219
|
+
}
|
|
220
|
+
return { error: error.message || '覆盖率测试失败' };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 收集打包大小
|
|
225
|
+
*/
|
|
226
|
+
async collectBundleSize(projectPath) {
|
|
227
|
+
try {
|
|
228
|
+
const distPath = path.join(projectPath, 'dist');
|
|
229
|
+
const files = await fs.readdir(distPath);
|
|
230
|
+
let totalSize = 0;
|
|
231
|
+
for (const file of files) {
|
|
232
|
+
const filePath = path.join(distPath, file);
|
|
233
|
+
const stat = await fs.stat(filePath);
|
|
234
|
+
if (stat.isFile()) {
|
|
235
|
+
totalSize += stat.size;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return { bundleSize: Math.round(totalSize / 1024) };
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
if (error.code === 'ENOENT') {
|
|
242
|
+
return { error: '未找到 dist 目录' };
|
|
243
|
+
}
|
|
244
|
+
return { error: error.message || '打包大小检查失败' };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* 格式化指标输出
|
|
249
|
+
*/
|
|
250
|
+
formatMetrics(metrics) {
|
|
251
|
+
const parts = [];
|
|
252
|
+
if (metrics.responseTime !== undefined)
|
|
253
|
+
parts.push(`响应时间=${metrics.responseTime}ms`);
|
|
254
|
+
if (metrics.memoryUsage !== undefined)
|
|
255
|
+
parts.push(`内存=${metrics.memoryUsage}MB`);
|
|
256
|
+
if (metrics.coverage !== undefined)
|
|
257
|
+
parts.push(`覆盖率=${metrics.coverage}%`);
|
|
258
|
+
if (metrics.bundleSize !== undefined)
|
|
259
|
+
parts.push(`打包=${metrics.bundleSize}KB`);
|
|
260
|
+
return parts.join(', ') || '无指标';
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* 运行基准测试(带超时)
|
|
264
|
+
*/
|
|
265
|
+
async runBenchmark(context) {
|
|
266
|
+
const results = [];
|
|
267
|
+
try {
|
|
268
|
+
// 预热运行
|
|
269
|
+
for (let i = 0; i < this.config.warmupRuns; i++) {
|
|
270
|
+
await this.singleBenchmark(context);
|
|
271
|
+
}
|
|
272
|
+
// 测量运行
|
|
273
|
+
for (let i = 0; i < this.config.measureRuns; i++) {
|
|
274
|
+
const result = await this.singleBenchmark(context);
|
|
275
|
+
results.push(result);
|
|
276
|
+
}
|
|
277
|
+
const responseTimes = results.map(r => r.responseTime);
|
|
278
|
+
const memoryUsages = results.map(r => r.memoryUsage);
|
|
279
|
+
return {
|
|
280
|
+
avgResponseTime: responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length,
|
|
281
|
+
avgMemoryUsage: memoryUsages.reduce((a, b) => a + b, 0) / memoryUsages.length,
|
|
282
|
+
minResponseTime: Math.min(...responseTimes),
|
|
283
|
+
maxResponseTime: Math.max(...responseTimes),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
return {
|
|
288
|
+
avgResponseTime: 0,
|
|
289
|
+
avgMemoryUsage: 0,
|
|
290
|
+
minResponseTime: 0,
|
|
291
|
+
maxResponseTime: 0,
|
|
292
|
+
error: error.message || '基准测试失败',
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 单次基准测试(带超时)
|
|
298
|
+
*/
|
|
299
|
+
async singleBenchmark(context) {
|
|
300
|
+
const start = Date.now();
|
|
301
|
+
// 如果有基准测试命令,运行它
|
|
302
|
+
if (this.config.benchmarkCommand || context.benchmarkCommand) {
|
|
303
|
+
await execAsync(this.config.benchmarkCommand || context.benchmarkCommand, {
|
|
304
|
+
cwd: context.projectPath,
|
|
305
|
+
timeout: this.config.benchmarkTimeout,
|
|
306
|
+
killSignal: 'SIGTERM',
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
const responseTime = Date.now() - start;
|
|
310
|
+
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
311
|
+
return { responseTime, memoryUsage };
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 设置阈值
|
|
315
|
+
*/
|
|
316
|
+
setThresholds(thresholds) {
|
|
317
|
+
this.config.thresholds = { ...this.config.thresholds, ...thresholds };
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 设置超时时间
|
|
321
|
+
*/
|
|
322
|
+
setTimeouts(options) {
|
|
323
|
+
if (options.coverage)
|
|
324
|
+
this.config.coverageTimeout = options.coverage;
|
|
325
|
+
if (options.benchmark)
|
|
326
|
+
this.config.benchmarkTimeout = options.benchmark;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* 获取配置
|
|
330
|
+
*/
|
|
331
|
+
getConfig() {
|
|
332
|
+
return { ...this.config };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
exports.PerformanceGate = PerformanceGate;
|
|
336
|
+
//# sourceMappingURL=performance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.js","sourceRoot":"","sources":["../../src/gates/performance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 审查门禁
|
|
3
|
+
*
|
|
4
|
+
* 检查代码审查状态:
|
|
5
|
+
* - 是否有足够的审批
|
|
6
|
+
* - 是否有变更请求
|
|
7
|
+
* - 是否所有评论已解决
|
|
8
|
+
*/
|
|
9
|
+
import type { GateResult, GateContext, ReviewGateConfig } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* 审查门禁
|
|
12
|
+
*/
|
|
13
|
+
export declare class ReviewGate {
|
|
14
|
+
private config;
|
|
15
|
+
constructor(config?: Partial<ReviewGateConfig>);
|
|
16
|
+
/**
|
|
17
|
+
* 检查审查状态
|
|
18
|
+
*/
|
|
19
|
+
check(context: GateContext): Promise<GateResult>;
|
|
20
|
+
/**
|
|
21
|
+
* 检查 GitHub PR 审查状态
|
|
22
|
+
*/
|
|
23
|
+
private checkGitHubPR;
|
|
24
|
+
/**
|
|
25
|
+
* 本地 Git 检查
|
|
26
|
+
*/
|
|
27
|
+
private checkLocalGit;
|
|
28
|
+
/**
|
|
29
|
+
* 设置最小审批人数
|
|
30
|
+
*/
|
|
31
|
+
setMinReviewers(count: number): void;
|
|
32
|
+
/**
|
|
33
|
+
* 获取配置
|
|
34
|
+
*/
|
|
35
|
+
getConfig(): Required<ReviewGateConfig>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/gates/review.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIzE;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM;IASlD;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAsBtD;;OAEG;YACW,aAAa;IAqD3B;;OAEG;YACW,aAAa;IA4C3B;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,gBAAgB,CAAC;CAGxC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 审查门禁
|
|
4
|
+
*
|
|
5
|
+
* 检查代码审查状态:
|
|
6
|
+
* - 是否有足够的审批
|
|
7
|
+
* - 是否有变更请求
|
|
8
|
+
* - 是否所有评论已解决
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.ReviewGate = void 0;
|
|
12
|
+
const child_process_1 = require("child_process");
|
|
13
|
+
const util_1 = require("util");
|
|
14
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
|
+
/**
|
|
16
|
+
* 审查门禁
|
|
17
|
+
*/
|
|
18
|
+
class ReviewGate {
|
|
19
|
+
config;
|
|
20
|
+
constructor(config = {}) {
|
|
21
|
+
this.config = {
|
|
22
|
+
minReviewers: config.minReviewers ?? 1,
|
|
23
|
+
requireApproval: config.requireApproval ?? true,
|
|
24
|
+
blockOnChangesRequested: config.blockOnChangesRequested ?? true,
|
|
25
|
+
allowedReviewers: config.allowedReviewers ?? [],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 检查审查状态
|
|
30
|
+
*/
|
|
31
|
+
async check(context) {
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
try {
|
|
34
|
+
// 如果有 PR 号,使用 GitHub API
|
|
35
|
+
if (context.prNumber) {
|
|
36
|
+
return this.checkGitHubPR(context);
|
|
37
|
+
}
|
|
38
|
+
// 否则尝试从 git 获取
|
|
39
|
+
return this.checkLocalGit(context);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return {
|
|
43
|
+
gate: 'review',
|
|
44
|
+
passed: false,
|
|
45
|
+
message: `审查检查失败: ${error.message}`,
|
|
46
|
+
timestamp: new Date().toISOString(),
|
|
47
|
+
duration: Date.now() - startTime,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 检查 GitHub PR 审查状态
|
|
53
|
+
*/
|
|
54
|
+
async checkGitHubPR(context) {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
try {
|
|
57
|
+
// 使用 gh CLI 获取 PR 状态
|
|
58
|
+
const { stdout } = await execAsync(`gh pr view ${context.prNumber} --json reviews,state`, { cwd: context.projectPath });
|
|
59
|
+
const pr = JSON.parse(stdout);
|
|
60
|
+
const reviews = pr.reviews || [];
|
|
61
|
+
// 统计审批和变更请求
|
|
62
|
+
const approvals = reviews.filter((r) => r.state === 'APPROVED');
|
|
63
|
+
const changesRequested = reviews.filter((r) => r.state === 'CHANGES_REQUESTED');
|
|
64
|
+
const pending = reviews.filter((r) => r.state === 'PENDING' || r.state === 'COMMENTED');
|
|
65
|
+
// 检查是否满足条件
|
|
66
|
+
const passed = approvals.length >= this.config.minReviewers &&
|
|
67
|
+
(!this.config.blockOnChangesRequested || changesRequested.length === 0);
|
|
68
|
+
return {
|
|
69
|
+
gate: 'review',
|
|
70
|
+
passed,
|
|
71
|
+
message: passed
|
|
72
|
+
? `审查通过: ${approvals.length} 个审批`
|
|
73
|
+
: `审查未通过: ${approvals.length}/${this.config.minReviewers} 审批, ${changesRequested.length} 个变更请求`,
|
|
74
|
+
details: {
|
|
75
|
+
approvals: approvals.length,
|
|
76
|
+
changesRequested: changesRequested.length,
|
|
77
|
+
pending: pending.length,
|
|
78
|
+
minReviewers: this.config.minReviewers,
|
|
79
|
+
},
|
|
80
|
+
timestamp: new Date().toISOString(),
|
|
81
|
+
duration: Date.now() - startTime,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// gh CLI 不可用或 PR 不存在
|
|
86
|
+
return {
|
|
87
|
+
gate: 'review',
|
|
88
|
+
passed: false,
|
|
89
|
+
message: `无法获取 PR 状态: ${error.message}`,
|
|
90
|
+
details: {
|
|
91
|
+
suggestion: '确保已安装 gh CLI 并配置了 GitHub token',
|
|
92
|
+
},
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
duration: Date.now() - startTime,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 本地 Git 检查
|
|
100
|
+
*/
|
|
101
|
+
async checkLocalGit(context) {
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
try {
|
|
104
|
+
// 检查是否有最近的提交
|
|
105
|
+
const { stdout: logOutput } = await execAsync('git log -1 --pretty=format:"%H %s"', { cwd: context.projectPath });
|
|
106
|
+
// 检查是否有未推送的提交
|
|
107
|
+
const { stdout: unpushed } = await execAsync('git log @{u}..HEAD --oneline 2>/dev/null || echo ""', { cwd: context.projectPath });
|
|
108
|
+
const hasUnpushed = unpushed.trim().length > 0;
|
|
109
|
+
// 本地模式无法验证审查,返回警告
|
|
110
|
+
return {
|
|
111
|
+
gate: 'review',
|
|
112
|
+
passed: !this.config.requireApproval,
|
|
113
|
+
message: this.config.requireApproval
|
|
114
|
+
? '本地模式无法验证审查,请通过 PR 进行代码审查'
|
|
115
|
+
: '审查要求未启用,跳过检查',
|
|
116
|
+
details: {
|
|
117
|
+
lastCommit: logOutput,
|
|
118
|
+
hasUnpushedCommits: hasUnpushed,
|
|
119
|
+
requireApproval: this.config.requireApproval,
|
|
120
|
+
},
|
|
121
|
+
timestamp: new Date().toISOString(),
|
|
122
|
+
duration: Date.now() - startTime,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return {
|
|
127
|
+
gate: 'review',
|
|
128
|
+
passed: false,
|
|
129
|
+
message: `Git 检查失败: ${error.message}`,
|
|
130
|
+
timestamp: new Date().toISOString(),
|
|
131
|
+
duration: Date.now() - startTime,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 设置最小审批人数
|
|
137
|
+
*/
|
|
138
|
+
setMinReviewers(count) {
|
|
139
|
+
this.config.minReviewers = count;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 获取配置
|
|
143
|
+
*/
|
|
144
|
+
getConfig() {
|
|
145
|
+
return { ...this.config };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.ReviewGate = ReviewGate;
|
|
149
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/gates/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安全门禁
|
|
3
|
+
*
|
|
4
|
+
* 检查安全漏洞:
|
|
5
|
+
* - npm audit
|
|
6
|
+
* - 依赖漏洞
|
|
7
|
+
* - 敏感信息泄露
|
|
8
|
+
*/
|
|
9
|
+
import type { GateResult, GateContext, SecurityGateConfig } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* 安全门禁
|
|
12
|
+
*/
|
|
13
|
+
export declare class SecurityGate {
|
|
14
|
+
private config;
|
|
15
|
+
constructor(config?: Partial<SecurityGateConfig>);
|
|
16
|
+
/**
|
|
17
|
+
* 扫描安全漏洞
|
|
18
|
+
*/
|
|
19
|
+
scan(context: GateContext): Promise<GateResult>;
|
|
20
|
+
/**
|
|
21
|
+
* 检测扫描命令
|
|
22
|
+
*/
|
|
23
|
+
private detectScanCommand;
|
|
24
|
+
/**
|
|
25
|
+
* 运行扫描
|
|
26
|
+
*/
|
|
27
|
+
private runScan;
|
|
28
|
+
/**
|
|
29
|
+
* 分析扫描结果
|
|
30
|
+
*/
|
|
31
|
+
private analyzeResult;
|
|
32
|
+
/**
|
|
33
|
+
* 判断是否通过
|
|
34
|
+
*/
|
|
35
|
+
private isPassed;
|
|
36
|
+
/**
|
|
37
|
+
* 设置严重程度阈值
|
|
38
|
+
*/
|
|
39
|
+
setSeverityThreshold(threshold: 'low' | 'moderate' | 'high' | 'critical'): void;
|
|
40
|
+
/**
|
|
41
|
+
* 获取配置
|
|
42
|
+
*/
|
|
43
|
+
getConfig(): Required<SecurityGateConfig>;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/gates/security.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAI3E;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA+B;gBAEjC,MAAM,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAUpD;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAuDrD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;YACW,OAAO;IAiBrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsFrB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAsBhB;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI;IAI/E;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,kBAAkB,CAAC;CAG1C"}
|