def pull_request():
    """
    Process a `PullRequestEvent`_ from Github.

    .. _PullRequestEvent: https://developer.github.com/v3/activity/events/types/#pullrequestevent
    """
    # TODO: We need to untangle this, there are **four** `return`s in
    #       this function!
    msg = "Incoming GitHub PR request: {}".format(request.data)
    print(msg, file=sys.stderr)

    try:
        event = request.get_json()
    except ValueError:
        msg = "Invalid JSON from Github: {data}".format(data=request.data)
        print(msg, file=sys.stderr)
        raise ValueError(msg)
    sentry.client.extra_context({"event": event})

    if "pull_request" not in event and "hook" in event and "zen" in event:
        # this is a ping
        repo = event.get("repository", {}).get("full_name")
        print("ping from {repo}".format(repo=repo), file=sys.stderr)
        return "PONG"

    pr = event["pull_request"]
    pr_number = pr['number']
    repo = pr["base"]["repo"]["full_name"].decode('utf-8')
    action = event["action"]
    # `synchronize` action is when a new commit is made for the PR
    ignored_actions = set(("labeled", "synchronize"))
    if action in ignored_actions:
        msg = "Ignoring {action} events from github".format(action=action)
        print(msg, file=sys.stderr)
        return msg, 200

    pr_activity = "{}/pull/{} {}".format(repo, pr_number, action)
    if action == "opened":
        msg = "{}, processing...".format(pr_activity)
        print(msg, file=sys.stderr)
        result = pull_request_opened.delay(pr,
                                           wsgi_environ=minimal_wsgi_environ())
    elif action == "closed":
        msg = "{}, processing...".format(pr_activity)
        print(msg, file=sys.stderr)
        result = pull_request_closed.delay(pr)
    else:
        msg = "{}, rejecting with `400 Bad request`".format(pr_activity)
        print(msg, file=sys.stderr)
        # TODO: Is this really kosher? We should do no-op, not reject
        #       the request!
        return "Don't know how to handle this.", 400

    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    print("Job status URL: {}".format(status_url), file=sys.stderr)

    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp
def process_pr():
    if request.method == "GET":
        return render_template("github_process_pr.html")
    repo = request.form.get("repo", "")
    if not repo:
        resp = jsonify({"error": "repo required"})
        resp.status_code = 400
        return resp
    num = request.form.get("number")
    if not num:
        resp = jsonify({"error": "num required"})
        resp.status_code = 400
        return resp
    num = int(num)
    pr_resp = github.get("/repos/{repo}/pulls/{num}".format(repo=repo, num=num))
    if not pr_resp.ok:
        resp = jsonify({"error": pr_resp.text})
        resp.status_code = 400
        return resp

    pr = pr_resp.json()
    result = pull_request_opened.delay(
        pr, ignore_internal=False, check_contractor=False,
        wsgi_environ=minimal_wsgi_environ(),
    )
    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp
Exemple #3
0
def process_pr():
    """
    Process (or re-process) a pull request.

    Normally, when a pull request is opened, we check to see if the author is
    an edX employee, or a contractor working for edX. If so, we don't process
    the pull request normally -- either it is skipped, or we add an informative
    comment without making a JIRA ticket. Using this endpoint will skip those
    checks. We will make a JIRA ticket if one doesn't already exist, without
    checking to see if the author is special.
    """
    repo = request.form.get("repo", "")
    if not repo:
        resp = jsonify({"error": "Pull request repo required"})
        resp.status_code = 400
        return resp
    num = request.form.get("number")
    if not num:
        resp = jsonify({"error": "Pull request number required"})
        resp.status_code = 400
        return resp
    num = int(num)
    pr_resp = github.get("/repos/{repo}/pulls/{num}".format(repo=repo,
                                                            num=num))
    if not pr_resp.ok:
        resp = jsonify({"error": pr_resp.text})
        resp.status_code = 400
        return resp

    repo_resp = github.get("/repos/{repo}".format(repo=repo))
    repo_json = repo_resp.json()
    if not repo_json["permissions"]["admin"]:
        resp = jsonify({
            "error":
            "This bot does not have permissions for repo '{}'.\n\nPlease manually make an OSPR ticket on JIRA."
            .format(repo)
        })
        resp.status_code = 400
        return resp

    pr = pr_resp.json()
    result = pull_request_opened.delay(
        pr,
        ignore_internal=False,
        check_contractor=False,
        wsgi_environ=minimal_wsgi_environ(),
    )
    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp
