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