用 GitHub Actions 实现 Issue 自动化处理的实战经验
为什么我要折腾 Issue 自动化
最近接手了一个开源项目,Issue 区天天被各种“怎么用”“能不能加个功能”刷屏,看得我头大。手动打标签、关重复 issue、催 PR 更新,这些活儿干多了真上头。于是我就琢磨:能不能让机器人帮我干点脏活?
市面上能搞 Issue 自动化的方案其实不少,主流就三种:GitHub Actions + 自定义脚本、Probot(官方推荐的 JS 框架)、还有第三方服务比如 Linear 或 ZenHub 的集成。我挨个试了一遍,踩了不少坑,今天就唠唠哪个更值得用。
谁更灵活?谁更省事?
先说结论:小团队或个人项目,我首选 GitHub Actions;要搞复杂逻辑或者长期维护,Probot 更稳。至于第三方服务,除非公司已经买了,否则我不碰——绑定太深,迁移成本高。
GitHub Actions 的好处是不用额外部署服务,直接写 YAML 配置就行。比如自动给新 issue 打个 needs-triage 标签:
name: Auto-label new issues
on:
issues:
types: [opened]
jobs:
label:
runs-on: ubuntu-latest
steps:
- name: Add label
run: |
gh issue edit "$NUMBER" --add-label "needs-triage"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NUMBER: ${{ github.event.issue.number }}
这段代码跑起来基本没问题,但注意:gh CLI 工具默认没装,得自己加一步 uses: actions/setup-node@v3 或者直接用 curl 调 API。我第一次写的时候就忘了这茬,CI 跑失败三次才反应过来。
而 Probot 就专业多了。它本质是个 Node.js 应用,监听 GitHub Webhook,事件来了直接回调函数处理。比如同样打标签,代码是这样的:
module.exports = (app) => {
app.on('issues.opened', async (context) => {
const issue = context.payload.issue;
await context.octokit.issues.addLabels({
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
issue_number: issue.number,
labels: ['needs-triage']
});
});
};
看起来代码量差不多?但 Probot 的优势在于状态管理和错误重试。Actions 里如果 API 调用失败,整个 job 就挂了,你得自己写 retry 逻辑;Probot 内置了重试机制,还能把失败记录存数据库(如果你配了的话)。而且 Probot 支持本地调试,npm start 起个服务,用 smee.io 转发 webhook,比在 Actions 里反复 push 测试快多了。
踩坑提醒:这三点一定注意
第一,权限问题。Actions 默认用 GITHUB_TOKEN,但这个 token 不能触发其他 workflow!什么意思?比如你有个 action 是“当 issue 打上 bug 标签时,自动创建一个 PR”,结果你会发现 PR 根本不会触发 CI。解决方案是换 Personal Access Token(PAT),但 PAT 又有安全风险——别把 repo 权限开太大。
第二,Probot 的部署门槛。虽然代码简单,但你得有个服务器跑 Node 服务,还得配 HTTPS(GitHub 要求 webhook 必须是 https)。我一开始图省事用 Vercel,结果发现 Vercel 的 serverless 函数超时时间只有 10 秒,处理大批量 issue 时经常 timeout。后来换成 Railway 才稳住。
第三,第三方服务的“黑盒”问题。像 Linear 这种,表面看配置简单,拖拽几下就行。但一旦出问题,你根本不知道是它内部逻辑错了还是 GitHub API 返回异常。有次 Linear 把我们所有 issue 的 assignee 全清空了,客服查了三天才说是他们缓存 bug。这种事在自研方案里几乎不可能发生——代码是你写的,锅也是你背,但至少能快速修。
我的选型逻辑
现在我手上有三个项目,自动化方案各不相同:
- 个人玩具项目:直接上 GitHub Actions。代码少,改起来快,反正挂了也没人骂我。
- 团队核心开源库:Probot + Railway 部署。需要稳定性和可维护性,多花点时间搭环境值得。
- 公司内部项目:Linear。因为公司已经买了全家桶,和 Jira 同步方便,省去对接成本。
特别提一句:如果你只是想做点简单的事,比如自动关 30 天没回复的 issue,其实 GitHub 官方就有现成 action 叫 actions/stale。别自己造轮子,我见过有人硬写了个 Python 脚本跑 cron job,结果时区搞错,半夜狂关 issue,被 contributor 喷到删 repo……
再给个真实案例:之前有个需求是“当 PR 关联的 issue 被关闭时,自动在 PR 评论里 @ 提交者”。用 Actions 实现要调两次 API(先查 issue 状态,再发评论),YAML 写得又臭又长;用 Probot 就一行事件监听:pull_request.closed + 查关联 issue。最后我果断切到 Probot,代码从 50 行降到 15 行,还少了两个 bug。
核心代码就这几行
很多人觉得 Issue 自动化很玄乎,其实核心逻辑就三步:
- 监听事件(issue opened / labeled / closed)
- 调 GitHub API 拿数据
- 根据条件执行操作(打标签 / 评论 / 关闭)
以“自动回复模板问题”为例,用户提 issue 时如果标题带 [Question],机器人就回复使用文档链接。Probot 版本:
app.on('issues.opened', async (context) => {
const { title, number } = context.payload.issue;
if (title.includes('[Question]')) {
await context.octokit.issues.createComment({
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
issue_number: number,
body: 请先查阅文档:https://jztheme.com/docsn如有疑问再补充细节。
});
}
});
Actions 版本就得用 curl 拼 JSON:
- name: Comment on question issues
if: contains(github.event.issue.title, '[Question]')
run: |
curl -L
-X POST
-H "Accept: application/vnd.github+json"
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"
-H "X-GitHub-Api-Version: 2022-11-28"
https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments
-d '{"body":"请先查阅文档:https://jztheme.com/docsn如有疑问再补充细节。"}'
对比一下,Probot 的可读性和可维护性明显高一截。而且 Actions 里字符串拼接容易出错——换行符 n 得写成 \n,引号要转义,烦死了。
最后说两句
Issue 自动化不是银弹,搞不好反而增加维护负担。我的建议是:先手动跑两周,记下重复操作,再决定要不要自动化。有些场景其实加个 issue template 就能解决 80% 问题,别一上来就写代码。
以上是我踩坑后的总结,目前主力用 Probot,但小项目还是偷懒用 Actions。有更优的实现方式欢迎评论区交流——比如有没有人试过 Deno 写 webhook handler?听说冷启动更快……

暂无评论