| OLD | NEW |
| 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 | 8 |
| 9 from google.appengine.api import users | 9 from google.appengine.api import users |
| 10 | 10 |
| 11 from common import constants | 11 from common import constants |
| 12 from common.base_handler import BaseHandler | 12 from common.base_handler import BaseHandler |
| 13 from common.base_handler import Permission | 13 from common.base_handler import Permission |
| 14 from common.waterfall import failure_type | 14 from common.waterfall import failure_type |
| 15 from handlers import handlers_util | 15 from handlers import handlers_util |
| 16 from handlers import result_status | 16 from handlers import result_status |
| 17 from handlers.result_status import NO_TRY_JOB_REASON_MAP | 17 from handlers.result_status import NO_TRY_JOB_REASON_MAP |
| 18 from model import analysis_approach_type | |
| 19 from model import analysis_status | 18 from model import analysis_status |
| 20 from model import result_status as analysis_result_status | 19 from model import result_status as analysis_result_status |
| 21 from model import suspected_cl_status | 20 from model import suspected_cl_status |
| 22 from model.result_status import RESULT_STATUS_TO_DESCRIPTION | 21 from model.result_status import RESULT_STATUS_TO_DESCRIPTION |
| 23 from model.suspected_cl_confidence import SuspectedCLConfidence | 22 from model.suspected_cl_confidence import SuspectedCLConfidence |
| 24 from model.suspected_cl_status import CL_STATUS_TO_DESCRIPTION | 23 from model.suspected_cl_status import CL_STATUS_TO_DESCRIPTION |
| 25 from model.wf_analysis import WfAnalysis | 24 from model.wf_analysis import WfAnalysis |
| 26 from model.wf_suspected_cl import WfSuspectedCL | 25 from model.wf_suspected_cl import WfSuspectedCL |
| 27 from model.wf_try_job import WfTryJob | 26 from model.wf_try_job import WfTryJob |
| 28 from waterfall import build_failure_analysis_pipelines | 27 from waterfall import build_failure_analysis_pipelines |
| 29 from waterfall import build_util | 28 from waterfall import build_util |
| 30 from waterfall import buildbot | 29 from waterfall import buildbot |
| 30 from waterfall import suspected_cl_util |
| 31 from waterfall import waterfall_config | 31 from waterfall import waterfall_config |
| 32 | 32 |
| 33 | 33 |
| 34 NON_SWARMING = object() | 34 NON_SWARMING = object() |
| 35 | 35 |
| 36 | 36 |
| 37 _ANALYSIS_CL_STATUS_MAP = { | 37 _ANALYSIS_CL_STATUS_MAP = { |
| 38 analysis_result_status.FOUND_CORRECT: suspected_cl_status.CORRECT, | 38 analysis_result_status.FOUND_CORRECT: suspected_cl_status.CORRECT, |
| 39 analysis_result_status.FOUND_INCORRECT: suspected_cl_status.INCORRECT | 39 analysis_result_status.FOUND_INCORRECT: suspected_cl_status.INCORRECT |
| 40 } | 40 } |
| 41 | 41 |
| 42 | 42 |
| 43 def _FormatDatetime(dt): | 43 def _FormatDatetime(dt): |
| 44 if not dt: | 44 if not dt: |
| 45 return None | 45 return None |
| 46 else: | 46 else: |
| 47 return dt.strftime('%Y-%m-%d %H:%M:%S UTC') | 47 return dt.strftime('%Y-%m-%d %H:%M:%S UTC') |
| 48 | 48 |
| 49 | 49 |
| 50 def _GetCLDict(analysis, cl_info): | 50 def _GetCLDict(analysis, cl_info): |
| 51 if not cl_info: | 51 if not cl_info: |
| 52 return {} | 52 return {} |
| 53 | 53 |
| 54 cl_keys = cl_info.split('/') | 54 cl_keys = suspected_cl_util.GetCLInfo(cl_info) |
| 55 repo_name = cl_keys[0] | 55 repo_name = cl_keys[0] |
| 56 revision = cl_keys[1] | 56 revision = cl_keys[1] |
| 57 for cl in analysis.suspected_cls: | 57 for cl in analysis.suspected_cls: |
| 58 if cl['repo_name'] == repo_name and cl['revision'] == revision: | 58 if cl['repo_name'] == repo_name and cl['revision'] == revision: |
| 59 return cl | 59 return cl |
| 60 return {} | 60 return {} |
| 61 | 61 |
| 62 | 62 |
| 63 def _GetTriageHistory(analysis): | 63 def _GetTriageHistory(analysis): |
| 64 if (not users.is_current_user_admin() or | 64 if (not users.is_current_user_admin() or |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 compile_failure = None | 324 compile_failure = None |
| 325 for failure in analysis.result.get('failures', []): | 325 for failure in analysis.result.get('failures', []): |
| 326 if failure['step_name'] == constants.COMPILE_STEP_NAME: | 326 if failure['step_name'] == constants.COMPILE_STEP_NAME: |
| 327 compile_failure = failure | 327 compile_failure = failure |
| 328 if compile_failure: # pragma: no branch. | 328 if compile_failure: # pragma: no branch. |
| 329 data['first_failure'] = compile_failure['first_failure'] | 329 data['first_failure'] = compile_failure['first_failure'] |
| 330 data['last_pass'] = compile_failure['last_pass'] | 330 data['last_pass'] = compile_failure['last_pass'] |
| 331 data['suspected_cls_by_heuristic'] = compile_failure['suspected_cls'] | 331 data['suspected_cls_by_heuristic'] = compile_failure['suspected_cls'] |
| 332 | 332 |
| 333 | 333 |
| 334 def _PercentFormat(float_number): | |
| 335 if not float_number or not isinstance(float_number, float): | |
| 336 return None | |
| 337 return '%d%%' % (round(float_number * 100)) | |
| 338 | |
| 339 | |
| 340 def _GetConfidenceScore(confidence, cl_build): | |
| 341 | |
| 342 if not confidence: | |
| 343 return None | |
| 344 | |
| 345 if cl_build['failure_type'] == failure_type.COMPILE: | |
| 346 if cl_build['approaches'] == [ | |
| 347 analysis_approach_type.HEURISTIC, analysis_approach_type.TRY_JOB]: | |
| 348 return _PercentFormat(confidence.compile_heuristic_try_job.confidence) | |
| 349 elif cl_build['approaches'] == [analysis_approach_type.TRY_JOB]: | |
| 350 return _PercentFormat(confidence.compile_try_job.confidence) | |
| 351 elif (cl_build['approaches'] == [analysis_approach_type.HEURISTIC] and | |
| 352 cl_build['top_score']): | |
| 353 for confidence_info in confidence.compile_heuristic: | |
| 354 if confidence_info.score == cl_build['top_score']: | |
| 355 return _PercentFormat(confidence_info.confidence) | |
| 356 return None | |
| 357 else: | |
| 358 if cl_build['approaches'] == [ | |
| 359 analysis_approach_type.HEURISTIC, analysis_approach_type.TRY_JOB]: | |
| 360 return _PercentFormat(confidence.test_heuristic_try_job.confidence) | |
| 361 elif cl_build['approaches'] == [analysis_approach_type.TRY_JOB]: | |
| 362 return _PercentFormat(confidence.test_try_job.confidence) | |
| 363 elif (cl_build['approaches'] == [analysis_approach_type.HEURISTIC] and | |
| 364 cl_build['top_score']): | |
| 365 for confidence_info in confidence.test_heuristic: | |
| 366 if confidence_info.score == cl_build['top_score']: | |
| 367 return _PercentFormat(confidence_info.confidence) | |
| 368 return None | |
| 369 | |
| 370 | |
| 371 def _GetAllSuspectedCLsAndCheckStatus( | 334 def _GetAllSuspectedCLsAndCheckStatus( |
| 372 master_name, builder_name, build_number, analysis): | 335 master_name, builder_name, build_number, analysis): |
| 373 build_key = build_util.CreateBuildId( | 336 build_key = build_util.CreateBuildId( |
| 374 master_name, builder_name, build_number) | 337 master_name, builder_name, build_number) |
| 375 suspected_cls = copy.deepcopy(analysis.suspected_cls) | 338 suspected_cls = copy.deepcopy(analysis.suspected_cls) |
| 376 if not suspected_cls: | 339 if not suspected_cls: |
| 377 return [] | 340 return [] |
| 378 | 341 |
| 379 cl_confidences = SuspectedCLConfidence.Get() | 342 confidences = SuspectedCLConfidence.Get() |
| 380 | 343 |
| 381 for cl in suspected_cls: | 344 for cl in suspected_cls: |
| 382 cl['status'] = _ANALYSIS_CL_STATUS_MAP.get(analysis.result_status, None) | 345 cl['status'] = _ANALYSIS_CL_STATUS_MAP.get(analysis.result_status, None) |
| 383 cl['confidence'] = None | 346 cl['confidence'] = None |
| 384 | 347 |
| 385 suspected_cl = WfSuspectedCL.Get(cl['repo_name'], cl['revision']) | 348 suspected_cl = WfSuspectedCL.Get(cl['repo_name'], cl['revision']) |
| 386 if not suspected_cl: | 349 if not suspected_cl: |
| 387 continue | 350 continue |
| 388 | 351 |
| 389 build = suspected_cl.builds.get(build_key) | 352 build = suspected_cl.builds.get(build_key) |
| 390 if build: | 353 if build: |
| 391 cl['status'] = build['status'] | 354 cl['status'] = build['status'] |
| 392 cl['confidence'] = _GetConfidenceScore(cl_confidences, build) | 355 cl['confidence'] = '%d%%' % ( |
| 356 suspected_cl_util.GetSuspectedCLConfidenceScore(confidences, build)) |
| 393 | 357 |
| 394 return suspected_cls | 358 return suspected_cls |
| 395 | 359 |
| 396 | 360 |
| 397 class BuildFailure(BaseHandler): | 361 class BuildFailure(BaseHandler): |
| 398 PERMISSION_LEVEL = Permission.ANYONE | 362 PERMISSION_LEVEL = Permission.ANYONE |
| 399 | 363 |
| 400 def _ShowTriageHelpButton(self): | 364 def _ShowTriageHelpButton(self): |
| 401 return users.is_current_user_admin() | 365 return users.is_current_user_admin() |
| 402 | 366 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 else: | 462 else: |
| 499 self._PrepareDataForTestFailures( | 463 self._PrepareDataForTestFailures( |
| 500 analysis, build_info, data, self._ShowDebugInfo()) | 464 analysis, build_info, data, self._ShowDebugInfo()) |
| 501 return { | 465 return { |
| 502 'template': 'waterfall/test_failure.html', | 466 'template': 'waterfall/test_failure.html', |
| 503 'data': data | 467 'data': data |
| 504 } | 468 } |
| 505 | 469 |
| 506 def HandlePost(self): # pragma: no cover | 470 def HandlePost(self): # pragma: no cover |
| 507 return self.HandleGet() | 471 return self.HandleGet() |
| OLD | NEW |