Cancelling rest of job if condition is met.

When a developer opens a PR, we want to run a job only if code within certain files have changed. The issue is that in order to know whether to run the job or not, the job needs to be run first in order to checkout the repo to perform a git diff on it (kind of a chicken and egg)! So, having established that, I thought maybe we can let the job run. There would be a step (after the checkout@v1) that would then determine whether to continue the job execution or not. If not, then cancel rest of job. Is there a “cancel rest of job” command? We’d want it to also not be considered a failed job. Thanks! 

1 Like

@blackswan2019 ,

We have no the “cancel rest of job” command.
As a workaround, you can try using the needs and if conditional on the subsequent jobs to meet your requests.
A simple demo:

jobs:
  job01:
    name: Job 01
    runs-on: ubuntu-latest
    outputs:
      run_rest_jobs: ${{ steps.set_output.outputs.run_jobs }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 2

      - name: git diff and set output
        id: set_output
        run: |
          codeChanges="only within certain files"
          if [[$codeChanges == "only within certain files"]]; then
            echo "::set-output name=run_jobs::true"
          else
            echo "::set-output name=run_jobs::false"
          fi
  job02:
    name: Job 02
    needs: [job01]
    if: needs.job01.outputs.run_rest_jobs == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: the rest jobs
        run: echo "run the rest jobs"

Description:

1) On job01 , in the " git diff and set output" step suppose the variable " codeChanges" is used to return the result of git diff. If the result confirms that the code changes only within certain files, set the step’s output parameter " run_jobs" to be " true", otherwise set " run_jobs" to be " false". The job’s output parameter " run_rest_jobs" will use the value of " run_jobs".

2) On job02 , use “needs: [job01]” to set only  job01  must complete successfully before job02  begins to run, and use the  if conditional ( if: needs.job01.outputs.run_rest_jobs == ‘true’ ) to check whether skip  job02  or not.

3) Similarly on other subsequent jobs.

Related docs:

jobs.<jobs_id>.outputs

Setting an output parameter

jobs.<job_id>.needs

jobs.<job_id>.if

steps context

needs context

2 Likes

@blackswan2019 ,

How are things going? Is my above suggestion helpful to you?

If you have any question about this ticket, feel free to tell me.

1 Like

Hi @brightran. I haven’t got around to trying it yet, but it looks like it would work. Will update once implemented! Thanks.

1 Like

@blackswan2019 ,

Okey, any progress, feel free to tell me.

1 Like

Hi @brightran , I have implemented the first part (similar to the job1), and the need requirement for job2 (the dependent job), but the if isn’t working. I noticed that the output from your job1 example is “run_jobs” whereas in job2, the if condition uses “run_rest_jobs”. Is there a reason they are different?

Overall, does my if condition look good? Thanks!

if: needs.native-code-diff-check.outputs.run_ios_job == 'true'

EDIT: Okay, I echoed out the needs context in job2, and it looks like the previous job (job1) never even sent the output value. I will investigate why this is!

NEEDS CONTEXT {
  "native-code-diff-check": {
    "result": "success",
    "outputs": {}
  }
}

EDIT 2: Solved it. It was a mismatch between run_jobs and run_ios_job in two lines respectively. 

outputs:
      run_rest_jobs: ${{ steps.native-files-check.outputs. **run\_jobs** }}

echo "::set-output name= **run\_ios\_job** ::true"

I set both to run_ios_job.

Your solution did the trick. Thanks for the great response and sample code/docs!

1 Like

@blane1988 ,

On job1, run_rest_jobs is a job-level output , run_jobs is a step-level output.

What you should know is, when job2 needs job1, job2 only can access job-level output from job1, and can’t directly access step-level output from job1. Because in the needs context , it only lists the job-level outputs on job1, and no expression syntax allows job2 to directly access the step-level outputs from job1 (such as " needs.job01.steps.set_output.outputs.run_jobs" is not supported).

So, on job2, if you want to get the value of the step-level output ( run_jobs ) from job1, you need to set a job-level output ( run_rest_jobs ), and pass the value of the step-level output to the job-level output. If job2 needs to access multiple step-level outputs on job1, you need to set a job-level output for each step-level output.

In order to easily distinguish between the job-level output and the step-level output, I give them different names. Of course, giving them the same name also is OK.

2 Likes