Skip to content

Commit

Permalink
Add script and workflow that is able to "cancel all CI runs for a spe…
Browse files Browse the repository at this point in the history
…cific PR/commit" (project-chip#35975)

* Add a script and workflow for 'cancel running workflows'.

The intent for this is to allow failing workflows to trigger
a "cancel all the rest of the runs" for a current PR.

* Restyle

* Rename parameter to make it clear it is a github token

* Update scripts/tools/cancel_workflows_for_pr.py

Co-authored-by: C Freeman <[email protected]>

---------

Co-authored-by: Andrei Litvin <[email protected]>
Co-authored-by: C Freeman <[email protected]>
  • Loading branch information
3 people authored and yyzhong-g committed Dec 11, 2024
1 parent f8859e1 commit 3f2f248
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/cancel_workflows_for_pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright (c) 2024 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Cancel workflow on PR
on:
workflow_dispatch:
inputs:
pull_request_id:
description: 'PR number to consider'
required: true
type: number
commit_sha:
description: 'Cancel runs for this specific SHA'
required: true
type: string

jobs:
cancel_workflow:
name: Report on pull requests

runs-on: ubuntu-latest

# Don't run on forked repos
if: github.repository_owner == 'project-chip'

steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Setup pip modules we use
run: |
pip install \
click \
coloredlogs \
pygithub \
&& echo "DONE installint python prerequisites"
- name: Cancel runs
run: |
scripts/tools/cancel_workflows_for_pr.py \
--pull-request ${{ inputs.pull_request_id }} \
--commit-sha "${{ inputs.commit_sha }}" \
--gh-api-token "${{ secrets.GITHUB_TOKEN }}"
87 changes: 87 additions & 0 deletions scripts/tools/cancel_workflows_for_pr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import logging

import click
import coloredlogs
from github import Github

__LOG_LEVELS__ = {
"debug": logging.DEBUG,
"info": logging.INFO,
"warn": logging.WARN,
"fatal": logging.FATAL,
}

REPOSITORY = "project-chip/connectedhomeip"


class Canceller:
def __init__(self, token):
self.api = Github(token)
self.repo = self.api.get_repo(REPOSITORY)

def cancel_all_runs(self, pr_number, commit_sha, dry_run):
pr = self.repo.get_pull(pr_number)
logging.info("Examining PR '%s'", pr.title)
for commit in pr.get_commits():
if commit.sha != commit_sha:
logging.info("Skipping SHA '%s' as it was not selected", commit.sha)
continue

for check_suite in commit.get_check_suites():
for run in check_suite.get_check_runs():
if run.status in {"in_progress", "queued"}:
if dry_run:
logging.warning("DRY RUN: Will not stop run %s", run.name)
else:
logging.warning("Stopping run %s", run.name)
self.repo.get_workflow_run(run.id).cancel()
else:
logging.info("Skip over run %s (%s)", run.name, run.status)


@click.command()
@click.option(
"--log-level",
default="INFO",
type=click.Choice(list(__LOG_LEVELS__.keys()), case_sensitive=False),
help="Determines the verbosity of script output.",
)
@click.option("--pull-request", type=int, help="Pull request number to consider")
@click.option("--commit-sha", help="Commit to look at when cancelling pull requests")
@click.option("--gh-api-token", help="Github token to use")
@click.option("--token-file", help="Read github token from the given file")
@click.option("--dry-run", default=False, is_flag=True, help="Actually cancel or not")
def main(log_level, pull_request, commit_sha, gh_api_token, token_file, dry_run):
coloredlogs.install(
level=__LOG_LEVELS__[log_level], fmt="%(asctime)s %(levelname)-7s %(message)s"
)

if gh_api_token:
gh_token = gh_api_token
elif token_file:
gh_token = open(token_file, "rt").read().strip()
else:
raise Exception("Require a --gh-api-token or --token-file to access github")

Canceller(gh_token).cancel_all_runs(pull_request, commit_sha, dry_run)


if __name__ == "__main__":
main()

0 comments on commit 3f2f248

Please sign in to comment.