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

Side by Side Diff: appengine/chromium_cq_status/handlers/patch_timeline_data.py

Issue 1236243002: chromium-cq-status timeline view uses cname argument. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 5 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 | « no previous file | appengine/chromium_cq_status/tests/patch_timeline_data_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Provides a JSON endpoint for CQ data as a series of Trace Viewer events. 5 """Provides a JSON endpoint for CQ data as a series of Trace Viewer events.
6 6
7 From the CQ data posted to the datastore, patch_timeline will construct a JSON 7 From the CQ data posted to the datastore, patch_timeline will construct a JSON
8 object that can be parsed by Trace Viewer to create a timeline view. 8 object that can be parsed by Trace Viewer to create a timeline view.
9 """ 9 """
10 10
(...skipping 25 matching lines...) Expand all
36 36
37 def get_attempts(issue, patch): # pragma: no cover 37 def get_attempts(issue, patch): # pragma: no cover
38 """Given an issue and a patch, returns a list of attempts. 38 """Given an issue and a patch, returns a list of attempts.
39 39
40 Returns a list of attempts. Attempts are lists of records which fall within 40 Returns a list of attempts. Attempts are lists of records which fall within
41 the endpoints of patch_start and patch_stop actions, inclusive. 41 the endpoints of patch_start and patch_stop actions, inclusive.
42 """ 42 """
43 query = Record.query().order(Record.timestamp).filter( 43 query = Record.query().order(Record.timestamp).filter(
44 Record.tags == TAG_ISSUE % issue, 44 Record.tags == TAG_ISSUE % issue,
45 Record.tags == TAG_PATCHSET % patch) 45 Record.tags == TAG_PATCHSET % patch)
46 attempts = []
47 attempt = None 46 attempt = None
48 for record in query: 47 for record in query:
49 action = record.fields.get('action') 48 action = record.fields.get('action')
50 if attempt is None and action == 'patch_start': 49 if attempt is None and action == 'patch_start':
51 attempt = [record] 50 attempt = [record]
52 # Sometimes CQ sends multiple patch_start in a single attempt. These 51 # Sometimes CQ sends multiple patch_start in a single attempt. These
53 # are ignored (only the first patch_start is kept). 52 # are ignored (only the first patch_start is kept).
54 if attempt is not None and action != 'patch_start': 53 if attempt is not None and action != 'patch_start':
55 attempt.append(record) 54 attempt.append(record)
56 if action == 'patch_stop': 55 if action == 'patch_stop':
57 attempts.append(attempt) 56 yield attempt
58 attempt = None 57 attempt = None
59 if attempt != None: 58 if attempt != None:
60 attempts.append(attempt) 59 yield attempt
61 return attempts
62 60
63 61
64 def attempts_to_events(attempts): # pragma: no cover 62 def attempts_to_events(attempts): # pragma: no cover
65 """Given a list of attempts, returns a list of Trace Viewer events. 63 """Given a list of attempts, returns a list of Trace Viewer events.
66 64
67 Attempts are a list of CQ records which fall between patch_start and 65 Attempts are a list of CQ records which fall between patch_start and
68 patch_stop actions. Each record is converted to a Trace Viewer event 66 patch_stop actions. Each record is converted to a Trace Viewer event
69 of type 'B' or 'E', representing begin and end respectively. 67 of type 'B' or 'E', representing begin and end respectively.
70 68
71 Occasinally CQ runs jobs without first a record representing a trigger 69 Occasinally CQ runs jobs without first a record representing a trigger
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 patch_ready_to_commit: single 'B' event representing start of commit attempt 128 patch_ready_to_commit: single 'B' event representing start of commit attempt
131 patch_committed: single 'E' event representing successful commit 129 patch_committed: single 'E' event representing successful commit
132 patch_failed: single 'E' event representing completed patch attempt 130 patch_failed: single 'E' event representing completed patch attempt
133 patch_stop: single 'E' event representing the end of the attempt. 131 patch_stop: single 'E' event representing the end of the attempt.
134 verifier_trigger: multiple 'B' events, one for each builder triggered. 132 verifier_trigger: multiple 'B' events, one for each builder triggered.
135 verifier_jobs_update: multiple 'E' events, one for each builder success 133 verifier_jobs_update: multiple 'E' events, one for each builder success
136 or failure. 134 or failure.
137 """ 135 """
138 action = record.fields.get('action') 136 action = record.fields.get('action')
139 attempt_string = 'Attempt %d' % attempt_number 137 attempt_string = 'Attempt %d' % attempt_number
138 timestamp = record.fields.get('timestamp')
140 if action == 'verifier_trigger': 139 if action == 'verifier_trigger':
141 timestamp = record.fields['timestamp']
142 masters = record.fields.get('trybots', {}) 140 masters = record.fields.get('trybots', {})
143 for master in masters: 141 for master in masters:
144 for builder in masters[master]: 142 for builder in masters[master]:
145 yield TraceViewerEvent(builder, master, 'B', timestamp, attempt_string, 143 yield TraceViewerEvent(builder, master, 'B', timestamp, attempt_string,
146 builder) 144 builder, 'cq_build_running')
147 elif action == 'verifier_jobs_update': 145 elif action == 'verifier_jobs_update':
148 job_states = record.fields.get('jobs', {}) 146 job_states = record.fields.get('jobs', {})
149 # CQ splits jobs into lists based on their state. 147 # CQ splits jobs into lists based on their state.
150 for cq_job_state, jobs in job_states.iteritems(): 148 for cq_job_state, jobs in job_states.iteritems():
151 # Jobs can be in many different states, JOB_STATE maps them to 149 # Jobs can be in many different states, JOB_STATE maps them to
152 # 'running' or not. 150 # 'running' or not.
153 job_state = JOB_STATE.get(cq_job_state) 151 job_state = JOB_STATE.get(cq_job_state)
154 if not job_state or job_state == 'running': 152 if not job_state or job_state == 'running':
155 continue 153 continue
156 for job_info in jobs: 154 for job_info in jobs:
157 master = job_info['master'] 155 master = job_info['master']
158 builder = job_info['builder'] 156 builder = job_info['builder']
159 timestamp = rietveld_timestamp(job_info['timestamp']) 157 timestamp = rietveld_timestamp(job_info['timestamp'])
158 cname = 'cq_build_' + job_state
160 args = { 159 args = {
161 'build_url': job_info.get('url'), 160 'build_url': job_info.get('url'),
162 'job_state': job_state,
163 } 161 }
164 yield TraceViewerEvent(builder, master, 'E', timestamp, attempt_string, 162 yield TraceViewerEvent(builder, master, 'E', timestamp, attempt_string,
165 builder, args) 163 builder, cname, args)
166 elif action == 'patch_start': 164 elif action == 'patch_start':
167 yield TraceViewerEvent(attempt_string, 'Patch Progress', 'B', 165 yield TraceViewerEvent(attempt_string, 'Patch Progress', 'B',
168 record.fields['timestamp'], attempt_string, 166 timestamp, attempt_string,
169 'Patch Progress', {'job_state': 'attempt_running'}) 167 'Patch Progress', 'cq_build_attempt_running')
170 elif action == 'patch_ready_to_commit': 168 elif action == 'patch_ready_to_commit':
171 yield TraceViewerEvent('Patch Committing', 'Patch Progress', 'B', 169 yield TraceViewerEvent('Patch Committing', 'Patch Progress', 'B',
172 record.fields['timestamp'], attempt_string, 170 timestamp, attempt_string,
173 'Patch Progress', {'job_state': 'attempt_running'}) 171 'Patch Progress', 'cq_build_attempt_running')
174 elif action == 'patch_committed': 172 elif action == 'patch_committed':
175 yield TraceViewerEvent('Patch Committing', 'Patch Progress', 'E', 173 yield TraceViewerEvent('Patch Committing', 'Patch Progress', 'E',
176 record.fields['timestamp'], attempt_string, 174 timestamp, attempt_string,
177 'Patch Progress', {'job_state': 'attempt_passed'}) 175 'Patch Progress', 'cq_build_attempt_passed')
178 elif action == 'patch_stop': 176 elif action == 'patch_stop':
179 state = 'attempt_' 177 cname = 'cq_build_attempt_'
180 if 'successfully committed' in record.fields['message']: 178 if 'successfully committed' in record.fields['message']:
181 state += 'passed' 179 cname += 'passed'
182 else: 180 else:
183 state += 'failed' 181 cname += 'failed'
184 yield TraceViewerEvent(attempt_string, 'Patch Progress', 'E', 182 yield TraceViewerEvent(attempt_string, 'Patch Progress', 'E',
185 record.fields['timestamp'], attempt_string, 183 timestamp, attempt_string, 'Patch Progress',
186 'Patch Progress', { 184 cname, {'action': action})
187 'job_state': state,
188 'action': action,
189 })
190 185
191 186
192 class TraceViewerEvent(): # pragma: no cover 187 class TraceViewerEvent(): # pragma: no cover
193 """A class used to create JSON objects corresponding to an event. 188 """A class used to create JSON objects corresponding to an event.
194 189
195 Trace Viewer requires a specific set of fields, described below: 190 Trace Viewer requires a specific set of fields, described below:
196 191
197 name: the name of the event, displayed as a label on the interval 192 name: the name of the event, displayed as a label on the interval
198 cat: category of the event, used with the search functionality 193 cat: category of the event, used with the search functionality
199 ph: type of event. for CQ data, it will be 'B' or 'E' for begin or end 194 ph: type of event. for CQ data, it will be 'B' or 'E' for begin or end
200 ts: timestamp of event 195 ts: timestamp of event
201 pid: process id, used for grouping threads 196 pid: process id, used for grouping threads
202 tid: thread id, displayed to the left of all intervals with the same thread 197 tid: thread id, displayed to the left of all intervals with the same thread
203 """ 198 """
204 def __init__(self, name, cat, ph, ts, pid, tid, args=None): 199 def __init__(self, name, cat, ph, ts, pid, tid, cname, args=None):
205 self.name = name 200 self.name = name
206 self.cat = cat 201 self.cat = cat
207 self.ph = ph 202 self.ph = ph
208 self.ts = ts 203 self.ts = ts
209 self.pid = pid 204 self.pid = pid
210 self.tid = tid 205 self.tid = tid
206 self.cname = cname
211 self.args = args or {} 207 self.args = args or {}
212 208
213 def to_dict(self): 209 def to_dict(self):
214 return { 210 return {
215 'name': self.name, 211 'name': self.name,
216 'cat': self.cat, 212 'cat': self.cat,
217 'ph': self.ph, 213 'ph': self.ph,
218 'ts': int(self.ts * 1000000), 214 'ts': int(self.ts * 1000000),
219 'pid': self.pid, 215 'pid': self.pid,
220 'tid': self.tid, 216 'tid': self.tid,
217 'cname': self.cname,
221 'args': self.args 218 'args': self.args
222 } 219 }
223 220
224 def builder_key(self): 221 def builder_key(self):
225 """Returns an identifier for the build of the form master/builder.""" 222 """Returns an identifier for the build of the form master/builder."""
226 return self.cat + '/' + self.name 223 return self.cat + '/' + self.name
227 224
228 225
229 def rietveld_timestamp(timestamp_string): # pragma: no cover 226 def rietveld_timestamp(timestamp_string): # pragma: no cover
230 """Converts a Rietveld timestamp into a unix timestamp.""" 227 """Converts a Rietveld timestamp into a unix timestamp."""
231 try: 228 try:
232 return to_unix_timestamp( 229 return to_unix_timestamp(
233 datetime.strptime(timestamp_string, RIETVELD_TIMESTAMP_FORMAT)) 230 datetime.strptime(timestamp_string, RIETVELD_TIMESTAMP_FORMAT))
234 except ValueError: 231 except ValueError:
235 return None 232 return None
OLDNEW
« no previous file with comments | « no previous file | appengine/chromium_cq_status/tests/patch_timeline_data_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698