在大型组织和 Monorepo 项目中,CI/CD 的 DRY(Don’t Repeat Yourself)原则至关重要。GitHub Actions 提供可复用工作流(Reusable Workflows)和 Composite Actions,让组织级别的工作流标准化成为可能。本文覆盖从可复用设计到 Monorepo CI 的完整实践。
一、可复用工作流(Reusable Workflows)
1.1 为什么需要可复用工作流?
多个项目的重复 CI 配置:
- Project A: install → lint → test → build
- Project B: install → lint → test → build
- Project C: install → lint → test → build
→ 提取到 shared-workflows → 所有项目调用同一模板
优势:集中维护、统一标准、减少重复、强制合规。
1.2 定义可复用工作流
# .github/workflows/reusable-test.yml
name: Reusable Node.js Test
on:
workflow_call:
inputs:
node-version:
description: 'Node.js version'
type: string
required: true
default: '20'
run-e2e:
description: 'Run E2E tests'
type: boolean
required: false
default: false
working-directory:
description: 'Working directory'
type: string
required: false
default: '.'
secrets:
codecov-token:
description: 'Codecov upload token'
required: false
outputs:
test-passed:
description: 'Whether tests passed'
value: ${{ jobs.test.outputs.result }}
jobs:
test:
runs-on: ubuntu-latest
outputs:
result: ${{ steps.test.outputs.result }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
working-directory: ${{ inputs.working-directory }}
- name: Run Lint
run: npm run lint
working-directory: ${{ inputs.working-directory }}
- name: Run Type Check
run: npm run type-check
working-directory: ${{ inputs.working-directory }}
- name: Run Tests
id: test
run: |
npm test -- --coverage
echo "result=success" >> $GITHUB_OUTPUT
working-directory: ${{ inputs.working-directory }}
- name: Upload Coverage
if: inputs.codecov-token != ''
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.codecov-token }}
files: ${{ inputs.working-directory }}/coverage/lcov.info
- name: Run E2E
if: inputs.run-e2e
run: npm run test:e2e
working-directory: ${{ inputs.working-directory }}
1.3 调用可复用工作流
# .github/workflows/main.yml
name: CI
on: [push, pull_request]
jobs:
call-test:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
run-e2e: true
secrets:
codecov-token: ${{ secrets.CODECOV_TOKEN }}
1.4 跨仓库调用
jobs:
call-shared:
uses: my-org/shared-workflows/.github/workflows/test.yml@main
with:
node-version: '20'
secrets:
inherit # 继承调用仓库的 secrets
二、Monorepo CI 策略
2.1 pnpm Workspace + Turborepo
name: Monorepo CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
setup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Build & Test affected
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
run: pnpm turbo run lint type-check test build --filter=[origin/main...HEAD]
- name: Build all (main branch)
if: github.ref == 'refs/heads/main'
run: pnpm turbo run build
2.2 基于路径的筛选
on:
push:
paths:
- 'apps/web/**'
- 'packages/ui/**'
- 'package.json'
- 'pnpm-lock.yaml'
- '.github/workflows/web.yml'
三、Composite Action 组合
# .github/actions/setup/action.yml
name: 'Setup Node + pnpm + Cache'
description: 'Sets up Node.js with pnpm and caching'
inputs:
node-version:
description: 'Node.js version'
required: true
default: '20'
runs:
using: "composite"
steps:
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
shell: bash
四、发布自动化
4.1 Changesets 自动版本管理
name: Release
on:
push:
branches: [main]
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- name: Create Release PR or Publish
uses: changesets/action@v1
with:
version: pnpm changeset version
publish: pnpm changeset publish
commit: 'chore(release): version packages'
title: 'chore(release): version packages'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
五、性能优化矩阵
| 优化手段 | 效果 | 适用 |
|---|---|---|
cache: 'npm' | -30~60s | 通用 |
pnpm store 缓存 | -40% | pnpm 项目 |
turbo run --filter | 只构建变更 | Monorepo |
paths 过滤 | 避免无意义触发 | 大仓库 |
cancel-in-progress | 节省并发资源 | 快速迭代 |
相关阅读
- GitHub Actions 详解 — 核心概念与语法
- GitHub Actions Node.js CI — 测试流水线
- GitHub Actions Docker CI/CD — 容器化构建
- GitHub Actions 安全 — 权限与审计
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。
「saas」更多文章
自定义域名接入 Cloudflare:CDN 加速与缓存规则配置实战
手把手讲解自定义域名接入 Cloudflare CDN 的完整流程:NS 接管、SSL/TLS 模式选择、橙云代理与灰云 DNS 的区别,并用 2024 年后的新 Cache Rules 引擎实战配置静态资源长缓存、HTML 不缓存、后台 Bypass,让边缘缓存命中率最大化。
Hugo 部署到 Cloudflare Pages 实战:从 Git 推送到全球边缘上线
详解 Cloudflare Pages 部署 Hugo 静态站的完整流程,涵盖框架预设、HUGO_VERSION 环境变量固定、构建命令、自定义域名、分支预览、_headers 缓存安全头配置及常见构建失败排查,一次推送即可全球边缘上线。
Cloudflare Workers 入门实战:在边缘运行你的第一行代码
一份面向初学者的 cloudflare workers 教程,从 V8 Isolate 运行时模型讲起,手把手演示 wrangler 初始化、路由分发、KV 存储、Cache API 缓存响应与环境变量配置,帮你在 30 分钟内部署第一个生产可用的边缘 Serverless 应用。