GitHub Actions 矩阵构建 #

矩阵构建允许你使用不同的配置并行运行作业,非常适合多版本、多平台测试。本节详细介绍矩阵构建的配置和使用。

矩阵概述 #

什么是矩阵构建? #

矩阵构建是一种策略,可以:

  • 使用多个变量组合
  • 并行执行多个作业
  • 测试多版本、多平台
  • 减少总体执行时间

基本概念 #

yaml
strategy:
  matrix:
    node: [16, 18, 20]    # 变量1
    os: [ubuntu-latest]   # 变量2

这会生成 3 × 1 = 3 个作业。

基本矩阵 #

单一变量 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: node --version

多变量组合 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: node --version

这会生成 3 × 3 = 9 个作业。

使用矩阵变量 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - name: Display matrix info
        run: |
          echo "Node version: ${{ matrix.node }}"
          echo "OS: ${{ matrix.os }}"

include配置 #

添加额外配置 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest]
        include:
          - node: 20
            os: windows-latest
            experimental: true
          - node: 20
            os: macos-latest
            coverage: true
    runs-on: ${{ matrix.os }}
    steps:
      - name: Check experimental
        if: matrix.experimental
        run: echo "Experimental build"
      - name: Check coverage
        if: matrix.coverage
        run: npm run coverage

完全自定义矩阵 #

yaml
jobs:
  test:
    strategy:
      matrix:
        include:
          - node: 16
            os: ubuntu-latest
            env: production
          - node: 18
            os: ubuntu-latest
            env: production
          - node: 20
            os: ubuntu-latest
            env: production
          - node: 20
            os: windows-latest
            env: production
          - node: 20
            os: macos-latest
            env: production
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: echo "Environment: ${{ matrix.env }}"

exclude配置 #

排除特定组合 #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest, windows-latest]
        exclude:
          - node: 16
            os: windows-latest
          - node: 18
            os: windows-latest
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

策略选项 #

fail-fast #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
      fail-fast: true  # 一个失败,取消其他作业
yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
      fail-fast: false  # 一个失败,继续执行其他作业

max-parallel #

yaml
jobs:
  test:
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest, windows-latest, macos-latest]
      max-parallel: 4  # 最多并行4个作业

实际应用示例 #

多语言版本测试 #

yaml
jobs:
  test:
    strategy:
      matrix:
        include:
          - language: node
            version: 16
          - language: node
            version: 18
          - language: node
            version: 20
          - language: python
            version: '3.9'
          - language: python
            version: '3.10'
          - language: python
            version: '3.11'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        if: matrix.language == 'node'
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.version }}
      
      - name: Setup Python
        if: matrix.language == 'python'
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.version }}
      
      - name: Test
        run: |
          if [ "${{ matrix.language }}" == "node" ]; then
            npm test
          else
            pytest
          fi

多浏览器测试 #

yaml
jobs:
  test:
    strategy:
      matrix:
        browser: [chrome, firefox, safari]
        os: [ubuntu-latest, macos-latest]
        exclude:
          - browser: safari
            os: ubuntu-latest
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: npm run test:${{ matrix.browser }}

多数据库测试 #

yaml
jobs:
  test:
    strategy:
      matrix:
        database:
          - type: postgres
            version: '14'
            port: 5432
          - type: postgres
            version: '15'
            port: 5432
          - type: mysql
            version: '8.0'
            port: 3306
    runs-on: ubuntu-latest
    services:
      db:
        image: ${{ matrix.database.type }}:${{ matrix.database.version }}
        ports:
          - ${{ matrix.database.port }}:${{ matrix.database.port }}
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: npm test
        env:
          DB_TYPE: ${{ matrix.database.type }}
          DB_PORT: ${{ matrix.database.port }}

多环境部署 #

yaml
jobs:
  deploy:
    strategy:
      matrix:
        environment:
          - name: staging
            url: staging.example.com
            replicas: 2
          - name: production
            url: example.com
            replicas: 5
    runs-on: ubuntu-latest
    environment: ${{ matrix.environment.name }}
    steps:
      - name: Deploy
        run: |
          echo "Deploying to ${{ matrix.environment.name }}"
          echo "URL: ${{ matrix.environment.url }}"
          echo "Replicas: ${{ matrix.environment.replicas }}"

动态矩阵 #

从文件生成矩阵 #

yaml
jobs:
  setup:
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - uses: actions/checkout@v4
      - id: set-matrix
        run: |
          echo "matrix=$(cat matrix.json | jq -c .)" >> $GITHUB_OUTPUT

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

根据条件生成矩阵 #

yaml
jobs:
  setup:
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: |
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            echo 'matrix={"include":[{"node":"16"},{"node":"18"},{"node":"20"}]}' >> $GITHUB_OUTPUT
          else
            echo 'matrix={"include":[{"node":"20"}]}' >> $GITHUB_OUTPUT
          fi

  test:
    needs: setup
    strategy:
      matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

矩阵可视化 #

3x3矩阵 #

text
           ubuntu-latest    windows-latest    macos-latest
Node 16    [job 1]          [job 2]           [job 3]
Node 18    [job 4]          [job 5]           [job 6]
Node 20    [job 7]          [job 8]           [job 9]

排除后的矩阵 #

text
           ubuntu-latest    windows-latest    macos-latest
Node 16    [job 1]          [excluded]        [job 3]
Node 18    [job 4]          [excluded]        [job 6]
Node 20    [job 7]          [job 8]           [job 9]

最佳实践 #

1. 合理设置矩阵大小 #

yaml
# 推荐:关键版本
matrix:
  node: [18, 20]

# 不推荐:过多版本
matrix:
  node: [14, 15, 16, 17, 18, 19, 20]

2. 使用fail-fast控制 #

yaml
# CI中使用fail-fast: true
strategy:
  fail-fast: true

# 实验性测试中使用fail-fast: false
strategy:
  fail-fast: false

3. 标记实验性配置 #

yaml
matrix:
  include:
    - node: 20
      os: ubuntu-latest
      experimental: false
    - node: 21
      os: ubuntu-latest
      experimental: true

4. 使用max-parallel控制资源 #

yaml
strategy:
  max-parallel: 4

5. 条件执行特定配置 #

yaml
steps:
  - name: Coverage report
    if: matrix.node == '20' && matrix.os == 'ubuntu-latest'
    run: npm run coverage

常见问题 #

Q: 矩阵作业数量有限制吗? #

有。默认最多256个作业。

Q: 如何调试特定矩阵配置? #

使用条件运行特定配置:

yaml
steps:
  - name: Debug step
    if: matrix.node == '20' && matrix.os == 'ubuntu-latest'
    run: echo "Debug info"

Q: 如何跳过失败的矩阵作业? #

yaml
steps:
  - name: Might fail
    run: exit 1
    continue-on-error: ${{ matrix.experimental == true }}

下一步学习 #

小结 #

  • 矩阵构建支持多配置并行执行
  • 使用include添加额外配置
  • 使用exclude排除特定组合
  • fail-fast控制失败处理
  • max-parallel控制并行数量
  • 可以动态生成矩阵
  • 合理设置矩阵大小优化资源使用
最后更新:2026-03-28