|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# |
| 3 | +# Copyright (c) 2024 Project CHIP Authors |
| 4 | +# |
| 5 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | +# you may not use this file except in compliance with the License. |
| 7 | +# You may obtain a copy of the License at |
| 8 | +# |
| 9 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +# |
| 11 | +# Unless required by applicable law or agreed to in writing, software |
| 12 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | +# See the License for the specific language governing permissions and |
| 15 | +# limitations under the License. |
| 16 | +# |
| 17 | + |
| 18 | +import logging |
| 19 | + |
| 20 | +import click |
| 21 | +import coloredlogs |
| 22 | +from github import Github |
| 23 | + |
| 24 | +__LOG_LEVELS__ = { |
| 25 | + "debug": logging.DEBUG, |
| 26 | + "info": logging.INFO, |
| 27 | + "warn": logging.WARN, |
| 28 | + "fatal": logging.FATAL, |
| 29 | +} |
| 30 | + |
| 31 | +REPOSITORY = "project-chip/connectedhomeip" |
| 32 | + |
| 33 | + |
| 34 | +class Canceller: |
| 35 | + def __init__(self, token): |
| 36 | + self.api = Github(token) |
| 37 | + self.repo = self.api.get_repo(REPOSITORY) |
| 38 | + |
| 39 | + def cancel_all_runs(self, pr_number, commit_sha, dry_run): |
| 40 | + pr = self.repo.get_pull(pr_number) |
| 41 | + logging.info("Examining PR '%s'", pr.title) |
| 42 | + for commit in pr.get_commits(): |
| 43 | + if commit.sha != commit_sha: |
| 44 | + logging.info("Skipping SHA '%s' as it was not selected", commit.sha) |
| 45 | + continue |
| 46 | + |
| 47 | + for check_suite in commit.get_check_suites(): |
| 48 | + for run in check_suite.get_check_runs(): |
| 49 | + if run.status in {"in_progress", "queued"}: |
| 50 | + if dry_run: |
| 51 | + logging.warning("DRY RUN: Will not stop run %s", run.name) |
| 52 | + else: |
| 53 | + logging.warning("Stopping run %s", run.name) |
| 54 | + self.repo.get_workflow_run(run.id).cancel() |
| 55 | + else: |
| 56 | + logging.info("Skip over run %s (%s)", run.name, run.status) |
| 57 | + |
| 58 | + |
| 59 | +@click.command() |
| 60 | +@click.option( |
| 61 | + "--log-level", |
| 62 | + default="INFO", |
| 63 | + type=click.Choice(list(__LOG_LEVELS__.keys()), case_sensitive=False), |
| 64 | + help="Determines the verbosity of script output.", |
| 65 | +) |
| 66 | +@click.option("--pull-request", type=int, help="Pull request number to consider") |
| 67 | +@click.option("--commit-sha", help="Commit to look at when cancelling pull requests") |
| 68 | +@click.option("--gh-api-token", help="Github token to use") |
| 69 | +@click.option("--token-file", help="Read github token from the given file") |
| 70 | +@click.option("--dry-run", default=False, is_flag=True, help="Actually cancel or not") |
| 71 | +def main(log_level, pull_request, commit_sha, gh_api_token, token_file, dry_run): |
| 72 | + coloredlogs.install( |
| 73 | + level=__LOG_LEVELS__[log_level], fmt="%(asctime)s %(levelname)-7s %(message)s" |
| 74 | + ) |
| 75 | + |
| 76 | + if gh_api_token: |
| 77 | + gh_token = gh_api_token |
| 78 | + elif token_file: |
| 79 | + gh_token = open(token_file, "rt").read().strip() |
| 80 | + else: |
| 81 | + raise Exception("Require a --gh-api-token or --token-file to access github") |
| 82 | + |
| 83 | + Canceller(gh_token).cancel_all_runs(pull_request, commit_sha, dry_run) |
| 84 | + |
| 85 | + |
| 86 | +if __name__ == "__main__": |
| 87 | + main() |
0 commit comments