GitHub Actions 作业依赖 #

作业依赖是控制工作流执行顺序的核心机制。本节详细介绍如何配置和使用作业依赖。

依赖概述 #

什么是作业依赖? #

作业依赖定义了作业之间的执行顺序:

  • 被依赖的作业先执行
  • 依赖的作业等待前置作业完成
  • 可以设置多个依赖

依赖关系图 #

text
┌─────────┐
│  build  │
└────┬────┘
     │
     ├─────────────────┐
     │                 │
     ▼                 ▼
┌─────────┐     ┌─────────┐
│ test-1  │     │ test-2  │
└────┬────┘     └────┬────┘
     │                 │
     └────────┬────────┘
              │
              ▼
        ┌─────────┐
        │ deploy  │
        └─────────┘

基本依赖 #

单一依赖 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing..."

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."

多个依赖 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  test-unit:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Unit testing..."

  test-integration:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Integration testing..."

  test-e2e:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "E2E testing..."

  deploy:
    needs: [test-unit, test-integration, test-e2e]
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."

依赖状态 #

查看依赖状态 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Check dependency status
        run: |
          echo "Build result: ${{ needs.build.result }}"
          echo "Build output: ${{ needs.build.outputs.version }}"

状态值 #

状态 描述
success 成功完成
failure 执行失败
cancelled 被取消
skipped 被跳过

条件执行 #

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  notify-success:
    needs: build
    if: success()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Build succeeded"

  notify-failure:
    needs: build
    if: failure()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Build failed"

作业输出传递 #

定义输出 #

yaml
jobs:
  build:
    outputs:
      version: ${{ steps.version.outputs.value }}
      artifact: ${{ steps.artifact.outputs.path }}
    runs-on: ubuntu-latest
    steps:
      - id: version
        run: echo "value=1.0.0" >> $GITHUB_OUTPUT
      - id: artifact
        run: echo "path=dist/" >> $GITHUB_OUTPUT

使用输出 #

yaml
jobs:
  build:
    outputs:
      version: ${{ steps.version.outputs.value }}
    steps:
      - id: version
        run: echo "value=1.0.0" >> $GITHUB_OUTPUT

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Use build output
        run: |
          echo "Deploying version ${{ needs.build.outputs.version }}"

多作业输出 #

yaml
jobs:
  setup:
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: |
          echo 'matrix={"include":[{"node":"16"},{"node":"18"},{"node":"20"}]}' >> $GITHUB_OUTPUT

  test:
    needs: setup
    strategy:
      matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing Node ${{ matrix.node }}"

复杂依赖示例 #

CI/CD流水线 #

yaml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint

  type-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run type-check

  test-unit:
    needs: [lint, type-check]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:unit

  test-integration:
    needs: [lint, type-check]
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
        ports:
          - 5432:5432
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:integration

  test-e2e:
    needs: [lint, type-check]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:e2e

  build:
    needs: [test-unit, test-integration, test-e2e]
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.value }}
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run build
      - id: version
        run: echo "value=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

  deploy-staging:
    needs: build
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
      - run: ./deploy.sh staging

  deploy-production:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
      - run: ./deploy.sh production

  notify:
    needs: [deploy-staging, deploy-production]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - name: Notify on success
        if: success()
        run: echo "Deployment successful"
      - name: Notify on failure
        if: failure()
        run: echo "Deployment failed"

微服务构建 #

yaml
jobs:
  detect-changes:
    outputs:
      service-a: ${{ steps.filter.outputs.service-a }}
      service-b: ${{ steps.filter.outputs.service-b }}
      service-c: ${{ steps.filter.outputs.service-c }}
    steps:
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: |
            service-a:
              - 'services/a/**'
            service-b:
              - 'services/b/**'
            service-c:
              - 'services/c/**'

  build-service-a:
    needs: detect-changes
    if: needs.detect-changes.outputs.service-a == 'true'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building service A"

  build-service-b:
    needs: detect-changes
    if: needs.detect-changes.outputs.service-b == 'true'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building service B"

  build-service-c:
    needs: detect-changes
    if: needs.detect-changes.outputs.service-c == 'true'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building service C"

  deploy:
    needs: [build-service-a, build-service-b, build-service-c]
    if: always() && (needs.build-service-a.result == 'success' || needs.build-service-b.result == 'success' || needs.build-service-c.result == 'success')
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying changed services"

依赖图可视化 #

简单依赖 #

text
build → test → deploy

并行依赖 #

text
        ┌──→ test-unit ──┐
build ──┼──→ test-int ───┼──→ deploy
        └──→ test-e2e ───┘

复杂依赖 #

text
              ┌──→ lint ────────┐
              │                  │
              ├──→ type-check ───┤
              │                  │
setup ────────┼──→ test-unit ────┼──→ build ──→ deploy
              │                  │
              ├──→ test-int ─────┤
              │                  │
              └──→ test-e2e ─────┘

最佳实践 #

1. 合理设置依赖 #

yaml
# 并行执行独立任务
jobs:
  lint:
    runs-on: ubuntu-latest
  type-check:
    runs-on: ubuntu-latest
  test:
    runs-on: ubuntu-latest

  # 依赖多个任务
  build:
    needs: [lint, type-check, test]

2. 使用输出传递数据 #

yaml
jobs:
  build:
    outputs:
      version: ${{ steps.version.outputs.value }}

3. 条件执行 #

yaml
jobs:
  deploy:
    needs: build
    if: success() && github.ref == 'refs/heads/main'

4. 处理失败情况 #

yaml
jobs:
  cleanup:
    needs: [build, test, deploy]
    if: always()

5. 使用环境保护 #

yaml
jobs:
  deploy:
    needs: build
    environment: production

下一步学习 #

小结 #

  • 使用needs设置作业依赖
  • 支持单一和多个依赖
  • 可以访问依赖作业的状态和输出
  • 使用条件控制执行流程
  • 合理设置依赖优化执行效率
  • 使用环境保护敏感操作
最后更新:2026-03-28