Matrix

Contents

Matrix#

Overview

Teaching: 5 min | Exercises: 10 min

Questions

  • How can we make job templates?

Objectives

  • Don’t Repeat Yourself (DRY)

  • Use a single job for multiple jobs

Matrix#

From the previous lesson, we tried to build the code against two different ROOT images by adding an extra job:

jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
      - run: echo hello world

  build_skim:
    runs-on: ubuntu-latest
    container: rootproject/root:6.32.04-ubuntu24.04
    steps:
      - name: checkout repository
        uses: actions/checkout@v6
      - name: build
        run: |
          COMPILER=$(root-config --cxx)
          FLAGS=$(root-config --cflags --libs)
          $COMPILER -g -O3 -Wall -Wextra -Wpedantic -o skim skim.cxx $FLAGS

  build_skim_latest:
    runs-on: ubuntu-latest
    container: rootproject/root:latest
    steps:
      - name: checkout repository
        uses: actions/checkout@v6
      - name: latest
        run: |
          COMPILER=$(root-config --cxx)
          FLAGS=$(root-config --cflags --libs)
          $COMPILER -g -O3 -Wall -Wextra -Wpedantic -o skim skim.cxx $FLAGS

We could do better using matrix. The latter allows us to test the code against a combination of versions in a single job.

name: example
on: push
jobs: 
  build_skim:
    runs-on: ubuntu-latest
    container: rootproject/root:${{ matrix.version }}
    strategy:
      matrix:
        version: [6.32.04-ubuntu24.04, latest]
    steps:
      - name: checkout repository
        uses: actions/checkout@v6

      - name: build
        run: |
          COMPILER=$(root-config --cxx)
          FLAGS=$(root-config --cflags --libs)
          $COMPILER -g -O3 -Wall -Wextra -Wpedantic -o skim skim.cxx $FLAGS

More details on matrix: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstrategymatrix.

Parsing numbers in YAML

Beware of one YAML pitfall when listing versions in a matrix: YAML parses unquoted numbers, and a number with a trailing zero like 3.10 is read as the float 3.1 (the trailing zero is dropped). A matrix like version: [3.9, 3.10, 3.11] would therefore silently run on 3.9, 3.1, and 3.11. This bit many projects when Python 3.10 was released — their CI matrices requested Python 3.1 instead. Avoid it by always quoting version numbers as strings: version: ['3.9', '3.10', '3.11'].

We can push the changes to GitHub and see how it will look like.

git add .github/workflows/main.yml
git commit -m "add multi jobs"
git push -u origin feature/add-actions

While the jobs are running, let’s imagine we don’t want our CI/CD to crash if that happens. We have to add continue-on-error: true to a job

runs-on: ubuntu-latest
continue-on-error: true

For the matrix case, GitHub Actions cancels all in-progress and queued jobs in the matrix if any matrix job fails (the rest of the workflow is unaffected). This can be prevented by using the fail-fast: false key:value.

strategy:
  fail-fast: false

More details: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idcontinue-on-error.

Allow a specific matrix job to fail

But what if we want to only allow the job with version set to latest to fail without failing the workflow run?

Look how much cleaner you’ve made the code. You should now see that it’s pretty easy to start adding more build jobs for other images in a relatively clean way, as you’ve now abstracted the actual building from the definitions.

Key Points

  • Using matrix allows to test the code against a combination of versions.