Home > Software engineering >  Github Actions - How to handle a ) in json when passing it across steps
Github Actions - How to handle a ) in json when passing it across steps

Time:01-06

I am querying the github api and then using jq to parse some values from the result

  - uses: octokit/[email protected]
    id: get_in_progress_workflow_run
    with:
      route: GET /repos/myorg/myrepo/actions/runs?page=1&per_page=20
    env:
      GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
  - name: Get waiting pull_request_id
    id: get_pr_id
    run: |
     prId="$(echo '${{ steps.get_in_progress_workflow_run.outputs.data }}' | jq '.workflow_runs[] | first(select(.status=="in_progress")) | .pull_requests[0] | .number')";
     echo "prId=$prId" >> "$GITHUB_OUTPUT";

This works fine unless the json result from the first step contains a closing parenthesis. When this happens the command substitution get's closed and I get an error about the next line of json being an unrecognized command.

line 1055: timestamp:: command not found

and line 1055

"head_commit": {
      "id": "67fb50d15527690eesasdaddc4425fdda5d4e1eba8",
      "tree_id": "37df61a25863dce0e3aec7a61df928f53ca64235",
      "message": "message with a )",
      "timestamp": "2023-01-05T20:27:05Z",

Is there any way to avoid this? I have tried stripping out the ) but I find that no matter how I try to print json from the github context into bash it errors out before I can do anything with it. And there doesn't appear to be a way to do string substitution from the github context.

For instance even just assigning the string to a variable fails with the same error

  - name: Get waiting pull_request_id
    id: get_pr_id
    run: |
     json='${{ steps.get_in_progress_workflow_run.outputs.data }}';

fails with

syntax error near unexpected token `)'

CodePudding user response:

${{ .. }} does string interpolation before the shell gets to see anything, so any special character in there can mess up your shell script. It's also a vector for shell injection.

To fix both, set the value in the environment first, and then reference it:

  - name: Get waiting pull_request_id
    id: get_pr_id
    env:
      data: ${{ steps.get_in_progress_workflow_run.outputs.data }}
    run: |
     prId="$(echo "$data" | jq '
         .workflow_runs[]
         | first(select(.status=="in_progress"))
         | .pull_requests[0].number
     ')"
     echo "prId=$prId" >> "$GITHUB_OUTPUT"

Alternatively, you can use the GitHub CLI to make the request without an additional action, and use the --jq parameter instead of stand-alone jq:

 - name: Get waiting pull_request_id
   id: get_pr_id
   env:
    GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
   run: |
     id=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs" \
         --method GET \
         --raw-field per_page=20 \
         --jq '
             .workflow_runs[]
             | first(select(.status=="in_progress"))
             | .pull_requests[0].number
         ')

     echo "prId=$id" >> "$GITHUB_OUTPUT"
  • Related