Search code examples
jsongithub-actions

Get array object from JSON and loop through list


I need to use a GitHub Actions workflow that will perform an API call to get a list of IDs, then loop through the list of IDs and perform an API POST using each of these.

The problem I'm having is that the API returns multiple array objects and I am not able to access just the array object.

The "json-project" in Job 1 (define-matrix) is an example of what is being returned from the first API call.

---
name: Test Loop
on:
  push:
    branches: [development]
    
jobs:
  # Job 1: Collect data
  define-matrix:
    runs-on: ubuntu-latest

    outputs:
      json-project: ${{ steps.project-step.outputs.json-project }}

    steps:
      - name: Define Project String
        id: project-step
        run: |
          echo "json-project={\"count\":2,\"include\":[{\"project\":\"1\",\"config\":\"Debug\"},{\"project\":\"2\",\"config\":\"Release\"}]}" >> "$GITHUB_OUTPUT"
        

  # Job 2: Print the output of the "define-matrix" job
  print-output:
    runs-on: ubuntu-latest
    needs: define-matrix
      
    steps:
      - name: Print project-json variable
        id: print-stuff
        run: |
          echo ${{ toJson(needs.define-matrix.outputs.json-project) }}
          echo ${{ toJson(needs.define-matrix.outputs.json-project) }} | jq -r '.include[].project'

  # Job 3: Loop through array
  print-array-output:
    runs-on: ubuntu-latest
    needs: define-matrix

    strategy:
      matrix: ${{ fromJson(needs.define-matrix.outputs.json-project) }}
      
    steps:
      - name: Print project-json variable
        id: print-array-item
        run: |
          curl --insecure --request POST --url ${{ vars.url }}/projects/${{ matrix.include.project }}/update/


When I run this job, Job 3 (print-array-output) returns the following error:

Error when evaluating 'strategy' for job 'print-array-output'. .github/workflows/test-loop2.yml (Line: 40, Col: 15): Unexpected value '2'

It seems to be erroring because the "count" object is in front of the "include" array. But I can't figure out how to get the strategy/matrix to only use the "include" object.

Can anyone offer any suggestions?


Solution

  • You can use the property dereference operator . along with fromJson to get the include array only and set the strategy.matrix.include directly like this:

    strategy:
      matrix:
        include: ${{ fromJson(needs.define-matrix.outputs.json-project).include }}
    

    and, later use matrix.project and matrix.config to access the values.

    Here's the updated workflow :

    name: matrix_test
    
    on: workflow_dispatch
    
    jobs:
      define-matrix:
        runs-on: ubuntu-latest
    
        outputs:
          json-project: ${{ steps.project-step.outputs.json-project }}
    
        steps:
          - name: Define Project String
            id: project-step
            run: echo 'json-project={"count":2,"include":[{"project":"1","config":"Debug"},{"project":"2","config":"Release"}]}' >>"$GITHUB_OUTPUT"
    
      print-output:
        runs-on: ubuntu-latest
        needs: define-matrix
    
        steps:
          - name: Print project-json variable
            run: echo '${{ needs.define-matrix.outputs.json-project }}' | jq -r '.include[].project'
    
      print-array-output:
        runs-on: ubuntu-latest
        needs: define-matrix
    
        strategy:
          matrix:
            include: ${{ fromJson(needs.define-matrix.outputs.json-project).include }}
    
        steps:
          - name: Print project-json variable
            run: echo '${{ matrix.project }} | ${{ matrix.config }}'