Blob Blame Raw
# -*- coding: utf-8 -*-

"""
 (c) 2016 - Copyright Red Hat Inc

 Authors:
   Lubomír Sedlář <lubomir.sedlar@gmail.com>
   Farhaan Bukhsh <farhaan.bukhsh@gmail.com>
   Pierre-Yves Chibon <pingou@pingoured.fr>

"""

from __future__ import unicode_literals, absolute_import

# pylint: disable=too-many-locals
import logging
import time
import pagure.exceptions
import pagure.lib.query

from pagure.config import config as pagure_config

_log = logging.getLogger(__name__)

BUILD_STATS = {
    "SUCCESS": ("Build #%s successful", pagure_config["FLAG_SUCCESS"], 100),
    "FAILURE": ("Build #%s failed", pagure_config["FLAG_FAILURE"], 0),
    "ABORTED": ("Build #%s aborted", "error", 0),
    "BUILDING": ("Build #%s in progress", pagure_config["FLAG_PENDING"], 0),
}


def process_jenkins_build(session, project, build_id, iteration=0):
    """  Gets the build info from jenkins and flags that particular
    pull-request.
    """
    import jenkins

    # This import is needed as pagure.lib relies on Project.ci_hook to be
    # defined and accessible and this happens in pagure.hooks.pagure_ci
    from pagure.hooks import pagure_ci  # noqa: E402,F401

    # Jenkins Base URL
    _log.info("Querying jenkins at: %s", project.ci_hook.ci_url)
    jenk = jenkins.Jenkins(
        project.ci_hook.ci_url,
        username=project.ci_hook.ci_username or None,
        password=project.ci_hook.ci_password or None,
    )
    jenkins_name = project.ci_hook.ci_job
    _log.info(
        "Querying jenkins for project: %s, build: %s", jenkins_name, build_id
    )
    try:
        build_info = jenk.get_build_info(jenkins_name, build_id)
    except jenkins.NotFoundException:
        _log.debug("Could not find build %s at: %s", build_id, jenkins_name)
        raise pagure.exceptions.PagureException(
            "Could not find build %s at: %s" % (build_id, jenkins_name)
        )

    if build_info.get("building") is True:
        if iteration < 5:
            _log.info("Build is still going, let's wait a sec and try again")
            time.sleep(1)
            return process_jenkins_build(
                session, project, build_id, iteration=iteration + 1
            )
        _log.info(
            "We've been waiting for 5 seconds and the build is still "
            "not finished, so let's keep going."
        )

    result = build_info.get("result")
    if not result and build_info.get("building") is True:
        result = "BUILDING"

    _log.info("Result from jenkins: %s", result)
    url = build_info["url"]
    _log.info("URL from jenkins: %s", url)

    pr_id = None
    for action in build_info["actions"]:
        for cause in action.get("causes", []):
            try:
                pr_id = int(cause["note"])
            except (KeyError, ValueError):
                continue

    if not pr_id:
        raise pagure.exceptions.NoCorrespondingPR("No corresponding PR found")

    if not result or result not in BUILD_STATS:
        raise pagure.exceptions.PagureException(
            "Unknown build status: %s" % result
        )

    request = pagure.lib.query.search_pull_requests(
        session, project_id=project.id, requestid=pr_id
    )

    if not request:
        raise pagure.exceptions.PagureException("Request not found")

    comment, state, percent = BUILD_STATS[result]
    comment = comment % build_id
    # Adding build ID to the CI type
    username = "%s" % project.ci_hook.ci_type
    if request.commit_stop:
        comment += " (commit: %s)" % (request.commit_stop[:8])

    uid = None
    for flag in request.flags:
        if (
            flag.status == pagure_config["FLAG_PENDING"]
            and flag.username == username
        ):
            uid = flag.uid
            break

    _log.info("Flag's UID: %s", uid)
    pagure.lib.query.add_pull_request_flag(
        session,
        request=request,
        username=username,
        percent=percent,
        comment=comment,
        url=url,
        status=state,
        uid=uid,
        user=project.user.username,
        token=None,
    )
    session.commit()


def trigger_jenkins_build(
    project_path,
    url,
    job,
    token,
    branch,
    branch_to,
    cause,
    ci_username=None,
    ci_password=None,
):
    """ Trigger a build on a jenkins instance."""
    try:
        import jenkins
    except ImportError:
        _log.error("Pagure-CI: Failed to load the jenkins module, bailing")
        return

    _log.info("Jenkins CI")

    repo = "%s/%s" % (pagure_config["GIT_URL_GIT"].rstrip("/"), project_path)

    data = {
        "cause": cause,
        "REPO": repo,
        "BRANCH": branch,
        "BRANCH_TO": branch_to,
    }

    server = jenkins.Jenkins(
        url, username=ci_username or None, password=ci_password or None
    )
    _log.info(
        "Pagure-CI: Triggering at: %s for: %s - data: %s", url, job, data
    )
    try:
        server.build_job(name=job, parameters=data, token=token)
        _log.info("Pagure-CI: Build triggered")
    except Exception as err:
        _log.info("Pagure-CI:An error occured: %s", err)