Boolean inputs are not actually booleans in composite actions
Describe the bug
I'm not sure if closed issues are monitored, as there was no reaction from official side at all. This is a new issue related to https://github.com/actions/runner/issues/1483.
For composite actions boolean inputs are not actually booleans.
To Reproduce
inputs:
...
generate-release-notes:
description: ...
required: false
type: boolean
default: false
runs:
using: composite
steps:
- name: Create Release
uses: actions/github-script@v6
with:
script: |
github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
...
generate_release_notes: ${{ inputs.generate-release-notes && 'true' || 'false' }}
});
Caller:
- uses: flobernd/actions/github/create-release@master
with:
tag-name: v1.2.4
generate-release-notes: true
This line always evaluates to false:
generate_release_notes: ${{ inputs.generate-release-notes && 'true' || 'false' }}
The explicit syntax does incorrectly evaluate to false as well:
generate_release_notes: ${{ inputs.generate-release-notes == true && 'true' || 'false' }}
Correct behavior is only observed when using string semantics:
generate_release_notes: ${{ inputs.generate-release-notes == 'true' && 'true' || 'false' }}
Expected behavior
generate_release_notes: ${{ inputs.generate-release-notes && 'true' || 'false' }}
generate_release_notes: ${{ inputs.generate-release-notes == true && 'true' || 'false' }}
Evaluates to true.
Runner Version and Platform
GitHub managed runners (latest version). All platforms.
Would be nice to have non string inputs in composite actions, especially the object type would be great in my opinion
inputs:
...
myobjinput:
description: ...
required: false
type: object
runs:
using: composite
steps:
- run: |
echo '${{ tojson(inputs.myobjinput) }}'
Fun fact this composite action will also use the type string for myobjinput, because the type property is not parsed / supported in composite actions yet. Just the parser is instructed to be relaxed to not throw an error if you invent your own properties, I think you can add anything under an input yaml mapping.
~~Action Inputs are still saved in a Dictionary<string, string>, which cannot even store a true boolean~~, I'm not affiliated with GitHub, only a contributor of one bug fix.
I bumped on this also today. I am calling my composite action from a workflow with a boolean input as follows:
...
on:
workflow_dispatch:
inputs:
realRun:
description: Really run?
default: false
type: boolean
...
jobs:
run-tests:
- uses: my-org/test-run@main
with:
realRun: ${{ inputs.realRun == true }}
And this is how my composite action my-org/test-run@main looks like from some relevant parts (some debugging added and a lot of things omitted here):
...
inputs:
realRun:
description: Really run?
default: false
type: boolean
...
runs:
using: composite
steps:
- name: Check realRun input value
shell: bash
run: echo "realRun==${{ inputs.realRun == true }}"
- name: Run tests
if: ${{ inputs.realRun == true }}
shell: bash
run: ${{ github.action_path }}/bin/run_tests.sh
That will always echo realRun==false on the first step and will never run the second step, independent on whether the input value is given as boolean true or false. That is because it seems the realRun input value is treated as string in the composite action.
I know I can get it working by using string 'true' in the expressions above, instead of boolean true, but it will work only as long as this bug with treating boolean inputs as strings in a composite action has been fixed.
I was hoping to do something similiar with the output of a composite action, but there doesn't seem to be any way to force it to be a boolean either. I'm using:
outputs:
image_exists:
description: true if an image with the given exists, false otherwise
value: ${{ fromJSON(steps.verify_image_exists.outputs.image_exists) }}
This shouldn't be surprising given that it is documented but it's still frustrating and you end up with the same "always evaluates to false" problem.
Agree with @veleek - this is very frustrating to have conditions like the following:
if: needs.get-pr-labels.outputs.build-label-present == 'true' || needs.get-pr-labels.outputs.deploy-label-present == 'true'
It would be nicer if the outputs were boolean, so the condition looks like this:
if: needs.get-pr-labels.outputs.build-label-present || needs.get-pr-labels.outputs.deploy-label-present
The outputs in the composite actions look like this:
on:
workflow_call:
outputs:
build-label-present:
description: "cicd:build label is present in the PR"
value: ${{ contains(github.event.pull_request.labels.*.name, 'cicd:build') }}
deploy-label-present:
description: "cicd:deploy:* label is present in the PR"
value: ${{ contains(toJSON(github.event.pull_request.labels.*.name), 'cicd:deploy:') }}
+1 to this. Just recently ran into this exact issue, with the only reasonable workaround being to use string semantics as detailed in the original post.
This appears to be true for docker based actions as well.
+1
Just ran into this issue as well. There doesn't seem to be any related information on the official documentation, and it is very non-intuitive to have inputs support multiple types in workflows and "normal" actions but not in composite actions. I hope this behavior can be changed.
I just spend several hours trying to pass a true value... The way to do it is:
Job:
env:
SOME_ENV: ${{ github.event_name == 'pull_request' }}
jobs:
somejob:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up build
uses: ./.github/actions/xxx
with:
some-input-value: ${{ env.SOME_ENV == 'true' }}
Composite:
name: Set up build
description: Steps before build
inputs:
some-input-value:
description: "Holy moly this was difficult"
required: false
default: false
type: boolean
runs:
using: composite
steps:
- name: "Input flag:"
run: echo "Inputflag: " && echo ${{ inputs.some-input-value== 'true' }}
shell: bash
- name: "Some action"
uses: someorg/someaction@v999
if: ${{ inputs.some-input-value == 'true' }}
This makes no sense at all and is not documented.
Also worth nothing that if expressions are always evaluated to strings https://docs.github.com/en/actions/learn-github-actions/expressions#about-expressions
Then it seems unclear how this will ever work for passing variables from workflow call/dispatch. E.g.
workflow dispatch with boolean
-> calls composite action
with:
variable: ${{ inputs.from_workflow_dispatch_boolean }} <--- this could start as a boolean from the dispatch but be coerced to a string by ${{
I am also running into this and trying to sort out how to work around this.
I would suggest not doing a workaround that involves using type: boolean but then treating it as a string, such as if: ${{ inputs.some-input-value == 'true' }}. My reasoning is that if GitHub actually fixes this issue, those workarounds would no longer be expected to function. After a fix to this issue, comparing a boolean == 'true' would return false, which is not what you want in the long-term.
I have been thinking about this more lately and I'm starting to think that this is not a bug and instead is us using yaml syntax that is not actually supported or documented by GitHub.
workflow_call and workflow_dispatch have inputs sections documented that include the type field, so it led me and others to think that composite actions can have that field too.
However, the inputs documentation for composite actions doesn't document the type field at all. So when we put type: boolean in there, we are just adding a field that GitHub doesn't know about just like if I was to add someflagijustmadeup: true, so it is ignored.
@grossag, while I think that you're correct in that this is simply not a supported feature of GHActions, I think the rest of this thread makes it very clear that people would REALLY like if it we're supported. The fact that it's nearly identical to other mechanisms for declaring inputs except that it's missing type is confusing on it's own and probably worth doing something about.
This bug just cost me half of a work day. Why isn't anyone addressing this?
it 2024 and GH actions doesn't treat booleans as booleans in any other software... that's a shame.
Yeah, I just came across this scenario too, which led me here.
The docs are pretty explicit in defining the inputs for composite actions and workflow dispatch inputs.
However, I still found myself asking the question, 'Is the boolean input I am using in my workflow going to be passed in as a boolean or string when calling my composite action?'.
At minimum, there should be a Note block added to the docs to explicitly call this out. Until this actually gets implemented (Original issue was opened in 21 so it doesn't seem likely), the note block will eliminate any confusion people have.