Vikas Rathore
Vikas Rathore

Reputation: 8801

How to put conditional job in need of another job in Github Action

Below is my GitHub workflow

name: APP Build
on:
  push:
    branches:
      - feature/test

jobs:
  test-1:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'push' && contains( github.event.head_commit.message, 'test1') }}
    steps:
      - name: test-fail
        run: echo "test1"
  test-2:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'push' && contains( github.event.head_commit.message, 'test2') }}
    steps:
      - name: test-fail
        run: echo "test1"
  notify-slack:
    name: Slack Notification
    runs-on: ubuntu-latest
    needs: [test-1, test-2]
    steps:
      - name: Slack Notification
        uses: rtCamp/[email protected]
        env:
          SLACK_CHANNEL: alert
          SLACK_COLOR: "${{ job.status == 'success' && 'good' || 'danger' }}"

Question: test1 and test2 job is conditional as per my commit message but notify slack need either test1 or test2. I can't put both because if either the job skip notify-slack will skip as well. How to make this work?

Upvotes: 20

Views: 18579

Answers (3)

Filipe Pina
Filipe Pina

Reputation: 2239

I've just bumped into this issue myself and I didn't like the solutions here as it requires if: always()... to be added to EVERY job after the conditional one, making it hard to maintain.

I noticed that workflow status was success even if only the first job executed and everything else was skipped, so I decided to try to move the conditional part to a separate workflow and call it as a re-usable workflow.

In my case, I had 2 conditionally exclusive jobs, so one of them always executed, not exactly the same as your test-1 and test-2 (where both can be skipped).

name: test helper

on:
  workflow_call:

jobs:
  test-1:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo h1
    if: ${{ true }}
  
  test-2:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo bc
    if: ${{ false }}

Then the main workflow

jobs:
  tests:
    uses: ./.github/workflows/helper.yaml
  notify-slack:
    name: Slack Notification
    runs-on: ubuntu-latest
    needs: tests

I found this a cleaner approach. If workflow fails, it will be failure. If the jobs are skipped or successful, workflow is successful.

I think only scenario that needs tweaking is if you need notify-slack to be skipped if both steps are skipped.

Not sure about the best way for that, but using workflow output (combining outcomes) could work.

Upvotes: 0

Krzysztof Madej
Krzysztof Madej

Reputation: 40603

There is an issue on Github about this. You need to add condition like below:

  test-1:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'push' && contains( github.event.head_commit.message, 'test1') }}
    steps:
      - name: test-fail
        run: echo "test1"
  test-2:
    runs-on: ubuntu-latest
    if: ${{ github.event_name == 'push' && contains( github.event.head_commit.message, 'test2') }}
    steps:
      - name: test-fail
        run: echo "test1"
  notify-slack:
    name: Slack Notification
    runs-on: ubuntu-latest
    needs: [test-1, test-2]
    if: |
      always() && 
      (needs.test-1.result == 'success' || needs.test-1.result == 'skipped') && 
      (needs.test-2.result == 'success' || needs.test-2.result == 'skipped') && 
      !(needs.test-1.result == 'skipped' && needs.test-2.result == 'skipped')
    steps:
      - name: Slack Notification
        uses: rtCamp/[email protected]
        env:
          SLACK_CHANNEL: alert
          SLACK_COLOR: "${{ job.status == 'success' && 'good' || 'danger' }}"

Upvotes: 23

mkungla
mkungla

Reputation: 3538

Implementation such condition can be achieved by using following workflow logic

jobs:
  A:
    runs-on: ubuntu-latest
    steps:
      - run: echo "success always"
  B:
    runs-on: ubuntu-latest
    if: false
    steps:
      - run: echo "this will never run"
  C:
    runs-on: ubuntu-latest
    steps:
      - run: |
          exho "here to fail"
          exit 1

  D:
    runs-on: ubuntu-latest
    needs: [A, B, C]
    if: |
      always() &&
      !contains(needs.*.result, 'cancelled')
    # you can add conditions if needed e.g.
    # !contains(needs.*.result, 'failure')
    steps:
      - run: echo "${{ toJSON(needs) }}"

Your need to modify also your SLACK_COLOR logic. job.status == 'success' will not work since it will always be success for this job regardless did any of the dependencies failed. Use needs for your logic e.g. job D output is:

{
  A: {
    result: success,
    outputs: {}
  },
  B: {
    result: skipped,
    outputs: {}
  },
  C: {
    result: failure,
    outputs: {}
  }
}

so you SLACK_COLOR could be set like this

SLACK_COLOR: "${{ contains(needs.*.result, 'failure') && 'danger' || 'good' }}"

Upvotes: 7

Related Questions