feat(review-summary): 新增文件过滤功能并优化缺陷率计算

1. 新增 `includes` 配置项支持 glob 模式过滤文件,排除测试、配置等非业务代码
2. 使用 micromatch 库实现文件过滤,支持 `!` 排除模式和 matchBase 匹配
3. 未配置时自动 fallback 读取 `review.includes`,与代码审查使用相同规则
4. 过滤同时影响 `additions`、`deletions` 和 `changedFiles` 统计
5. 缺陷率计算中排除标题以 "Merge" 开头的 PR,避免合并操作影
This commit is contained in:
Lyda
2026-03-02 17:31:03 +08:00
parent f6681ecdcd
commit 9655f828ce
5 changed files with 57 additions and 3 deletions

View File

@@ -66,6 +66,23 @@ spaceflow review-summary -p this-month -o file --output-file report.md
| `last-15-days` | 最近 15 天 |
| `last-30-days` | 最近 30 天 |
## 文件过滤
统计代码行数和变更文件时,支持通过 glob 模式过滤文件,排除测试、配置等非业务代码:
```json
{
"review-summary": {
"includes": ["*/**/*.ts", "!*/**/*.spec.*", "!*/**/*.config.*"]
}
}
```
- 支持 `!` 排除模式(如 `!*/**/*.spec.*` 排除测试文件)
- 使用 [micromatch](https://github.com/micromatch/micromatch) 语法,`matchBase` 模式
- **未配置时自动 fallback 读取 `review.includes`**,与代码审查使用相同的过滤规则
- 过滤同时影响 `additions``deletions``changedFiles` 统计
## 评分策略
支持四种评分策略,通过 `strategy` 配置切换:

View File

@@ -19,10 +19,12 @@
"dev": "spaceflow dev"
},
"dependencies": {
"@spaceflow/review": "workspace:*"
"@spaceflow/review": "workspace:*",
"micromatch": "^4.0.8"
},
"devDependencies": {
"@spaceflow/cli": "workspace:*",
"@types/micromatch": "^4.0.9",
"@types/node": "catalog:"
},
"peerDependencies": {

View File

@@ -2,6 +2,7 @@ import { GitProviderService, shouldLog, normalizeVerbose } from "@spaceflow/core
import type { IConfigReader } from "@spaceflow/core";
import type { PullRequest, Issue, CiConfig } from "@spaceflow/core";
import { MarkdownFormatter, type ReviewIssue } from "@spaceflow/review";
import micromatch from "micromatch";
import { writeFileSync } from "fs";
import { join } from "path";
import type {
@@ -159,8 +160,13 @@ export class PeriodSummaryService {
let additions = 0;
let deletions = 0;
let changedFiles = 0;
const includes = this.resolveIncludes();
try {
const files = await this.gitProvider.getPullRequestFiles(owner, repo, pr.number!);
const allFiles = await this.gitProvider.getPullRequestFiles(owner, repo, pr.number!);
const files =
includes.length > 0
? allFiles.filter((f) => micromatch.isMatch(f.filename ?? "", includes, { matchBase: true }))
: allFiles;
changedFiles = files.length;
for (const file of files) {
additions += file.additions ?? 0;
@@ -371,6 +377,22 @@ export class PeriodSummaryService {
return userMap;
}
/**
* 解析文件过滤 glob 模式:优先使用 review-summary.includesfallback 到 review.includes
*/
protected resolveIncludes(): string[] {
const config = this.getStrategyConfig();
if (config.includes && config.includes.length > 0) {
return config.includes;
}
try {
const reviewConfig = this.config.get<{ includes?: string[] }>("review");
return reviewConfig?.includes ?? [];
} catch {
return [];
}
}
/**
* 获取当前评分策略配置
*/
@@ -470,7 +492,10 @@ export class PeriodSummaryService {
const weights = { ...DEFAULT_DEFECT_RATE_WEIGHTS, ...config.defectRateWeights };
if (stats.prs.length === 0) return 0;
let complianceSum = 0;
let counted = 0;
for (const pr of stats.prs) {
// 跳过 merge PR标题以 "Merge" 开头),合并操作不纳入缺陷率统计
if (pr.title.startsWith("Merge")) continue;
const totalLines = pr.additions + pr.deletions;
const per100 = Math.max(1, totalLines / 100);
const penalty =
@@ -478,8 +503,10 @@ export class PeriodSummaryService {
const recovery = (pr.fixedErrors + pr.fixedWarns) * weights.fixedDiscount;
const compliance = Math.min(1, Math.max(0, 1 - penalty + recovery));
complianceSum += compliance;
counted++;
}
const avgCompliance = complianceSum / stats.prs.length;
if (counted === 0) return 0;
const avgCompliance = complianceSum / counted;
return Math.round((1 - avgCompliance) * 1000) / 10;
}

View File

@@ -191,6 +191,8 @@ export interface DefectRateWeights {
export interface ReviewSummaryConfig {
/** 评分策略,默认 "weighted" */
strategy?: ScoreStrategy;
/** 文件过滤 glob 模式,未设置时 fallback 读取 review.includes支持 ! 排除模式 */
includes?: string[];
/** 加权模式权重配置strategy 为 "weighted" 时生效) */
scoreWeights?: WeightedScoreWeights;
/** 分数累计模式权重配置strategy 为 "commit-based" 时生效) */

6
pnpm-lock.yaml generated
View File

@@ -188,10 +188,16 @@ importers:
'@spaceflow/review':
specifier: workspace:*
version: link:../review
micromatch:
specifier: ^4.0.8
version: 4.0.8
devDependencies:
'@spaceflow/cli':
specifier: workspace:*
version: link:../../packages/cli
'@types/micromatch':
specifier: ^4.0.9
version: 4.0.10
'@types/node':
specifier: 'catalog:'
version: 22.19.1