实战复盘:用 Claude Code 从零搭一个 GitHub PR 统计工具
本文是《Claude Code 实战》系列第 7 篇。前六篇分别讲了工作流、Plan、MCP、子 Agent、记忆管理------这篇把它们串起来,做一次完整的从零到一。
要做什么
场景:团队每周站会要报 PR 数据------合并了几个、平均多久合入、谁提交最多。手动数 GitHub 页面太蠢,于是决定写一个 CLI 小工具。
验收标准:
- 输入:仓库名(
owner/repo),可选时间范围 - 输出:合并/待合/关闭各多少、平均合入时间、Top 5 贡献者
- 命令行:
pr-stats owner/repo --days 7 - 用 GitHub API,支持 token 认证
第一步:让 AI 理解现状
项目目录是空的。先给 Claude Code 一句指令,附带关键约束让它放在正确的盘上:
在 D:/projects/pr-stats/ 下初始化一个 Go 项目,
做一个 CLI 工具 pr-stats,功能是拉取 GitHub 仓库的 PR 数据做统计。
先别写代码,先看看项目环境有什么。
Claude Code 自动执行 ls,确认目录为空,然后问我 Go 版本偏好。我回:
用 Go 1.22+。先不用 Go 模块以外的第三方依赖库------用标准库 net/http 调 GitHub API,自己写 JSON 解析。
这里体现了第一篇讲的"给对上下文"------告诉它语言版本、不用什么、用什么。而不是扔一句"帮我写个工具"让它猜。
第二步:Plan------先出方案
有了上下文,Claude Code 开始规划。我明确要求它先出方案:
用 Plan 模式,先梳理完整的实现方案再动手
大概 15 秒后,它给出方案(摘要):
实现路径:
1. 项目骨架:main.go、go.mod
2. api/github.go - GitHub API 客户端(请求封装、pagination 处理)
3. model/pr.go - PR 数据结构
4. stats/analyzer.go - 统计逻辑(合入时间计算、贡献者排序)
5. cli/formatter.go - 输出格式化(表格/JSON)
6. 集成测试:用 GitHub 公开仓库验证
关键决策:
- REST API:GET /repos/{owner}/{repo}/pulls?state=all&per_page=100
- 分页用 Link header 解析,不猜总量
- 合入时间用 merged_at - created_at(不含 review 等待时间)
- 时间范围:用 created_at 或 updated_at 过滤(命令行 --filter-by 参数选择)
我审了一下,提了两个修正:
分页遍历改为:先拿第一页,用最后一页的 Link header 估算总页数,
如果超过 50 页就截断并警告,别无限循环。
时间过滤默认用 updated_at,因为我们关心的是"最近有活动的 PR"。
Plan 模式的价值就在这里------它在写代码之前暴露理解偏差,改方案成本远低于改代码。
第三步:并行实现------多文件开工
Plan 通过后,我说:
按方案实现。分文件写,可以并行做的就同时做。每写完一个文件跑对应测试。
Claude Code 启动了两个子 Agent:一个负责 API 层(api/github.go),一个负责数据模型和统计逻辑(model/pr.go + stats/analyzer.go)。主 agent 负责 main.go 和 CLI 层的串联。
这就是第 5 篇讲的子 Agent 并行------API 层和统计层没有依赖,不用等一个完了再开另一个。
几分钟后两个子 Agent 回来。API 层返回了核心代码:
go
// api/github.go(核心片段)
func (c *Client) ListPRs(ctx context.Context, owner, repo string, opts ListPROptions) ([]PullRequest, error) {
var all []PullRequest
page := 1
for {
u := fmt.Sprintf("https://api.github.com/repos/%s/%s/pulls?state=all&per_page=100&page=%d", owner, repo, page)
req, _ := http.NewRequestWithContext(ctx, "GET", u, nil)
req.Header.Set("Accept", "application/vnd.github+json")
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
}
resp, err := c.http.Do(req)
// ... 解析 JSON,处理分页
if page >= 50 { break } // 上限
page++
}
return all, nil
}
统计层也交稿了。我扫了一遍------计算 merged_at - created_at 时没处理 nil 时间(未合入的 PR),模型里 MergedAt 用了指针但统计函数里没判空。
这就是必须 review 的地方------AI 写代码很快,但边界条件容易漏。我标出来让它修,它改了统计函数加上 if pr.MergedAt == nil { continue }。
第四步:跑起来,然后翻车
修完边界条件,让它编译跑测试:
go build 然后对 golang/go 仓库跑 pr-stats golang/go --days 30
编译通过,运行报错:
Error: API rate limit exceeded (403)
没带 token,GitHub 对未认证请求限 60 次/小时。这个坑 AI 在实现时没预判------它写了 token 支持但没在 CLI 入口强制提示用户。
我加上 token 再试:
set GITHUB_TOKEN=xxx # Windows
pr-stats golang/go --days 30
输出:
Period: last 30 days (filtered by updated_at)
Status Count Avg time to merge
────────────── ──────── ──────────────────
Merged 267 2.3 days
Open 152 N/A
Closed 48 5.1 days
Top contributors:
1. user_a 42 PRs
2. user_b 31 PRs
3. user_c 28 PRs
4. user_d 25 PRs
5. user_e 19 PRs
数据出来了。格式还行,但我想加上每周趋势:
在统计输出里加一个"过去 4 周每周合并数量"的趋势段,
另外把它输出格式改成默认表格、加 --json 参数输出 JSON。
Claude Code 改 cli/formatter.go 和 stats/analyzer.go,加了按周聚合和 JSON 输出。再跑一遍,结果正常。
整个过程从需求到能用的工具,大约 12 分钟------其中 3 分钟我在审方案和修边界,其他时间 AI 在写代码。
复盘:人做了什么,AI 做了什么
| 环节 | 人 | AI |
|---|---|---|
| 需求定义 | 说清楚要什么、验收标准 | 理解并确认 |
| Plan | 审查方案,修正两个决策 | 出完整方案,分析取舍 |
| 实现 | 零代码,只 review diff | 跨文件并行写,处理分页、边界 |
| 测试 | 指定测试仓库和参数 | 编译、运行、解释错误 |
| 边界修复 | 发现 nil 时间问题、token 缺提示 | 按要求修,没辩解 |
| 迭代 | "加每周趋势" | 改 formatter + analyzer,一次通过 |
哪些环节必须人介入:
- Plan 审查------AI 的"合理方案"不一定是你要的
- Diff review------边界条件 AI 容易漏
- 首次运行------缺 token 这种环境问题 AI 无法预判
- 功能方向------工具做成什么样,是你说了算
哪些可以放手:
- 多文件实现------没有依赖的子模块让它并行写
- 格式化和样板代码
- 分页、API 细节------这类机械工作 AI 比人快且少出错
小结
这个 pr-stats 工具加起来不到 400 行 Go 代码,但完整走了一遍 Claude Code 的实战流:给上下文 → Plan → 并行实现 → 跑 → 修 → 迭代。
核心感受:别期待一遍过。AI 写代码快、但边界漏、环境盲。把心力省在机械实现上,省下来的时间用在审查和决策上------这才是正确的分工。
第 8 篇收官------避坑指南。把整个系列里踩过的坑、浪费过的时间、总结出的教训集中讲清楚。读完相当于省下几十个小时的试错成本。
标签 :Claude Code、AI编程、实战、自动化工具、AI Agent、开发工具