Exemple #4
0
def pull_request():
    """
    Process a `PullRequestEvent`_ from Github.

    .. _PullRequestEvent: https://developer.github.com/v3/activity/events/types/#pullrequestevent
    """
    try:
        event = request.get_json()
    except ValueError:
        raise ValueError(
            "Invalid JSON from Github: {data}".format(data=request.data))
    sentry.client.extra_context({"event": event})

    if "pull_request" not in event and "hook" in event and "zen" in event:
        # this is a ping
        repo = event.get("repository", {}).get("full_name")
        print("ping from {repo}".format(repo=repo), file=sys.stderr)
        return "PONG"

    pr = event["pull_request"]
    repo = pr["base"]["repo"]["full_name"].decode('utf-8')
    action = event["action"]
    ignored_actions = set(("labeled", "synchronize"))
    if action in ignored_actions:
        msg = "Ignoring {action} events from github".format(action=action)
        return msg, 200

    if action == "opened":
        result = pull_request_opened.delay(pr,
                                           wsgi_environ=minimal_wsgi_environ())
    elif action == "closed":
        result = pull_request_closed.delay(pr)
    else:
        print(
            "Received {action} event on PR #{num} against {repo}, don't know how to handle it"
            .format(
                action=event["action"],
                repo=pr["base"]["repo"]["full_name"].decode('utf-8'),
                num=pr["number"],
            ),
            file=sys.stderr)
        return "Don't know how to handle this.", 400

    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp
def process_pr():
    """
    Process (or re-process) a pull request.

    Normally, when a pull request is opened, we check to see if the author is
    an edX employee, or a contractor working for edX. If so, we don't process
    the pull request normally -- either it is skipped, or we add an informative
    comment without making a JIRA ticket. Using this endpoint will skip those
    checks. We will make a JIRA ticket if one doesn't already exist, without
    checking to see if the author is special.
    """
    repo = request.form.get("repo", "")
    if not repo:
        resp = jsonify({"error": "Pull request repo required"})
        resp.status_code = 400
        return resp
    num = request.form.get("number")
    if not num:
        resp = jsonify({"error": "Pull request number required"})
        resp.status_code = 400
        return resp
    num = int(num)
    pr_resp = github.get("/repos/{repo}/pulls/{num}".format(repo=repo, num=num))
    if not pr_resp.ok:
        resp = jsonify({"error": pr_resp.text})
        resp.status_code = 400
        return resp

    repo_resp = github.get("/repos/{repo}".format(repo=repo))
    repo_json = repo_resp.json()
    if not repo_json["permissions"]["admin"]:
        resp = jsonify({
            "error": "This bot does not have permissions for repo '{}'.\n\nPlease manually make an OSPR ticket on JIRA.".format(repo)
        })
        resp.status_code = 400
        return resp

    pr = pr_resp.json()
    result = pull_request_opened.delay(
        pr, ignore_internal=False, check_contractor=False,
        wsgi_environ=minimal_wsgi_environ(),
    )
    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp
def pull_request():
    """
    Process a `PullRequestEvent`_ from Github.

    .. _PullRequestEvent: https://developer.github.com/v3/activity/events/types/#pullrequestevent
    """
    try:
        event = request.get_json()
    except ValueError:
        raise ValueError("Invalid JSON from Github: {data}".format(data=request.data))
    sentry.client.extra_context({"event": event})

    if "pull_request" not in event and "hook" in event and "zen" in event:
        # this is a ping
        repo = event.get("repository", {}).get("full_name")
        print("ping from {repo}".format(repo=repo), file=sys.stderr)
        return "PONG"

    pr = event["pull_request"]
    repo = pr["base"]["repo"]["full_name"].decode('utf-8')
    action = event["action"]
    ignored_actions = set(("labeled", "synchronize"))
    if action in ignored_actions:
        msg = "Ignoring {action} events from github".format(action=action)
        return msg, 200

    if action == "opened":
        result = pull_request_opened.delay(pr, wsgi_environ=minimal_wsgi_environ())
    elif action == "closed":
        result = pull_request_closed.delay(pr)
    else:
        print(
            "Received {action} event on PR #{num} against {repo}, don't know how to handle it".format(
                action=event["action"],
                repo=pr["base"]["repo"]["full_name"].decode('utf-8'),
                num=pr["number"],
            ),
            file=sys.stderr
        )
        return "Don't know how to handle this.", 400

    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp
def process_pr():
    if request.method == "GET":
        return render_template("github_process_pr.html")
    repo = request.form.get("repo", "")
    if not repo:
        resp = jsonify({"error": "Pull request repo required"})
        resp.status_code = 400
        return resp
    num = request.form.get("number")
    if not num:
        resp = jsonify({"error": "Pull request number required"})
        resp.status_code = 400
        return resp
    num = int(num)
    pr_resp = github.get("/repos/{repo}/pulls/{num}".format(repo=repo, num=num))
    if not pr_resp.ok:
        resp = jsonify({"error": pr_resp.text})
        resp.status_code = 400
        return resp

    repo_resp = github.get("/repos/{repo}".format(repo=repo))
    repo_json = repo_resp.json()
    if not repo_json["permissions"]["admin"]:
        resp = jsonify({
            "error": "This bot does not have permissions for repo '{}'.\n\nPlease manually make an OSPR ticket on JIRA.".format(repo)
        })
        resp.status_code = 400
        return resp

    pr = pr_resp.json()
    result = pull_request_opened.delay(
        pr, ignore_internal=False, check_contractor=False,
        wsgi_environ=minimal_wsgi_environ(),
    )
    status_url = url_for("tasks.status", task_id=result.id, _external=True)
    resp = jsonify({"message": "queued", "status_url": status_url})
    resp.status_code = 202
    resp.headers["Location"] = status_url
    return resp