GitHub Actions 矩阵构建

FreeGuideOnline 最新 2026-07-12

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


上面的配置会产生 **3(操作系统)× 3(Node.js 版本)= 9** 个并行作业。每个作业都可以通过 `${{ matrix.os }}` 和 `${{ matrix.node-version }}` 访问当前组合的具体值。

### 变量命名与引用

矩阵中的变量名可以自定义,例如 `python-version`、`browser` 等。在作业的其他部分(如 `runs-on`、`steps`、`env`)都可以通过上下文 `${{ matrix.<variable> }}` 来引用。注意,变量名只能包含字母、数字、`-` 和 `_`,且不能以 `github` 开头。

## 扩展矩阵功能

除了直接生成笛卡尔积,GitHub Actions 还提供了更精细的控制选项。

### 使用 `include` 添加特定组合

有时你需要添加一些不便于用乘积表达的组合,或者为某些组合附加额外配置。`include` 允许你向矩阵中手动追加作业,并且可以引入**不属于原始矩阵的新变量**。

```yaml
strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node-version: [18]
    include:
      - os: ubuntu-latest
        node-version: 16
        experimental: true
      - os: macos-latest
        node-version: 20
        experimental: false

上面的配置会生成以下作业:

  • (ubuntu-latest, 18) -- 来自原有乘积
  • (windows-latest, 18) -- 来自原有乘积
  • (ubuntu-latest, 16) -- 由 include 追加,并带有一个额外的 experimental 变量
  • (macos-latest, 20) -- 由 include 追加

你可以在后续步骤中通过 ${{ matrix.experimental }} 访问这个额外变量(在未定义该变量的作业中,此值为空)。

使用 exclude 移除不需要的组合

如果某些组合没有意义或不需要测试,可以用 exclude 从矩阵中删除。

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    browser: [chrome, firefox, edge]
    exclude:
      - os: windows-latest
        browser: firefox
      - os: ubuntu-latest
        browser: edge

原先生成 2 × 3 = 6 个组合,排除后只剩下 4 个作业。

控制并行与失败行为

你可以在 strategy 下设置更多属性来控制整个矩阵作业组的行为。

  • max-parallel:限制同时运行的作业数量。例如,当你的账户并发作业数有限,或想避免对目标服务的瞬间压力时,可以设置 max-parallel: 2
  • fail-fast:默认值为 true。一旦任何一个矩阵作业失败,GitHub 会取消所有其他仍在运行或排队的作业。如果你想即使有作业失败也让其他作业继续跑完(以收集完整的失败信息),可以设置为 false
strategy:
  fail-fast: false
  max-parallel: 4
  matrix:
    ...

实战示例:多平台多语言测试

下面的例子展示了一个实际项目中常见的场景:一个 Python 库需要在不同操作系统和 Python 版本下运行测试,同时使用 include 添加一个特殊的“最新开发环境”组合,并用 exclude 排除不必要的旧版本 Python 在 Windows 上的测试。

name: CI

on: [push, pull_request]

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ["3.8", "3.9", "3.10", "3.11"]
        exclude:
          # 不在 Windows 上测试 Python 3.8
          - os: windows-latest
            python-version: "3.8"
        include:
          # 额外加入一个 ubuntu 下的 Python 3.12-dev 环境
          - os: ubuntu-latest
            python-version: "3.12-dev"
            allow-failure: true

    runs-on: ${{ matrix.os }}
    continue-on-error: ${{ matrix.allow-failure == true }}
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pip install -r requirements-dev.txt
      - run: pytest

这里用到了 continue-on-error 上下文,依赖 include 中额外定义的 allow-failure 变量,使得实验性 Python 版本的失败不会标记整个工作流为失败。

动态矩阵与条件矩阵

有时候,你需要根据分支、标签或其他上下文动态生成矩阵变量。虽然标准 YAML 矩阵是静态的,但你可以通过 fromJSON() 函数结合前序步骤来动态定义矩阵。

一种常见模式是使用一个输出 JSON 的步骤,再通过作业输出传递给下游的矩阵作业。

jobs:
  prepare-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: |
          if [ "${{ github.ref }}" = "refs/heads/main" ]; then
            echo '{"node": [16, 18, 20]}' > matrix.json
          else
            echo '{"node": [20]}' > matrix.json
          fi
          echo "matrix=$(cat matrix.json)" >> $GITHUB_OUTPUT          

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