Search code examples
githubgithub-actions

Github Actions: set-output does not seem to work


I have a workflow that executes a bunch of fuzz tests and, at the end, calculates the total number of files in all crashers sub-directories. Later, in another job, I use that number to send a notification to Slack. But, for some reason, ::set-output produces no output and, most importantly, the next job does not get run even though the number of crashers is not zero!

jobs:
  fuzz-nightly-test:
    runs-on: ubuntu-latest
    steps:
      ...
      - name: Set crashers count
        working-directory: test/fuzz
        run: echo "::set-output name=crashers-count::$(find . -type d -name 'crashers' | xargs -I % sh -c 'ls % | wc -l' | awk '{total += $1} END {print total}')"
        id: set-crashers-count

   outputs:
     crashers-count: ${{ steps.set-crashers-count.outputs.crashers-count }}

  fuzz-nightly-fail:
    needs: fuzz-nightly-test
    if: ${{ needs.set-crashers-count.outputs.crashers-count != 0 }}
    runs-on: ubuntu-latest
    steps:
      ...

Does anybody know what I am doing wrong? Thank you!


Solution

  • I did a bunch of tests with a similar minimal example and I think I figured out the issue. Most immediately, in your if directive in your fuzz-nightly-fail job, you need to be accessing needs.<job_id>.outputs.<job_output_id> rather than needs.<step_id>.outputs.<job_output_id>. Therefore, the if directive would become if: ${{ needs.fuzz-nightly-test.outputs.crashers-count != 0 }}.

    Additionally, you should probably make a step output ID that's distinct from the job output ID to save yourself from some confusion about what context object is being referenced where. So, the run statement in your first job could be something like run: echo "::set-output name=count::$(find . -type d -name 'crashers' | xargs -I % sh -c 'ls % | wc -l' | awk '{total += $1} END {print total}')" and the job output would also be changed to crashers-count: ${{ steps.set-crashers-count.outputs.count }}. Putting this all together, we get

    jobs:
      fuzz-nightly-test:
        runs-on: ubuntu-latest
        steps:
          ...
          - name: Set crashers count
            working-directory: test/fuzz
            run: echo "::set-output name=count::$(find . -type d -name 'crashers' | xargs -I % sh -c 'ls % | wc -l' | awk '{total += $1} END {print total}')"
            id: set-crashers-count
    
       outputs:
         crashers-count: ${{ steps.set-crashers-count.outputs.count }}
    
      fuzz-nightly-fail:
        needs: fuzz-nightly-test
        if: ${{ needs.fuzz-nightly-test.outputs.crashers-count != 0 }}
        runs-on: ubuntu-latest
        steps:
          ...
    

    The reason for this isn't immediately obvious from the documentation alone, but the example here implies that <step_id>.outputs.foo is different from <job_id>.outputs.foo - jobs.job1.outputs.output1 is defined as that job's steps.step1.outputs.test.

    You can see a (very) minimal example of this here, with its corresponding workflow run here.