If (not) startswith mutually exclusive steps

Hi,

I am trying to have two mutually exclusive steps in my workflow, based on an input parameter’s value:

      - name: Create release branch
        if: startsWith(${{ github.event.inputs.from_branch }}, 'release/') != true
        run: |
          echo "NEW_BRANCH=release/${{ github.event.inputs.release_number }}" >> $GITHUB_ENV
      - name: Use existing release branch
        if: startsWith(${{ github.event.inputs.from_branch }}, 'release/')
        run: |
          echo "NEW_BRANCH=${{ github.event.inputs.from_branch }}" >> $GITHUB_ENV

But if I specify ‘dev’ as input, both steps are executed. If I specify ‘release/0.0.0’ as input, also both steps get executed. Whatever input I give, always both steps are executed. As if the if statements / startswith don’t work at all.

I tried also:

!(startsWith(${{ github.event.inputs.from_branch }}, 'release/'))
"!startsWith(${{ github.event.inputs.from_branch }}, 'release/')"
"!(startsWith(${{ github.event.inputs.from_branch }}, 'release/'))"

None of them seem to work. I read https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions, but there’s no example of how to use the ‘not’ operator.

Valentijn

@valentijnscholten,

You are using the incorrect expression syntax for the if conditional in your workflow.
Change them like as this can work:

- name: Create release branch
  if: ${{ !startsWith(github.event.inputs.from_branch, 'release/') }}
  run: |
    echo "NEW_BRANCH=release/${{ github.event.inputs.release_number }}" >> $GITHUB_ENV

- name: Use existing release branch
  if: ${{ startsWith(github.event.inputs.from_branch, 'release/') }}
  run: |
    echo "NEW_BRANCH=${{ github.event.inputs.from_branch }}" >> $GITHUB_ENV

There are few points you need to know when setting if conditionals (jobs.<job_id>.if or jobs.<job_id>.steps.if) in your workflow:

  1. If you want to use the expression syntax “${{ }}” in the if conditionals, you should use it to surround the whole condition statement, and you do not need to use it for each referenced context expression in the condition statement.

    • The correct syntax.

      if: ${{ startsWith(github.event.inputs.from_branch, 'release/') }}  ✅
      
    • The incorrect syntax.

      if: startsWith(${{ github.event.inputs.from_branch }}, 'release/')  ❌
      
  2. In most cases, you can directly omit the expression syntax “${{ }}” in the if conditionals.

    if: startsWith(github.event.inputs.from_branch, 'release/')  ✅
    
  3. If the condition statement is started with “!” (Not), the expression syntax “${{ }}” can’t be omitted.

    • The correct syntax.
      if: ${{ !startsWith(github.event.inputs.from_branch, 'release/') }}  ✅
      
    • The incorrect syntax.
      if: !startsWith(github.event.inputs.from_branch, 'release/')  ❌
      

In addition, you can enable debug logging to view the result of the if conditionals for each step from the debug logs. From the logs, you can see how the job evaluates the if conditionals for each step and returns the final result (true or false).
For example:

2 Likes

Wow, best reply ever. Thank you @brightran !

That’s really good to know. Are there other cases which require ${{ }}? And are they listed in the documentation? They really should be!

I suppose this has less to do with GitHub Actions and more with YAML in general.

  • A leading ! is reserved for tagging
  • Leading * and & are reserved for anchors
  • A leading question mark followed by whitespace is reserved for complex mapping keys:
    ? [foo, bar]
    : baz
    

With the if condition wrapped in ${{ }}, issues with above special characters are avoided because the string starts with $. Alternatively, one can also write:

  • if: >-
      !startsWith(github.event.inputs.from_branch, 'release/')
    
  • if: "!startsWith(github.event.inputs.from_branch, 'release/')"
  • if: '!startsWith(github.event.inputs.from_branch, ''release/'')'