| OLD | NEW |
| 1 """Provides API wrapper for the codesite issue tracker""" | 1 """Provides API wrapper for the codesite issue tracker""" |
| 2 | 2 |
| 3 import httplib2 | 3 import httplib2 |
| 4 import logging | 4 import logging |
| 5 import time | 5 import time |
| 6 | 6 |
| 7 from apiclient import discovery | 7 from apiclient import discovery |
| 8 from apiclient.errors import HttpError | 8 from apiclient.errors import HttpError |
| 9 from issue_tracker.issue import Issue | 9 from issue_tracker.issue import Issue |
| 10 from issue_tracker.comment import Comment | 10 from issue_tracker.comment import Comment |
| 11 from oauth2client.appengine import AppAssertionCredentials | 11 from oauth2client.appengine import AppAssertionCredentials |
| 12 | 12 |
| 13 import gae_ts_mon | |
| 14 | |
| 15 | 13 |
| 16 # TODO(akuegel): Do we want to use a different timeout? Do we want to use a | 14 # TODO(akuegel): Do we want to use a different timeout? Do we want to use a |
| 17 # cache? See documentation here: | 15 # cache? See documentation here: |
| 18 # https://github.com/jcgregorio/httplib2/blob/master/python2/httplib2/__init__.p
y#L1142 | 16 # https://github.com/jcgregorio/httplib2/blob/master/python2/httplib2/__init__.p
y#L1142 |
| 19 def _createHttpObject(scope): # pragma: no cover | 17 def _createHttpObject(scope): # pragma: no cover |
| 20 credentials = AppAssertionCredentials(scope=scope) | 18 credentials = AppAssertionCredentials(scope=scope) |
| 21 return credentials.authorize(httplib2.Http()) | 19 return credentials.authorize(httplib2.Http()) |
| 22 | 20 |
| 23 | 21 |
| 24 def _buildClient(api_name, api_version, http, | 22 def _buildClient(api_name, api_version, http, |
| (...skipping 21 matching lines...) Expand all Loading... |
| 46 logging.exception( | 44 logging.exception( |
| 47 'apiclient.discovery.build() failed for %s too many times.', | 45 'apiclient.discovery.build() failed for %s too many times.', |
| 48 api_name) | 46 api_name) |
| 49 raise e | 47 raise e |
| 50 return client | 48 return client |
| 51 | 49 |
| 52 | 50 |
| 53 class IssueTrackerAPI(object): # pragma: no cover | 51 class IssueTrackerAPI(object): # pragma: no cover |
| 54 CAN_ALL = 'all' | 52 CAN_ALL = 'all' |
| 55 | 53 |
| 56 issue_tracker_requests = gae_ts_mon.CounterMetric( | |
| 57 'flakiness_pipeline/issue_tracker_requests', | |
| 58 description='Number of requests to the issue tracker') | |
| 59 | |
| 60 """A wrapper around the issue tracker api.""" | 54 """A wrapper around the issue tracker api.""" |
| 61 def __init__(self, project_name): | 55 def __init__(self, project_name): |
| 62 self.project_name = project_name | 56 self.project_name = project_name |
| 63 | 57 |
| 64 self.client = _buildClient( | 58 self.client = _buildClient( |
| 65 'monorail', 'v1', | 59 'monorail', 'v1', |
| 66 _createHttpObject('https://www.googleapis.com/auth/userinfo.email'), | 60 _createHttpObject('https://www.googleapis.com/auth/userinfo.email'), |
| 67 'https://monorail-prod.appspot.com/_ah/api/discovery/v1/apis/{api}/' | 61 'https://monorail-prod.appspot.com/_ah/api/discovery/v1/apis/{api}/' |
| 68 '{apiVersion}/rest') | 62 '{apiVersion}/rest') |
| 69 | 63 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 91 body['owner'] = {'name': issue.owner} | 85 body['owner'] = {'name': issue.owner} |
| 92 if issue.labels: | 86 if issue.labels: |
| 93 body['labels'] = issue.labels | 87 body['labels'] = issue.labels |
| 94 if issue.components: | 88 if issue.components: |
| 95 body['components'] = issue.components | 89 body['components'] = issue.components |
| 96 if issue.cc: | 90 if issue.cc: |
| 97 body['cc'] = [{'name': user} for user in issue.cc] | 91 body['cc'] = [{'name': user} for user in issue.cc] |
| 98 request = self.client.issues().insert( | 92 request = self.client.issues().insert( |
| 99 projectId=self.project_name, sendEmail=send_email, body=body) | 93 projectId=self.project_name, sendEmail=send_email, body=body) |
| 100 tmp = self._retry_api_call(request) | 94 tmp = self._retry_api_call(request) |
| 101 self.issue_tracker_requests.increment( | |
| 102 {'source': 'chromium-try-flakes', 'operation': 'issues_insert'}) | |
| 103 issue.id = int(tmp['id']) | 95 issue.id = int(tmp['id']) |
| 104 issue.dirty = False | 96 issue.dirty = False |
| 105 return issue | 97 return issue |
| 106 | 98 |
| 107 def update(self, issue, comment=None, send_email=True): | 99 def update(self, issue, comment=None, send_email=True): |
| 108 if not issue.dirty and not comment: | 100 if not issue.dirty and not comment: |
| 109 return issue | 101 return issue |
| 110 | 102 |
| 111 updates = {} | 103 updates = {} |
| 112 if 'summary' in issue.changed: | 104 if 'summary' in issue.changed: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 131 body = {'id': issue.id, | 123 body = {'id': issue.id, |
| 132 'updates': updates} | 124 'updates': updates} |
| 133 | 125 |
| 134 if comment: | 126 if comment: |
| 135 body['content'] = comment | 127 body['content'] = comment |
| 136 | 128 |
| 137 request = self.client.issues().comments().insert( | 129 request = self.client.issues().comments().insert( |
| 138 projectId=self.project_name, issueId=issue.id, sendEmail=send_email, | 130 projectId=self.project_name, issueId=issue.id, sendEmail=send_email, |
| 139 body=body) | 131 body=body) |
| 140 self._retry_api_call(request) | 132 self._retry_api_call(request) |
| 141 self.issue_tracker_requests.increment( | |
| 142 {'source': 'chromium-try-flakes', 'operation': 'comments_insert'}) | |
| 143 | 133 |
| 144 if issue.owner == '----': | 134 if issue.owner == '----': |
| 145 issue.owner = '' | 135 issue.owner = '' |
| 146 | 136 |
| 147 issue.dirty = False | 137 issue.dirty = False |
| 148 return issue | 138 return issue |
| 149 | 139 |
| 150 def addComment(self, issue_id, comment, send_email=True): | 140 def addComment(self, issue_id, comment, send_email=True): |
| 151 issue = self.getIssue(issue_id) | 141 issue = self.getIssue(issue_id) |
| 152 self.update(issue, comment, send_email) | 142 self.update(issue, comment, send_email) |
| 153 | 143 |
| 154 def getCommentCount(self, issue_id): | 144 def getCommentCount(self, issue_id): |
| 155 request = self.client.issues().comments().list( | 145 request = self.client.issues().comments().list( |
| 156 projectId=self.project_name, issueId=issue_id, startIndex=1, | 146 projectId=self.project_name, issueId=issue_id, startIndex=1, |
| 157 maxResults=0) | 147 maxResults=0) |
| 158 feed = self._retry_api_call(request) | 148 feed = self._retry_api_call(request) |
| 159 self.issue_tracker_requests.increment( | |
| 160 {'source': 'chromium-try-flakes', 'operation': 'comments_list'}) | |
| 161 return feed.get('totalResults', '0') | 149 return feed.get('totalResults', '0') |
| 162 | 150 |
| 163 def getComments(self, issue_id): | 151 def getComments(self, issue_id): |
| 164 rtn = [] | 152 rtn = [] |
| 165 | 153 |
| 166 request = self.client.issues().comments().list( | 154 request = self.client.issues().comments().list( |
| 167 projectId=self.project_name, issueId=issue_id) | 155 projectId=self.project_name, issueId=issue_id) |
| 168 feed = self._retry_api_call(request) | 156 feed = self._retry_api_call(request) |
| 169 self.issue_tracker_requests.increment( | |
| 170 {'source': 'chromium-try-flakes', 'operation': 'comments_list'}) | |
| 171 rtn.extend([Comment(entry) for entry in feed['items']]) | 157 rtn.extend([Comment(entry) for entry in feed['items']]) |
| 172 total_results = feed['totalResults'] | 158 total_results = feed['totalResults'] |
| 173 if not total_results: | 159 if not total_results: |
| 174 return rtn | 160 return rtn |
| 175 | 161 |
| 176 while len(rtn) < total_results: | 162 while len(rtn) < total_results: |
| 177 request = self.client.issues().comments().list( | 163 request = self.client.issues().comments().list( |
| 178 projectId=self.project_name, issueId=issue_id, startIndex=len(rtn)) | 164 projectId=self.project_name, issueId=issue_id, startIndex=len(rtn)) |
| 179 feed = self._retry_api_call(request) | 165 feed = self._retry_api_call(request) |
| 180 self.issue_tracker_requests.increment( | |
| 181 {'source': 'chromium-try-flakes', 'operation': 'comments_list'}) | |
| 182 rtn.extend([Comment(entry) for entry in feed['items']]) | 166 rtn.extend([Comment(entry) for entry in feed['items']]) |
| 183 | 167 |
| 184 return rtn | 168 return rtn |
| 185 | 169 |
| 186 def getFirstComment(self, issue_id): | 170 def getFirstComment(self, issue_id): |
| 187 request = self.client.issues().comments().list( | 171 request = self.client.issues().comments().list( |
| 188 projectId=self.project_name, issueId=issue_id, startIndex=0, | 172 projectId=self.project_name, issueId=issue_id, startIndex=0, |
| 189 maxResults=1) | 173 maxResults=1) |
| 190 feed = self._retry_api_call(request) | 174 feed = self._retry_api_call(request) |
| 191 self.issue_tracker_requests.increment( | |
| 192 {'source': 'chromium-try-flakes', 'operation': 'comments_list'}) | |
| 193 if 'items' in feed and len(feed['items']) > 0: | 175 if 'items' in feed and len(feed['items']) > 0: |
| 194 return Comment(feed['items'][0]) | 176 return Comment(feed['items'][0]) |
| 195 return None | 177 return None |
| 196 | 178 |
| 197 def getLastComment(self, issue_id): | 179 def getLastComment(self, issue_id): |
| 198 total_results = self.getCommentCount(issue_id) | 180 total_results = self.getCommentCount(issue_id) |
| 199 request = self.client.issues().comments().list( | 181 request = self.client.issues().comments().list( |
| 200 projectId=self.project_name, issueId=issue_id, | 182 projectId=self.project_name, issueId=issue_id, |
| 201 startIndex=total_results-1, maxResults=1) | 183 startIndex=total_results-1, maxResults=1) |
| 202 feed = self._retry_api_call(request) | 184 feed = self._retry_api_call(request) |
| 203 self.issue_tracker_requests.increment( | |
| 204 {'source': 'chromium-try-flakes', 'operation': 'comments_list'}) | |
| 205 if 'items' in feed and len(feed['items']) > 0: | 185 if 'items' in feed and len(feed['items']) > 0: |
| 206 return Comment(feed['items'][0]) | 186 return Comment(feed['items'][0]) |
| 207 return None | 187 return None |
| 208 | 188 |
| 209 def getIssue(self, issue_id): | 189 def getIssue(self, issue_id): |
| 210 """Retrieve a set of issues in a project.""" | 190 """Retrieve a set of issues in a project.""" |
| 211 request = self.client.issues().get( | 191 request = self.client.issues().get( |
| 212 projectId=self.project_name, issueId=issue_id) | 192 projectId=self.project_name, issueId=issue_id) |
| 213 self.issue_tracker_requests.increment( | |
| 214 {'source': 'chromium-try-flakes', 'operation': 'issues_get'}) | |
| 215 entry = self._retry_api_call(request) | 193 entry = self._retry_api_call(request) |
| 216 return Issue(entry) | 194 return Issue(entry) |
| OLD | NEW |