Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(652)

Side by Side Diff: appengine/chromium_try_flakes/issue_tracker/issue_tracker_api.py

Issue 2387153002: Report all flakes reported to issue tracker also to FindIt (Closed)
Patch Set: Addressed comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/chromium_try_flakes/handlers/test/flake_issues_test.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 """Provides API wrapper for the codesite issue tracker""" 1 """Provides API wrapper for the codesite issue tracker"""
2 2
3 import httplib2 3 from endpoints import endpoints
4 import logging
5 import time
6
7 from apiclient import discovery
8 from apiclient.errors import HttpError
9 from issue_tracker.issue import Issue 4 from issue_tracker.issue import Issue
10 from issue_tracker.comment import Comment 5 from issue_tracker.comment import Comment
11 from oauth2client.appengine import AppAssertionCredentials
12
13
14 # TODO(akuegel): Do we want to use a different timeout? Do we want to use a
15 # cache? See documentation here:
16 # https://github.com/jcgregorio/httplib2/blob/master/python2/httplib2/__init__.p y#L1142
17 def _createHttpObject(scope): # pragma: no cover
18 credentials = AppAssertionCredentials(scope=scope)
19 return credentials.authorize(httplib2.Http())
20
21
22 def _buildClient(api_name, api_version, http,
23 discovery_url): # pragma: no cover
24 # This occassionally hits a 503 "Backend Error". Hopefully a simple retry
25 # can recover.
26 tries_left = 5
27 tries_wait = 10
28 while tries_left:
29 tries_left -= 1
30 try:
31 client = discovery.build(
32 api_name, api_version,
33 discoveryServiceUrl=discovery_url,
34 http=http)
35 break
36 except HttpError as e:
37 if tries_left:
38 logging.error(
39 'apiclient.discovery.build() failed for %s: %s', api_name, e)
40 logging.error(
41 'Retrying apiclient.discovery.build() in %s seconds.', tries_wait)
42 time.sleep(tries_wait)
43 else:
44 logging.exception(
45 'apiclient.discovery.build() failed for %s too many times.',
46 api_name)
47 raise e
48 return client
49 6
50 7
51 class IssueTrackerAPI(object): # pragma: no cover 8 class IssueTrackerAPI(object): # pragma: no cover
52 CAN_ALL = 'all' 9 CAN_ALL = 'all'
53 10
54 """A wrapper around the issue tracker api.""" 11 """A wrapper around the issue tracker api."""
55 def __init__(self, project_name): 12 def __init__(self, project_name):
56 self.project_name = project_name 13 self.project_name = project_name
57 14 self.client = endpoints.build_client(
58 self.client = _buildClient( 15 'monorail', 'v1', 'https://monorail-prod.appspot.com/_ah/api/discovery'
59 'monorail', 'v1', 16 '/v1/apis/{api}/{apiVersion}/rest')
60 _createHttpObject('https://www.googleapis.com/auth/userinfo.email'),
61 'https://monorail-prod.appspot.com/_ah/api/discovery/v1/apis/{api}/'
62 '{apiVersion}/rest')
63
64 def _retry_api_call(self, request, num_retries=5):
65 retries = 0
66 while True:
67 try:
68 return request.execute()
69 except HttpError as e:
70 # This retries internal server (500, 503) and quota (403) errors.
71 if retries == num_retries or e.resp.status not in [403, 500, 503]:
72 raise
73 time.sleep(2**retries)
74 retries += 1
75 17
76 def create(self, issue, send_email=True): 18 def create(self, issue, send_email=True):
77 body = {} 19 body = {}
78 assert issue.summary 20 assert issue.summary
79 body['summary'] = issue.summary 21 body['summary'] = issue.summary
80 if issue.description: 22 if issue.description:
81 body['description'] = issue.description 23 body['description'] = issue.description
82 if issue.status: 24 if issue.status:
83 body['status'] = issue.status 25 body['status'] = issue.status
84 if issue.owner: 26 if issue.owner:
85 body['owner'] = {'name': issue.owner} 27 body['owner'] = {'name': issue.owner}
86 if issue.labels: 28 if issue.labels:
87 body['labels'] = issue.labels 29 body['labels'] = issue.labels
88 if issue.components: 30 if issue.components:
89 body['components'] = issue.components 31 body['components'] = issue.components
90 if issue.cc: 32 if issue.cc:
91 body['cc'] = [{'name': user} for user in issue.cc] 33 body['cc'] = [{'name': user} for user in issue.cc]
92 request = self.client.issues().insert( 34 request = self.client.issues().insert(
93 projectId=self.project_name, sendEmail=send_email, body=body) 35 projectId=self.project_name, sendEmail=send_email, body=body)
94 tmp = self._retry_api_call(request) 36 tmp = endpoints._retry__request(request)
95 issue.id = int(tmp['id']) 37 issue.id = int(tmp['id'])
96 issue.dirty = False 38 issue.dirty = False
97 return issue 39 return issue
98 40
99 def update(self, issue, comment=None, send_email=True): 41 def update(self, issue, comment=None, send_email=True):
100 if not issue.dirty and not comment: 42 if not issue.dirty and not comment:
101 return issue 43 return issue
102 44
103 updates = {} 45 updates = {}
104 if 'summary' in issue.changed: 46 if 'summary' in issue.changed:
(...skipping 17 matching lines...) Expand all
122 64
123 body = {'id': issue.id, 65 body = {'id': issue.id,
124 'updates': updates} 66 'updates': updates}
125 67
126 if comment: 68 if comment:
127 body['content'] = comment 69 body['content'] = comment
128 70
129 request = self.client.issues().comments().insert( 71 request = self.client.issues().comments().insert(
130 projectId=self.project_name, issueId=issue.id, sendEmail=send_email, 72 projectId=self.project_name, issueId=issue.id, sendEmail=send_email,
131 body=body) 73 body=body)
132 self._retry_api_call(request) 74 endpoints.retry_request(request)
133 75
134 if issue.owner == '----': 76 if issue.owner == '----':
135 issue.owner = '' 77 issue.owner = ''
136 78
137 issue.dirty = False 79 issue.dirty = False
138 return issue 80 return issue
139 81
140 def addComment(self, issue_id, comment, send_email=True): 82 def addComment(self, issue_id, comment, send_email=True):
141 issue = self.getIssue(issue_id) 83 issue = self.getIssue(issue_id)
142 self.update(issue, comment, send_email) 84 self.update(issue, comment, send_email)
143 85
144 def getCommentCount(self, issue_id): 86 def getCommentCount(self, issue_id):
145 request = self.client.issues().comments().list( 87 request = self.client.issues().comments().list(
146 projectId=self.project_name, issueId=issue_id, startIndex=1, 88 projectId=self.project_name, issueId=issue_id, startIndex=1,
147 maxResults=0) 89 maxResults=0)
148 feed = self._retry_api_call(request) 90 feed = endpoints.retry_request(request)
149 return feed.get('totalResults', '0') 91 return feed.get('totalResults', '0')
150 92
151 def getComments(self, issue_id): 93 def getComments(self, issue_id):
152 rtn = [] 94 rtn = []
153 95
154 request = self.client.issues().comments().list( 96 request = self.client.issues().comments().list(
155 projectId=self.project_name, issueId=issue_id) 97 projectId=self.project_name, issueId=issue_id)
156 feed = self._retry_api_call(request) 98 feed = endpoints.retry_request(request)
157 rtn.extend([Comment(entry) for entry in feed['items']]) 99 rtn.extend([Comment(entry) for entry in feed['items']])
158 total_results = feed['totalResults'] 100 total_results = feed['totalResults']
159 if not total_results: 101 if not total_results:
160 return rtn 102 return rtn
161 103
162 while len(rtn) < total_results: 104 while len(rtn) < total_results:
163 request = self.client.issues().comments().list( 105 request = self.client.issues().comments().list(
164 projectId=self.project_name, issueId=issue_id, startIndex=len(rtn)) 106 projectId=self.project_name, issueId=issue_id, startIndex=len(rtn))
165 feed = self._retry_api_call(request) 107 feed = endpoints.retry_request(request)
166 rtn.extend([Comment(entry) for entry in feed['items']]) 108 rtn.extend([Comment(entry) for entry in feed['items']])
167 109
168 return rtn 110 return rtn
169 111
170 def getFirstComment(self, issue_id): 112 def getFirstComment(self, issue_id):
171 request = self.client.issues().comments().list( 113 request = self.client.issues().comments().list(
172 projectId=self.project_name, issueId=issue_id, startIndex=0, 114 projectId=self.project_name, issueId=issue_id, startIndex=0,
173 maxResults=1) 115 maxResults=1)
174 feed = self._retry_api_call(request) 116 feed = endpoints.retry_request(request)
175 if 'items' in feed and len(feed['items']) > 0: 117 if 'items' in feed and len(feed['items']) > 0:
176 return Comment(feed['items'][0]) 118 return Comment(feed['items'][0])
177 return None 119 return None
178 120
179 def getLastComment(self, issue_id): 121 def getLastComment(self, issue_id):
180 total_results = self.getCommentCount(issue_id) 122 total_results = self.getCommentCount(issue_id)
181 request = self.client.issues().comments().list( 123 request = self.client.issues().comments().list(
182 projectId=self.project_name, issueId=issue_id, 124 projectId=self.project_name, issueId=issue_id,
183 startIndex=total_results-1, maxResults=1) 125 startIndex=total_results-1, maxResults=1)
184 feed = self._retry_api_call(request) 126 feed = endpoints.retry_request(request)
185 if 'items' in feed and len(feed['items']) > 0: 127 if 'items' in feed and len(feed['items']) > 0:
186 return Comment(feed['items'][0]) 128 return Comment(feed['items'][0])
187 return None 129 return None
188 130
189 def getIssue(self, issue_id): 131 def getIssue(self, issue_id):
190 """Retrieve a set of issues in a project.""" 132 """Retrieve a set of issues in a project."""
191 request = self.client.issues().get( 133 request = self.client.issues().get(
192 projectId=self.project_name, issueId=issue_id) 134 projectId=self.project_name, issueId=issue_id)
193 entry = self._retry_api_call(request) 135 entry = endpoints.retry_request(request)
194 return Issue(entry) 136 return Issue(entry)
OLDNEW
« no previous file with comments | « appengine/chromium_try_flakes/handlers/test/flake_issues_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698