0

GitHub Actions let us define matrices to launch several variations of a single job. For instance for starting a job on two operating systems:

name: Build
on:
  push
    branches: [ main ]
jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - (…)

GitHub Actions also let us use a Docker container on Linux:

name: Build
on:
  push
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    container: my-docker/container:0.1.0
    steps:
      - (…)

Is it possible to use both at the same time: running a job on several operating systems using matrices, and using a Docker container specifically for Linux? Something among the lines of (this code is invalid):

name: Build
on:
  push
    branches: [ main ]
jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    container:
      if: matrix.os == 'ubuntu-latest'
      image: my-docker/container:0.1.0
    steps:
      - (…)

This code is not correct because container cannot have a if keyword. If I remove the if, the code is correct but the job will fail on macOS runners (which cannot run Docker). How do I enable container for Linux and disable it for everything else? I found no information at all about this use case in the documentation.

Jim
  • 416
  • 2
  • 4
  • 16
  • Does this answer your question? [Paired values in github actions matrix](https://stackoverflow.com/questions/66025220/paired-values-in-github-actions-matrix) – jonrsharpe Aug 17 '23 at 07:57
  • @jonrsharpe I am afraid no, this does not explain how I can use the `container` directive only for Linux. For example a macOS runner will see this directive and fail while trying to run a Docker command. – Jim Aug 17 '23 at 08:03
  • https://stackoverflow.com/a/73953210/12555857 – rkochar Aug 17 '23 at 08:13
  • @rkochar I do not understand how this can solve the problem, can you elaborate? – Jim Aug 17 '23 at 16:11

1 Answers1

1

I think you could do something like this:

name: Build
on:
  push:
    branches: [ main ]
env:
  WITH_IMAGE: '{"image": "my-docker/container:0.1.0"}'
  NO_IMAGE: '{"image": null}'
jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        container: [WITH_IMAGE, NO_IMAGE]
        exclude:
          - os: ubuntu-latest
            container: NO_IMAGE
          - os: macos-latest
            container: WITH_IMAGE
    runs-on: ${{ matrix.os }}
    container: ${{ fromJSON(env[matrix.container]) }}
    steps:
      - (…)

I haven't tested this, so it may need some tweaks, but hopefully it conveys the gist of the solution. This is based on this GitHub documentation and a similar issue I encountered recently: Conditional use of container depending on the group it runs-on for GitHub Actions

Essentially, it uses exclusions so you only get the combinations you want, then passes a null image to container when you don't want to use a container.

Shawn
  • 8,374
  • 5
  • 37
  • 60
  • The key point in this answer is that it is possible to pass `null` as an image to `container` which effectively disables Docker when needed. Then the strategy for passing a dynamic value to `container` can differ: it can be as @Shawn described here, or using [paired values](https://stackoverflow.com/a/68940067) or just using something like: `container: ${{ matrix.os == 'ubuntu-latest' && 'my-docker/container:0.1.0' || null }}` (refer to [Expressions](https://docs.github.com/en/actions/learn-github-actions/expressions#example)). Also note that while passsing `null` works, it seems undocumented. – Jim Aug 22 '23 at 07:29