Reputation: 1557
For my project, I have a pretty long github action that is triggered when a new pull request is created. These are the triggers I use:
on:
pull_request:
types: [opened, ready_for_review, labeled]
This action is defined as a "status check" requirement for my pull request, to make sure that the action is running fine before allowing someone to merge his PR.
But, my PRs also require to be up to date with develop
before being allowed to merge anything.
So the scenario I encounter frequently is this:
My issue with that scenario, is that, even though my github action run is now completely invalid/obsolete (because the content of the branch changed), the action itself is still running. I need to manually go to the actions tab and cancel this run.
Is there a way to automatically cancel this run, if the content of the branch or the PR changed ?
Upvotes: 5
Views: 4850
Reputation: 51
I recently came across this exact issue and the solution was to create an action that listens for pushes on the target branch and then uses the API to cancel anything running that points the same branch.
name: Cancel out of date workflow runs
on:
push:
branches:
- master
jobs:
cancel-pr-workflows:
runs-on: ubuntu-20.04
steps:
- uses: octokit/[email protected]
id: get_active_workflows
with:
route: GET /repos/{repository}/actions/runs?status=in_progress&event=pull_request
repository: ${{ github.repository }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Extract workflow ids
id: extract_workflow_ids
run: |
current_branch=${GITHUB_REF##*/}
# loop thru the workflows found & filter out ones that are not on PRs pointing to this branch
# or do not match "Automated tests"
workflow_ids=$(echo '${{ steps.get_active_workflows.outputs.data }}' | \
jq '.workflow_runs | map({id, name, baseBranch: .pull_requests[0].base.ref})' | \
jq 'map(select(.name == "Automated tests" and .baseBranch == "'$current_branch'")) | map(.id)' | \
jq 'join(",")')
# strip the wrapping quote marks before passing to next step
echo 'WORKFLOW_IDS='$(echo $workflow_ids | tr -d '"') >> $GITHUB_ENV
- name: Cancel active workflows
run: |
for i in ${WORKFLOW_IDS//,/ }
do
echo "Cancelling workflow with id: $i"
# use curl here as I have no idea how to use a github action in a loop
curl \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/actions/runs/$i/cancel
done
Upvotes: 5
Reputation: 22970
As CI job ares executed in a different github runners, there is no direct way to automatically cancel previous CI jobs natively with Github Actions.
However, there as some workarounds to help you resolve your issue:
1 - use the Github API to cancel workflow runs directly (which might not be trivial to automate in your specific case).
2 - use a cancel-workflow-action, that will cancel any previous runs that are not completed
for a given workflow.
3 - use a skip-duplicate-actions, to skip duplicate workflow-runs after merges, pull requests or similar.
4 - use the native concurrency
field to ensure that only a single job or workflow using the same concurrency group will run at a time.
Upvotes: 8