def check(self, app, sha, config): token = current_app.config['GITHUB_TOKEN'] if not token: raise CheckFailed('GITHUB_TOKEN is not set') api_root = (config.get('api_root') or current_app.config['GITHUB_API_ROOT']).rstrip('/') all_contexts = set(config.get('contexts') or []) contexts = all_contexts.copy() repo = config['repo'] url = '{api_root}/repos/{repo}/commits/{ref}/check-runs'.format( api_root=api_root, repo=repo, ref=sha, ) headers = { 'Accept': 'application/vnd.github.antiope-preview+json', 'Authorization': 'token {}'.format(token), } resp = http.get(url, headers=headers) check_runs_dict = resp.json() if not check_runs_dict or not check_runs_dict.get('total_count'): raise CheckFailed('No contexts were present in GitHub') valid_contexts = set() for check_run in check_runs_dict.get('check_runs', []): check_name = check_run['name'] if all_contexts and check_name not in all_contexts: continue if check_run['conclusion'] == 'success': valid_contexts.add(check_name) try: contexts.remove(check_name) except KeyError: pass if check_name in valid_contexts: continue if contexts and check_name not in contexts: continue check_run['description'] = check_run['output']['title'] if check_run['status'] in ['queued', 'in_progress']: raise CheckPending(ERR_CHECK.format(**check_run)) elif check_run['conclusion'] != 'success': raise CheckFailed(ERR_CHECK.format(**check_run)) contexts.remove(check_name) if contexts: raise CheckFailed(ERR_MISSING_CONTEXT.format( iter(contexts).next()))
def check(self, app, sha, config): token = current_app.config['GITHUB_TOKEN'] if not token: raise CheckFailed('GITHUB_TOKEN is not set') api_root = (config.get('api_root') or current_app.config['GITHUB_API_ROOT']).rstrip('/') all_contexts = set(config.get('contexts') or []) contexts = all_contexts.copy() repo = config['repo'] url = '{api_root}/repos/{repo}/commits/{ref}/statuses'.format( api_root=api_root, repo=repo, ref=sha, ) headers = { 'Accepts': 'application/json', 'Authorization': 'token {}'.format(token), } resp = http.get(url, headers=headers) context_list = resp.json() if not context_list: raise CheckFailed('No contexts were present in GitHub') valid_contexts = set() for data in context_list: if all_contexts and data['context'] not in all_contexts: continue if data['state'] == 'success': valid_contexts.add(data['context']) try: contexts.remove(data['context']) except KeyError: pass if data['context'] in valid_contexts: continue if contexts and data['context'] not in contexts: continue if data['state'] == 'pending': raise CheckPending(ERR_CHECK.format(**data)) elif data['state'] != 'success': raise CheckFailed(ERR_CHECK.format(**data)) contexts.remove(data['context']) if contexts: raise CheckFailed(ERR_MISSING_CONTEXT.format( iter(contexts).next()))
def check(self, app, sha, config): token = current_app.config["GITHUB_TOKEN"] if not token: raise CheckFailed("GITHUB_TOKEN is not set") api_root = (config.get("api_root") or current_app.config["GITHUB_API_ROOT"]).rstrip("/") all_contexts = set(config.get("contexts") or []) contexts = all_contexts.copy() repo = config["repo"] url = f"{api_root}/repos/{repo}/commits/{sha}/statuses" headers = { "Accepts": "application/json", "Authorization": f"token {token}" } resp = http.get(url, headers=headers) context_list = resp.json() if not context_list: raise CheckFailed( "No contexts were present in GitHub. " "This means that no statuses, like CI results, " "were found for the commit. You may want to wait a bit, " "or failing that, deploy a new commit.") valid_contexts = set() for data in context_list: if all_contexts and data["context"] not in all_contexts: continue if data["state"] == "success": valid_contexts.add(data["context"]) try: contexts.remove(data["context"]) except KeyError: pass if data["context"] in valid_contexts: continue if contexts and data["context"] not in contexts: continue if data["state"] == "pending": raise CheckPending(ERR_CHECK.format(**data)) elif data["state"] != "success": raise CheckFailed(ERR_CHECK.format(**data)) contexts.remove(data["context"]) if contexts: raise CheckFailed(ERR_MISSING_CONTEXT.format(next(iter(contexts))))
def check(self, app, sha, config): token = current_app.config["GITHUB_TOKEN"] if not token: raise CheckFailed("GITHUB_TOKEN is not set") api_root = (config.get("api_root") or current_app.config["GITHUB_API_ROOT"]).rstrip("/") all_contexts = set(config.get("contexts") or []) contexts = all_contexts.copy() repo = config["repo"] url = f"{api_root}/repos/{repo}/commits/{sha}/check-runs" headers = { "Accept": "application/vnd.github.antiope-preview+json", "Authorization": f"token {token}", } resp = http.get(url, headers=headers) check_runs_dict = resp.json() if not check_runs_dict or not check_runs_dict.get("total_count"): raise CheckFailed("No contexts were present in GitHub") valid_contexts = set() for check_run in check_runs_dict.get("check_runs", []): check_name = check_run["name"] if all_contexts and check_name not in all_contexts: continue if check_run["conclusion"] == "success": valid_contexts.add(check_name) try: contexts.remove(check_name) except KeyError: pass if check_name in valid_contexts: continue if contexts and check_name not in contexts: continue check_run["description"] = check_run["output"]["title"] if check_run["status"] in ["queued", "in_progress"]: raise CheckPending(ERR_CHECK.format(**check_run)) elif check_run["conclusion"] != "success": raise CheckFailed(ERR_CHECK.format(**check_run)) contexts.remove(check_name) if contexts: raise CheckFailed(ERR_MISSING_CONTEXT.format(next(iter(contexts))))
def check(self, app, sha, config): token = current_app.config['GITHUB_TOKEN'] if not token: raise CheckFailed('GITHUB_TOKEN is not set') api_root = (config.get('api_root') or current_app.config['GITHUB_API_ROOT']).rstrip('/') contexts = set(config['contexts']) repo = config['repo'] url = '{api_root}/repos/{repo}/commits/{ref}/statuses'.format( api_root=api_root, repo=repo, ref=sha, ) headers = { 'Accepts': 'application/json', 'Authorization': 'token {}'.format(token), } resp = http.get(url, headers=headers) for data in resp.json(): if data['context'] not in contexts: continue if data['state'] == 'pending': raise CheckPending( ERR_CHECK.format(data['context'], data['state'])) elif data['state'] != 'success': raise CheckFailed( ERR_CHECK.format(data['context'], data['state'])) contexts.remove(data['context']) if contexts: raise CheckFailed(ERR_MISSING_CONTEXT.format( iter(contexts).next()))
def check(self, app, sha, config): """Check build status Arguments: app {str} -- optional sha {str} -- required, commit SHA of build to check config {dict} -- optional dict to pass additional args """ api_root = ( f"https://cloudbuild.googleapis.com/v1/projects/{config['project']}/builds" ) oauth_token = config.get("oauth_token") if oauth_token is None: oauth_token = (check_output( ["gcloud", "auth", "print-access-token"]).rstrip().decode("utf-8")) params = {} image_name = config.get("image_name") if image_name is None: # Note: this doesn't work with the new "Cloud Build GitHub App" way of checking out repositories. params[ "filter"] = f'sourceProvenance.resolvedRepoSource.commitSha="{sha}"' else: # Should work for both cases ("Cloud Build GitHub App" and "GitHub (mirrored)"). # This should be working fine even if "images" contains multiple entries. params["filter"] = f'images="{image_name}:{sha}"' headers = { "Accepts": "application/json", "Authorization": f"Bearer {oauth_token}", } resp = http.get(api_root, headers=headers, params=params) if resp.status_code != 200: if resp.status_code == 503: raise CheckPending("Temporary Google failure") raise CheckFailed( f"[ ERROR {resp.status_code} ]\tNo data for build present") build_data = resp.json() if "builds" not in build_data: raise CheckPending("Build has not started yet.") build_id = build_data["builds"][0]["id"] build_status = build_data["builds"][0]["status"] build_url = build_data["builds"][0]["logUrl"] build_logs = build_data["builds"][0].get("logsBucket") gcloudstatus = { "STATUS_UNKNOWN": "Status of the build is unknown.", "QUEUED": "Build or step is queued; work has not yet begun.", "WORKING": "Build or step is being executed.", "SUCCESS": "Build or step finished successfully.", "FAILURE": "Build or step failed to complete successfully.", "INTERNAL_ERROR": "Build or step failed due to an internal cause.", "TIMEOUT": "Build or step took longer than was allowed.", "CANCELLED": "Build or step was canceled by a user.", } if build_status == "FAILURE": if build_logs: build_logtext = f"https://storage.googleapis.com/{build_logs[5:].rstrip('/')}/log-{build_id}.txt" logs_text = http.get(build_logtext, headers=headers).text else: logs_text = "<unknown>" raise CheckFailed( f"[ {build_status} ]\t{gcloudstatus['FAILURE']}\nSee details: {build_url}\nPrinting log...\n\n\n{logs_text}" ) if build_status in ["QUEUED", "WORKING"]: raise CheckPending( f"[ {build_status} ]\t{gcloudstatus[build_status]}\nSee details: {build_url}" ) if build_status == "SUCCESS": return raise CheckFailed( f"[ {build_status} ]\t{gcloudstatus[build_status]}\n")
def check(self, app, sha, config): """Check build status Arguments: app {str} -- optional sha {str} -- required, commit SHA of build to check config {dict} -- optional dict to pass additional args """ api_root = u"https://cloudbuild.googleapis.com/v1/projects/{}/builds".format( config["project"] ) oauth_command = "gcloud auth application-default print-access-token" oauth_token = config.get("oauth_token") if oauth_token is None: oauth_token = subprocess.check_output(shlex.split(oauth_command)).rstrip() params = { "filter": u'sourceProvenance.resolvedRepoSource.commitSha="{}"'.format(sha) } headers = { "Accepts": "application/json", u"Authorization": "Bearer {}".format(oauth_token), } resp = http.get(api_root, headers=headers, params=params) if resp.status_code != 200: raise CheckFailed( u"[ ERROR {} ]\tNo data for build present".format(resp.status_code) ) build_data = resp.json() if "builds" not in build_data: raise CheckPending("Build has not started yet.") build_id = build_data["builds"][0]["id"] build_status = build_data["builds"][0]["status"] build_url = build_data["builds"][0]["logUrl"] build_logs = build_data["builds"][0]["logsBucket"] gcloudstatus = { "STATUS_UNKNOWN": "Status of the build is unknown.", "QUEUED": "Build or step is queued; work has not yet begun.", "WORKING": "Build or step is being executed.", "SUCCESS": "Build or step finished successfully.", "FAILURE": "Build or step failed to complete successfully.", "INTERNAL_ERROR": "Build or step failed due to an internal cause.", "TIMEOUT": "Build or step took longer than was allowed.", "CANCELLED": "Build or step was canceled by a user.", } if build_status == "FAILURE": build_logtext = u"https://storage.googleapis.com/{}/log-{}.txt".format( build_logs[5:], build_id ) log = http.get(build_logtext, headers=headers) raise CheckFailed( u"[ {} ]\t{}\nSee details: {}\nPrinting log...\n\n\n{}".format( build_status, gcloudstatus["FAILURE"], build_url, log.text ) ) if build_status in ["QUEUED", "WORKING"]: raise CheckPending( u"[ {} ]\t{}\nSee details: {}".format( build_status, gcloudstatus[build_status], build_url ) ) if build_status == "SUCCESS": return raise CheckFailed(u"[ {} ]\t{}\n".format(build_status, gcloudstatus[build_status]))
def check(self, app, sha, config): token = current_app.config["GITHUB_TOKEN"] if not token: raise CheckFailed("GITHUB_TOKEN is not set") api_root = (config.get("api_root") or current_app.config["GITHUB_API_ROOT"]).rstrip("/") all_contexts = set(config.get("contexts") or []) contexts = all_contexts.copy() repo = config["repo"] url = f"{api_root}/repos/{repo}/commits/{sha}/check-runs" headers = { "Accept": "application/vnd.github.antiope-preview+json", "Authorization": f"token {token}", } params = { "per_page": 100, "page": 1, } total_count = None check_runs = [] while True: resp = http.get(url, headers=headers, params=params) check_runs_dict = resp.json() if not check_runs_dict or not check_runs_dict.get("total_count"): raise CheckFailed( "No contexts were present in GitHub. " "This means that no statuses, like CI results, " "were found for the commit. You may want to wait a bit, " "or failing that, deploy a new commit.") if total_count is None: total_count = int(check_runs_dict["total_count"]) check_runs.extend(check_runs_dict.get("check_runs", [])) if params["per_page"] * params["page"] >= total_count: break else: params["page"] += 1 valid_contexts = set() for check_run in check_runs: check_name = check_run["name"] if all_contexts and check_name not in all_contexts: continue if check_run["conclusion"] == "success": valid_contexts.add(check_name) try: contexts.remove(check_name) except KeyError: pass if check_name in valid_contexts: continue if contexts and check_name not in contexts: continue check_run["description"] = check_run["output"]["title"] if check_run["status"] in ["queued", "in_progress"]: raise CheckPending(ERR_CHECK.format(**check_run)) elif check_run["conclusion"] != "success": raise CheckFailed(ERR_CHECK.format(**check_run)) contexts.remove(check_name) if contexts: raise CheckFailed(ERR_MISSING_CONTEXT.format(next(iter(contexts))))