Skip to content

GitHub action to create a reusable and potentially dynamic matrix for workflow jobs.

License

Notifications You must be signed in to change notification settings

druzsan/setup-matrix

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

📦 Setup matrix

⏱️ Quickstart 🔍 CI 🧪 Unit Test 🧪 Integration Test

GitHub action to create reusable dynamic job matrices for your workflows.

This action adresses a wide known problem of reusing the same job matrix multiple times or even generating a matrix on the fly.

The main goal of this action is to be as much compatible with built-in GitHub matrices as possible and thus allow you a smooth transition in your workflow.

All given examples can be found as GitHub workflows and respective runs.

⏱️ Quickstart

Modified matrix example.

jobs:
  # Setup matrix
  setup-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.setup-matrix.outputs.matrix }}
    steps:
      - id: setup-matrix
        uses: druzsan/setup-matrix@v2
        with:
          # Use | to preserve valid YAML syntax
          matrix: |
            fruit: [apple, pear]
            animal: [quick red fox, lazy dog]
            include:
              - color: green
              - color: pink
                animal: quick red fox
              - color: brown
                animal: cat
            exclude:
              - fruit: apple
                animal: lazy dog
  # Setup python and print version
  echo:
    needs: setup-matrix
    strategy:
      matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "fruit: ${{ matrix.fruit }}, animal: ${{ matrix.fruit }}, color: ${{ matrix.color }}"

Workflow runs.

For more examples, see advanced usage

📥 Inputs

Action has only one required input matrix, whose syntax is exactly the same as the built-in matrix provided as string.

Full YAML syntax is supported inside input, so you even can add inline comments which will be ignored during parsing.

Not only syntax validity, but also built-in matrix restrictions (e.g. empty resulting matrix) are checked. Error logs try to give as much infomation on problem as possible.

It is highly recommended to use | prefix for multi-line strings:

uses: druzsan/setup-matrix@v2
with:
  matrix: | # Setup matrix with OS and Python version
    os: [ubuntu-latest, windows-latest]
    python-version: [3.8, 3.10, 3.12]
    include:
      - os: windows-latest
        python-version: 3.8  # Only use Python 3.8 for MacOS
    exclude:
      - os: windows-latest
        python-version: 3.12  # Do not use Python 3.12 for Windows

Flow YAML syntax is also supported:

uses: druzsan/setup-matrix@v2
with:
  matrix: '{ os: [ubuntu-latest, windows-latest], python-version: [3.8, 3.10, 3.12] }'

📤 Outputs

Parsed matrix is printed inside the action step as a pretty formated YAML, so you can visually inspect it.

Parsed matrix is also set as MATRIX environment variable.

matrix

valid JSON matrix ready to be set as jobs.<job_id>.outputs used in jobs.<job_id>.strategy:

strategy:
  matrix: ${{ fromJson(needs.<job_id>.outputs.matrix) }}

💪 Advanced Usage

♻️ Reusable Matrix

Sometimes you need to run different jobs on the same set of configurations, e.g. check code formatting, code types and lint code.

Build matrix:

setup-matrix:
  runs-on: ubuntu-latest
  outputs:
    matrix: ${{ steps.setup-matrix.outputs.matrix }}
  steps:
    - id: setup-matrix
      uses: druzsan/setup-matrix@v2
      with:
        matrix: |
          os: [ubuntu-latest, windows-latest, macos-latest]
          python-version: [3.8, 3.10, 3.12]

Reuse matrix:

check-format:
  needs: setup-matrix
  strategy:
    matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - run: python -m pip install -IU pip setuptools wheel
    - run: pip install -IUr requirements.txt -r requirements-dev.txt
    - run: black --check .
typecheck:
  needs: setup-matrix
  strategy:
    matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - run: python -m pip install -IU pip setuptools wheel
    - run: pip install -IUr requirements.txt -r requirements-dev.txt
    - run: mypy main.py && mypy tests
lint:
  needs: setup-matrix
  strategy:
    matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - run: python -m pip install -IU pip setuptools wheel
    - run: pip install -IUr requirements.txt -r requirements-dev.txt
    - run: ruff check main.py tests

Full solution using the setup-matrix action and its runs.

Solution using the built-in matrix and its runs.

🌊 Dynamic Matrix

Sometimes you need to run a job on different sets of configurations, depending on branch, triggering event etc.

Build matrix:

setup-matrix:
  runs-on: ubuntu-latest
  outputs:
    matrix: ${{ steps.setup-matrix.outputs.matrix }}
  steps:
    # Setup matrix on a dev branch
    - if: startsWith(github.ref, 'refs/tags/')
      uses: druzsan/setup-matrix@v2
      with:
        matrix: |
          os: [ubuntu-latest, windows-latest, macos-latest]
          python-version: [3.8, 3.10, 3.12]
    # Setup matrix on the main branch
    - if: github.ref == 'refs/heads/main'
      uses: druzsan/setup-matrix@v2
      with:
        matrix: |
          os: [ubuntu-latest]
          python-version: [3.8, 3.10, 3.12]
          include:
            - os: windows-latest
              python-version: 3.8
            - os: macos-latest
              python-version: 3.8
    # Setup matrix on a tag
    - if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/')
      uses: druzsan/setup-matrix@v2
      with:
        matrix: |
          os: [ubuntu-latest]
          python-version: [3.8]
    # MATRIX environment variable is set by the last executed action
    - id: setup-matrix
      run: echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

Use dynamic matrix:

unit-test:
  needs: setup-matrix
  strategy:
    matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - run: python -m pip install -IU pip setuptools wheel
    - run: pip install -IUr requirements.txt -r requirements-dev.txt
    - run: python -m pytest

Full solution using the setup-matrix action and its runs.

Solution using the built-in matrix and its runs.

ℹ️ Limitations

Since the action uses Python and Dockerfile, is is mandatory to run it on an Ubuntu runner.

⚠️ Breaking Changes

Version 1 syntax is no longer supported. Update inputs when switching to version 2.