Run a job if at least one of the previous ones succeeded

I have been trying to write a workflow with the following logic:

  1. Job A, B and C run or might be skipped
  2. Job D needs to run if at least one of A, B or C succeed and none of them failed
  3. If all of them (A, B and C) are skipped, D shouldn’t run

I managed to get 1 to work but as soon as I use always() in combination with whatever condition it will always run and not comply with 3.
I have a very hard time understanding always() and failure(). These functions don’t them to behave like regular booleans.

You can see this behaviour in this test workflow.

I tried the following without success:

  • if: ${{ contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }}
  • if: ${{ !failure() && contains(needs.*.result, 'success') }}
  • if: ${{ always() && contains(needs.*.result, 'success') }}
  • if: ${{ always() && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }}
  • if: ${{ always() && !failure() && contains(needs.*.result, 'success') }}

And nothing seems to work. Without any of the job status functions all the jobs are skipped if a single dependency is skipped (as stated in the doc). But as soon as you add one of these functions, it always runs.

In an other hand it seem to work correctly when a job depends on only 2 jobs. As you can see in this different workflow

:wave: Hey @benjamin-bergia,

It looks like the 4th option you tried works and meets your criteria.

   if: ${{ always() && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }}

Workflow:


name: Job Conditionals

on: workflow_dispatch

jobs:
  a:
    if: true
    runs-on: ubuntu-latest

    steps:
      - run: echo "Hello world"
  b:
    if: false
    runs-on: ubuntu-latest

    steps:
      - run: echo "Hello world"
  c:
    if: false
    runs-on: ubuntu-latest

    steps:
      - run: echo "Hello world"
  
  d:
   needs: [a, b, c]
   if: ${{ always() && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }}
   runs-on: ubuntu-latest

   steps:
    - run: echo "Hello world"
  1. A runs, B & C are skipped => D runs
    Update job-conditionals.yml · joshmgross/actions-testing@53072ac · GitHub

  2. A fails, B & C are skipped => D runs
    Update job-conditionals.yml · joshmgross/actions-testing@4a505ea · GitHub

  3. A, B, & C are skipped => D is skipped
    Update job-conditionals.yml · joshmgross/actions-testing@8d0f58b · GitHub

  4. A runs, B is skipped, C fails => D is skipped