How to cancel previous runs in the PR when you push new commits(update the current) in github-actions

Viewed 6752

When I push my commits to a PR my tests are triggered for this commit. After that, if I push additional commits to this PR, tests in Github Actions runs on both commits.

I need to cancel the previous run and run only on the most recent pushed commit.

How can I configure my yaml file to achieve that?

4 Answers

You can use Concurrency:

Concurrency ensures that only a single job or workflow using the same concurrency group will run at a time.

concurrency: 
  group: ${{ github.head_ref }}
  cancel-in-progress: true

To cancel a currently running workflow from the same PR, branch or tag when a new workflow is triggered you can use:

name: Workflow X

on: # ...

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs: # ...

Explanation:

  • ${{ github.workflow }}: the workflow name is used to generate the concurrency group (e.g. Workflow 1). That allows you to have more than one different workflow (eg. workflow1.yaml and workflow2.yaml) triggered on the same event (e.g. a PR). Otherwise, workflow1.yaml would cancel workflow2.yaml or viceversa.
  • ${{ github.event.pull_request.number: when the trigger event is a PR, it will use the PR number to generate the concurrency group (e.g. workflow1-33).
  • || github.ref }}: when the trigger is not a PR but a push, it will use the branch or tag name to generate the concurrency group (e.g. workflow1-branch1).
  • cancel-in-progress: true: if cancel-in-progress is omitted or set to false, when a new workflow is triggered, the currently running workflow won't be cancelled, and the new workflow will be queued pending until the previous one is done.

Ref: https://docs.github.com/en/actions/using-jobs/using-concurrency

Update

This is no longer valid, GitHub Actions has improved this experience since. Check out the alternative answer first.

Old answer

Like we had "There's an app for that!", now it's "There's an Action for that!":

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Cancel Previous Runs
        uses: styfle/cancel-workflow-action@0.8.0
        with:
          access_token: ${{ github.token }}
      #- name: Run Tests
      #  uses: actions/setup-node@v1
      #  run: node test.js
      # ... etc

https://github.com/styfle/cancel-workflow-action

You will also want to make sure you account for having multiple workflows in the same repository so that you only cancel in-progress runs of the same workflow.

Snippet from the Using concurrency GitHub docs:

concurrency: 
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Full, working example (Source):

name: CI with in-progress cancellations

on:
  pull_request:
    branches: [ main ]
  workflow_dispatch:

# This is what will cancel the workflow
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Print concurrency group
        run: echo '${{ github.workflow }}-${{ github.ref }}'
      - name: Sleep 15s
        run: sleep 15s
Related