Initial commit
This commit is contained in:
460
commands/pr-auto-update.md
Normal file
460
commands/pr-auto-update.md
Normal file
@@ -0,0 +1,460 @@
|
||||
## PR 自动更新
|
||||
|
||||
## 概述
|
||||
|
||||
自动更新 Pull Request 描述和标签的命令。通过分析 Git 更改内容,生成并设置适当的描述文本和标签。
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
/pr-auto-update [选项] [PR 编号]
|
||||
```
|
||||
|
||||
### 选项
|
||||
|
||||
- `--pr <编号>` : 指定目标 PR 编号 (省略时从当前分支自动检测)
|
||||
- `--description-only` : 仅更新描述 (不修改标签)
|
||||
- `--labels-only` : 仅更新标签 (不修改描述)
|
||||
- `--dry-run` : 不执行实际更新,仅显示生成的内容
|
||||
- `--lang <语言>` : 指定语言 (zh-cn, en)
|
||||
|
||||
### 基本示例
|
||||
|
||||
```bash
|
||||
# 自动更新当前分支的 PR
|
||||
/pr-auto-update
|
||||
|
||||
# 更新特定的 PR
|
||||
/pr-auto-update --pr 1234
|
||||
|
||||
# 仅更新描述
|
||||
/pr-auto-update --description-only
|
||||
|
||||
# 预演模式确认
|
||||
/pr-auto-update --dry-run
|
||||
```
|
||||
|
||||
## 功能详情
|
||||
|
||||
### 1. PR 自动检测
|
||||
|
||||
从当前分支自动检测对应的 PR:
|
||||
|
||||
```bash
|
||||
# 从分支搜索 PR
|
||||
gh pr list --head $(git branch --show-current) --json number,title,url
|
||||
```
|
||||
|
||||
### 2. 更改内容分析
|
||||
|
||||
收集和分析以下信息:
|
||||
|
||||
- **文件更改**: 添加、删除、修改的文件
|
||||
- **代码分析**: import 语句、函数定义、类定义的更改
|
||||
- **测试**: 测试文件的存在与内容
|
||||
- **文档**: README、docs 的更新
|
||||
- **配置**: package.json、pubspec.yaml、配置文件的更改
|
||||
- **CI/CD**: GitHub Actions、workflow 的更改
|
||||
|
||||
### 3. 描述文本自动生成
|
||||
|
||||
#### 模板处理优先级
|
||||
|
||||
1. **现有 PR 描述**: **完全遵循**已存在的内容
|
||||
2. **项目模板**: 从 `.github/PULL_REQUEST_TEMPLATE.md` 获取结构
|
||||
3. **默认模板**: 上述不存在时的后备方案
|
||||
|
||||
#### 现有内容保留规则
|
||||
|
||||
**重要**: 不修改现有内容
|
||||
|
||||
- 保留已写的部分
|
||||
- 仅补充空白部分
|
||||
- 保留功能性注释 (如 Copilot review rule 等)
|
||||
|
||||
#### 项目模板的使用
|
||||
|
||||
```bash
|
||||
# 解析 .github/PULL_REQUEST_TEMPLATE.md 的结构
|
||||
parse_template_structure() {
|
||||
local template_file="$1"
|
||||
|
||||
if [ -f "$template_file" ]; then
|
||||
# 提取部分结构
|
||||
grep -E '^##|^###' "$template_file"
|
||||
|
||||
# 识别注释占位符
|
||||
grep -E '<!--.*-->' "$template_file"
|
||||
|
||||
# 完全遵循现有模板结构
|
||||
cat "$template_file"
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 标签自动设置
|
||||
|
||||
#### 标签获取机制
|
||||
|
||||
**优先级**:
|
||||
|
||||
1. **`.github/labels.yml`**: 从项目特定的标签定义获取
|
||||
2. **GitHub API**: 使用 `gh api repos/{OWNER}/{REPO}/labels --jq '.[].name'` 获取现有标签
|
||||
|
||||
#### 自动判定规则
|
||||
|
||||
**基于文件模式**:
|
||||
|
||||
- 文档: `*.md`, `README`, `docs/` → 包含 `documentation|docs|doc` 的标签
|
||||
- 测试: `test`, `spec` → 包含 `test|testing` 的标签
|
||||
- CI/CD: `.github/`, `*.yml`, `Dockerfile` → 包含 `ci|build|infra|ops` 的标签
|
||||
- 依赖: `package.json`, `pubspec.yaml`, `requirements.txt` → 包含 `dependencies|deps` 的标签
|
||||
|
||||
**基于更改内容**:
|
||||
|
||||
- Bug 修复: `fix|bug|error|crash|修复` → 包含 `bug|fix` 的标签
|
||||
- 新功能: `feat|feature|add|implement|新功能|实装` → 包含 `feature|enhancement|feat` 的标签
|
||||
- 重构: `refactor|clean|重构` → 包含 `refactor|cleanup|clean` 的标签
|
||||
- 性能: `performance|perf|optimize|性能` → 包含 `performance|perf` 的标签
|
||||
- 安全: `security|secure|安全` → 包含 `security` 的标签
|
||||
|
||||
#### 约束
|
||||
|
||||
- **最多 3 个**: 自动选择的标签数量上限
|
||||
- **仅限现有标签**: 禁止创建新标签
|
||||
- **部分匹配**: 根据标签名是否包含关键词判定
|
||||
|
||||
#### 实际使用示例
|
||||
|
||||
**存在 `.github/labels.yml` 时**:
|
||||
|
||||
```bash
|
||||
# 从标签定义自动获取
|
||||
grep "^- name:" .github/labels.yml | sed "s/^- name: '\\?\\([^']*\\)'\\?/\\1/"
|
||||
|
||||
# 例:使用项目特定的标签体系
|
||||
```
|
||||
|
||||
**从 GitHub API 获取时**:
|
||||
|
||||
```bash
|
||||
# 获取现有标签列表
|
||||
gh api repos/{OWNER}/{REPO}/labels --jq '.[].name'
|
||||
|
||||
# 例:使用 bug, enhancement, documentation 等标准标签
|
||||
```
|
||||
|
||||
### 5. 执行流程
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# 1. PR 检测与获取
|
||||
detect_pr() {
|
||||
if [ -n "$PR_NUMBER" ]; then
|
||||
echo $PR_NUMBER
|
||||
else
|
||||
gh pr list --head $(git branch --show-current) --json number --jq '.[0].number'
|
||||
fi
|
||||
}
|
||||
|
||||
# 2. 更改内容分析
|
||||
analyze_changes() {
|
||||
local pr_number=$1
|
||||
|
||||
# 获取文件更改
|
||||
gh pr diff $pr_number --name-only
|
||||
|
||||
# 内容分析
|
||||
gh pr diff $pr_number | head -1000
|
||||
}
|
||||
|
||||
# 3. 描述生成
|
||||
generate_description() {
|
||||
local pr_number=$1
|
||||
local changes=$2
|
||||
|
||||
# 获取当前 PR 描述
|
||||
local current_body=$(gh pr view $pr_number --json body --jq -r .body)
|
||||
|
||||
# 如有现有内容则直接使用
|
||||
if [ -n "$current_body" ]; then
|
||||
echo "$current_body"
|
||||
else
|
||||
# 从模板生成新内容
|
||||
local template_file=".github/PULL_REQUEST_TEMPLATE.md"
|
||||
if [ -f "$template_file" ]; then
|
||||
generate_from_template "$(cat "$template_file")" "$changes"
|
||||
else
|
||||
generate_from_template "" "$changes"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 从模板生成
|
||||
generate_from_template() {
|
||||
local template="$1"
|
||||
local changes="$2"
|
||||
|
||||
if [ -n "$template" ]; then
|
||||
# 直接使用模板 (保留 HTML 注释)
|
||||
echo "$template"
|
||||
else
|
||||
# 使用默认格式生成
|
||||
echo "## What does this change?"
|
||||
echo ""
|
||||
echo "$changes"
|
||||
fi
|
||||
}
|
||||
|
||||
# 4. 标签确定
|
||||
determine_labels() {
|
||||
local changes=$1
|
||||
local file_list=$2
|
||||
local pr_number=$3
|
||||
|
||||
# 获取可用标签
|
||||
local available_labels=()
|
||||
if [ -f ".github/labels.yml" ]; then
|
||||
# 从 labels.yml 提取标签名
|
||||
available_labels=($(grep "^- name:" .github/labels.yml | sed "s/^- name: '\\?\\([^']*\\)'\\?/\\1/"))
|
||||
else
|
||||
# 从 GitHub API 获取标签
|
||||
local repo_info=$(gh repo view --json owner,name)
|
||||
local owner=$(echo "$repo_info" | jq -r .owner.login)
|
||||
local repo=$(echo "$repo_info" | jq -r .name)
|
||||
available_labels=($(gh api "repos/$owner/$repo/labels" --jq '.[].name'))
|
||||
fi
|
||||
|
||||
local suggested_labels=()
|
||||
|
||||
# 通用模式匹配
|
||||
analyze_change_patterns "$file_list" "$changes" available_labels suggested_labels
|
||||
|
||||
# 限制最多 3 个
|
||||
echo "${suggested_labels[@]:0:3}"
|
||||
}
|
||||
|
||||
# 根据更改模式确定标签
|
||||
analyze_change_patterns() {
|
||||
local file_list="$1"
|
||||
local changes="$2"
|
||||
local -n available_ref=$3
|
||||
local -n suggested_ref=$4
|
||||
|
||||
# 根据文件类型判定
|
||||
if echo "$file_list" | grep -q "\\.md$\\|README\\|docs/"; then
|
||||
add_matching_label "documentation\\|docs\\|doc" available_ref suggested_ref
|
||||
fi
|
||||
|
||||
if echo "$file_list" | grep -q "test\\|spec"; then
|
||||
add_matching_label "test\\|testing" available_ref suggested_ref
|
||||
fi
|
||||
|
||||
# 根据更改内容判定
|
||||
if echo "$changes" | grep -iq "fix\\|bug\\|error\\|crash\\|修复"; then
|
||||
add_matching_label "bug\\|fix" available_ref suggested_ref
|
||||
fi
|
||||
|
||||
if echo "$changes" | grep -iq "feat\\|feature\\|add\\|implement\\|新功能\\|实现"; then
|
||||
add_matching_label "feature\\|enhancement\\|feat" available_ref suggested_ref
|
||||
fi
|
||||
}
|
||||
|
||||
# 添加匹配的标签
|
||||
add_matching_label() {
|
||||
local pattern="$1"
|
||||
local -n available_ref=$2
|
||||
local -n suggested_ref=$3
|
||||
|
||||
# 如果已有 3 个则跳过
|
||||
if [ ${#suggested_ref[@]} -ge 3 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# 添加匹配模式的第一个标签
|
||||
for available_label in "${available_ref[@]}"; do
|
||||
if echo "$available_label" | grep -iq "$pattern"; then
|
||||
# 重复检查
|
||||
local already_exists=false
|
||||
for existing in "${suggested_ref[@]}"; do
|
||||
if [ "$existing" = "$available_label" ]; then
|
||||
already_exists=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$already_exists" = false ]; then
|
||||
suggested_ref+=("$available_label")
|
||||
return
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# 为兼容性保留旧函数
|
||||
find_and_add_label() {
|
||||
add_matching_label "$@"
|
||||
}
|
||||
|
||||
# 5. PR 更新
|
||||
update_pr() {
|
||||
local pr_number=$1
|
||||
local description="$2"
|
||||
local labels="$3"
|
||||
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "=== DRY RUN ==="
|
||||
echo "Description:"
|
||||
echo "$description"
|
||||
echo "Labels: $labels"
|
||||
else
|
||||
# 获取仓库信息
|
||||
local repo_info=$(gh repo view --json owner,name)
|
||||
local owner=$(echo "$repo_info" | jq -r .owner.login)
|
||||
local repo=$(echo "$repo_info" | jq -r .name)
|
||||
|
||||
# 使用 GitHub API 更新正文 (保留 HTML 注释)
|
||||
# 正确处理 JSON 转义
|
||||
local escaped_body=$(echo "$description" | jq -R -s .)
|
||||
gh api \
|
||||
--method PATCH \
|
||||
"/repos/$owner/$repo/pulls/$pr_number" \
|
||||
--field body="$description"
|
||||
|
||||
# 标签使用常规 gh 命令即可
|
||||
if [ -n "$labels" ]; then
|
||||
gh pr edit $pr_number --add-label "$labels"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
## 配置文件 (未来扩展用)
|
||||
|
||||
`~/.claude/pr-auto-update.config`:
|
||||
|
||||
```json
|
||||
{
|
||||
"language": "zh-cn",
|
||||
"max_labels": 3
|
||||
}
|
||||
```
|
||||
|
||||
## 常见模式
|
||||
|
||||
### Flutter 项目
|
||||
|
||||
```markdown
|
||||
## What does this change?
|
||||
|
||||
实现了{功能名}。解决了用户的{问题}。
|
||||
|
||||
### 主要更改内容
|
||||
|
||||
- **UI 实现**: 新建{画面名}
|
||||
- **状态管理**: 添加 Riverpod Provider
|
||||
- **API 集成**: 实现 GraphQL 查询与变更
|
||||
- **测试**: 添加 Widget 测试和单元测试
|
||||
|
||||
### 技术规格
|
||||
|
||||
- **架构**: {使用的模式}
|
||||
- **依赖**: {新增的包}
|
||||
- **性能**: {优化内容}
|
||||
```
|
||||
|
||||
### Node.js 项目
|
||||
|
||||
```markdown
|
||||
## What does this change?
|
||||
|
||||
实现了{API 名}端点。支持{用例}。
|
||||
|
||||
### 主要更改内容
|
||||
|
||||
- **API 实现**: 新建{端点}
|
||||
- **验证**: 添加请求验证逻辑
|
||||
- **数据库**: 实现对{表名}的操作
|
||||
- **测试**: 添加集成测试和单元测试
|
||||
|
||||
### 安全性
|
||||
|
||||
- **认证**: JWT 令牌验证
|
||||
- **授权**: 基于角色的访问控制
|
||||
- **输入验证**: SQL 注入防护
|
||||
```
|
||||
|
||||
### CI/CD 改进
|
||||
|
||||
```markdown
|
||||
## What does this change?
|
||||
|
||||
改进了 GitHub Actions 工作流。实现了{效果}。
|
||||
|
||||
### 改进内容
|
||||
|
||||
- **性能**: 构建时间减少{时间}
|
||||
- **可靠性**: 增强错误处理
|
||||
- **安全性**: 改进密钥管理
|
||||
|
||||
### 技术细节
|
||||
|
||||
- **并行化**: {作业名}并行执行
|
||||
- **缓存**: 优化{缓存对象}的缓存策略
|
||||
- **监控**: 添加{指标}监控
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **完全保留现有内容**:
|
||||
- **一字不改**现有描述内容
|
||||
- 仅补充空白注释和占位符
|
||||
- 尊重用户有意编写的内容
|
||||
|
||||
2. **模板优先级**:
|
||||
- 现有 PR 描述 > `.github/PULL_REQUEST_TEMPLATE.md` > 默认
|
||||
- 完全遵循项目特定的模板结构
|
||||
|
||||
3. **标签约束**:
|
||||
- 如存在 `.github/labels.yml` 则优先使用
|
||||
- 不存在时从 GitHub API 获取现有标签
|
||||
- 禁止创建新标签
|
||||
- 自动选择最多 3 个
|
||||
|
||||
4. **安全更新**:
|
||||
- 推荐使用 `--dry-run` 预先确认
|
||||
- 包含敏感信息的更改时显示警告
|
||||
- 保存原始描述作为备份
|
||||
|
||||
5. **保持一致性**:
|
||||
- 符合项目现有 PR 风格
|
||||
- 统一语言 (日语/英语)
|
||||
- 继承标签规则
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **找不到 PR**: 检查分支名与 PR 的关联
|
||||
2. **权限错误**: 检查 GitHub CLI 的认证状态
|
||||
3. **无法设置标签**: 检查仓库权限
|
||||
4. **HTML 注释被转义**: GitHub CLI 的规格导致 `<!-- -->` 被转换为 `<!-- -->`
|
||||
|
||||
### GitHub CLI 的 HTML 注释转义问题
|
||||
|
||||
**重要**: GitHub CLI (`gh pr edit`) 会自动转义 HTML 注释。此外,Shell 的重定向处理可能混入 `EOF < /dev/null` 等非法字符串。
|
||||
|
||||
#### 根本解决方案
|
||||
|
||||
1. **使用 GitHub API 的 --field 选项**: 使用 `--field` 进行适当的转义处理
|
||||
2. **简化 Shell 处理**: 避免复杂的重定向和管道处理
|
||||
3. **简化模板处理**: 废除 HTML 注释移除处理,完全保留
|
||||
4. **正确处理 JSON 转义**: 正确处理特殊字符
|
||||
|
||||
### 调试选项
|
||||
|
||||
```bash
|
||||
# 输出详细日志 (实现时添加)
|
||||
/pr-auto-update --verbose
|
||||
```
|
||||
Reference in New Issue
Block a user