docs icon indicating copy to clipboard operation
docs copied to clipboard

Unclear when to use expression syntax with literals

Open schalkneethling opened this issue 2 years ago • 30 comments

Code of Conduct

What article on docs.github.com is affected?

https://docs.github.com/en/actions/learn-github-actions/expressions#literals

What part(s) of the article would you like to see updated?

The following section talks about the literal data types used with expression syntax. The example that follows seems to indicate that when specifying anything that is not meant to be a string should be set using expression syntax.

However, if one attempts to do this in, for example, the inputs section of a workflow, the validator shows an error that is quite the opposite:

Screenshot of validator tooltip status that a boolean was expected, but instead it got a string

On re-reading this part, I assume it is referring specifically to when setting environmental variables?

Additional information

No response

schalkneethling avatar May 15 '22 15:05 schalkneethling

Thanks @schalkneethling, I'll get this triaged for review.

steveward avatar May 17 '22 15:05 steveward

@schalkneethling

Experimenting with using templates for workflow_dispatch inputs, I found the following to be true:

  1. No matter what the input type, if I tried to use default: ${{ true }}, I got a workflow error: "A template expression is not allowed in this context"
  2. In spite of this, I could use default: ${{ 'true' }} without getting a workflow error. However, doing this was never useful: a. Using default: ${{ 'true' }} when the input type was boolean resulted in the input checkbox not being checked, and the the default value was treated as false. b. Using default: ${{ 'true' }} when the input type was specified to be a string would literally display the default ${{ 'true' }} in the input text box. Actually trying to display this input value with a Bash statement such as echo "The string you entered is: ${{ github.event.inputs.my_string_input }}" would cause the workflow to error out at that point in the workflow with the error "The string you entered is: ${{ 'true' }}: bad substitution". In fact, the question of setting defaults aside, any string input that looks like an expression template is likely to cause the workflow to crash: there doesn't seem to be any escaping of syntactically-significant input characters.
  3. The declared type of an input seems only to affect how input entry is presented to the user: boolean types present as a check box, choice types present as a dropdown, and string types present as a text box. By the time you use github.event.inputs.my_input, that value has been cast or converted to a string, seemingly according to the rules outlined in the Learn GitHub Actions section on functions. For example, even if you give input variable my_boolean type "boolean" and check the resulting input box when you run the workflow, ${{ github.event.inputs.my_boolean == 'true' }} will evaluate to true, but ${{ github.event.inputs.my_boolean == true }} will evaluate to false.

I think the way inputs are treated in the context of workflow_call events is significantly different, but I'm still testing this out.

By the way, what validator did you use to get the above screen shot?

gsrohde avatar May 22 '22 21:05 gsrohde

By the way, what validator did you use to get the above screen shot?

That was GitHub’s native in-browser workflow editor.

schalkneethling avatar May 23 '22 09:05 schalkneethling

That was GitHub’s native in-browser workflow editor.

Thanks. For what it's worth, the validator gives me a slightly different error for the case you mention—namely, "type is set to boolean but default has invalid value". [UPDATE: Trying this again today, I get exactly the same error from the validator that you got.] If the type is set to string, however, the validator doesn't complain at all about a default of ${{ true }}; but trying to run a workflow with this default immediately errors out with the message "A template expression is not allowed in this context", as I mentioned in point 1 above.

As for using template expressions for setting environment, it seems they can be used, but needn't be if one is merely setting an environment variable to a literal value. All of the following, for example, result in the expression ${{ env.true-string-* == 'true' }} evaluating to true (and ${{ env.true-string-* == true }} evaluating to false!), where * is a number 1 through 6.

env:
  true-string-1: true
  true-string-2: ${{ 'true' }}
  true-string-3: 'true'
  true-string-4: !!bool true
  true-string-5: ${{ true }}
  true-string-6: ${{ fromJSON(true) }}

gsrohde avatar May 23 '22 18:05 gsrohde

[@schalkneethling: While the following comment might be of interest to you if you use called workflows, it is primarily motivated by the hope that @steveward or whoever from the GitHub team works on this issue will see fit to either uniformize the behavior of workflow_dispatch inputs and workflow_call inputs or rewrite or add to the documentation in order to make clear how they work very differently.]

