mirror of
https://github.com/Lydanne/spaceflow.git
synced 2026-03-09 18:52:24 +08:00
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:
@@ -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` 配置切换:
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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.includes,fallback 到 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
6
pnpm-lock.yaml
generated
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user