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

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

Issue 2361583002: [Findit] UI change and triage change for cl level trige. (Closed)
Patch Set: fixes on result page. Created 4 years, 3 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
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 from datetime import datetime 6 from datetime import datetime
7 7
8 from google.appengine.api import users 8 from google.appengine.api import users
9 9
10 from common import constants 10 from common import constants
11 from common.base_handler import BaseHandler 11 from common.base_handler import BaseHandler
12 from common.base_handler import Permission 12 from common.base_handler import Permission
13 from common.waterfall import failure_type 13 from common.waterfall import failure_type
14 from handlers import handlers_util 14 from handlers import handlers_util
15 from handlers import result_status 15 from handlers import result_status
16 from handlers.result_status import NO_TRY_JOB_REASON_MAP 16 from handlers.result_status import NO_TRY_JOB_REASON_MAP
17 from model import analysis_status 17 from model import analysis_status
18 from model.result_status import RESULT_STATUS_TO_DESCRIPTION
19 from model.suspected_cl_status import CL_STATUS_TO_DESCRIPTION
18 from model.wf_analysis import WfAnalysis 20 from model.wf_analysis import WfAnalysis
21 from model.wf_suspected_cl import WfSuspectedCL
19 from model.wf_try_job import WfTryJob 22 from model.wf_try_job import WfTryJob
20 from model.result_status import RESULT_STATUS_TO_DESCRIPTION
21 from waterfall import build_failure_analysis_pipelines 23 from waterfall import build_failure_analysis_pipelines
22 from waterfall import buildbot 24 from waterfall import buildbot
23 from waterfall import waterfall_config 25 from waterfall import waterfall_config
24 26
25 27
26 NON_SWARMING = object() 28 NON_SWARMING = object()
27 29
28 30
29 def _FormatDatetime(dt): 31 def _FormatDatetime(dt):
30 if not dt: 32 if not dt:
31 return None 33 return None
32 else: 34 else:
33 return dt.strftime('%Y-%m-%d %H:%M:%S UTC') 35 return dt.strftime('%Y-%m-%d %H:%M:%S UTC')
34 36
35 37
38 def _GetCLDict(analysis, cl_info):
39 if not cl_info:
40 return None
lijeffrey 2016/09/23 05:09:09 nit: how about instead of returning None, return {
chanli 2016/09/24 01:09:40 Done.
41
42 cl_keys = cl_info.split('/')
43 repo_name = cl_keys[0]
44 revision = cl_keys[1]
45 for cl in analysis.suspected_cls:
46 if cl['repo_name'] == repo_name and cl['revision'] == revision:
47 return cl
48 return None
49
50
36 def _GetTriageHistory(analysis): 51 def _GetTriageHistory(analysis):
37 if (not users.is_current_user_admin() or 52 if (not users.is_current_user_admin() or
38 not analysis.completed or 53 not analysis.completed or
39 not analysis.triage_history): 54 not analysis.triage_history):
40 return None 55 return None
41 56
42 triage_history = [] 57 triage_history = []
43 for triage_record in analysis.triage_history: 58 for triage_record in analysis.triage_history:
59
44 triage_history.append({ 60 triage_history.append({
45 'triage_time': _FormatDatetime( 61 'triage_time': _FormatDatetime(
46 datetime.utcfromtimestamp(triage_record['triage_timestamp'])), 62 datetime.utcfromtimestamp(triage_record['triage_timestamp'])),
47 'user_name': triage_record['user_name'], 63 'user_name': triage_record['user_name'],
48 'result_status': RESULT_STATUS_TO_DESCRIPTION.get( 64 'triaged_cl': _GetCLDict(analysis, triage_record.get('triaged_cl')),
49 triage_record['result_status']), 65 'result_status': (
66 RESULT_STATUS_TO_DESCRIPTION.get(triage_record.get('result_status'))
67 or CL_STATUS_TO_DESCRIPTION.get(triage_record.get('cl_status'))),
50 'version': triage_record.get('version'), 68 'version': triage_record.get('version'),
51 }) 69 })
52 70
53 return triage_history 71 return triage_history
54 72
55 73
56 def _GetOrganizedAnalysisResultBySuspectedCL(analysis_result): 74 def _GetOrganizedAnalysisResultBySuspectedCL(analysis_result):
57 """Group tests it they have the same suspected CLs.""" 75 """Group tests it they have the same suspected CLs."""
58 organized_results = defaultdict(list) 76 organized_results = defaultdict(list)
59 77
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 compile_failure = None 313 compile_failure = None
296 for failure in analysis.result.get('failures', []): 314 for failure in analysis.result.get('failures', []):
297 if failure['step_name'] == constants.COMPILE_STEP_NAME: 315 if failure['step_name'] == constants.COMPILE_STEP_NAME:
298 compile_failure = failure 316 compile_failure = failure
299 if compile_failure: # pragma: no branch. 317 if compile_failure: # pragma: no branch.
300 data['first_failure'] = compile_failure['first_failure'] 318 data['first_failure'] = compile_failure['first_failure']
301 data['last_pass'] = compile_failure['last_pass'] 319 data['last_pass'] = compile_failure['last_pass']
302 data['suspected_cls_by_heuristic'] = compile_failure['suspected_cls'] 320 data['suspected_cls_by_heuristic'] = compile_failure['suspected_cls']
303 321
304 322
323 def _GetAllSuspectedCLsAndCheckStatus(
324 master_name, builder_name, build_number, analysis):
325 build_key = '%s/%s/%d' % (master_name, builder_name, build_number)
lijeffrey 2016/09/23 05:09:09 nit: how about import base_build_model and use Cre
stgao 2016/09/23 19:35:41 This encoding and decoding should be abstracted in
chanli 2016/09/24 01:09:40 Done.
chanli 2016/09/24 01:09:40 Done.
326 suspected_cls = analysis.suspected_cls
stgao 2016/09/23 19:35:41 Should we do a deep copy first before modifying?
chanli 2016/09/24 01:09:40 Oops, Done.
327 if not suspected_cls:
328 return []
329
330 for cl in suspected_cls:
331 cl['status'] = None
332 cl_object = WfSuspectedCL.Get(cl['repo_name'], cl['revision'])
stgao 2016/09/23 19:35:41 Can we map var name to its class_name for easier r
chanli 2016/09/24 01:09:40 Done.
333 # TODO(chanli): Write a script to convert legacy data before enable
334 # this change.
335 if not cl_object:
336 continue
337
338 build = cl_object.builds.get(build_key)
339 import json
340 print json.dumps(build, indent =2)
lijeffrey 2016/09/23 05:09:09 nit: remove print before committing
chanli 2016/09/24 01:09:40 Done.
341 if build:
342 cl['status'] = build['status']
343
344 return suspected_cls
345
346
305 class BuildFailure(BaseHandler): 347 class BuildFailure(BaseHandler):
306 PERMISSION_LEVEL = Permission.ANYONE 348 PERMISSION_LEVEL = Permission.ANYONE
307 349
308 def _ShowDebugInfo(self): 350 def _ShowDebugInfo(self):
309 # Show debug info only if the app is run locally during development, if the 351 # Show debug info only if the app is run locally during development, if the
310 # currently logged-in user is an admin, or if it is explicitly requested 352 # currently logged-in user is an admin, or if it is explicitly requested
311 # with parameter 'debug=1'. 353 # with parameter 'debug=1'.
312 return users.is_current_user_admin() or self.request.get('debug') == '1' 354 return users.is_current_user_admin() or self.request.get('debug') == '1'
313 355
314 def _ShowTriageHelpButton(self): 356 def _ShowTriageHelpButton(self):
(...skipping 18 matching lines...) Expand all
333 'triage_history': _GetTriageHistory(analysis), 375 'triage_history': _GetTriageHistory(analysis),
334 'show_triage_help_button': self._ShowTriageHelpButton(), 376 'show_triage_help_button': self._ShowTriageHelpButton(),
335 'triage_reference_analysis_master_name': 377 'triage_reference_analysis_master_name':
336 analysis.triage_reference_analysis_master_name, 378 analysis.triage_reference_analysis_master_name,
337 'triage_reference_analysis_builder_name': 379 'triage_reference_analysis_builder_name':
338 analysis.triage_reference_analysis_builder_name, 380 analysis.triage_reference_analysis_builder_name,
339 'triage_reference_analysis_build_number': 381 'triage_reference_analysis_build_number':
340 analysis.triage_reference_analysis_build_number 382 analysis.triage_reference_analysis_build_number
341 } 383 }
342 384
343 def _PrepareDataForCompileFailure(self, analysis): 385 def _PrepareDataForCompileFailure(self, analysis, data):
344 data = self._PrepareCommonDataForFailure(analysis)
345 386
346 # Check result from heuristic analysis. 387 # Check result from heuristic analysis.
347 _PopulateHeuristicDataForCompileFailure(analysis, data) 388 _PopulateHeuristicDataForCompileFailure(analysis, data)
348 # Check result from try job. 389 # Check result from try job.
349 data['try_job'] = _PrepareTryJobDataForCompileFailure(analysis) 390 data['try_job'] = _PrepareTryJobDataForCompileFailure(analysis)
350 391
351 return data 392 def _PrepareDataForTestFailures(self, analysis, build_info, data,
393 show_debug_info=False):
352 394
353 def _PrepareDataForTestFailures(self, analysis, build_info,
354 show_debug_info=False):
355 data = self._PrepareCommonDataForFailure(analysis)
356 data['status_message_map'] = result_status.STATUS_MESSAGE_MAP 395 data['status_message_map'] = result_status.STATUS_MESSAGE_MAP
357 396
358 organized_results = _GetOrganizedAnalysisResultBySuspectedCL( 397 organized_results = _GetOrganizedAnalysisResultBySuspectedCL(
359 analysis.result) 398 analysis.result)
360 analysis_result = _GetAnalysisResultWithTryJobInfo( 399 analysis_result = _GetAnalysisResultWithTryJobInfo(
361 show_debug_info, organized_results, *build_info) 400 show_debug_info, organized_results, *build_info)
362 401
363 data['analysis_result'] = analysis_result 402 data['analysis_result'] = analysis_result
364 return data 403 return data
365 404
(...skipping 29 matching lines...) Expand all
395 build_completed = (users.is_current_user_admin() and 434 build_completed = (users.is_current_user_admin() and
396 self.request.get('build_completed') == '1') 435 self.request.get('build_completed') == '1')
397 force_try_job = (users.is_current_user_admin() and 436 force_try_job = (users.is_current_user_admin() and
398 self.request.get('force_try_job') == '1') 437 self.request.get('force_try_job') == '1')
399 analysis = build_failure_analysis_pipelines.ScheduleAnalysisIfNeeded( 438 analysis = build_failure_analysis_pipelines.ScheduleAnalysisIfNeeded(
400 master_name, builder_name, build_number, 439 master_name, builder_name, build_number,
401 build_completed=build_completed, force=force, 440 build_completed=build_completed, force=force,
402 force_try_job=force_try_job, 441 force_try_job=force_try_job,
403 queue_name=constants.WATERFALL_ANALYSIS_QUEUE) 442 queue_name=constants.WATERFALL_ANALYSIS_QUEUE)
404 443
444 data = self._PrepareCommonDataForFailure(analysis)
445 data['suspected_cls'] = _GetAllSuspectedCLsAndCheckStatus(
446 master_name, builder_name, build_number, analysis)
447
405 if analysis.failure_type == failure_type.COMPILE: 448 if analysis.failure_type == failure_type.COMPILE:
449 self._PrepareDataForCompileFailure(analysis, data)
406 return { 450 return {
407 'template': 'waterfall/compile_failure.html', 451 'template': 'waterfall/compile_failure.html',
408 'data': self._PrepareDataForCompileFailure(analysis), 452 'data': data
409 } 453 }
410 else: 454 else:
455 self._PrepareDataForTestFailures(
456 analysis, build_info, data, self._ShowDebugInfo())
411 return { 457 return {
412 'template': 'waterfall/test_failure.html', 458 'template': 'waterfall/test_failure.html',
413 'data': self._PrepareDataForTestFailures(analysis, build_info, 459 'data': data
414 self._ShowDebugInfo()),
415 } 460 }
416 461
462
lijeffrey 2016/09/23 05:09:09 nit: too many blank lines
chanli 2016/09/24 01:09:40 Done.
417 def HandlePost(self): # pragma: no cover 463 def HandlePost(self): # pragma: no cover
418 return self.HandleGet() 464 return self.HandleGet()
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/handlers/test/build_failure_test.py » ('j') | appengine/findit/handlers/triage_suspected_cl.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698