I am interested in why this always() condition is not behaving as expected in a Github workflow.
I have a core pipeline, which works just fine. If the secondary workflow fails, the tertiary still runs but only if boolean output from secondary workflow == true.
Within the secondary pipeline, the output step is supposed to run only if a boolean input is set to true. Although I have used the exact same syntax, it only seems to run if the condition is always() rather than always() &&.
This is the core pipeline (which works):
name: Core Pipeline
on:
workflow_dispatch:
inputs:
boolean:
description: 'boolean'
required: false
default: true
type: boolean
jobs:
secondary-workflow:
uses: ./.github/workflows/secondary-workflow.yaml
with:
boolean: true
tertiary-workflow:
needs: secondary-workflow
uses: ./.github/workflows/tertiary-workflow.yaml
if: always() && needs.secondary-workflow.outputs.boolean == 'true'
This is secondary-workflow (doesn't work as intended):
on:
workflow_call:
inputs:
boolean:
description: 'Boolean'
required: false
default: true
type: boolean
outputs:
boolean:
description: "Test Output"
value: ${{ jobs.job-4.outputs.boolean }}
jobs:
job-1:
runs-on: ubuntu-latest
steps:
- name: job 1
run: echo 'This job runs'
job-2:
runs-on: ubuntu-latest
needs: job-1
steps:
- name: job 2
run: echo 'This job runs'
job-3:
runs-on: ubuntu-latest
needs: [job-1, job-2]
steps:
- name: Exit
run: echo "This job fails"; exit 1
job-4:
runs-on: ubuntu-latest
needs: [job-1, job-2, job-3]
if: always() && inputs.boolean == 'true' (ADDING THE && CAUSES THE JOB TO BE SKIPPED)
steps:
- id: setOutput
run: echo "boolean=true" >> $GITHUB_OUTPUT; echo "OUTPUT_SET"
outputs:
boolean: ${{ steps.setOutput.outputs.boolean }}
My question is, why does adding a second condition in addition to always() work for the core pipeline but not for the secondary pipeline?
Thanks!
CodePudding user response:
When you compare
if: always() && inputs.boolean == 'true'
you're comparing a boolean to a string. On type mismatch, actions coerce the operands to numbers; true
becomes 1
, and 'true'
(the string) becomes NaN
, and 1 == NaN
is false. To fix, you can compare to a boolean literal instead of a string:
if: always() && inputs.boolean == true
or you should be able to just check the boolean on its own:
if: always() && inputs.boolean
As for why the seemingly identical condition works in one place and not in the other, my guess is that the input parameter in the reusable workflow is typed as a boolean, whereas needs.secondary-workflow.outputs.boolean
is a string, so comparison to 'true'
works.