Skip to content

Commit bf40732

Browse files
committed
refactor(pdk): extract shared scope filtering logic
- create utils/commit.ts for shared scope extraction functions - replace duplicate scope filtering logic in github.ts and ai-changelog.ts - add comprehensive testing documentation
1 parent c10b710 commit bf40732

4 files changed

Lines changed: 164 additions & 32 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# PDK Filter Scopes 功能测试指南
2+
3+
## 功能概述
4+
5+
PDK 的 `--filter-scopes` 参数用于在生成 changelog 时过滤特定 scope 的 commit。默认情况下支持全部 scope,可通过 CLI 参数指定需要包含的 scope。
6+
7+
## 测试场景
8+
9+
### 1. 基本功能测试
10+
11+
#### 测试默认行为(包含所有 scope)
12+
```bash
13+
# 生成包含所有 scope 的 changelog
14+
pdk changelog --from-tag=v1.0.0 --to-tag=v1.1.0
15+
#
16+
pdk release --filter-scopes=""
17+
```
18+
19+
#### 测试指定 scope 过滤
20+
```bash
21+
# 只生成特定 scope 的 changelog
22+
pdk changelog --from-tag=v1.0.0 --to-tag=v1.1.0 --filter-scopes=tars,agent
23+
#
24+
pdk release --filter-scopes=tars,agent
25+
```
26+
27+
### 2. AI 生成 changelog 测试
28+
29+
#### 使用 AI 生成 + scope 过滤
30+
```bash
31+
pdk changelog --use-ai --filter-scopes=tars,agent --provider=azure-openai --model=gpt-4o
32+
#
33+
pdk release --use-ai --filter-scopes=tars,agent --provider=azure-openai --model=gpt-4o
34+
```
35+
36+
### 3. 实际项目测试
37+
38+
#### 在 multimodal 项目中测试
39+
```bash
40+
cd multimodal
41+
# 使用预配置的 scope 过滤
42+
pnpm release:ai:dryrun
43+
```
44+
45+
#### 在 infra 项目中测试
46+
```bash
47+
cd infra
48+
# 测试包含所有 scope(适合 infra monorepo)
49+
pdk changelog --filter-scopes=""
50+
# 或指定 infra 相关 scope
51+
pdk changelog --filter-scopes=infra,pdk,build
52+
```
53+
54+
## 验证方法
55+
56+
### 1. 检查 commit 过滤效果
57+
创建测试 commit:
58+
```bash
59+
feat(tars): add new feature
60+
feat(agent): improve performance
61+
feat(infra): update build system
62+
chore: update dependencies
63+
```
64+
65+
使用不同 filter 参数验证:
66+
```bash
67+
# 应包含所有 commit
68+
pdk changelog --filter-scopes=""
69+
70+
# 只包含 tars 和 agent 的 feat
71+
pdk changelog --filter-scopes="tars,agent"
72+
73+
# 只包含 infra 相关
74+
pdk changelog --filter-scopes="infra,pdk,build"
75+
```
76+
77+
### 2. 验证 AI 生成结果
78+
```bash
79+
# AI 生成时应用 scope 过滤
80+
pdk changelog --use-ai --filter-scopes="tars,agent" --dry-run
81+
```
82+
83+
### 3. 验证 GitHub Release 生成
84+
```bash
85+
# 生成 GitHub Release 时应用 scope 过滤
86+
pdk release --create-github-release --filter-scopes="tars,agent" --dry-run
87+
```
88+
89+
## 常见问题排查
90+
91+
### 1. 空结果
92+
- 检查 tag 是否存在:`git tag --list`
93+
- 检查 commit 格式是否符合 conventional commits
94+
- 验证 scope 名称是否正确
95+
96+
### 2. 过滤不生效
97+
- 确认 scope 名称大小写敏感
98+
- 检查是否有空格或特殊字符
99+
- 验证 commit message 格式:`type(scope): description`
100+
101+
### 3. AI 生成异常
102+
- 检查 API key 和配置
103+
- 验证网络连接
104+
- 查看详细错误日志
105+
106+
## 最佳实践
107+
108+
1. **项目配置**:在 package.json 中预定义常用的 scope 组合
109+
2. **CI/CD 集成**:在发布流程中使用固定的 scope 过滤
110+
3. **文档维护**:保持 scope 命名规范的一致性
111+
4. **测试覆盖**:定期验证不同 scope 组合的生成效果

