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

Side by Side Diff: appengine/findit/handlers/build_failure.py

Issue 1895693002: [Findit] Add a new UI page for compile failures. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 4 years, 8 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/findit/handlers/test/build_failure_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 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 from collections import defaultdict 5 from collections import defaultdict
6 import copy 6 import copy
7 from datetime import datetime 7 from datetime import datetime
8 import logging
8 import os 9 import os
9 10
10 from google.appengine.api import users 11 from google.appengine.api import users
11 12
13 from common import constants
12 from common.base_handler import BaseHandler 14 from common.base_handler import BaseHandler
13 from common.base_handler import Permission 15 from common.base_handler import Permission
14 from common import constants 16 from common.waterfall import failure_type
15 from handlers import handlers_util 17 from handlers import handlers_util
16 from handlers import result_status 18 from handlers import result_status
17 from handlers.result_status import NO_TRY_JOB_REASON_MAP 19 from handlers.result_status import NO_TRY_JOB_REASON_MAP
18 from model import analysis_status 20 from model import analysis_status
19 from model.wf_analysis import WfAnalysis 21 from model.wf_analysis import WfAnalysis
22 from model.wf_try_job import WfTryJob
20 from model.result_status import RESULT_STATUS_TO_DESCRIPTION 23 from model.result_status import RESULT_STATUS_TO_DESCRIPTION
21 from waterfall import build_failure_analysis_pipelines 24 from waterfall import build_failure_analysis_pipelines
22 from waterfall import buildbot 25 from waterfall import buildbot
23 from waterfall import waterfall_config 26 from waterfall import waterfall_config
24 27
25 28
26 NON_SWARMING = object() 29 NON_SWARMING = object()
27 30
28 31
29 def _FormatDatetime(dt): 32 def _FormatDatetime(dt):
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 return updated_results 264 return updated_results
262 265
263 266
264 class BuildFailure(BaseHandler): 267 class BuildFailure(BaseHandler):
265 PERMISSION_LEVEL = Permission.ANYONE 268 PERMISSION_LEVEL = Permission.ANYONE
266 269
267 def _ShowDebugInfo(self): 270 def _ShowDebugInfo(self):
268 # Show debug info only if the app is run locally during development, if the 271 # Show debug info only if the app is run locally during development, if the
269 # currently logged-in user is an admin, or if it is explicitly requested 272 # currently logged-in user is an admin, or if it is explicitly requested
270 # with parameter 'debug=1'. 273 # with parameter 'debug=1'.
271 return (os.environ['SERVER_SOFTWARE'].startswith('Development') or 274 return (
272 users.is_current_user_admin() or self.request.get('debug') == '1') 275 users.is_current_user_admin() or self.request.get('debug') == '1')
273 276
274 def _ShowTriageHelpButton(self): 277 def _ShowTriageHelpButton(self):
275 return users.is_current_user_admin() 278 return users.is_current_user_admin()
276 279
280 def _PrepareCommonDataForFailure(self, analysis):
281 return {
282 'master_name': analysis.master_name,
283 'builder_name': analysis.builder_name,
284 'build_number': analysis.build_number,
285 'pipeline_status_path': analysis.pipeline_status_path,
286 'show_debug_info': self._ShowDebugInfo(),
287 'analysis_request_time': _FormatDatetime(analysis.request_time),
288 'analysis_start_time': _FormatDatetime(analysis.start_time),
289 'analysis_end_time': _FormatDatetime(analysis.end_time),
290 'analysis_duration': analysis.duration,
291 'analysis_update_time': _FormatDatetime(analysis.updated_time),
292 'analysis_completed': analysis.completed,
293 'analysis_failed': analysis.failed,
294 'analysis_correct': analysis.correct,
295 'triage_history': _GetTriageHistory(analysis),
296 'show_triage_help_button': self._ShowTriageHelpButton(),
297 'status_message_map': result_status.STATUS_MESSAGE_MAP
298 }
299
300 @staticmethod
301 def _PrepareTryJobDataForCompileFailure(analysis):
302 try_job_data = {}
303 if not (analysis.failure_result_map and # pragma: no branch.
304 constants.COMPILE_STEP_NAME in analysis.failure_result_map):
305 return try_job_data # pragma: no cover.
306
307 referred_build_keys = analysis.failure_result_map[
308 constants.COMPILE_STEP_NAME].split('/')
309 try_job = WfTryJob.Get(*referred_build_keys)
310 if not try_job or not try_job.compile_results:
311 return try_job_data # pragma: no cover.
312 result = try_job.compile_results[-1]
313
314 try_job_data['status'] = analysis_status.STATUS_TO_DESCRIPTION.get(
315 try_job.status, 'unknown').lower()
316 try_job_data['url'] = result.get('url')
317 try_job_data['completed'] = try_job.completed
318 try_job_data['failed'] = try_job.failed
319 try_job_data['culprit'] = result.get(
320 'culprit', {}).get(constants.COMPILE_STEP_NAME)
321
322 return try_job_data
323
324 @staticmethod
325 def _PopulateHeuristicDataForCompileFailure(analysis, data):
326 if analysis.result: # pragma: no branch.
327 compile_failure = None
328 for failure in analysis.result.get('failures', []):
329 if failure['step_name'] == constants.COMPILE_STEP_NAME:
330 compile_failure = failure
331 if compile_failure: # pragma: no branch.
332 data['first_failure'] = compile_failure['first_failure']
333 data['last_pass'] = compile_failure['last_pass']
334 data['suspected_cls_by_heuristic'] = compile_failure['suspected_cls']
335
336 def _PrepareDataForCompileFailure(self, analysis):
337 data = self._PrepareCommonDataForFailure(analysis)
338
339 # Check result from heuristic analysis.
340 self._PopulateHeuristicDataForCompileFailure(analysis, data)
341 # Check result from try job.
342 data['try_job'] = self._PrepareTryJobDataForCompileFailure(analysis)
343
344 return data
345
346 def _PrepareDataForTestFailures(self, analysis, build_info):
347 data = self._PrepareCommonDataForFailure(analysis)
348
349 organized_results = _GetOrganizedAnalysisResultBySuspectedCL(
350 analysis.result)
351 analysis_result = _GetAnalysisResultWithTryJobInfo(
352 organized_results, *build_info)
353 data['analysis_result'] = analysis_result
354
355 return data
356
277 def HandleGet(self): 357 def HandleGet(self):
278 """Triggers analysis of a build failure on demand and return current result. 358 """Triggers analysis of a build failure on demand and return current result.
279 359
280 If the final analysis result is available, set cache-control to 1 day to 360 If the final analysis result is available, set cache-control to 1 day to
281 avoid overload by unnecessary and frequent query from clients; otherwise 361 avoid overload by unnecessary and frequent query from clients; otherwise
282 set cache-control to 5 seconds to allow repeated query. 362 set cache-control to 5 seconds to allow repeated query.
283 363
284 Serve HTML page or JSON result as requested. 364 Serve HTML page or JSON result as requested.
285 """ 365 """
286 url = self.request.get('url').strip() 366 url = self.request.get('url').strip()
(...skipping 16 matching lines...) Expand all
303 # Only allow admin to force a re-run and set the build_completed. 383 # Only allow admin to force a re-run and set the build_completed.
304 force = (users.is_current_user_admin() and 384 force = (users.is_current_user_admin() and
305 self.request.get('force') == '1') 385 self.request.get('force') == '1')
306 build_completed = (users.is_current_user_admin() and 386 build_completed = (users.is_current_user_admin() and
307 self.request.get('build_completed') == '1') 387 self.request.get('build_completed') == '1')
308 analysis = build_failure_analysis_pipelines.ScheduleAnalysisIfNeeded( 388 analysis = build_failure_analysis_pipelines.ScheduleAnalysisIfNeeded(
309 master_name, builder_name, build_number, 389 master_name, builder_name, build_number,
310 build_completed=build_completed, force=force, 390 build_completed=build_completed, force=force,
311 queue_name=constants.WATERFALL_ANALYSIS_QUEUE) 391 queue_name=constants.WATERFALL_ANALYSIS_QUEUE)
312 392
313 organized_results = _GetOrganizedAnalysisResultBySuspectedCL( 393 if analysis.failure_type == failure_type.COMPILE: # pragma: no branch
314 analysis.result) 394 return {
315 analysis_result = _GetAnalysisResultWithTryJobInfo( 395 'template': 'waterfall/compile_failure.html',
316 organized_results, *build_info) 396 'data': self._PrepareDataForCompileFailure(analysis),
317 397 }
318 data = { 398 else:
319 'master_name': analysis.master_name, 399 return {
320 'builder_name': analysis.builder_name, 400 'template': 'build_failure.html',
321 'build_number': analysis.build_number, 401 'data': self._PrepareDataForTestFailures(analysis, build_info),
322 'pipeline_status_path': analysis.pipeline_status_path, 402 }
323 'show_debug_info': self._ShowDebugInfo(),
324 'analysis_request_time': _FormatDatetime(analysis.request_time),
325 'analysis_start_time': _FormatDatetime(analysis.start_time),
326 'analysis_end_time': _FormatDatetime(analysis.end_time),
327 'analysis_duration': analysis.duration,
328 'analysis_update_time': _FormatDatetime(analysis.updated_time),
329 'analysis_completed': analysis.completed,
330 'analysis_failed': analysis.failed,
331 'analysis_result': analysis_result,
332 'analysis_correct': analysis.correct,
333 'triage_history': _GetTriageHistory(analysis),
334 'show_triage_help_button': self._ShowTriageHelpButton(),
335 'status_message_map': result_status.STATUS_MESSAGE_MAP
336 }
337
338 return {'template': 'build_failure.html', 'data': data}
339 403
340 def HandlePost(self): # pragma: no cover 404 def HandlePost(self): # pragma: no cover
341 return self.HandleGet() 405 return self.HandleGet()
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/handlers/test/build_failure_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698