Bug in IF conditions on inputs for reusable workflows

Problem:

When a reusable workflow (called workflow), contains if conditions (based on the input of the job) at job level, there is a observation that the if condition seems to execute and use value globally (causing jobs which are being skipped because of a check).

Example

Caller workflow: Simple workflow calling a reusable workflow passing in the github event (PR or push) to the reusable workflow

name: caller-workflow
on:
  pull_request:
  push:
    branches:
      - master
# 2
jobs:
  call-the-workflow:
    uses: action-foobar/action-testing/.github/workflows/called_workflow.yml@master
    with:
      TRIGGER_EVENT : ${{ github.event_name }}

Reusable workflow: Workflow with a sequence of job which has conditions based on the input (whether it is a pull_request or a push)

name: tf-app-dns-reusable

on:
  workflow_call:
    inputs:
      TRIGGER_EVENT:
        description: trigger event for the workflow
        required: true
        type: string

jobs:
  lint:
    runs-on: ubuntu-latest
    name: Validate terraform configuration

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: debug
        run: |
          echo ${{ inputs.TRIGGER_EVENT }}
  plan-non-prod:
    if: ${{ inputs.TRIGGER_EVENT == 'pull_request' }}
    needs: lint
    runs-on: ubuntu-latest
    name: Plan Application DNS Non Prod
    steps:
      - name: debug
        run: |
          echo "triggered event"
          echo ${{ inputs.TRIGGER_EVENT }}
  plan-prod:
    if: ${{ inputs.TRIGGER_EVENT == 'pull_request' }}
    needs: "plan-non-prod"
    runs-on: ubuntu-latest
    name: Plan Application DNS Prod
    steps:
      - name: debug
        run: |
          echo "triggered event"
          echo ${{ inputs.TRIGGER_EVENT }}
  apply-non-prod:
    if: ${{ inputs.TRIGGER_EVENT == 'push' }}
    needs: lint
    runs-on: ubuntu-latest
    name: apply non prod
    steps:
      - name: debug
        run: |
          echo "triggered event"
          echo ${{ inputs.TRIGGER_EVENT }}

Observation

  • Job 3 gets the check skipped , even though the condition is valid and matches as Job 2 (Job 3 only depends on success of job 2 and the same IF condition as job2.

  • On removal of the IF condition on Job 4 , then Job 3 executes fine .

Which implies of some sort of “state” of the IF condition (since there is no relationship between Job 4 and Job 3).

PS: This was working perfectly fine till 11PM GMT 10th Jan . (as we have a lot of jobs on this setup)

The observation of runs can be found in this repository here → push stuff · action-foobar/action-testing@500bca2 · GitHub

6 Likes

Same issue seen on our pipelines here:

Faced same issue, our CI/CD is pretty much blocked now

I’ve even removed the IF, and the second job continues to be skipped. We are really blocked!

Screenshot from 2022-01-11 14-50-44

Seems to happen when a sibling job gets skipped, any subsequent jobs then get skipped, even if they are not related.

See run Create main.yml · wongjn/test@f05463b · GitHub.
See that Testing/test job is skipped even though the dependent job, Testing/start was successful.
This happens because Testing/assets has been skipped via the input assets being false . Setting assets to true will now mean Testing/test now runs because Testing/assets is not skipped. This seems to be an erroneous coupling of these jobs even though the graph indicates there should be no dependency.

2 Likes

Thanks for the info. With this we are able to workaround temporarily. Also opened a github ticket pointing to this thread to see if we raise the criticality on this.

Watch this issue - Bug in IF conditions on inputs for reusable workflows · Issue #1602 · actions/runner · GitHub

1 Like

@Surveyforcustomers invalid link

If i realy understend, you need change the job 3 like this:

plan-prod:
    if: ${{ always() }} && ${{needs.plan-non-prod.outputs.status == 'success'    
    needs: "plan-non-prod"
    runs-on: ubuntu-latest
    name: Plan Application DNS Prod
...

Will run always and check output status of plan-non-prod is success. But i don’t test is, i have some like this

You need to wrap the whole expression in ${{ ... }} or leave them off entirely:

    if: ${{ always() && needs.plan-non-prod.outputs.status == 'success' }}

With partial expressions the output is just a string (e.g. “true && false”) and a non-empty string evaluates to true.

1 Like