你的第十个仓库还在复制粘贴 CI 配置?这件事今天被可复用工作流彻底变了
你的团队有十个仓库,每个仓库的 CI 流程差不多:安装依赖、跑测试、构建镜像、推送到某个环境。区别只是 node-version 写 18 还是 20,镜像名换成当前仓库名。当你要改一套 npm ci 参数,或者加一个 CodeQL 扫描步骤,对不起——十个仓库各改一遍,然后祈祷没有哪个仓库漏改了。
GitHub Actions 可复用工作流(Reusable Workflows)就是来解决这个问题的。你把「跑测试」这件事写一次,放在 .github/workflows/test.yml 里,其他九个仓库只需要三行 YAML 就能调用,参数通过 with 传入,变更只改一个文件所有仓库同步生效。
怎么写
可复用工作流本质上就是一个普通的 workflow 文件,区别在于它的 trigger 不是 push 或 pull_request,而是 workflow_call。被调用方(called workflow)定义好输入参数(inputs)和密钥(secrets),调用方(caller workflow)只需要 uses 引用即可。
先看被调用方,.github/workflows/test.yml:
workflow_call 声明了这个文件可以被复用。inputs 定义了调用时可以传入的参数——node-version 是必须项,working-directory 有默认值所以可选。secrets 同理,NPM_TOKEN 不是必须项,所以用 required: false。
再看调用方,在任意一个业务仓库里:
三行 uses 加两行 with,这个仓库的测试流程就完整了。secrets: NPM_TOKEN 这行看似简单,但这里有个细节:可复用工作流不会自动继承调用方的 secrets,必须显式传递。secrets: inherit 是另一个选项,等同于把调用方所有 secrets 传进去,适合快速原型,但生产环境建议显式声明——你得知道你在传递什么。
跨仓库调用:.github 仓库模式
同一个仓库内引用用 uses: ./.github/workflows/test.yml。但如果你的团队有二十个仓库都需要跑同一套测试,最佳实践是建一个专门的 .github 仓库(比如 my-org/.github),把可复用工作流集中管理,二十个仓库通过路径引用:
引用外部仓库的可复用工作流时,强烈建议 pin 到完整版本号或 commit SHA,而不是 @main 或 @master。可复用工作流的调用方构建确定性依赖——你的 pipeline 安全依赖于被调用方不变。如果 @v2 指向的 tag 被 force-push 或者 main 分支被覆盖,你 pipeline 的行为也会跟着变。GitHub 在 2026 年已经明确建议所有 CI/CD 供应链使用 SHA pinning。
版本号策略参考:v2.1.0 tag → SHA 对应关系存在一个 changelog 文件里,每次升级走 PR review,这样调用方的升级是可预期的而不是静默的。
三个生产级实战模式
模式一:并发取消 + 复用工作流
往同一个分支频繁 push 时,旧 run 还在跑,新 run 又触发了——浪费 runner 时间。可复用工作流和并发控制天然配合:
取消的是调用方这条 workflow run,不是可复用工作流本身,所以可复用工作流的执行记录里不会有一堆被取消的孤岛 run。
模式二:复用工作流 + matrix 并行
可复用工作流和 matrix 是两个正交维度——可复用处理纵向逻辑复用(一次写、多次用),matrix 处理横向并行(一个 job 定义、多套配置同时跑)。两者完全可以组合:
test.yml 写一次,9 个 job(3 × 3)自动生成,每个跑不同 Node 版本加不同目录。不用复制粘贴九份 job 定义,改一行 matrix 配置九条并行就全变了。
模式三:部署环境和审批门禁
可复用工作流里的 job 可以声明 environment,从而触发 GitHub Environments 的保护规则——人工审批、等待计时器、环境分支限制都可以直接复用,不需要每个仓库单独配置:
调用方引用这个 job 时,production 环境的审批门禁自动生效——这是复用工作流一个容易被忽视的价值:安全策略的复用。审批流程只写一次,规则在所有调用方一致,不会出现 A 仓库配置了生产审批但 B 仓库忘了配的漏洞。
可复用工作流 vs 复合 Action
有人会问:Action 也能复用步骤,为什么要多一层可复用工作流?
关键区别:Action 是 step 级别的复用,工作流是 job 级别的复用。
Composite Action 写进 action.yml,在 workflow 里是一个 step,不能包含独立 job,不能声明独立的 runs-on。当你需要「checkout → setup → install → test → build → deploy」这一整套独立 job 时,Action 做不到——你只能写一个可复用工作流,每个 job 独立选 runner、独立声明 permissions。
实际经验法则:如果只是「checkout 加 setup 加 npm install」这个组合动作反复出现,做成 Composite Action;如果是一套完整的 CI/CD 流程(多个 job、有依赖关系、需要独立 runner),做成可复用工作流。
怎么起步
第一步,审计你手里复制粘贴最多的那个 workflow 文件。把 on: push 改成 on: workflow_call,把硬编码的参数提取成 inputs,把 secrets 声明成 secrets,把文件移到一个公共目录下。这大概需要 30 分钟。
第二步,给这个公共目录建一个独立 Git 仓库(或者用现有 .github 仓库),在另一个业务仓库里引用它。先跑通一个端到端验证。
第三步,把其他仓库里相同逻辑的 job 逐个替换成 uses:。每换一个仓库,跑一次全流程,确认行为一致。
这套模式在 monorepo 和多仓库场景都适用。迁移完成后你会发现:改一套 npm ci 参数只用改一个文件,CI 配置的一致性从靠人的纪律变成了靠架构的天然约束。
三句话总结:
- 可复用工作流把 CI 逻辑从「复制粘贴」变成「一次写、处处用」
- 跨仓库复用时 pin 到 SHA 版本,生产环境显式声明 secrets
- 和 matrix、并发取消、环境门禁组合,让 pipeline 管理从操作变成架构设计
评论区
登录后可评论。