From 5cdbb39c102723d0eefe51bd0417a5437c2bffd8 Mon Sep 17 00:00:00 2001 From: Jason M Miller Date: Tue, 10 Dec 2024 08:01:26 -0700 Subject: [PATCH] Adding create_release.py script Closes #29514 --- scripts/create_release.py | 148 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100755 scripts/create_release.py diff --git a/scripts/create_release.py b/scripts/create_release.py new file mode 100755 index 000000000000..836fdef091fa --- /dev/null +++ b/scripts/create_release.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +#* This file is part of the MOOSE framework +#* https://www.mooseframework.org +#* +#* All rights reserved, see COPYRIGHT for full restrictions +#* https://github.com/idaholab/moose/blob/master/COPYRIGHT +#* +#* Licensed under LGPL 2.1, please see LICENSE for details +#* https://www.gnu.org/licenses/lgpl-2.1.html + +import sys +import os +import argparse + +try: + import requests # type: ignore # for exceptions +except ModuleNotFoundError: + print('Could not load `requests`. Please install this package.') + sys.exit(1) +try: + import github # type: ignore # for exceptions + from github import Github, Auth # type: ignore +except ModuleNotFoundError: + print('Could not load `pygithub` module. Please install the GitHub Python API module.') + sys.exit(1) + +parser = argparse.ArgumentParser(description='Output links associated with CI/CD', + epilog=f'Example usage: {os.path.basename(__file__)} ' + '-t /path/to/token' + f' github.com/idaholab/moose abc123') +# ASCII Color codes +RED = '\033[91m' +GREEN = '\033[92m' +RESET = '\033[0m' + +class GitHubAPI(): + """ handle GH calls """ + def __init__(self, github_args): + auth = Auth.Token(github_args.token) + (self.__host, self.__owner, self.__repo) = github_args.uri.split('/') + self.sha = github_args.sha + self.gh = Github(base_url=f'https://api.{self.__host}', auth=auth) + + @staticmethod + def get_merge(commit) -> str: + """ return SHA responsible for creating SHA """ + return commit.raw_data['parents'][-1]['sha'] + + def get_commbined_status(self, commit) ->str: + """ + return status dictionary of supplied commit + (only works with PR commits) + """ + return commit.get_combined_status() + + def get_repo(self) ->(object): + """ return repo object """ + try: + repo = self.gh.get_repo(f'{self.__owner}/{self.__repo}') + except github.GithubException as e: + print(e.status, e.data['message']) + sys.exit(1) + except requests.exceptions.ConnectionError as e: + print(f'Error connecting to server: {self.__host}\n\n{e}') + sys.exit(1) + return repo + + def get_commit(self, sha=None) ->object: + """ get {OWNER}/{REPO}/commits/{HASH} """ + repo = self.get_repo() + sha = sha if sha is not None else self.sha + try: + commit = repo.get_commit(sha=sha) + except github.GithubException as e: + print(e.status, e.data['message']) + sys.exit(1) + return commit + +def parse_args(argv): + """ parses arguments """ + parser.add_argument('uri', nargs='?', metavar='URI', + help='URI to GitHub repo. exp: github.com/idaholab/moose') + parser.add_argument('sha', nargs='?', metavar='SHA', + help='Povided SHA to be considered for release') + parser.add_argument('-t','--token', nargs='?', + help='Your GitHub API Token. Can either be an environment variable' + ' containing your token, or a path to a file containing your token, or ' + ' the token itself. For security purposes, ideally this should be a path' + ' to your token. To create a token, see:' + ' https://github.com/settings/tokens') + + return parser.parse_args(argv) + +def check_args(argv): + """ checks command line options """ + c_args = parse_args(argv) + + # verify all arguments are supplied + if not c_args.uri or not c_args.sha or not c_args.token: + print('ERROR: required arguments missing. Usage:\n') + parser.print_help() + sys.exit(1) + + # verify proper URI + if len(c_args.uri.split('/')) != 3: + print(f'\nSupplied URI not properly constructed: {c_args.uri}\nThe URI should contain' + ' three items separated by forward slashes.\n\n\thostname/namespace/repo\n') + sys.exit(1) + + ### determine how to handle token + # ...supplied path to token + if os.path.exists(c_args.token): + with open(c_args.token, 'r', encoding='utf-8') as t_file: + c_args.token = str(t_file.read()).strip() + # ...supplied environment variable with path to token + elif os.getenv(c_args.token, None) and os.path.exists(os.getenv(c_args.token, None)): + with open(os.getenv(c_args.token, None), 'r', encoding='utf-8') as t_file: + c_args.token = str(t_file.read()).strip() + # ...supplied environment variable with token + elif os.getenv(c_args.token, None): + c_args.token = os.getenv(c_args.token) + elif len(c_args.token) != 40: + print('WARING: supplied token is not of the correct length, and is therefor' + ' probably\nwrong. Permission errors mar occur.\n') + # ...if nothing was true, then assume argument supplied is the token + + return c_args + +def get_parent(gh, commit): + """ return commits responsible for merge """ + _sha = gh.get_merge(commit) + return gh.get_commit(_sha) + +def main(args): + """ entry point """ + gh = GitHubAPI(args) + commit = gh.get_commit() + _p = get_parent(gh, commit) + status = gh.get_commbined_status(_p) + print(f'PR: {status.state}\nGitHub: {_p.html_url}') + print(status.raw_data) + for status in status.statuses: + print(f'\t{status.state} {status.target_url} {status.context}') + #print(f'{RED}{status}{RESET}\nstatuses: {status.statuses}') + +if __name__ == '__main__': + m_args = check_args(sys.argv[1:]) + sys.exit(main(m_args))