skip to Main Content

The standard way of running a workflow on several operating systems is using a matrix:

jobs:
  package:
    strategy:
      matrix:
        os: [ubuntu, macos, windows]
    runs-on: ${{ matrix.os }}-latest

In some cases, it’s useful to run the workflow on only one of the operating systems, for example, when debugging or when only one of them changed and there’s no need to run the other two. How can only one of them be run?

One solution is to comment out the elements you don’t need, but this is a very local and fragile solution.
Another could be creating 4 different workflows (one for each system + one for all), but this is cumbersome and gets complicated when you have a chain of workflows such as build -> package -> deploy that now needs 4 variants each.

I tried using the choice input to be able to select the systems,

on:
  workflow_dispatch:
    inputs:
      os:
        type: choice
        options:
          - windows
          - macos
          - ubuntu
          - ubuntu, macos, windows
        required: true


jobs:
  package:
    strategy:
      matrix:
        os: "${{ github.event.inputs.os }}"
    runs-on: ${{ matrix.os }}-latest

which works for the single system choice, but not for the multiple one because it’s taken as a single string "ubuntu, macos, windows".

I also tried to use a boolean inputs to select any combination I need:

on:
  workflow_dispatch:
    inputs:
      ubuntu:
        required: true
        type: boolean
      macos:
        required: true
        type: boolean
      windows:
        required: true
        type: boolean

but I’m not sure how to combine them into a matrix. I could do

...
jobs:
  ubuntu:
    if:  ${{ inputs.ubuntu }} 
    runs-on: ubuntu-latest
    steps: ...
  macos:
    if:  ${{ inputs.macos}} 
    runs-on: macos-latest
    steps: ...
  windows:
    if:  ${{ inputs.windows}} 
    runs-on: windows-latest
    steps: ...

Is there a way I’m "supposed" to use to achieve this functionality? Consider also that these workflows can be reusable (run the build -> package -> deploy sequence on a single OS or all), so the OS inputs can be also received from calling workflows.

2

Answers


  1. Chosen as BEST ANSWER

    Based on Azeem's answer, I shortened the inputs and matrix handling to omit the "latest" suffix, and added it only in the runs-on key where it is strictly needed. This way ${{ matrix.os }} resolves to just the plain OS name (ubuntu), which can be used elsewhere.

    I also added the reusable workflow workflow_call inputs so the workflow can be called with the same type of input:

    name: package
    
    on:
      workflow_dispatch:
        inputs:
          os:
            description: "Operating System"
            required: true
            type: choice
            options:
              - '["ubuntu", "macos", "windows"]'
              - '["windows"]'
              - '["macos"]'
              - '["ubuntu"]'
      workflow_call:
        inputs:
          os:
            required: true
            type: string
    
    jobs:
      package:
        strategy:
          matrix:
            os: ${{ fromJson(inputs.os) }}
        runs-on: ${{ matrix.os }}-latest
        ...
    
    name: release
    
    on:
      workflow_dispatch:
        inputs:
          os:
            description: "Operating System"
            required: true
            type: choice
            options:
              - '["ubuntu", "macos", "windows"]'
              - '["windows"]'
              - '["macos"]'
              - '["ubuntu"]'
    
    jobs:
      package:
        uses: ./.github/workflows/package.yml
        with:
          os: ${{ inputs.os }} # pass the expected string format to `package`
      release:
        ...
    

  2. To make it work directly without the need of an intermediate job, you can provide options as JSON arrays and then use fromJson function to create matrix like this:

    name: os_matrix_from_inputs
    
    on:
      workflow_dispatch:
        inputs:
          os:
            description: Select OS
            type: choice
            options:
            - '["ubuntu-latest"]'
            - '["windows-latest"]'
            - '["macos-latest"]'
            - '["ubuntu-latest", "macos-latest", "windows-latest"]'
            default: '["ubuntu-latest"]'
            required: true
    
    jobs:
      ci:
        strategy:
          matrix:
            os: ${{ fromJson(inputs.os) }}
        runs-on: ${{ matrix.os }}
    
        steps:
        - name: Check
          run: echo '${{ matrix.os }}'
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search