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
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(): """ 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