#!/usr/bin/python # 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 argparse import logging import requests import json import threading class FailedPR: def __init__(self, url, status): self.url = url self.status = status self.target_url = target_url self.created_at = created_at self.updated_at = updated_at def to_json(self): return json.dumps(self.__dict__) def get_args(): parser = argparse.ArgumentParser( description='Bootstrap repositories.') parser.add_argument( '--gh-orgs', nargs='+', default=['opentelekomcloud-docs'], help='One or more GitHub organizations to be queried for failed Pull ' 'Requests.\n' 'Default: [opentelekomcloud-docs]' ) parser.add_argument( '--gitea-orgs', nargs='+', default=['docs'], help='One or more Gitea organizations to be queried for failed Pull ' 'Requests.\n' 'Default: [docs]' ) parser.add_argument( '--gh-token', help='API Token for GitHub.' ) parser.add_argument( '--gitea-token', help='API Token for Gitea' ) parser.add_argument( '--debug', action='store_true', help='Set debug mode on.' ) parser.add_argument( '--gitea-url', default='https://gitea.eco.tsi-dev.otc-service.com/api/v1/', help='Base URL for API request.\n' 'Default: https://gitea.eco.tsi-dev.otc-service.com/api/v1/' ) parser.add_argument( '--hoster', default=['gitea', 'github'], nargs='+', help='Git hoster to be queried for failed Pull Requests.\n' 'Default: [github, gitea].' ) return(parser.parse_args()) def get_repos(url, path, headers): repositories = [] i = 1 while True: try: req_url = url + path + str(i) res = requests.request('GET', url=req_url, headers=headers) if res.json(): for repo in res.json(): repositories.append(repo) i+=1 continue else: break except Exception as e: print("An error has occured: " + str(e)) print("The request status is: " + str(res.status_code) + " | " + str(res.reason)) break return(repositories) def get_failed_gitea_commits(repositories, headers, args): failed_commits = [] pull_path = 'repos/docs/' status_path = pull_path pulls = [] for repo in repositories: try: url = args.url + pull_path + repo['name'] + '/pulls?state=open' res = requests.request('GET', url=url, headers=headers) if res.json(): for pull in res.json(): pulls.append(pull) for pull in pulls: try: url = args.url + status_path + repo['name'] + '/commits/' + pull['head']['ref'] + '/statuses?limit=1' res_sta = requests.request('GET', url=url, headers=headers) if res_sta.json(): if res_sta.json()[0]['status'] == 'failure': failed_commits.append({ 'url': pull['url'], 'status': res_sta.json()[0]['status'], 'target_url': res_sta.json()[0]['target_url'], 'created_at': pull['created_at'], 'updated_at': res_sta.json()[0]['updated_at'] }) continue else: continue except Exception as e: print("An error has occured: " + str(e)) print("The request status is: " + str(res_sta.status_code) + " | " + str(res_sta.reason)) break continue else: continue except Exception as e: print("An error has occured: " + str(e)) print("The request status is: " + str(res.status_code) + " | " + str(res.reason)) break return(failed_commits) def get_github_repos(url, headers, gh_org): repositories = [] i = 1 while True: try: req_url = url + 'orgs/' + gh_org + '/repos?page=' + str(i) res = requests.request('GET', url=req_url, headers=headers) if res.json(): for repo in res.json(): repositories.append(repo) i+=1 continue else: break except Exception as e: print("An error has occured: " + str(e)) print("The request status is: " + str(res.status_code) + " | " + str(res.reason)) break return(repositories) def get_github_prs(url, headers, gh_org, repo): pullrequests = [] i = 1 while True: try: req_url = url + 'repos/' + gh_org + '/' + repo + '/pulls?state=open&page=' + str(i) res = requests.request('GET', url=req_url, headers=headers) if res.json(): for pr in res.json(): pullrequests.append(pr) i+=1 continue else: break except Exception as e: print("An error has occured: " + str(e)) print("The request status is: " + str(res.status_code) + " | " + str(res.reason)) break return(pullrequests) def get_failed_gh_commits(pull, url, gh_org, repo, headers): failed_commits = [] try: req_url = url + 'repos/' + gh_org + '/' + repo['name'] + '/commits/' + pull['head']['sha'] + '/check-runs' res_sta = requests.request('GET', url=req_url, headers=headers) if res_sta.json(): if len(res_sta.json()['check_runs']) != 0: if res_sta.json()['check_runs'][0]['conclusion'] == 'failure': o = FailedPR( url=pull['html_url'], status=res_sta.json()['check_runs'][0]['conclusion'], target_url=res_sta.json()['check_runs'][0]['details_url'], created_at=pull['created_at'], updated_at=res_sta.json()['check_runs'][0]['completed_at'] ) failed_commits.append(o) else: o = FailedPR( url=pull['html_url'], status='', target_url='', created_at=pull['created_at'], updated_at=res_sta.json()['check_runs'][0]['completed_at'] ) failed_commits.append(o) except Exception as e: print("An error has occured: " + str(e)) print("The request status is: " + str(res_sta.status_code) + " | " + str(res_sta.reason)) print(json.dumps(res_sta.json())) exit() return(failed_commits) def main(): args = get_args() failed_commits = [] if args.debug: logging.basicConfig(level=logging.DEBUG) for h in args.hoster: if h == 'gitea': repo_path = 'orgs/docs/repos?limit=50&page=' headers = {} headers['accept'] = 'application/json' if not args.gitea_token: raise Exception('Please, provide Gitea Token as argument.') headers['Authorization'] = 'token ' + args.gitea_token repositories = get_repos(url=args.gitea_url, path=repo_path, headers=headers) commits = get_failed_gitea_commits(repositories=repositories, headers=headers, args=args) failed_commits.extend(commits) elif h == 'github': url = 'https://api.github.com/' headers = {} headers['accept'] = 'application/json' if not args.gh_token: raise Exception('Please, provide GitHub Token as argument.') headers['Authorization'] = 'Bearer ' + args.gh_token for org in args.gh_orgs: repos = get_github_repos(url=url, headers=headers, gh_org=org) for repo in repos: pulls = get_github_prs(url=url, headers=headers, gh_org=org, repo=repo['name']) if pulls: for pull in pulls: commits = get_failed_gh_commits( pull=pull, url=url, gh_org=org, repo=repo, headers=headers) failed_commits.extend(commits) print(json.dumps(failed_commits)) if __name__ == '__main__': main()