Search code examples
githubgithub-actions

How can I configure a GitHub Actions strategy matrix to dynamically read a JSON list based on user input


How can I configure a GitHub Actions strategy matrix to dynamically retrieve values from a JSON list based on user input? Below is the workflow I'm using:

name: Matrix team test

on:
  workflow_dispatch:
    inputs:
      bosunEnvironment: # User Input Option - Will determine which bosun environment to build and deploy to.
        description: 'Bosun Environment'
        required: true
        default: 'dev'
        type: choice
        options:
          - 'dev'
          - 'stg'
          - 'prd'
      stsReplay:
        description: 'team to pick'
        required: true
        default: 'real-madrid'
        type: choice
        options:
          - 'manu'
          - 'chelsea'
          - 'real-madrid'
          - 'fc-barcelona'
          - 'bayern'
          - 'ac-milan'

env:
  REPLAY_MAP_JSON: |
    {
      "manu": ["casemiro","dalot","rashford"],
      "chelsea": ["sterling","james","silva"],
      "real-madrid": ["vini-jr","modric","kroos"],
      "bayern": ["sane","kane","alphonso"],
      "ac-milan": ["rafael-leao","giroud","pulisic"]
    }

jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: |
          input_replay="${{ inputs.stsReplay }}"
          echo "input_replay: $input_replay"
          values=$(jq -r ".\"${input_replay}\"[]" <<< "${REPLAY_MAP}")
          echo "values: $values"
          $values >> $GITHUB_OUTPUT
  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.job1.outputs.matrix) }}
    steps:
      - run: echo "Player ${{ matrix}}"

I need the strategy matrix to behave as follows:

  • If the workflow_dispatch input is set to 'real-madrid', the strategy matrix should iterate over the list of players in the JSON value, which in this case is ["vini-jr","modric","kroos"].

  • Similarly, if the workflow_dispatch input is set to 'bayern', the strategy matrix should iterate over the list of players in the JSON value, which in this case is ["sane","kane","alphonso"].

  • Attempting to utilize a shell script as depicted earlier, the fromJSON() function failed to parse the list accurately.

  • Even after returning the entire JSON with values=$(echo "$REPLAY_MAP" | jq -r '.["'"$input_replay"'"]') >> $GITHUB_OUTPUT, the strategy matrix still did not interpret the JSON correctly.


Solution

  • There are different issues in your workflow:

    1. You're not defining your output correctly on job1, it should be echo "output_name=$values" >> $GITHUB_OUTPUT

    2. Your parsing commands values=$(jq -r ".\"${input_replay}\"[]" <<< "${REPLAY_MAP}") doesn't seem to work as expected. There are different ways to resolve it, I will suggest one below (it might not be the best one).

    3. You are not using the matrix strategy correctly in your job2, it should be:

        strategy:
          matrix: 
            player: ${{fromJson(needs.job1.outputs.matrix)}}
    

    The following workflow configuration seems to work as expected:

    jobs:
      job1:
        runs-on: ubuntu-latest
        outputs:
          players: ${{ steps.set-matrix.outputs.values }}
        steps:
          - id: set-matrix
            run: |
              input_replay="real-madrid"
              echo "input_replay: $input_replay"
              values=$(echo "${REPLAY_MAP_JSON}" | jq -r --arg input_replay "$input_replay" '.[$input_replay] | map("\"\(.)\"") | join(", ")')
              echo "values:[$values]"
              echo "values=[$values]" >> $GITHUB_OUTPUT
      
      job2:
        needs: job1
        runs-on: ubuntu-latest
        strategy:
          matrix: 
            player: ${{fromJson(needs.job1.outputs.players)}}
        steps:
          - run: echo "Player ${{ matrix.player}}"