Boolean inputs are not actually booleans in composite actions
flobernd opened this issue ยท 15 comments
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 #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 , I'm not affiliated with GitHub, only a contributor of one bug fix.Dictionary<string, string>
, which cannot even store a true boolean
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.