def test_context_local(): responses.add(responses.GET, "https://google.com") # set up two apps with two different set of auth tokens app1 = Flask(__name__) ghbp1 = make_github_blueprint("foo1", "bar1", redirect_to="url1") app1.register_blueprint(ghbp1) ghbp1.token_getter(lambda: {"access_token": "app1"}) app2 = Flask(__name__) ghbp2 = make_github_blueprint("foo2", "bar2", redirect_to="url2") app2.register_blueprint(ghbp2) ghbp2.token_getter(lambda: {"access_token": "app2"}) # outside of a request context, referencing functions on the `github` object # will raise an exception with pytest.raises(RuntimeError): github.get("https://google.com") # inside of a request context, `github` should be a proxy to the correct # blueprint session with app1.test_request_context("/"): app1.preprocess_request() github.get("https://google.com") request = responses.calls[0].request assert request.headers["Authorization"] == "Bearer app1" with app2.test_request_context("/"): app2.preprocess_request() github.get("https://google.com") request = responses.calls[1].request assert request.headers["Authorization"] == "Bearer app2"
def logged_in(blueprint, token): from .models import User if blueprint.name == "facebook": resp = facebook.get("/me?fields=name,first_name,email") email = resp.json()["email"] f_name = resp.json()["first_name"] account_type = "facebook" elif blueprint.name == "github": user_info = github.get("/user") user_email = github.get("/user/emails") email = user_email.json()[0]["email"] f_name = user_info.json()["name"] account_type = "github" elif blueprint.name == "gitlab": resp = gitlab.get("user") email = resp.json()["email"] f_name = resp.json()["name"].split()[0] account_type = "gitlab" user = User.query.filter_by(email=email).first() if not user: user = User(email=email, f_name=f_name) user.account_type = account_type try: db.session.add(user) db.session.commit() except Exception as err: db.session.rollback() print(err) login_user(user) g.user = user flash(_("You have been logged in."), category="success")
def get_repos(): """Endpoint to get all repos and store in DB""" # Get our users repos and check user_resp = github.get("/user") resp = github.get("/user/repos") if not resp.ok: render_template('error.html', status_code=300) # Convert to readable user_resp = user_resp.json() username = user_resp['login'] resp = resp.json() # Loop and and save repos = {} for repo in resp: repos[repo['name']] = repo['git_url'] # Add/update database try: user_data = octoDB.query_user(username) if not user_data: raise Exception("Count not find user") user_data['repos'] = repos octoDB.update_user(username, user_data) except Exception as e: logging.warning(f"Something went wrong when syncing repos for {username}\nException: {e}") render_template('error.html', status_code=505) return redirect('/dashboard')
def control_panel(): """ TEAM COPPER ONLY!!! """ if not github.authorized: return redirect(url_for("github.login")) username = github.get("/user").json()['login'] resp = github.get("/user/orgs") if resp.ok: # Only Team Copper members can access the control panel all_orgs = resp.json() for org in all_orgs: if org['login'] == 'dcppc': copper_team_id = '2700235' mresp = github.get('/teams/%s/members/%s' % (copper_team_id, username)) if mresp.status_code == 204: # Business as usual return render_template("controlpanel.html") # Not in dcppc return render_template('403.html') # Could not reach Github return render_template('404.html')
def catch_all(path): if not github.authorized: return redirect(url_for("github.login")) username = github.get("/user").json()['login'] target_org = 'microsoft' static_path = app.config["RESULT_STATIC_PATH"] resp = github.get("/user/orgs") if resp.ok: all_orgs = resp.json() for org in all_orgs: if org['login'] == target_org: if (path == ''): return send_from_directory(static_path, 'index.html') elif (isdir(join(static_path, path))): return send_from_directory(join(static_path, path), 'index.html') elif (isfile(join(static_path, path))): return send_from_directory(static_path, path) else: return contents404 return contents403
def list_docs(doctype): if not github.authorized: return redirect(url_for("github.login")) username = github.get("/user").json()['login'] resp = github.get("/user/orgs") if resp.ok: all_orgs = resp.json() for org in all_orgs: if org['login'] == 'dcppc': # Business as usual search = Search(app.config["INDEX_DIR"]) results_list = search.get_list(doctype) for result in results_list: if 'created_time' in result.keys(): ct = result['created_time'] result['created_time'] = datetime.strftime( ct, "%Y-%m-%d %I:%M %p") if 'modified_time' in result.keys(): mt = result['modified_time'] result['modified_time'] = datetime.strftime( mt, "%Y-%m-%d %I:%M %p") if 'indexed_time' in result.keys(): it = result['indexed_time'] result['indexed_time'] = datetime.strftime( it, "%Y-%m-%d %I:%M %p") return jsonify(results_list) # nope return render_template('403.html')
def index(): if not github.authorized: return render_template("landing.html") else: json_username = github.get("/user").json() if 'message' in json_username.keys(): if 'API rate limit exceeded' in json_username['message']: return '<h2>Error connecting to Github!</h2> <p>Please file an issue in <a href="https://github.com/dcppc/centillion">dcppc/centillion</a></p>' username = github.get("/user").json()['login'] resp = github.get("/user/orgs") if resp.ok: # If they are in dcppc, redirect to search. # Otherwise, hit em with a 403 all_orgs = resp.json() for org in all_orgs: if org['login'] == 'dcppc': # Business as usual return redirect(url_for("search", query="", fields="")) # Not in dcppc return render_template('403.html') # Could not reach Github return render_template('404.html')
def github_login(): if not github.authorized: flash('Access denied - please try again', 'warning') return redirect(url_for("auth.login", local=1)) resp = github.get("/user") if not resp.ok: flash('Unable to access GitHub data', 'danger') return redirect(url_for("auth.login", local=1)) resp_user = resp.json() if 'email' not in resp_user or 'login' not in resp_user: flash('Invalid GitHub data format', 'danger') # print(resp_user) return redirect(url_for("auth.login", local=1)) resp_emails = github.get("/user/emails") if not resp.ok: flash('Unable to access GitHub e-mail data', 'danger') return redirect(url_for("auth.login", local=1)) for u in resp_emails.json(): if u['primary'] and u['verified']: return get_or_create_sso_user( resp_user['id'], resp_user['login'], u['email'], 'https://github.com/%s' % resp_user['login']) flash('Please verify an e-mail with GitHub', 'danger') return redirect(url_for("auth.login", local=1))
def index(): if not github.authorized: return redirect(url_for("github.login")) # Get user details resp = github.get("/user") ret = '<h2>USER DETAILS:</h2><br>' if resp.ok: ret += "You are %s on GitHub<br>" % resp.json()["login"] else: ret += 'FAILED AT GETTING USER DATA<br>' # Get user organizations ret += '<h2>ORGANIZATIONS:</h2><br>' resp = github.get("/user/orgs") if not resp.ok: ret += 'FAILED AT GETTING USERORG DATA<br>' else: u_orgs = resp.json() ret += "<pre>%s</pre><br>" % json.dumps(u_orgs, indent=4) # Check if user is part of Amedia for org in u_orgs: if org.get('id', None) == AMEDIA_ORG_ID: ret += '<h3>--- YOU ARE PART OF AMEDIA ORGANIZATION --- </h3>' break else: ret += '<h3>--- YOU ARE NOT MEMBER OF AMEDIA --- </h3>' # Finally return the retval return ret
def login(): if env == 'dev': flash('You are in dev mode, and don\'t need to login') return redirect(url_for('index')) if not github.authorized: return redirect(url_for("github.login")) user = github.get("/user").json() orgs = github.get(user['organizations_url']).json() # if you have opengridcc in your public organizations, you are a contributor :-) session['contributor'] = 'opengridcc' in {org['login'] for org in orgs} session['username'] = user["login"] if user_is_contributor(): flash('Welcome, {user}. Thanks for contributing to OpenGrid!'.format( user=session['username'])) else: flash( 'Welcome, {user}. Become an OpenGrid member to view all restricted pages\n' 'To register yourself as OpenGrid member, send a mail to [email protected]' .format(user=session['username'])) return redirect(url_for('index'))
def authorized(blueprint, token): if google.authorized: user_info = google.get("/oauth2/v2/userinfo") assert user_info.ok user_info = {'google': user_info.json()} user_email = user_info['google']['email'].lower() elif github.authorized: user_emails = github.get("/user/emails") user_email = [x for x in user_emails.json() if x['primary']][0]["email"].lower() user_info = {'github': github.get('/user').json()} user_info['github']['email'] = user_email else: flash("Error logging in!") return redirect(url_for("auth.choose_login")) # Create or get existing user. user = user_ds(user_email) if not user._exists: user.user_email = user_email user.user_info = user_info user.email_confirmation_code = unique_id() user.user_id = unique_id()[0:8] user.username = slugify("{}_{}".format(user_email.split("@")[0], unique_id()[0:4])) user.last_login = arrow.utcnow().datetime user.save() session['user'] = user.to_dict() logger.debug(session) flash("Successfully logged in!", 'success') return redirect(session.get("login_referrer", url_for('primary.primary')))
def update_index(run_which): """ TEAM COPPER ONLY!!! """ if not github.authorized: return redirect(url_for("github.login")) username = github.get("/user").json()['login'] resp = github.get("/user/orgs") if resp.ok: # Only Team Copper members can update the index all_orgs = resp.json() for org in all_orgs: if org['login'] == 'dcppc': copper_team_id = '2700235' mresp = github.get('/teams/%s/members/%s' % (copper_team_id, username)) if mresp.status_code == 204: # Business as usual UpdateIndexTask(app.config, diff_index=False, run_which=run_which) flash("Rebuilding index, check console output") # This redirects user to /control_panel route # to prevent accidental re-indexing return redirect(url_for("control_panel")) return render_template('403.html')
def before_request(): '''在 request 之前: 1、建立 MySQL 数据库连接 2、检验用户登录状态,若已登录则存入 g.user ''' # 建立 MySQL 连接,参数:host:port, database, user, passwd # torndb 默认已将 charset 设为 utf-8 g.db = torndb.Connection( config.MYSQL_HOST, config.MYSQL_DB, config.MYSQL_USER, config.MYSQL_PW ) g.user = None if github.authorized: gh_name = github.get("/user").json()['login'] find_user = g.db.get("SELECT * FROM User where ghName=%s", gh_name) if find_user == None: # 获取用户邮箱,需要用户在 github 的 profile 设置里把邮箱设为公开可见 email = github.get("/user").json()['email'] g.db.insert("INSERT INTO User (ghName, email) VALUES (%s, %s)", gh_name, email) g.user = g.db.get("SELECT * FROM User where ghName=%s", gh_name)
def new_function(old_function): if not github.authorized: if self.is_landing_page: return render_template("landing.html") else: return redirect(url_for("github.login")) try: username_payload = github.get('/user').json() username = username_payload['login'] except KeyError: err = "ERROR: Could not find 'login' key from /user endpoint of Github API, " err += "may have hit rate limit.\n" err += "Payload:\n" err += "%s" % (username_payload) logging.exception(err) return render_template('404.html') # The admin setting in the config file # affects which whitelist we use to # control access to the page. # # If this is an admin page, # use the admin whitelist, &c. if self.admin: logins_whitelist = app.config[ 'ADMIN_WHITELIST_GITHUB_LOGINS'] orgs_whitelist = app.config['ADMIN_WHITELIST_GITHUB_ORGS'] teams_whitelist = app.config[ 'ADMIN_WHITELIST_GITHUB_TEAMS'] else: logins_whitelist = app.config['WHITELIST_GITHUB_LOGINS'] orgs_whitelist = app.config['WHITELIST_GITHUB_ORGS'] teams_whitelist = app.config['WHITELIST_GITHUB_TEAMS'] if username in logins_whitelist: old_function(*args, **kwargs) # Proceed # For each of the user's organizations, # see if any are on the orgs whitelist resp = github.get("/user/orgs") if resp.ok: all_orgs = resp.json() for org in all_orgs: if org['login'] in orgs_whitelist: old_function(*args, **kwargs) # Proceed # For each of the team IDs on the whitelist, # check if the user is a member of that team for teamid in teams_whitelist: teamresp = github.get('/teams/%s/members/%s' % (copper_team_id, username)) if mresp.status_code == 204: old_function(*args, **kwargs) # Proceed # User is not on any whitelists return render_template('403.html')
def index(): if not github.authorized: return redirect(url_for('github.login')) username = github.get('/user').json()['login'] orgs = json.loads(github.get(f'/users/{username}/orgs').text) for org in orgs: if app.config.get('GITHUB_OAUTH_ALLOWED_ORGANIZATIONS') in org['login']: return render_template('index.html') return render_template('403page.html')
def templates(): if not github.authorized: return redirect(url_for('github.login')) username = github.get('/user').json()['login'] orgs = json.loads(github.get(f'/users/{username}/orgs').text) for org in orgs: if app.config.get('GITHUB_OAUTH_ALLOWED_ORGANIZATIONS') in org['login']: templates = db.session.query(Templates).order_by(Templates.template_id).all() return render_template('snippets/templates.html', templates=templates) return render_template('403page.html')
def joinjoin(): data = request.json repo = Project.query.filter_by(id=int(data['projectId'])).first() if repo == None: return "nah bruh",403 creds=session['githubuser'] if creds == None: return "nah son- you got no credentials",403 #github api calls are done with github.get(path) or github.post(path). you can see the pattern below. #here we need to tell the user to f**k themselves with a rusty pipe if they try to edit a repo they dont have write permissions for #dunno which api endpoint to hit but its probably not too bad write_user_list = github.get("/repos/"+repo.owner+"/"+repo.repo + "/contributors").json() for user in write_user_list: if user['login'] == session['githubuser']: break else: return "User does not have write access", 403 sesh = Session.query.filter_by(project_id=int(repo.id)).first() if sesh == None: print("session does not exist, creating new session") master = github.get("/repos/"+repo.owner+"/"+repo.repo+"/branches/"+repo.branch) head_tree_sha = master.json()['commit']['commit']['tree']['sha'] sesh = Session( owner = repo.owner, repo = repo.repo, branch = repo.branch, sha = head_tree_sha, project_id = repo.id, activemembers = None, ) db.session.add(sesh) db.session.commit() # make every file in the tree a temFile file_tree = github.get("/repos/"+ repo.owner +"/"+ repo.repo +"/git/trees/"+ head_tree_sha +"?recursive=1").json() for file in file_tree['tree']: formattedprint(file) if(file['type'] != "tree"): book = TemFile( session_id = sesh.id, path = file['path'], content = "", sha = file['sha'], md5 = hashlib.md5("".encode("utf-8")).hexdigest() ) formattedprint(book.path) db.session.add(book) db.session.commit() session['sessionId'] = sesh.id return "OK"
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 index(): if not github.authorized: return redirect(url_for("github.login")) username = github.get("/user").json()['login'] target_org = 'microsoft' resp = github.get("/user/orgs") if resp.ok: all_orgs = resp.json() for org in all_orgs: if org['login'] == target_org: return send_from_directory(os.getcwd(), 'index.html')
def index(name=None): if not github.authorized: return redirect(url_for("github.login")) resp = github.get("/user") assert resp.ok user = resp.json() resp = github.get("/rate_limit") assert resp.ok rate = resp.json() return render_template('index.html', name=user["login"], rate=rate['resources'])
def parse_request(): if not github.authorized: return redirect(url_for("github.login")) username = github.get("/user").json()['login'] resp = github.get("/user/orgs") if resp.ok: all_orgs = resp.json() for org in all_orgs: if org['login'] == 'dcppc': try: # Business as usual data = request.form.to_dict() data['github_login'] = username data['timestamp'] = datetime.now().strftime( "%Y-%m-%d %H:%M:%S") feedback_database = 'feedback_database.json' if not os.path.isfile(feedback_database): with open(feedback_database, 'w') as f: json_data = [data] json.dump(json_data, f, indent=4) else: json_data = [] with open(feedback_database, 'r') as f: json_data = json.load(f) json_data.append(data) with open(feedback_database, 'w') as f: json.dump(json_data, f, indent=4) ## Should be done with Javascript #flash("Thank you for your feedback!") return jsonify({ 'status': 'ok', 'message': 'Thank you for your feedback!' }) except: return jsonify({ 'status': 'error', 'message': 'An error was encountered while submitting your feedback. Try submitting an issue in the <a href="https://github.com/dcppc/centillion/issues/new">dcppc/centillion</a> repository.' }) # nope return render_template('403.html')
def jira_issue_status_changed(issue, changelog, bugsnag_context=None): bugsnag_context = bugsnag_context or {} pr_num = github_pr_num(issue) pr_repo = github_pr_repo(issue) pr_url = github_pr_url(issue) issue_url = pr_url.replace("pulls", "issues") status_changelog = [item for item in changelog["items"] if item["field"] == "status"][0] old_status = status_changelog["fromString"] new_status = status_changelog["toString"] # get github issue gh_issue_resp = github.get(issue_url) if not gh_issue_resp.ok: raise requests.exceptions.RequestException(gh_issue_resp.text) gh_issue = gh_issue_resp.json() # get repo labels repo_labels_resp = github.get("/repos/{repo}/labels".format(repo=pr_repo)) if not repo_labels_resp.ok: raise requests.exceptions.RequestException(repo_labels_resp.text) # map of label name to label URL repo_labels = {l["name"]: l["url"] for l in repo_labels_resp.json()} # map of label name lowercased to label name in the case that it is on Github repo_labels_lower = {name.lower(): name for name in repo_labels} # Get all the existing labels on this PR pr_labels = [label["name"] for label in gh_issue["labels"]] print("old labels: {}".format(pr_labels), file=sys.stderr) # remove old status label old_status_label = repo_labels_lower.get(old_status.lower(), old_status) print("old status label: {}".format(old_status_label), file=sys.stderr) if old_status_label in pr_labels: pr_labels.remove(old_status_label) # add new status label new_status_label = repo_labels_lower[new_status.lower()] print("new status label: {}".format(new_status_label), file=sys.stderr) if new_status_label not in pr_labels: pr_labels.append(new_status_label) print("new labels: {}".format(pr_labels), file=sys.stderr) # Update labels on github update_label_resp = github.patch(issue_url, json={"labels": pr_labels}) if not update_label_resp.ok: raise requests.exceptions.RequestException(update_label_resp.text) return "Changed labels of PR #{num} to {labels}".format(num=pr_num, labels=pr_labels)
def jira_issue_rejected(issue): issue_key = to_unicode(issue["key"]) pr_num = github_pr_num(issue) pr_url = github_pr_url(issue) issue_url = pr_url.replace("pulls", "issues") gh_issue_resp = github.get(issue_url) gh_issue_resp.raise_for_status() gh_issue = gh_issue_resp.json() sentry.client.extra_context({"github_issue": gh_issue}) if gh_issue["state"] == "closed": # nothing to do msg = "{key} was rejected, but PR #{num} was already closed".format( key=issue_key, num=pr_num) print(msg, file=sys.stderr) return msg # Comment on the PR to explain to look at JIRA username = to_unicode(gh_issue["user"]["login"]) comment = { "body": ("Hello @{username}: We are unable to continue with " "review of your submission at this time. Please see the " "associated JIRA ticket for more explanation.".format( username=username)) } comment_resp = github.post(issue_url + "/comments", json=comment) comment_resp.raise_for_status() # close the pull request on Github close_resp = github.patch(pr_url, json={"state": "closed"}) close_resp.raise_for_status() return "Closed PR #{num}".format(num=pr_num)
def github_whoami(): self_resp = github.get("/user") rate_limit_info = {k: v for k, v in self_resp.headers.items() if "ratelimit" in k} print("Rate limits: {}".format(rate_limit_info), file=sys.stderr) if not self_resp.ok: raise requests.exceptions.RequestException(self_resp.text) return self_resp.json()
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 wrapper_fetch_user(*args, **kwargs): if github.authorized: if not session.get("user_id"): r = github.get("/user") github_user = json.loads(r.text) user = User.query.filter(User.id == github_user["id"]).first() if user: user.github_login = github_user["login"] else: user = User(github_user["id"], github_user["login"], github_user["login"], "") db.session.add(user) db.session.commit() db.session.refresh(user) session["user_id"] = user.id else: user = User.query.filter(User.id == session["user_id"]).first() session["user"] = user.to_dict() session["user"]["is_admin"] = session["user"][ "github_login"] in app.config["DASHBOARD_ADMIN"] db.session.close() return func(*args, **kwargs)
def rateLimit(): if not github.authorized: return redirect(url_for("github.login")) resp = github.get("/rate_limit") assert resp.ok data = resp.json() return data
def add_alias(): """This is for adding alias""" # If not authorized if not github.authorized: return render_template('error.html', status_code=487) # Get the user and pull up their DB info resp = github.get("/user") if not resp.ok: render_template('error.html', status_code=300) resp = resp.json() username = resp['login'] # Get our users data, if they don't have any data create it try: user_data = octoDB.query_user(username) if not user_data: raise Exception("User not found") # Create a random number and email it to the user user_data = mail_client.send_code(resp['email'], user_data) octoDB.update_user(username, user_data) except Exception as e: logging.warning(f"Something went wrong when adding alias for {username}\nException: {e}") return render_template('error.html', status_code=505) kwargs = "alias_requested" return redirect(f"/dashboard?kwargs={kwargs}")
def jira_issue_rejected(issue): issue_key = to_unicode(issue["key"]) pr_num = github_pr_num(issue) pr_url = github_pr_url(issue) issue_url = pr_url.replace("pulls", "issues") gh_issue_resp = github.get(issue_url) gh_issue_resp.raise_for_status() gh_issue = gh_issue_resp.json() sentry.client.extra_context({"github_issue": gh_issue}) if gh_issue["state"] == "closed": # nothing to do msg = "{key} was rejected, but PR #{num} was already closed".format( key=issue_key, num=pr_num ) print(msg, file=sys.stderr) return msg # Comment on the PR to explain to look at JIRA username = to_unicode(gh_issue["user"]["login"]) comment = {"body": ( "Hello @{username}: We are unable to continue with " "review of your submission at this time. Please see the " "associated JIRA ticket for more explanation.".format(username=username) )} comment_resp = github.post(issue_url + "/comments", json=comment) comment_resp.raise_for_status() # close the pull request on Github close_resp = github.patch(pr_url, json={"state": "closed"}) close_resp.raise_for_status() return "Closed PR #{num}".format(num=pr_num)
def github_login(): if not github.authorized: return redirect(url_for('github.login')) else: account_info = github.get('/user') if account_info.ok: account_info_json = account_info.json() print("account info json", account_info_json) with app.app_context(): user = { "username": "******", "email": "*****@*****.**", "login": account_info_json['login'], "location": account_info_json['location'], "roleid": "" } db = database.createUser(user) print("user in db is...", db) if db: role = database.getRole(db['roleid']) if role: # token=generate_token.generateToken(account_info_json['name'],role['role']) token = generate_token.generateToken( db['username'], role['role']) print("token is...", token) session['bearerToken'] = token session['username'] = account_info_json['login'] rendered = render_template('blog.html', \ session=session) return rendered # return '<h1>Your Github name is {}'.format(account_info_json['login']) return '<h1>Request failed!</h1>'
def github_login(): if not github.authorized: return redirect(url_for('github.login')) account_info = github.get('/user') if account_info.ok: account_info_json = account_info.json() email = account_info_json['login'] session['email'] = email session['type'] = 'programmer' cur.execute('select * from emails where email=%s', (email, )) user = cur.fetchone() if user == None: status = 'False' cur.execute( 'insert into emails (email, status) values (%s, %s) returning id', (email, status)) conn.commit() return render_template('github.html', email=email) else: if user[2] == 'False': conn.commit() return render_template('github.html', email=email) else: id = user[0] conn.commit() return redirect(f'/profile/{id}') return '<h1> Request failed </h1>'
def dashboard(): """This is for displaying the dashboard""" # Check if our user is authorized and working if not github.authorized: return redirect(url_for("github.login")) resp = github.get("/user") if not resp.ok: render_template('error.html', status_code=300) # Get the username and password resp = resp.json() username = resp['login'] email = resp['email'] # Get our users data, if they don't have any data create it try: user_data = octoDB.query_user(username) if not user_data: user_data = octoDB.create_user(username, email) if user_data is False: raise Exception(f"DB Error updating user {username}") except Exception as e: logging.warning(f"Something went wrong when getting data for {username}.\nException: {e}") kwargs = request.args.get('kwargs') return render_template('dashboard.html', user_data=user_data, kwargs=kwargs)
def githubLogin(): if not github.authorized: return redirect(url_for("github.login")) res = github.get("/user") if res.ok: oauth = github_blueprint.session.access_token account_info = res.json() session['user_name'] = account_info["name"] session['user_email'] = account_info["email"] # check if user is in the DB otherwise add email, password, oauth token table = dynamodb.Table('oauthusers') # Query table to see if email exists response = table.query( KeyConditionExpression=Key('user_email').eq(session['user_email'])) items = response['Items'] # If email doesn't exist add information to database table if not items: table.put_item( Item={ 'user_email': session['user_email'], 'user_name': session['user_name'], 'oauth_token': oauth }) # Update oauth token if response['Items'][0]['oauth_token'] != oauth: table.put_item( Item={ 'user_email': session['user_email'], 'user_name': session['user_name'], 'oauth_token': oauth }) # validate oauth token if oauth == response['Items'][0]['oauth_token']: return redirect(url_for('dashboard'))
def get_gh_projects_info(): resp = github.get("/user/repos?affiliation=owner") json_data = resp.json() if resp.ok: return resp.json() else: []
def index(): if not github.authorized: return redirect("/auth") resp = github.get("/user") assert resp.ok githubData = resp.json() u = User.where('github_id', githubData["id"]).first() if u == None: print("none") user = User() user.name = githubData["name"] user.username = githubData["login"] user.email = githubData["email"] user.github_id = githubData["id"] user.avatar_url = githubData["avatar_url"] user.github_api_url = githubData["url"] user.access_token = session["github_oauth_token"]["access_token"] user.github_html_url = githubData["html_url"] user.save() u = user session["user"] = u.to_json() return render_template("search.html", user=u)
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 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
def login(): if env == 'dev': flash('You are in dev mode, and don\'t need to login') return redirect(url_for('index')) if not github.authorized: return redirect(url_for("github.login")) user = github.get("/user").json() orgs = github.get(user['organizations_url']).json() # if you have opengridcc in your public organizations, you are a contributor :-) session['contributor'] = 'opengridcc' in {org['login'] for org in orgs} session['username'] = user["login"] if user_is_contributor(): flash('Welcome, {user}. Thanks for contributing to OpenGrid!'.format(user=session['username'])) else: flash('Welcome, {user}. Become an OpenGrid contributor to view all restricted pages'.format( user=session['username'])) return redirect(url_for('index'))
def get_jira_issue_key(pull_request): # who am I? self_resp = github.get("/user") rate_limit_info = {k: v for k, v in self_resp.headers.items() if "ratelimit" in k} print("Rate limits: {}".format(rate_limit_info), file=sys.stderr) if not self_resp.ok: raise requests.exceptions.RequestException(self_resp.text) my_username = self_resp.json()["login"] # get my first comment on this pull request comments_resp = github.get("/repos/{repo}/issues/{num}/comments".format( repo=pull_request["base"]["repo"]["full_name"], num=pull_request["number"], )) if not comments_resp.ok: raise requests.exceptions.RequestException(comments_resp.text) my_comments = [comment for comment in comments_resp.json() if comment["user"]["login"] == my_username] if len(my_comments) < 1: return None # search for the first occurrance of a JIRA ticket key in the comment body match = re.search(r"\b([A-Z]{2,}-\d+)\b", my_comments[0]["body"]) if match: return match.group(0) return None
def index(): """ Just to verify that things are working """ github_username = None if github_session._client.token: gh_user_resp = github_session.get("/user") if gh_user_resp.ok: github_username = gh_user_resp.json()["login"] jira_username = None if jira_session.auth.client.resource_owner_key: jira_user_resp = jira_session.get("/rest/api/2/myself") if jira_user_resp.ok: jira_username = jira_user_resp.json()["name"] return render_template("main.html", github_username=github_username, jira_username=jira_username, )
def jira_issue_rejected(issue, bugsnag_context=None): bugsnag_context = bugsnag_context or {} issue_key = to_unicode(issue["key"]) pr_num = github_pr_num(issue) pr_url = github_pr_url(issue) issue_url = pr_url.replace("pulls", "issues") gh_issue_resp = github.get(issue_url) if not gh_issue_resp.ok: raise requests.exceptions.RequestException(gh_issue_resp.text) gh_issue = gh_issue_resp.json() bugsnag_context["github_issue"] = gh_issue bugsnag.configure_request(meta_data=bugsnag_context) if gh_issue["state"] == "closed": # nothing to do msg = "{key} was rejected, but PR #{num} was already closed".format( key=issue_key, num=pr_num ) print(msg, file=sys.stderr) return msg # Comment on the PR to explain to look at JIRA username = to_unicode(gh_issue["user"]["login"]) comment = {"body": ( "Hello @{username}: We are unable to continue with " "review of your submission at this time. Please see the " "associated JIRA ticket for more explanation.".format(username=username) )} comment_resp = github.post(issue_url + "/comments", json=comment) # close the pull request on Github close_resp = github.patch(pr_url, json={"state": "closed"}) if not close_resp.ok or not comment_resp.ok: bugsnag_context['request_headers'] = close_resp.request.headers bugsnag_context['request_url'] = close_resp.request.url bugsnag_context['request_method'] = close_resp.request.method bugsnag.configure_request(meta_data=bugsnag_context) bug_text = '' if not close_resp.ok: bug_text += "Failed to close; " + close_resp.text if not comment_resp.ok: bug_text += "Failed to comment on the PR; " + comment_resp.text raise requests.exceptions.RequestException(bug_text) return "Closed PR #{num}".format(num=pr_num)
def index(): """ Display an HTML overview page, with links to other functions that this application can perform. """ github_username = None if github_session.authorized: gh_user_resp = github_session.get("/user") if gh_user_resp.ok: github_username = gh_user_resp.json()["login"] jira_username = None if jira_session.authorized: jira_user_resp = jira_session.get("/rest/api/2/myself") if jira_user_resp.ok: jira_username = jira_user_resp.json()["name"] return render_template("main.html", github_username=github_username, jira_username=jira_username, )
def github_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 return pr_opened(pr_resp.json(), ignore_internal=False, check_contractor=False)
def github_community_pr_comment(pull_request, jira_issue, people=None): """ For a newly-created pull request from an open source contributor, write a welcoming comment on the pull request. The comment should: * contain a link to the JIRA issue * check for contributor agreement * check for AUTHORS entry * contain a link to our process documentation """ people = people or get_people_file() people = {user.lower(): values for user, values in people.items()} pr_author = pull_request["user"]["login"].decode('utf-8').lower() created_at = parse_date(pull_request["created_at"]).replace(tzinfo=None) # does the user have a valid, signed contributor agreement? has_signed_agreement = ( pr_author in people and people[pr_author].get("expires_on", date.max) > created_at.date() ) # is the user in the AUTHORS file? in_authors_file = False name = people.get(pr_author, {}).get("name", "") if name: authors_url = "https://raw.githubusercontent.com/{repo}/{branch}/AUTHORS".format( repo=pull_request["head"]["repo"]["full_name"].decode('utf-8'), branch=pull_request["head"]["ref"].decode('utf-8'), ) authors_resp = github.get(authors_url) if authors_resp.ok: authors_content = authors_resp.text if name in authors_content: in_authors_file = True doc_url = "http://edx-developer-guide.readthedocs.org/en/latest/process/overview.html" issue_key = jira_issue["key"].decode('utf-8') issue_url = "https://openedx.atlassian.net/browse/{key}".format(key=issue_key) contributing_url = "https://github.com/edx/edx-platform/blob/master/CONTRIBUTING.rst" agreement_url = "http://open.edx.org/sites/default/files/wysiwyg/individual-contributor-agreement.pdf" authors_url = "https://github.com/{repo}/blob/master/AUTHORS".format( repo=pull_request["base"]["repo"]["full_name"].decode('utf-8'), ) comment = ( "Thanks for the pull request, @{user}! I've created " "[{issue_key}]({issue_url}) to keep track of it in JIRA. " "JIRA is a place for product owners to prioritize feature reviews " "by the engineering development teams. " "\n\nFeel free to add as much of the following information to the ticket:" "\n- supporting documentation" "\n- edx-code email threads" "\n- timeline information ('this must be merged by XX date', and why that is)" "\n- partner information ('this is a course on edx.org')" "\n- any other information that can help Product understand the context for the PR" "\n\nAll technical communication about the code itself will still be " "done via the Github pull request interface. " "As a reminder, [our process documentation is here]({doc_url})." ).format( user=pull_request["user"]["login"].decode('utf-8'), issue_key=issue_key, issue_url=issue_url, doc_url=doc_url, ) if not has_signed_agreement or not in_authors_file: todo = "" if not has_signed_agreement: todo += ( "submitted a [signed contributor agreement]({agreement_url}) " "or indicated your institutional affiliation" ).format( agreement_url=agreement_url, ) if not has_signed_agreement and not in_authors_file: todo += " and " if not in_authors_file: todo += "added yourself to the [AUTHORS]({authors_url}) file".format( authors_url=authors_url, ) comment += ("\n\n" "We can't start reviewing your pull request until you've {todo}. " "Please see the [CONTRIBUTING]({contributing_url}) file for " "more information." ).format(todo=todo, contributing_url=contributing_url) return comment
def pr_opened(pr, ignore_internal=True, check_contractor=True, bugsnag_context=None): bugsnag_context = bugsnag_context or {} user = pr["user"]["login"].decode('utf-8') repo = pr["base"]["repo"]["full_name"] num = pr["number"] if ignore_internal and is_internal_pull_request(pr): # not an open source pull request, don't create an issue for it print( "@{user} opened PR #{num} against {repo} (internal PR)".format( user=user, repo=repo, num=num, ), file=sys.stderr ) return "internal pull request" if check_contractor and is_contractor_pull_request(pr): # don't create a JIRA issue, but leave a comment comment = { "body": github_contractor_pr_comment(pr), } url = "/repos/{repo}/issues/{num}/comments".format( repo=repo, num=num, ) comment_resp = github.post(url, json=comment) comment_resp.raise_for_status() return "contractor pull request" issue_key = get_jira_issue_key(pr) if issue_key: msg = "Already created {key} for PR #{num} against {repo}".format( key=issue_key, num=pr["number"], repo=pr["base"]["repo"]["full_name"], ) print(msg, file=sys.stderr) return msg repo = pr["base"]["repo"]["full_name"].decode('utf-8') people = get_people_file() custom_fields = get_jira_custom_fields() if user in people: user_name = people[user].get("name", "") else: user_resp = github.get(pr["user"]["url"]) if user_resp.ok: user_name = user_resp.json().get("name", user) else: user_name = user # create an issue on JIRA! new_issue = { "fields": { "project": { "key": "OSPR", }, "issuetype": { "name": "Pull Request Review", }, "summary": pr["title"], "description": pr["body"], custom_fields["URL"]: pr["html_url"], custom_fields["PR Number"]: pr["number"], custom_fields["Repo"]: pr["base"]["repo"]["full_name"], custom_fields["Contributor Name"]: user_name, } } institution = people.get(user, {}).get("institution", None) if institution: new_issue["fields"][custom_fields["Customer"]] = [institution] bugsnag_context["new_issue"] = new_issue bugsnag.configure_request(meta_data=bugsnag_context) resp = jira.post("/rest/api/2/issue", json=new_issue) resp.raise_for_status() new_issue_body = resp.json() issue_key = new_issue_body["key"].decode('utf-8') bugsnag_context["new_issue"]["key"] = issue_key bugsnag.configure_request(meta_data=bugsnag_context) # add a comment to the Github pull request with a link to the JIRA issue comment = { "body": github_community_pr_comment(pr, new_issue_body, people), } url = "/repos/{repo}/issues/{num}/comments".format( repo=repo, num=pr["number"], ) comment_resp = github.post(url, json=comment) comment_resp.raise_for_status() # Add the "Needs Triage" label to the PR issue_url = "/repos/{repo}/issues/{num}".format(repo=repo, num=pr["number"]) label_resp = github.patch(issue_url, data=json.dumps({"labels": ["needs triage", "open-source-contribution"]})) label_resp.raise_for_status() print( "@{user} opened PR #{num} against {repo}, created {issue} to track it".format( user=user, repo=repo, num=pr["number"], issue=issue_key, ), file=sys.stderr ) return "created {key}".format(key=issue_key)
def pr_opened(pr, bugsnag_context=None): bugsnag_context = bugsnag_context or {} user = pr["user"]["login"] repo = pr["base"]["repo"]["full_name"] people = get_people_file() if user in people and people[user].get("institution", "") == "edX": # not an open source pull request, don't create an issue for it print( "@{user} opened PR #{num} against {repo} (internal PR)".format( user=user, repo=pr["base"]["repo"]["full_name"], num=pr["number"] ), file=sys.stderr ) return "internal pull request" field_resp = jira.get("/rest/api/2/field") if not field_resp.ok: raise requests.exceptions.RequestException(field_resp.text) field_map = dict(pop_dict_id(f) for f in field_resp.json()) custom_fields = { value["name"]: id for id, value in field_map.items() if value["custom"] } user_resp = github.get(pr["user"]["url"]) if user_resp.ok: user_name = user_resp.json().get("name", user) else: user_name = user # create an issue on JIRA! new_issue = { "fields": { "project": { "key": "OSPR", }, "issuetype": { "name": "Pull Request Review", }, "summary": pr["title"], "description": pr["body"], custom_fields["URL"]: pr["html_url"], custom_fields["PR Number"]: pr["number"], custom_fields["Repo"]: pr["base"]["repo"]["full_name"], custom_fields["Contributor Name"]: user_name, } } institution = people.get(user, {}).get("institution", None) if institution: new_issue["fields"][custom_fields["Customer"]] = [institution] bugsnag_context["new_issue"] = new_issue bugsnag.configure_request(meta_data=bugsnag_context) resp = jira.post("/rest/api/2/issue", data=json.dumps(new_issue)) if not resp.ok: raise requests.exceptions.RequestException(resp.text) new_issue_body = resp.json() bugsnag_context["new_issue"]["key"] = new_issue_body["key"] bugsnag.configure_request(meta_data=bugsnag_context) # add a comment to the Github pull request with a link to the JIRA issue comment = { "body": github_pr_comment(pr, new_issue_body, people), } url = "/repos/{repo}/issues/{num}/comments".format( repo=repo, num=pr["number"], ) comment_resp = github.post(url, data=json.dumps(comment)) if not comment_resp.ok: raise requests.exceptions.RequestException(comment_resp.text) print( "@{user} opened PR #{num} against {repo}, created {issue} to track it".format( user=user, repo=repo, num=pr["number"], issue=new_issue_body["key"] ), file=sys.stderr ) return "created!"
def jira_issue_updated(): """ Received an "issue updated" event from JIRA. https://developer.atlassian.com/display/JIRADEV/JIRA+Webhooks+Overview """ try: event = request.get_json() except ValueError: raise ValueError("Invalid JSON from JIRA: {data}".format( data=request.data.decode('utf-8') )) bugsnag_context = {"event": event} bugsnag.configure_request(meta_data=bugsnag_context) if app.debug: print(json.dumps(event), file=sys.stderr) issue_key = event["issue"]["key"].decode('utf-8') # is the issue an open source pull request? if event["issue"]["fields"]["project"]["key"] != "OSPR": # TODO: if the issue has just been moved from the OSPR project to a new project, # change the label to "engineering review". Need to figure out if we can tell that # the ticket has just moved projects. return "I don't care" # is there a changelog? changelog = event.get("changelog") if not changelog: # it was just someone adding a comment return "I don't care" # did the issue change status? status_changelog_items = [item for item in changelog["items"] if item["field"] == "status"] if len(status_changelog_items) == 0: return "I don't care" # construct Github API URL custom_fields = get_jira_custom_fields() pr_repo = event["issue"]["fields"].get(custom_fields["Repo"], "") pr_num = event["issue"]["fields"].get(custom_fields["PR Number"]) if not pr_repo or not pr_num: fail_msg = '{key} is missing "Repo" or "PR Number" fields'.format(key=issue_key) raise Exception(fail_msg) pr_num = int(pr_num) pr_url = "/repos/{repo}/pulls/{num}".format(repo=pr_repo, num=pr_num) # Need to use the Issues API for label manipulation issue_url = "/repos/{repo}/issues/{num}".format(repo=pr_repo, num=pr_num) old_status = status_changelog_items[0]["fromString"] new_status = status_changelog_items[0]["toString"] if new_status == "Rejected": issue_resp = github.get(issue_url) if not issue_resp.ok: raise requests.exceptions.RequestException(issue_resp.text) issue = issue_resp.json() if issue["state"] == "closed": # nothing to do msg = "{key} was rejected, but PR #{num} was already closed".format( key=issue_key, num=pr_num ) print(msg, file=sys.stderr) return msg # Comment on the PR to explain to look at JIRA username = issue["user"]["login"].decode('utf-8') comment = {"body": ( "Hello @{username}: We are unable to continue with " "review of your submission at this time. Please see the " "associated JIRA ticket for more explanation.".format(username=username) )} comment_resp = github.post(issue_url + "/comments", json=comment) # close the pull request on Github close_resp = github.patch(pr_url, json={"state": "closed"}) if not close_resp.ok or not comment_resp.ok: bugsnag_context['request_headers'] = close_resp.request.headers bugsnag_context['request_url'] = close_resp.request.url bugsnag_context['request_method'] = close_resp.request.method bugsnag.configure_request(meta_data=bugsnag_context) bug_text = '' if not close_resp.ok: bug_text += "Failed to close; " + close_resp.text if not comment_resp.ok: bug_text += "Failed to comment on the PR; " + comment_resp.text raise requests.exceptions.RequestException(bug_text) return "Closed PR #{num}".format(num=pr_num) elif new_status in STATUS_LABEL_DICT: # Get all the existing labels on this PR label_list = github.get(issue_url).json()["labels"] # Add in the label representing the new status - just add in the plain string label label_list.append(STATUS_LABEL_DICT[new_status][0]) # remove the label representing the old status, if it exists if old_status in STATUS_LABEL_DICT: # Sometimes labels are strings ("needs triage") whereas other times they're dictionaries # with the label name, color, and url defined. Have not pinned down when or why this happens. for old_label in STATUS_LABEL_DICT[old_status]: try: if isinstance(old_label, dict): old_label["url"] = old_label["url"].format(pr_repo=pr_repo) label_list.remove(old_label) except ValueError: print("PR {num} does not have label {old_label} to remove".format(num=pr_num, old_label=old_label)) print("PR {num} only has labels {labels}".format(num=pr_num, labels=label_list)) else: print("PR {num}: Successfully removed label {old_label}".format(num=pr_num, old_label=old_label)) break # Post the new set of labels to github label_resp = github.patch(issue_url, json={"labels": label_list}) if not label_resp.ok: raise requests.exceptions.RequestException(label_resp.text) return "Changed label of PR #{num} to {labels}".format(num=pr_num, labels=label_list) return "no change necessary"
def github_whoami(): self_resp = github.get("/user") rate_limit_info = {k: v for k, v in self_resp.headers.items() if "ratelimit" in k} print("Rate limits: {}".format(rate_limit_info), file=sys.stderr) self_resp.raise_for_status() return self_resp.json()
def github_pr_comment(pull_request, jira_issue, people=None): """ For a newly-created pull request from an open source contributor, write a welcoming comment on the pull request. The comment should: * contain a link to the JIRA issue * check for contributor agreement * check for AUTHORS entry * contain a link to our process documentation """ people = people or get_people_file() people = {user.lower(): values for user, values in people.items()} pr_author = pull_request["user"]["login"].lower() # does the user have a signed contributor agreement? has_signed_agreement = pr_author in people # is the user in the AUTHORS file? in_authors_file = False authors_entry = people.get(pr_author, {}).get("authors_entry", "") if authors_entry: authors_url = "https://raw.githubusercontent.com/{repo}/{branch}/AUTHORS".format( repo=pull_request["head"]["repo"]["full_name"], branch=pull_request["head"]["ref"], ) authors_resp = github.get(authors_url) if authors_resp.ok: authors_content = authors_resp.text if authors_entry in authors_content: in_authors_file = True doc_url = "http://edx.readthedocs.org/projects/userdocs/en/latest/process/overview.html" issue_key = jira_issue["key"] issue_url = "https://openedx.atlassian.net/browse/{key}".format(key=issue_key) contributing_url = "https://github.com/edx/edx-platform/blob/master/CONTRIBUTING.rst" agreement_url = "http://code.edx.org/individual-contributor-agreement.pdf" authors_url = "https://github.com/edx/edx-platform/blob/master/AUTHORS" comment = ( "Thanks for the pull request, @{user}! I've created " "[{issue_key}]({issue_url}) to keep track of it in JIRA. " "JIRA is a place for product owners to prioritize feature reviews " "by the engineering development teams. Supporting information that is " "good to add there is anything that can help Product understand the " "context for the PR - supporting documentation, edx-code email threads, " "timeline information ('this must be merged by XX date', and why that is), " "partner information (this is for a course on edx.org, for example), etc. " "\n\nAll technical communication about the code itself will still be " "done via the Github pull request interface. " "As a reminder, [our process documentation is here]({doc_url})." ).format( user=pull_request["user"]["login"], issue_key=issue_key, issue_url=issue_url, doc_url=doc_url, ) if not has_signed_agreement or not in_authors_file: todo = "" if not has_signed_agreement: todo += ( "submitted a [signed contributor agreement]({agreement_url}) " "or indicated your institutional affiliation" ).format( agreement_url=agreement_url, ) if not has_signed_agreement and not in_authors_file: todo += " and " if not in_authors_file: todo += "added yourself to the [AUTHORS]({authors_url}) file".format( authors_url=authors_url, ) comment += ("\n\n" "We can't start reviewing your pull request until you've {todo}. " "Please see the [CONTRIBUTING]({contributing_url}) file for " "more information." ).format(todo=todo, contributing_url=contributing_url) return comment
def jira_issue_updated(): """ Received an "issue updated" event from JIRA. See `JIRA's webhook docs`_. .. _JIRA's webhook docs: https://developer.atlassian.com/display/JIRADEV/JIRA+Webhooks+Overview """ try: event = request.get_json() except ValueError: raise ValueError("Invalid JSON from JIRA: {data}".format( data=request.data.decode('utf-8') )) bugsnag_context = {"event": event} bugsnag.configure_request(meta_data=bugsnag_context) if app.debug: print(json.dumps(event), file=sys.stderr) if "issue" not in event: # It's rare, but we occasionally see junk data from JIRA. For example, # here's a real API request we've received on this handler: # {"baseUrl": "https://openedx.atlassian.net", # "key": "jira:1fec1026-b232-438f-adab-13b301059297", # "newVersion": 64005, "oldVersion": 64003} # If we don't have an "issue" key, it's junk. return "What is this shit!?", 400 # is this a comment? comment = event.get("comment") if comment: return jira_issue_comment_added(event["issue"], comment, bugsnag_context) # is the issue an open source pull request? if event["issue"]["fields"]["project"]["key"] != "OSPR": return "I don't care" # we don't care about OSPR subtasks if event["issue"]["fields"]["issuetype"]["subtask"]: return "ignoring subtasks" # don't care about feature proposals if event["issue"]["fields"]["issuetype"]["name"] == "Feature Proposal": return "ignoring feature propsals" # is there a changelog? changelog = event.get("changelog") if not changelog: # it was just someone adding a comment return "I don't care" # did the issue change status? status_changelog_items = [item for item in changelog["items"] if item["field"] == "status"] if len(status_changelog_items) == 0: return "I don't care" pr_repo = github_pr_repo(event["issue"]) if not pr_repo: issue_key = to_unicode(event["issue"]["key"]) fail_msg = '{key} is missing "Repo" field'.format(key=issue_key) fail_msg += ' {0}'.format(event["issue"]["fields"]["issuetype"]) raise Exception(fail_msg) repo_labels_resp = github.get("/repos/{repo}/labels".format(repo=pr_repo)) if not repo_labels_resp.ok: raise requests.exceptions.RequestException(repo_labels_resp.text) # map of label name to label URL repo_labels = {l["name"]: l["url"] for l in repo_labels_resp.json()} # map of label name lowercased to label name in the case that it is on Github repo_labels_lower = {name.lower(): name for name in repo_labels} old_status = status_changelog_items[0]["fromString"] new_status = status_changelog_items[0]["toString"] changes = [] if new_status == "Rejected": change = jira_issue_rejected(event["issue"], bugsnag_context) changes.append(change) elif 'blocked' in new_status.lower(): print("New status is: {}".format(new_status)) print("repo_labels_lower: {}".format(repo_labels_lower)) if new_status.lower() in repo_labels_lower: change = jira_issue_status_changed(event["issue"], event["changelog"], bugsnag_context) changes.append(change) if changes: return "\n".join(changes) else: return "no change necessary"
def index(): if not github.authorized: return redirect(url_for("github.login")) resp = github.get("/user") assert resp.ok return "You are @{login} on GitHub".format(login=resp.json()["login"])