def main(): homepage = memcache.get("homepage") if IS_DEV_APPSERVER or homepage is None: issues = Issue.query(Issue.state == "open").order(-Issue.updated_at).iter() homepage = render_template('index.html', session=session, issues=issues) memcache.set("homepage", value=homepage, time=60) return homepage
def update_pr(pr_number): logging.debug("Updating pull request %i" % pr_number) pr = Issue.get_or_create(pr_number) issue_response = raw_github_request(PULLS_BASE + '/%i' % pr_number, oauth_token=oauth_token, etag=pr.etag) if issue_response is None: logging.debug("PR %i hasn't changed since last visit; skipping" % pr_number) return "Done updating pull request %i (nothing changed)" % pr_number pr.pr_json = json.loads(issue_response.content) pr.etag = issue_response.headers["ETag"] pr.state = pr.pr_json['state'] pr.user = pr.pr_json['user']['login'] pr.updated_at = \ parse_datetime(pr.pr_json['updated_at']).astimezone(tz.tzutc()).replace(tzinfo=None) for issue_number in pr.parsed_title['jiras']: try: link_issue_to_pr("SPARK-%s" % issue_number, pr) except: logging.exception("Exception when linking to JIRA issue SPARK-%s" % issue_number) try: start_issue_progress("SPARK-%s" % issue_number) except: logging.exception( "Exception when starting progress on JIRA issue SPARK-%s" % issue_number) pr.put() # Write our modifications back to the database subtasks = [".update_pr_comments", ".update_pr_review_comments", ".update_pr_files"] for task in subtasks: taskqueue.add(url=url_for(task, pr_number=pr_number), queue_name='fresh-prs') return "Done updating pull request %i" % pr_number
def update_pr(pr_number): logging.debug("Updating pull request %i" % pr_number) pr = Issue.get_or_create(pr_number) issue_response = raw_github_request(get_pulls_base() + '/%i' % pr_number, oauth_token=oauth_token, etag=pr.etag) if issue_response is None: logging.debug("PR %i hasn't changed since last visit; skipping" % pr_number) return "Done updating pull request %i (nothing changed)" % pr_number pr.pr_json = json.loads(issue_response.content) pr.etag = issue_response.headers["ETag"] pr.state = pr.pr_json['state'] pr.user = pr.pr_json['user']['login'] pr.updated_at = \ parse_datetime(pr.pr_json['updated_at']).astimezone(tz.tzutc()).replace(tzinfo=None) for issue_number in pr.parsed_title['jiras']: try: link_issue_to_pr("%s-%s" % (app.config['JIRA_PROJECT'], issue_number), pr) except: logging.exception("Exception when linking to JIRA issue %s-%s" % (app.config['JIRA_PROJECT'], issue_number)) try: start_issue_progress("%s-%s" % (app.config['JIRA_PROJECT'], issue_number)) except: logging.exception( "Exception when starting progress on JIRA issue %s-%s" % (app.config['JIRA_PROJECT'], issue_number)) pr.put() # Write our modifications back to the database subtasks = [".update_pr_comments", ".update_pr_review_comments", ".update_pr_files"] for task in subtasks: taskqueue.add(url=url_for(task, pr_number=pr_number), queue_name='fresh-prs') return "Done updating pull request %i" % pr_number
def main(): issues = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() issues_by_component = defaultdict(list) for issue in issues: for component in issue.components: issues_by_component[component].append(issue) # Display the groups in the order listed in Issues._components grouped_issues = [(c[0], issues_by_component[c[0]]) for c in Issue._components] return build_response('index.html', grouped_issues=grouped_issues)
def update_all_jiras_for_open_prs(): """ Used to bulk-load information from JIRAs for all open PRs. Useful when upgrading from an earlier version of spark-prs. """ prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() jira_issues = set(itertools.chain.from_iterable(pr.parsed_title['jiras'] for pr in prs)) for issue in jira_issues: taskqueue.add(url="/tasks/update-jira-issue/SPARK-%i" % issue, queue_name='jira-issues') return "Queued JIRA issues for update: " + str(jira_issues)
def update_pr_files(pr_number): pr = Issue.get(pr_number) files_response = paginated_github_request(PULLS_BASE + "/%i/files" % pr_number, oauth_token=oauth_token, etag=pr.files_etag) if files_response is None: return "Files for PR %i are up-to-date" % pr_number else: pr.files_json, pr.files_etag = files_response pr.put() # Write our modifications back to the database return "Done updating files for PR %i" % pr_number
def update_all_jiras_for_open_prs(): """ Used to bulk-load information from JIRAs for all open PRs. Useful when upgrading from an earlier version of spark-prs. """ prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() jira_issues = set(itertools.chain.from_iterable(pr.parsed_title["jiras"] for pr in prs)) for issue in jira_issues: taskqueue.add(url="/tasks/update-jira-issue/SPARK-%i" % issue, queue_name="jira-issues") return "Queued JIRA issues for update: " + str(jira_issues)
def users(username): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() prs_authored = [p for p in prs if p.user == username] prs_commented_on = [ p for p in prs if username in dict(p.commenters) and p.user != username ] return build_response('user.html', username=username, prs_authored=prs_authored, prs_commented_on=prs_commented_on)
def update_pr_files(pr_number): pr = Issue.get(pr_number) files_response = paginated_github_request(get_pulls_base() + "/%i/files" % pr_number, oauth_token=oauth_token, etag=pr.files_etag) if files_response is None: return "Files for PR %i are up-to-date" % pr_number else: pr.files_json, pr.files_etag = files_response pr.put() # Write our modifications back to the database return "Done updating files for PR %i" % pr_number
def main(): issues = Issue.query( Issue.state == "open").order(-Issue.updated_at).fetch() issues_by_component = defaultdict(list) for issue in issues: for component in issue.components: issues_by_component[component].append(issue) # Display the groups in the order listed in Issues._components grouped_issues = [(c[0], issues_by_component[c[0]]) for c in Issue._components] return build_response('index.html', grouped_issues=grouped_issues)
def update_pr_review_comments(pr_number): pr = Issue.get(pr_number) pr_comments_response = paginated_github_request(PULLS_BASE + '/%i/comments' % pr_number, oauth_token=oauth_token) # TODO: after fixing #32, re-enable etags here: etag=self.pr_review_comments_etag) if pr_comments_response is None: return "Review comments for PR %i are up-to-date" % pr_number else: pr.pr_comments_json, pr.pr_comments_etag = pr_comments_response pr.cached_commenters = pr._compute_commenters() pr.put() # Write our modifications back to the database return "Done updating review comments for PR %i" % pr_number
def update_pr_review_comments(pr_number): pr = Issue.get(pr_number) pr_comments_response = paginated_github_request(get_pulls_base() + '/%i/comments' % pr_number, oauth_token=oauth_token) # TODO: after fixing #32, re-enable etags here: etag=self.pr_review_comments_etag) if pr_comments_response is None: return "Review comments for PR %i are up-to-date" % pr_number else: pr.pr_comments_json, pr.pr_comments_etag = pr_comments_response pr.cached_commenters = pr._compute_commenters() pr.put() # Write our modifications back to the database return "Done updating review comments for PR %i" % pr_number
def search_open_prs(): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() json_dicts = [] for pr in prs: try: last_jenkins_comment_dict = None if pr.last_jenkins_comment: last_jenkins_comment_dict = { 'body': pr.last_jenkins_comment['body'], 'user': {'login': pr.last_jenkins_comment['user']['login']}, 'html_url': pr.last_jenkins_comment['html_url'], 'date': [pr.last_jenkins_comment['created_at']], } d = { 'parsed_title': pr.parsed_title, 'number': pr.number, 'updated_at': str(pr.updated_at), 'user': pr.user, 'state': pr.state, 'components': pr.components, 'lines_added': pr.lines_added, 'lines_deleted': pr.lines_deleted, 'lines_changed': pr.lines_changed, 'is_mergeable': pr.is_mergeable, 'commenters': [{'username': u, 'data': d} for (u, d) in pr.commenters], 'last_jenkins_outcome': pr.last_jenkins_outcome, 'last_jenkins_comment': last_jenkins_comment_dict, } # Use the first JIRA's information to populate the "Priority" and "Issue Type" columns: jiras = pr.parsed_title["jiras"] if jiras: first_jira = JIRAIssue.get_by_id("%s-%i" % (app.config['JIRA_PROJECT'], jiras[0])) if first_jira: d['jira_priority_name'] = first_jira.priority_name d['jira_priority_icon_url'] = first_jira.priority_icon_url d['jira_issuetype_name'] = first_jira.issuetype_name d['jira_issuetype_icon_url'] = first_jira.issuetype_icon_url d['jira_shepherd_display_name'] = first_jira.shepherd_display_name # If a pull request is linked against multiple JIRA issues, then the target # versions should be union of the individual issues' target versions: target_versions = set() for jira_number in jiras: jira = JIRAIssue.get_by_id("%s-%i" % (app.config['JIRA_PROJECT'], jira_number)) if jira: target_versions.update(jira.target_versions) if target_versions: d['jira_target_versions'] = natsorted(target_versions) json_dicts.append(d) except: logging.error("Exception while processing PR #%i", pr.number) raise response = Response(json.dumps(json_dicts), mimetype='application/json') return response
def update_pr_comments(pr_number): pr = Issue.get(pr_number) comments_response = paginated_github_request(get_issues_base() + '/%i/comments' % pr_number, oauth_token=oauth_token) # TODO: after fixing #32, re-enable etags here: etag=self.comments_etag) if comments_response is None: return "Comments for PR %i are up-to-date" % pr_number else: pr.comments_json, pr.comments_etag = comments_response pr.cached_commenters = pr._compute_commenters() pr.cached_last_jenkins_outcome = None pr.last_jenkins_outcome # force recomputation of Jenkins outcome pr.put() # Write our modifications back to the database # Delete out-of-date comments from AmplabJenkins and SparkQA. jenkins_comment_to_preserve = pr.last_jenkins_comment sparkqa_token = app.config["SPARKQA_GITHUB_OAUTH_KEY"] amplabjenkins_token = app.config["AMPLAB_JENKINS_GITHUB_OAUTH_KEY"] sparkqa_start_comments = {} # Map from build ID to build start comment build_start_regex = r"Test build #(\d+) has started" build_end_regex = r"Test build #(\d+) (has finished|timed out)" for comment in (pr.comments_json or []): author = comment["user"]["login"] # Delete all comments from AmplabJenkins unless they are the comments that should be # displayed on the Spark PR dashboard. If we do not know which comment to preserve, then # do not delete any comments from AmplabJenkins. if jenkins_comment_to_preserve \ and author == "AmplabJenkins" \ and comment["url"] != jenkins_comment_to_preserve["url"]: raw_github_request(comment["url"], oauth_token=amplabjenkins_token, method="DELETE") elif author == "SparkQA": # Only delete build start notification comments from SparkQA and only delete them # after we've seen the corresponding build finished message. start_regex_match = re.search(build_start_regex, comment["body"]) if start_regex_match: sparkqa_start_comments[start_regex_match.groups() [0]] = comment else: end_regex_match = re.search(build_end_regex, comment["body"]) if end_regex_match: start_comment = sparkqa_start_comments.get( end_regex_match.groups()[0]) if start_comment: raw_github_request(start_comment["url"], oauth_token=sparkqa_token, method="DELETE") return "Done updating comments for PR %i" % pr_number
def build_response(template, max_age=60, **kwargs): navigation_bar = [ # (href, id, label, badge_value) ('/', 'index', 'Open PRs', int(Issue.query(Issue.state == "open").count())), ] if g.user and "admin" in g.user.roles: navigation_bar.append(('/admin', 'admin', 'Admin', None)) default_context = { 'profiler_includes': profiler_includes(), 'navigation_bar': navigation_bar, 'user': g.user, } rendered = render_template(template, **(dict(default_context.items() + kwargs.items()))) response = make_response(rendered) response.cache_control.max_age = max_age return response
def build_response(template, max_age=60, **kwargs): navigation_bar = [ # (href, id, label, badge_value) ('/', 'index', 'Open PRs', int(Issue.query(Issue.state == "open").count())), ] if g.user and "admin" in g.user.roles: navigation_bar.append(('/admin', 'admin', 'Admin', None)) default_context = { 'profiler_includes': profiler_includes(), 'navigation_bar': navigation_bar, 'user': g.user, } rendered = render_template( template, **(dict(default_context.items() + kwargs.items()))) response = make_response(rendered) response.cache_control.max_age = max_age return response
def update_pr_comments(pr_number): pr = Issue.get(pr_number) comments_response = paginated_github_request(get_issues_base() + '/%i/comments' % pr_number, oauth_token=oauth_token) # TODO: after fixing #32, re-enable etags here: etag=self.comments_etag) if comments_response is None: return "Comments for PR %i are up-to-date" % pr_number else: pr.comments_json, pr.comments_etag = comments_response pr.cached_commenters = pr._compute_commenters() pr.cached_last_jenkins_outcome = None pr.last_jenkins_outcome # force recomputation of Jenkins outcome pr.put() # Write our modifications back to the database # Delete out-of-date comments from AmplabJenkins and SparkQA. jenkins_comment_to_preserve = pr.last_jenkins_comment sparkqa_token = app.config["SPARKQA_GITHUB_OAUTH_KEY"] amplabjenkins_token = app.config["AMPLAB_JENKINS_GITHUB_OAUTH_KEY"] sparkqa_start_comments = {} # Map from build ID to build start comment build_start_regex = r"Test build #(\d+) has started" build_end_regex = r"Test build #(\d+) (has finished|timed out)" for comment in (pr.comments_json or []): author = comment["user"]["login"] # Delete all comments from AmplabJenkins unless they are the comments that should be # displayed on the Spark PR dashboard. If we do not know which comment to preserve, then # do not delete any comments from AmplabJenkins. if jenkins_comment_to_preserve \ and author == "AmplabJenkins" \ and comment["url"] != jenkins_comment_to_preserve["url"]: raw_github_request(comment["url"], oauth_token=amplabjenkins_token, method="DELETE") elif author == "SparkQA": # Only delete build start notification comments from SparkQA and only delete them # after we've seen the corresponding build finished message. start_regex_match = re.search(build_start_regex, comment["body"]) if start_regex_match: sparkqa_start_comments[start_regex_match.groups()[0]] = comment else: end_regex_match = re.search(build_end_regex, comment["body"]) if end_regex_match: start_comment = sparkqa_start_comments.get(end_regex_match.groups()[0]) if start_comment: raw_github_request(start_comment["url"], oauth_token=sparkqa_token, method="DELETE") return "Done updating comments for PR %i" % pr_number
def search_open_prs(): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() json_dicts = [] for pr in prs: last_jenkins_comment_dict = None if pr.last_jenkins_comment: last_jenkins_comment_dict = { 'body': pr.last_jenkins_comment['body'], 'user': { 'login': pr.last_jenkins_comment['user']['login'] }, 'html_url': pr.last_jenkins_comment['html_url'], } d = { 'parsed_title': pr.parsed_title, 'number': pr.number, 'updated_at': str(pr.updated_at), 'user': pr.user, 'state': pr.state, 'components': pr.components, 'lines_added': pr.lines_added, 'lines_deleted': pr.lines_deleted, 'lines_changed': pr.lines_changed, 'is_mergeable': pr.is_mergeable, 'commenters': [{ 'username': u, 'data': d } for (u, d) in pr.commenters], 'last_jenkins_outcome': pr.last_jenkins_outcome, 'last_jenkins_comment': last_jenkins_comment_dict, } # Use the first JIRA's information to populate the "Priority" and "Issue Type" columns: jiras = pr.parsed_title["jiras"] if jiras: first_jira = JIRAIssue.get_by_id("SPARK-%i" % jiras[0]) if first_jira: d['jira_priority_name'] = first_jira.priority_name d['jira_priority_icon_url'] = first_jira.priority_icon_url d['jira_issuetype_name'] = first_jira.issuetype_name d['jira_issuetype_icon_url'] = first_jira.issuetype_icon_url json_dicts.append(d) response = Response(json.dumps(json_dicts), mimetype='application/json') return response
def search_open_prs(): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() json_dicts = [] for pr in prs: last_jenkins_comment_dict = None if pr.last_jenkins_comment: last_jenkins_comment_dict = { 'body': pr.last_jenkins_comment['body'], 'user': {'login': pr.last_jenkins_comment['user']['login']}, 'html_url': pr.last_jenkins_comment['html_url'], 'date': [pr.last_jenkins_comment['created_at']], } d = { 'parsed_title': pr.parsed_title, 'number': pr.number, 'updated_at': str(pr.updated_at), 'user': pr.user, 'state': pr.state, 'components': pr.components, 'lines_added': pr.lines_added, 'lines_deleted': pr.lines_deleted, 'lines_changed': pr.lines_changed, 'is_mergeable': pr.is_mergeable, 'commenters': [{'username': u, 'data': d} for (u, d) in pr.commenters], 'last_jenkins_outcome': pr.last_jenkins_outcome, 'last_jenkins_comment': last_jenkins_comment_dict, } # Use the first JIRA's information to populate the "Priority" and "Issue Type" columns: jiras = pr.parsed_title["jiras"] if jiras: first_jira = JIRAIssue.get_by_id("SPARK-%i" % jiras[0]) if first_jira: d['jira_priority_name'] = first_jira.priority_name d['jira_priority_icon_url'] = first_jira.priority_icon_url d['jira_issuetype_name'] = first_jira.issuetype_name d['jira_issuetype_icon_url'] = first_jira.issuetype_icon_url d['jira_shepherd_display_name'] = first_jira.shepherd_display_name json_dicts.append(d) response = Response(json.dumps(json_dicts), mimetype='application/json') return response
def test_pr(number): """ Triggers a parametrized Jenkins build for testing Spark pull requests. """ if not (g.user and g.user.has_capability("jenkins")): return abort(403) pr = Issue.get_or_create(number) commit = pr.pr_json["head"]["sha"] target_branch = pr.pr_json["base"]["ref"] # The parameter names here were chosen to match the ones used by Jenkins' GitHub pull request # builder plugin: https://wiki.jenkins-ci.org/display/JENKINS/Github+pull+request+builder+plugin # In the Spark repo, the https://github.com/apache/spark/blob/master/dev/run-tests-jenkins # script reads these variables when posting pull request feedback. query = { 'token': app.config['JENKINS_PRB_TOKEN'], 'ghprbPullId': number, 'ghprbActualCommit': commit, 'ghprbTargetBranch': target_branch, 'ghprbPullTitle': pr.raw_title, # This matches the Jenkins plugin's logic; see # https://github.com/jenkinsci/ghprb-plugin/blob/master/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java#L146 # # It looks like origin/pr/*/merge ref points to the last successful test merge commit that # GitHub generates when it checks for mergeability. This API technically isn't documented, # but enough plugins seem to rely on it that it seems unlikely to change anytime soon # (if it does, we can always upgrade our tests to perform the merge ourselves). # # See also: https://developer.github.com/changes/2013-04-25-deprecating-merge-commit-sha/ 'sha1': ("origin/pr/%i/merge" % number) if pr.is_mergeable else commit, } trigger_url = "%sbuildWithParameters?%s" % ( app.config["JENKINS_PRB_JOB_URL"], urllib.urlencode(query)) logging.debug("Triggering Jenkins with url %s" % trigger_url) response = urlfetch.fetch(trigger_url, method="POST") if response.status_code not in (200, 201): logging.error("Jenkins responded with status code %i" % response.status_code) return response.content else: return redirect(app.config["JENKINS_PRB_JOB_URL"])
def test_pr(number): """ Triggers a parametrized Jenkins build for testing Spark pull requests. """ if not (g.user and g.user.has_capability("jenkins")): return abort(403) pr = Issue.get_or_create(number) commit = pr.pr_json["head"]["sha"] target_branch = pr.pr_json["base"]["ref"] # The parameter names here were chosen to match the ones used by Jenkins' GitHub pull request # builder plugin: https://wiki.jenkins-ci.org/display/JENKINS/Github+pull+request+builder+plugin # In the Spark repo, the https://github.com/apache/spark/blob/master/dev/run-tests-jenkins # script reads these variables when posting pull request feedback. query = { 'token': app.config['JENKINS_PRB_TOKEN'], 'ghprbPullId': number, 'ghprbActualCommit': commit, 'ghprbTargetBranch': target_branch, 'ghprbPullTitle': pr.raw_title.encode('utf-8'), # This matches the Jenkins plugin's logic; see # https://github.com/jenkinsci/ghprb-plugin/blob/master/src/main/java/org/jenkinsci/plugins/ghprb/GhprbTrigger.java#L146 # # It looks like origin/pr/*/merge ref points to the last successful test merge commit that # GitHub generates when it checks for mergeability. This API technically isn't documented, # but enough plugins seem to rely on it that it seems unlikely to change anytime soon # (if it does, we can always upgrade our tests to perform the merge ourselves). # # See also: https://developer.github.com/changes/2013-04-25-deprecating-merge-commit-sha/ 'sha1': ("origin/pr/%i/merge" % number) if pr.is_mergeable else commit, } trigger_url = "%sbuildWithParameters?%s" % (app.config["JENKINS_PRB_JOB_URL"], urllib.urlencode(query)) logging.debug("Triggering Jenkins with url %s" % trigger_url) response = urlfetch.fetch(trigger_url, method="POST") if response.status_code not in (200, 201): logging.error("Jenkins responded with status code %i" % response.status_code) return response.content else: return redirect(app.config["JENKINS_PRB_JOB_URL"])
def search_open_prs(): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() json_dicts = [] for pr in prs: last_jenkins_comment_dict = None if pr.last_jenkins_comment: last_jenkins_comment_dict = { "body": pr.last_jenkins_comment["body"], "user": {"login": pr.last_jenkins_comment["user"]["login"]}, "html_url": pr.last_jenkins_comment["html_url"], } d = { "parsed_title": pr.parsed_title, "number": pr.number, "updated_at": str(pr.updated_at), "user": pr.user, "state": pr.state, "components": pr.components, "lines_added": pr.lines_added, "lines_deleted": pr.lines_deleted, "lines_changed": pr.lines_changed, "is_mergeable": pr.is_mergeable, "commenters": [{"username": u, "data": d} for (u, d) in pr.commenters], "last_jenkins_outcome": pr.last_jenkins_outcome, "last_jenkins_comment": last_jenkins_comment_dict, } # Use the first JIRA's information to populate the "Priority" and "Issue Type" columns: jiras = pr.parsed_title["jiras"] if jiras: first_jira = JIRAIssue.get_by_id("SPARK-%i" % jiras[0]) if first_jira: d["jira_priority_name"] = first_jira.priority_name d["jira_priority_icon_url"] = first_jira.priority_icon_url d["jira_issuetype_name"] = first_jira.issuetype_name d["jira_issuetype_icon_url"] = first_jira.issuetype_icon_url d["jira_shepherd_display_name"] = first_jira.shepherd_display_name json_dicts.append(d) response = Response(json.dumps(json_dicts), mimetype="application/json") return response
def update_pr(number): Issue.get_or_create(number).update(app.config['GITHUB_OAUTH_KEY']) return "Done updating pull request %i" % number
def users(username): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() prs_authored = [p for p in prs if p.user == username] prs_commented_on = [p for p in prs if username in dict(p.commenters) and p.user != username] return build_response('user.html', username=username, prs_authored=prs_authored, prs_commented_on=prs_commented_on)
def all_prs_json(): offset = int(request.args.get('offset')) limit = 100 prs = Issue.query(Issue.number > offset).order(Issue.number).fetch(limit) return build_pr_json_response(prs)
def update_issue(number): Issue.get_or_create(number).update(app.config['GITHUB_OAUTH_KEY']) return "Done updating issue %i" % number
def search_stale_prs(): issueQuery = ndb.AND(Issue.state == "open", Issue.updated_at < datetime.datetime.today() - datetime.timedelta(days=30)) stalePrs = Issue.query(issueQuery).order(-Issue.updated_at).fetch() return search_prs(stalePrs)
def search_open_prs(): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() json_dicts = [] for pr in prs: try: last_jenkins_comment_dict = None if pr.last_jenkins_comment: last_jenkins_comment_dict = { 'body': pr.last_jenkins_comment['body'], 'user': { 'login': pr.last_jenkins_comment['user']['login'] }, 'html_url': pr.last_jenkins_comment['html_url'], 'date': [pr.last_jenkins_comment['created_at']], } d = { 'parsed_title': pr.parsed_title, 'number': pr.number, 'updated_at': str(pr.updated_at), 'user': pr.user, 'state': pr.state, 'components': pr.components, 'lines_added': pr.lines_added, 'lines_deleted': pr.lines_deleted, 'lines_changed': pr.lines_changed, 'is_mergeable': pr.is_mergeable, 'commenters': [{ 'username': u, 'data': d } for (u, d) in pr.commenters], 'last_jenkins_outcome': pr.last_jenkins_outcome, 'last_jenkins_comment': last_jenkins_comment_dict, } # Use the first JIRA's information to populate the "Priority" and "Issue Type" columns: jiras = pr.parsed_title["jiras"] if jiras: first_jira = JIRAIssue.get_by_id( "%s-%i" % (app.config['JIRA_PROJECT'], jiras[0])) if first_jira: d['jira_priority_name'] = first_jira.priority_name d['jira_priority_icon_url'] = first_jira.priority_icon_url d['jira_issuetype_name'] = first_jira.issuetype_name d['jira_issuetype_icon_url'] = first_jira.issuetype_icon_url d['jira_shepherd_display_name'] = first_jira.shepherd_display_name # If a pull request is linked against multiple JIRA issues, then the target # versions should be union of the individual issues' target versions: target_versions = set() for jira_number in jiras: jira = JIRAIssue.get_by_id( "%s-%i" % (app.config['JIRA_PROJECT'], jira_number)) if jira: target_versions.update(jira.target_versions) if target_versions: d['jira_target_versions'] = natsorted(target_versions) json_dicts.append(d) except: logging.error("Exception while processing PR #%i", pr.number) raise response = Response(json.dumps(json_dicts), mimetype='application/json') return response
def search_open_prs(): prs = Issue.query(Issue.state == "open").order(-Issue.updated_at).fetch() return search_prs(prs)
def update_pr(number): Issue.get_or_create(number).update(app.config["GITHUB_OAUTH_KEY"]) return "Done updating pull request %i" % number
def search_stale_prs(): issueQuery = ndb.AND( Issue.state == "open", Issue.updated_at < datetime.datetime.today() - datetime.timedelta(days=30)) stalePrs = Issue.query(issueQuery).order(-Issue.updated_at).fetch() return search_prs(stalePrs)
def refresh_all_prs(): prs = Issue.query(Issue.state == "open") for pr in prs: taskqueue.add(url=url_for(".update_pr", pr_number=pr.number), queue_name='old-prs') return "Enqueued tasks to refresh all open PRs"