98

I'm new to GitHub Actions, playing with various options to work out good approaches to CI/CD pipelines.

Initially I had all my CI steps under one job, doing the following:

  • checkout code from repo
  • lint
  • scan source for vulnerabilities
  • build
  • test
  • create image
  • scan image for vulnerabilities
  • push to AWS ECR

Some of those steps don't need to be done in sequence though; e.g. we could run linting and source code vulnerability scanning in parallel with the build; saving time (if we assume that those steps are going to pass).

i.e. essentially I'd like my pipeline to do something like this:

job1 = {
 - checkout code from repo #required per job, since each job runs on a different runner
 - lint
}
job2 = {
 - checkout code from repo
 - scan source for vulnerabilities
}
job3 = {
 - checkout code from repo
 - build
 - test
 - create image
 - scan image for vulnerabilities
 - await job1 & job2
 - push to AWS ECR
}

I have a couple of questions:

  1. Is it possible to setup some await jobN rule within a job; i.e. to view the status of one job from another?
  2. (only relevant if the answer to 1 is Yes): Is there any way to have the failure of one job immediately impact other jobs in the same workflow? i.e. If my linting job detects issues then I can immediately call this a fail, so would want the failure in job1 to immediately stop jobs 2 and 3 from consuming additional time, since they're no longer adding value.

2 Answers 2

141
Answer recommended by CI/CD Collective

Ideally, some of your jobs should be encapsulated in their own workflows, for example:

  • Workflow for testing the source by whatever means.
  • Workflow for (building and-) deploying.

and then, have these workflows depend on each other, or be triggered using different triggers.

Unfortunately, at least for the time being, workflow dependency is not an existing feature (reference).

Edit: Dependencies between workflows is now also possible, as discussed in this StackOverflow question.

Although I feel that including all of your mentioned jobs in a single workflow would create a long and hard to maintain file, I believe you can still achieve your goal by using some of the conditionals provided by the GitHub actions syntax.

Possible options:

Using the latter, a sample syntax may look like this:

jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]

And here is a workflow ready to be used for testing of the above approach. In this example, job 2 will run only after job 1 completes, and job 3 will not run, since it depends on a job that failed.

name: Experiment
on: [push]

jobs:
  job1:
    name: Job 1
    runs-on: ubuntu-latest

    steps:
    - name: Sleep and Run
      run: |
        echo "Sleeping for 10"
        sleep 10

  job2:
    name: Job 2
    needs: job1
    runs-on: ubuntu-latest

    steps:
    - name: Dependant is Running
      run: |
        echo "Completed job 2, but triggering failure"
        exit 1

  job3:
    name: Job 3
    needs: job2
    runs-on: ubuntu-latest

    steps:
    - name: Will never run
      run: |
        echo "If you can read this, the experiment failed"

Relevant docs:

5
  • 1
    Nice one, thanks @DannyB. Good point on splitting things up into different workflows; I'll have a think on how to handle that from a process perspective. RE: The needs piece; that's good, but forces the jobs to run sequentially, which removes the benefit I'm aiming for. My hope is to have those tasks which don't depend on one another run in parallel to decrease the time before we know if things have succeeded or failed.
    – JohnLBevan
    Commented Jul 29, 2020 at 9:44
  • 1
    You still can run some jobs in parallel. If a job does not depend on a successful completion of a previous job, it doesn't need it.
    – DannyB
    Commented Jul 29, 2020 at 11:09
  • 3
    If you still want, for example, job3 to run if job2 was unsuccessful or skipped, you can use if: ${{ always() }} on job3. docs.github.com/en/actions/using-workflows/… It will still enforce that job2 attempts to run first
    – gary69
    Commented Jan 21, 2022 at 21:13
  • Is it also possible to re-run the dependent jobs, only the last job fails? For example in case job3 fails, it will re-run job2 & job3 when triggering re-run failed jobs. Commented Aug 3, 2022 at 8:16
  • 1
    Seems like checking out code only once across jobs is unsupported github.com/actions/checkout/issues/19 Commented Dec 27, 2022 at 14:52
-6

If the depended job run a lot faster than its dependents. You can just let them run in parallel.

For example: Deploy an expressjs server is usually a lot faster than publishing to Google Play Console.

1
  • If a job truly depends on another, letting them run in parallel will cause race conditions (if they ever work). Commented Aug 23, 2023 at 16:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.