Miiite
Miiite

Reputation: 1557

Cancel Action run, when Pull Request changes

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

Answers (2)

Ritchie
Ritchie

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

GuiFalourd
GuiFalourd

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

Related Questions