Our workflow is configured to run when the following conditions are met:
name: '[apps] deploy'
on:
pull_request:
types:
- opened
- synchronize
- reopened
- ready_for_review
The problem I am seeing is that if the PR gets closed, the actions that have already started are allowed to continue.
As an example:

In this picture we can see that the PR was closed 19 minutes ago, but then 13 minutes ago (6 minutes later) one of the workers reported an error.
How do I ensure that the moment the PR is closed, all actions are cancelled?
I thought this is going to be a question with an obvious answer that I just overlooked, but turns out it isn't.
The most basic way to do this is using actions/github-script, e.g.
jobs:
comment:
permissions:
actions: write
contents: read
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.merged != true }}
steps:
- uses: actions/github-script@v7
with:
script: |
const workflowIds = [
'.github/workflows/deploy_review.yaml',
'.github/workflows/packages.yaml',
];
for (const workflowId of workflowIds) {
const workflowRuns = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: workflowId,
per_page: 100,
event: 'pull_request',
branch: context.payload.pull_request.head.ref,
});
const activeRuns = workflowRuns.data.workflow_runs.filter((workflowRun) => {
return workflowRun.status === 'queued' || workflowRun.status === 'in_progress';
});
for (const activeRun of activeRuns) {
await github.rest.actions.cancelWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: activeRun.id,
});
}
}
name: Cancel workflows on PR close
on:
pull_request:
types:
- closed
This workflow will be triggered when a PR is closed, and it will cancel workflows associated with the head branch.
This works, but it has a gotcha – this workflow will be queued just like any other workflow, so there are no guarantees that it will execute immediately.
Therefore, what we ended up doing is setting up a webhook that informs us of action = closed and triggers the same logic as above from the webhook handler.
I also want to mention that if you are using if: always() in your workflow, it cannot be cancelled. Consider replacing it with if: success() || failure().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With