Chapter 10

高级模式:可复用工作流与 Monorepo

消除 YAML 重复,用可复用工作流统一团队标准,掌握 Monorepo 的智能触发策略

可复用工作流(Reusable Workflows)

什么是可复用工作流?

可复用工作流(workflow_call)允许你将一个 Workflow 作为另一个 Workflow 的 Job 调用,实现"CI/CD 模板"的概念。团队可以定义标准化的构建、测试、部署流程,所有项目复用同一套模板,修改模板即可统一升级所有项目。

定义可复用工作流

# .github/workflows/reusable-deploy.yml(这是被调用的模板)
name: 可复用部署工作流

on:
  workflow_call:           # 声明此工作流可被调用
    inputs:
      environment:
        required: true
        type: string
        description: '部署环境(staging/production)'
      image-tag:
        required: true
        type: string
      dry-run:
        required: false
        type: boolean
        default: false
    secrets:
      AWS_ROLE_ARN:
        required: true
    outputs:
      deploy-url:
        description: '部署后的访问 URL'
        value: ${{ jobs.deploy.outputs.url }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    outputs:
      url: ${{ steps.deploy.outputs.url }}

    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - id: deploy
        name: 执行部署
        run: |
          if [[ "${{ inputs.dry-run }}" == "true" ]]; then
            echo "DRY RUN: 将部署 ${{ inputs.image-tag }} 到 ${{ inputs.environment }}"
          else
            # 实际部署逻辑
            DEPLOY_URL="https://app-${{ inputs.environment }}.example.com"
            echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
          fi

调用可复用工作流

# 项目 A 的 deploy.yml
name: 项目A部署流水线

on:
  push:
    branches: [main]

jobs:
  # 先运行自己的测试
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  # 调用共享的部署工作流
  deploy-staging:
    needs: test
    uses: my-org/.github/.github/workflows/reusable-deploy.yml@main
    with:
      environment: staging
      image-tag: ${{ github.sha }}
    secrets:
      AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN_STAGING }}

  deploy-production:
    needs: deploy-staging
    uses: my-org/.github/.github/workflows/reusable-deploy.yml@main
    with:
      environment: production
      image-tag: ${{ github.sha }}
    secrets:
      AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN_PROD }}

Monorepo 策略

路径过滤:智能触发

Monorepo 中包含多个服务,如果每次任意变更都触发所有 CI,既浪费资源又降低效率。使用 paths 过滤和动态检测变更实现智能触发:

# 服务A 专属 CI(只有 services/api/ 变更时触发)
name: API Service CI

on:
  push:
    paths:
      - 'services/api/**'
      - 'packages/shared/**'      # 共享包变更也要触发
      - '.github/workflows/ci-api.yml'  # CI 配置本身变更

jobs:
  test-api:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd services/api && npm test

动态检测变更文件(高级)

name: Monorepo Smart CI

on: [push, pull_request]

jobs:
  # 第一步:检测哪些服务有变更
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      api-changed: ${{ steps.filter.outputs.api }}
      web-changed: ${{ steps.filter.outputs.web }}
      mobile-changed: ${{ steps.filter.outputs.mobile }}
    steps:
      - uses: actions/checkout@v4
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: |
            api:
              - 'services/api/**'
              - 'packages/shared/**'
            web:
              - 'apps/web/**'
              - 'packages/ui/**'
            mobile:
              - 'apps/mobile/**'

  # 根据检测结果,条件性运行各服务 CI
  test-api:
    needs: detect-changes
    if: needs.detect-changes.outputs.api-changed == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd services/api && npm test

  test-web:
    needs: detect-changes
    if: needs.detect-changes.outputs.web-changed == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd apps/web && npm test

部署环境保护规则

为生产部署设置审批流

在 GitHub 仓库设置 → Environments 中配置 production 环境,添加保护规则:指定必须由哪些人员审批后才能部署。

jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production      # 引用设置了保护规则的环境
      url: https://app.example.com

    # 必须通过 production 环境的审批才会执行此 Job
    steps:
      - name: 执行生产部署
        run: ./deploy.sh production

  # 部署后烟雾测试
  smoke-test:
    needs: deploy-production
    runs-on: ubuntu-latest
    steps:
      - name: 健康检查
        run: |
          for i in {1..5}; do
            STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://app.example.com/health)
            if [[ "$STATUS" == "200" ]]; then
              echo "✅ 服务健康,HTTP $STATUS"
              exit 0
            fi
            echo "等待中... ($i/5)"
            sleep 30
          done
          echo "❌ 健康检查失败"
          exit 1
推荐 Monorepo 工具链

总结:GitHub Actions 最佳实践清单

安全
声明最小权限;使用 OIDC 替代长期密钥;固定 Action 版本到 commit SHA;定期运行 CodeQL 和 Trivy 扫描。
效率
使用 setup-* Action 的内置缓存;合理配置 paths 过滤避免不必要触发;并行运行独立 Job;使用 fail-fast: false 收集全量测试结果。
可维护性
提取共用步骤为 Composite Action;用可复用工作流统一团队标准;Workflow 文件加注释说明;配合 Dependabot 自动更新 Action 版本。
可靠性
为生产部署配置环境保护规则和审批流;部署后运行烟雾测试;失败时自动回滚;配置通知(Slack/钉钉)及时告警。

本章小结

本章核心要点