As I hinted in my first comment, the way inputs are treated in the context of workflow_call events is significantly different from how they are treated in the context of a workflow_dispatch event. For example,

  1. Using the expression syntax (${{ }}) to set a default for a workflow_call input is perfectly acceptable. ~Even the on-line validator agrees: if you change workflow_dispatch to workflow_call in the example above that flagged default: ${{ true }} as an error, you will see that error message disappear.~ [UPDATE: Trying this again today, I can no longer reproduce this behavior: default: ${{ true }} gets flagged as an error by the online validator both in the context of workflow_dispatch inputs and workflow_call inputs. Nevertheless, in spite of the message from the online validator, specifying ${{ true }} in the context of a workflow_call input works perfectly fine when the called workflow is actually run! The behavior is exactly the same as if default: true were specified. (Again, this is not the case when ${{ true }} is used as a default for workflow_dispatch inputs!)

    By the way, I only noticed today that in the example in your original post (https://github.com/project-calavera/calavera-reusable-actions/blob/7ddf5e2fe2108c91da05a269c4e0f56b5e40f8b5/.github/workflows/publish-release.yml#L19), you are using inputs in the context of workflow_call, not workflow_dispatch as I had originally thought.]

    While there really isn't any good reason to use ${{ true }} here instead of just true, there may be use cases where using expression syntax might be of some value. For example, you could use an expression like ${{ format('The event is {0}!', github.event_name) }} to set the default value of a workflow_call input of type string.

  2. The context expression for workflow_call inputs is simpler: inputs.my_input is used rather than github.event.inputs.my_input.

  3. A workflow_call input declared as boolean really is treated as a boolean value when used. For example, consider a workflow_dispatch input and a workflow_call input, both declared as boolean, both named true_boolean_value, and both set to or defaulted to true in a run of the workflow. Then (as I pointed out earlier), ${{ github.event.inputs.true_boolean_value == 'true' }} will evaluate to true, but {{ github.event.inputs.true_boolean_value == true }} will evaluate to false. With the workflow_call input, we have the reverse: ${{ inputs.true_boolean_value == 'true' }} evaluates to false, but ${{ inputs.true_boolean_value == true }} evaluates to true.

    Note that if you have a caller workflow that has (workflow_dispatch) boolean input true_boolean_value, and you want to pass this through to a called workflow having a like-named boolean input, you have to first convert the workflow_dispatch value to a bona fide boolean, e. g.

  call-reusable-workflow-boolean:
    uses: ./.github/workflows/reusable.yaml
    with:
      true_boolean_value: ${{ github.event.inputs.true_boolean_value == 'true' }}

or

  call-reusable-workflow-boolean:
    uses: ./.github/workflows/reusable.yaml
    with:
      true_boolean_value: ${{ fromJSON(github.event.inputs.true_boolean_value) }}

Just doing

  call-reusable-workflow-boolean:
    uses: ./.github/workflows/reusable.yaml
    with:
      true_boolean_value: ${{ github.event.inputs.true_boolean_value }}

will result in a type error, because ${{ github.event.inputs.true_boolean_value }} is seen as a string, and you can't pass a string for the value of a (workflow_call) input declared to be a boolean.

gsrohde avatar May 25 '22 17:05 gsrohde

Thanks for opening an issue! We've triaged this issue for technical review by a subject matter expert :eyes:

github-actions[bot] avatar May 30 '22 00:05 github-actions[bot]

Thanks for opening this, @schalkneethling. I think inputs can only provided as strings, but you can set the type using type, so

npm-publish:
  description: Whether to publish the package to npm
  default: true
  required: false
  type: boolean

is valid for specifiying an input that is a boolean (using strings in YAML)

but forcing an expression to be a boolean is not valid YAML for GitHub Actions, e.g. this wouldn't be valid:

npm-publish:
  description: Whether to publish the package to npm
  default: ${{ true}}
  required: false
  type: boolean

On re-reading this part, I assume it is referring specifically to when setting environmental variables?

I think you're right, but will get an SME to confirm

lucascosti avatar May 30 '22 00:05 lucascosti

Thanks for opening this, @schalkneethling. I think inputs can only provided as strings, but you can set the type using type, so

npm-publish:
  description: Whether to publish the package to npm
  default: true
  required: false
  type: boolean

is valid for specifiying an input that is a boolean (using strings in YAML)

but forcing an expression to be a boolean is not valid YAML for GitHub Actions, e.g. this wouldn't be valid:

npm-publish:
  description: Whether to publish the package to npm
  default: ${{ true}}
  required: false
  type: boolean

On re-reading this part, I assume it is referring specifically to when setting environmental variables?

I think you're right, but will get an SME to confirm

@lucascosti As I point out in my comment above, using

npm-publish:
  description: Whether to publish the package to npm
  default: ${{ true}}
  required: false
  type: boolean

works perfectly well in the context of on.workflow_call.inputs, even though the on-line validator may flag it as a type error. (And as I also point out, it doesn't work in the context of on.workflow_dispatch.inputs.)

And to address the original subject of this issue, as far as I can tell, it is never necessary to use expression syntax with literals. For example, in the article https://docs.github.com/en/actions/learn-github-actions/expressions#literals referenced by the original poster, as far as I can tell, for the non-string examples of environment variable settings,

env:
  myNull: null
  myBoolean: false
  myIntegerNumber: 711
  myFloatNumber: -9.2
  myHexNumber: 0xff
  myExponentialNumber: -2.99-e2

could just as well have been used as what is given there. (There may be some subtle difference, however, between (for example) myHexNumber: 0xff and myHexNumber: ${{ 0xff }}: In the first case, it is the YAML parser that interprets 0xff as the number 255. In the second case, the YAML parser sees ${{ 0xff }} as a string, and it is only when the ${{ }} expression is interpreted that the value is found to be a number.

gsrohde avatar May 30 '22 17:05 gsrohde

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Jun 06 '22 20:06 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Jun 14 '22 20:06 github-actions[bot]

So, some of this is sort of described in https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#providing-inputs

jsoref avatar Jul 06 '22 22:07 jsoref

So, some of this is sort of described in https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#providing-inputs

Thanks. This is very useful information. It appears that this note was added about June 9 or so, and references to github.event.inputs.* in the surrounding text were changed to simply inputs.* at about that time as well. I don't know what the workflow is for releasing changes to the documentation, so I don't know when this first appeared in the public-facing documentation. I also don't know if this was merely a clarification to the documentation or whether it reflects an actual change to the workings of GitHub Actions.

gsrohde avatar Jul 07 '22 20:07 gsrohde

They unified github.event.inputs and inputs around then.

This is probably the announcement: https://github.blog/changelog/2022-06-10-github-actions-inputs-unified-across-manual-and-reusable-workflows/

jsoref avatar Jul 07 '22 21:07 jsoref

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Jul 15 '22 20:07 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Jul 25 '22 20:07 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Aug 02 '22 20:08 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Aug 10 '22 20:08 github-actions[bot]

Thank you for your patience as we are working through our backlog 💛

cmwilson21 avatar Aug 11 '22 13:08 cmwilson21

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Sep 09 '22 20:09 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Oct 10 '22 20:10 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Nov 08 '22 20:11 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Dec 07 '22 16:12 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Jan 05 '23 16:01 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Feb 03 '23 16:02 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Mar 04 '23 16:03 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar Apr 03 '23 16:04 github-actions[bot]

This is a gentle bump for the docs team that this issue is waiting for technical review.

github-actions[bot] avatar May 02 '23 16:05 github-actions[bot]

👋 Hey all! Thanks to everyone for the open conversation and the support you all have extended to each other. I wanted to check in and see if the changes noted in the comment here covered this issue enough to close it out? If not, I'm happy to dig a bit further. Thanks again for being so great to each other! 💖

cmwilson21 avatar Jun 12 '23 14:06 cmwilson21

I don't think it did.

Some of the problems appear to be a disagreement between a validator and everyone else's expectations (including humans and the docs and the engine). It looks like the validator may have improved since?

That said, using https://github.com/mechanical-ink/calavera-reusable-actions/blob/7ddf5e2fe2108c91da05a269c4e0f56b5e40f8b5/.github/workflows/publish-release.yml (linked from the original description) in a new workflow file editor in a repository, I see:

image image

Invalid type found: one of string , number , boolean were expected but integer was found

I have no idea how number and integer differ. But the error message is incredibly confusing.

There are two founds and an expected and I can't possibly parse what it's trying to say.

https://github.com/actions/setup-node/blob/869f4dd0c7f320ae834c2724d92a364de3893c24/action.yml#L8-L9

jsoref avatar Jun 12 '23 15:06 jsoref

@jsoref Thanks for confirming and provided this additional information. I'll keep this up on the review board and surface it to some of our teams. 👍

cmwilson21 avatar Jun 13 '23 12:06 cmwilson21