예제 #1
0
    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()))
예제 #2
0
    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()))
예제 #3
0
    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))))
예제 #4
0
    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))))
예제 #5
0
    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()))
예제 #6
0
    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")
예제 #7
0
    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]))
예제 #8
0
    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))))