131

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?

0

5 Answers 5

214

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

Sign up to request clarification or add additional context in comments.

2 Comments

This is a great explanation, especially because adding ${{ github.workflow}} is important when there are different workflows to consider. Since github.ref for pull requests it is refs/pull/<pr_number>/merge it is also sufficiently unique. It seems that a slightly simpler group is as effective: group: ${{ github.workflow }}-${{ github.ref }} I'm therefore curious why it was necessary for the specific logic to handle event.pull_request.number in your answer.
I would also consider changing ${{ github.ref }} to ${{ github.ref || github.run_id }} as mentioned in the GitHub docs on concurrency. This allows for arbitrary events that might not have a ref, such as workflow_dispatch, to run the workflow in their own group. So in summary from both of my comments: group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
108

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

5 Comments

Works really well. Note: concurrency is "currently in beta and subject to change" as of 05/10/2021.
what level is this at? Every example just shows it all alone... not in a full file or example. Thank you.
@EmmanuelMess In your answer you say github.head_ref whereas in your repo reference you have just github.ref just as in github.community/t/…. Which one is better?
@CsabaToth github.ref see here. head_ref "is only available when the event that triggers a workflow run is either pull_request or pull_request_target." but ref is just "The branch or tag ref that triggered the workflow run."
18

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

Comments

4

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/[email protected]
        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

1 Comment

cancel-workflow-action is deprecated in favor of concurrency.
0

My case was to run the same workflow for push and pull_request. I wanted any action running previously to stop. The same applies if an action runs before a pull_request is open.

I figured out I could set them all to one group like this..

group: ${ {github.ref} || refs/heads/{github.href} }

Now it stops any previous action even before the pull request.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.