infra/pdk/src/utils/ai-changelog.ts

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { existsSync, readFileSync, writeFileSync } from 'fs';
22
import { execa } from 'execa';
33
import { logger } from './logger';
4+
import { shouldIncludeCommitByScope } from './commit';
45
import { AgentModel } from '@tarko/model-provider';
56

67
interface CommitEntry {
@@ -103,26 +104,9 @@ export class AIChangelogGenerator {
103104

104105
// Apply scope filter if provided
105106
if (filterScopes && filterScopes.length > 0) {
106-
return commits.filter((commit) => {
107-
const match = commit.message.match(/^(\w+)(\([^)]+\))?:\s*(.+)$/);
108-
if (match) {
109-
const [, , scopeStr] = match;
110-
111-
// Extract scope from scopeStr (remove parentheses)
112-
let scope = '';
113-
if (scopeStr) {
114-
const scopeMatch = scopeStr.match(/^\(([^)]+)\)$/);
115-
scope = scopeMatch ? scopeMatch[1] : '';
116-
}
117-
118-
// Include if no scope or scope matches filter
119-
if (!scope || filterScopes.includes(scope) || filterScopes.includes('all')) {
120-
return true;
121-
}
122-
return false;
123-
}
124-
return true; // Include non-conventional commits
125-
});
107+
return commits.filter((commit) =>
108+
shouldIncludeCommitByScope(commit.message, filterScopes)
109+
);
126110
}
127111

128112
return commits;

infra/pdk/src/utils/commit.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Git commit utilities
3+
*/
4+
5+
/**
6+
* Extract scope from conventional commit message
7+
* @param commitMessage - The commit message to extract scope from
8+
* @returns The extracted scope or empty string if no scope found
9+
*/
10+
export function extractScopeFromCommit(commitMessage: string): string {
11+
const match = commitMessage.match(/^(\w+)(\([^)]+\))?:\s*(.+)$/);
12+
if (!match) {
13+
return '';
14+
}
15+
16+
const [, , scopeStr] = match;
17+
18+
if (!scopeStr) {
19+
return '';
20+
}
21+
22+
const scopeMatch = scopeStr.match(/^\(([^)]+)\)$/);
23+
return scopeMatch ? scopeMatch[1] : '';
24+
}
25+
26+
/**
27+
* Check if a commit should be included based on scope filters
28+
* @param commitMessage - The commit message to check
29+
* @param filterScopes - Array of scopes to include (empty array means include all)
30+
* @returns True if the commit should be included
31+
*/
32+
export function shouldIncludeCommitByScope(
33+
commitMessage: string,
34+
filterScopes?: string[],
35+
): boolean {
36+
// If no filter provided, include all commits
37+
if (!filterScopes || filterScopes.length === 0) {
38+
return true;
39+
}
40+
41+
const scope = extractScopeFromCommit(commitMessage);
42+
43+
// Include if no scope or scope matches filter
44+
return !scope || filterScopes.includes(scope) || filterScopes.includes('all');
45+
}

infra/pdk/src/utils/github.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
import { execa } from 'execa';
1010
import { logger } from './logger';
11+
import { shouldIncludeCommitByScope } from './commit';
1112

1213
// Username mapping for commit authors to correct GitHub usernames
1314
const USERNAME_MAP: Record<string, string> = {
@@ -138,20 +139,11 @@ export async function generateReleaseNotes(
138139
commits.forEach((commit) => {
139140
const match = commit.subject.match(/^(\w+)(\([^)]+\))?:\s*(.+)$/);
140141
if (match) {
141-
const [, type, scopeStr] = match;
142-
143-
// Extract scope from scopeStr (remove parentheses)
144-
let scope = '';
145-
if (scopeStr) {
146-
const scopeMatch = scopeStr.match(/^\(([^)]+)\)$/);
147-
scope = scopeMatch ? scopeMatch[1] : '';
148-
}
142+
const [, type] = match;
149143

150144
// Apply scope filter if provided
151-
if (filterScopes && filterScopes.length > 0 && scope) {
152-
if (!filterScopes.includes(scope) && !filterScopes.includes('all')) {
153-
return; // Skip this commit
154-
}
145+
if (!shouldIncludeCommitByScope(commit.subject, filterScopes)) {
146+
return; // Skip this commit
155147
}
156148

157149
if (type in groups) {

0 commit comments

Comments
 (0)