Files
gh-wasabeef-claude-code-coo…/commands/pr-auto-update.md
2025-11-30 09:05:46 +08:00

461 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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 的规格导致 `<!-- -->` 被转换为 `&lt;!-- --&gt;`
### 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
```