| OLD | NEW |
| 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 | 5 |
| 6 from common import time_util | 6 from common import time_util |
| 7 from common.pipeline_wrapper import BasePipeline | 7 from common.pipeline_wrapper import BasePipeline |
| 8 from model import analysis_approach_type |
| 9 from model import analysis_status |
| 8 from model import result_status | 10 from model import result_status |
| 9 from model import analysis_status | |
| 10 from model.wf_analysis import WfAnalysis | 11 from model.wf_analysis import WfAnalysis |
| 11 from waterfall import build_failure_analysis | 12 from waterfall import build_failure_analysis |
| 13 from waterfall import suspected_cl_util |
| 12 | 14 |
| 13 | 15 |
| 14 def _GetResultAnalysisStatus(analysis_result): | 16 def _GetResultAnalysisStatus(analysis_result): |
| 15 """Returns the status of the analysis result. | 17 """Returns the status of the analysis result. |
| 16 | 18 |
| 17 We can decide the status based on: | 19 We can decide the status based on: |
| 18 1. whether we found any suspected CL(s). | 20 1. whether we found any suspected CL(s). |
| 19 2. whether we have triaged the failure. | 21 2. whether we have triaged the failure. |
| 20 3. whether our analysis result is the same as triaged result. | 22 3. whether our analysis result is the same as triaged result. |
| 21 """ | 23 """ |
| 22 # Now we can only set the status based on if we found any suspected CL(s). | 24 # Now we can only set the status based on if we found any suspected CL(s). |
| 23 # TODO: Add logic to decide the status after comparing with culprit CL(s). | 25 # TODO: Add logic to decide the status after comparing with culprit CL(s). |
| 24 if not analysis_result or not analysis_result['failures']: | 26 if not analysis_result or not analysis_result['failures']: |
| 25 return None | 27 return None |
| 26 | 28 |
| 27 for failure in analysis_result['failures']: | 29 for failure in analysis_result['failures']: |
| 28 if failure['suspected_cls']: | 30 if failure['suspected_cls']: |
| 29 return result_status.FOUND_UNTRIAGED | 31 return result_status.FOUND_UNTRIAGED |
| 30 | 32 |
| 31 return result_status.NOT_FOUND_UNTRIAGED | 33 return result_status.NOT_FOUND_UNTRIAGED |
| 32 | 34 |
| 33 | 35 |
| 34 def _GetSuspectedCLs(analysis_result): | 36 def _SaveSuspectedCLs( |
| 35 """Returns the suspected CLs we found in analysis.""" | 37 suspected_cls, master_name, builder_name, build_number, failure_type): |
| 36 suspected_cls = [] | 38 """Saves suspected CLs to dataStore.""" |
| 37 if not analysis_result or not analysis_result['failures']: | 39 for suspected_cl in suspected_cls: |
| 38 return suspected_cls | 40 suspected_cl_util.UpdateSuspectedCL( |
| 41 suspected_cl['repo_name'], suspected_cl['revision'], |
| 42 suspected_cl['commit_position'], analysis_approach_type.HEURISTIC, |
| 43 master_name, builder_name, build_number, failure_type, |
| 44 suspected_cl['failures'], suspected_cl['top_score']) |
| 39 | 45 |
| 40 for failure in analysis_result['failures']: | 46 |
| 41 for suspected_cl in failure['suspected_cls']: | 47 def _GetSuspectedCLsWithOnlyCLInfo(suspected_cls): |
| 42 cl_info = { | 48 """Removes failures and top_score from suspected_cls. |
| 43 'repo_name': suspected_cl['repo_name'], | 49 |
| 44 'revision': suspected_cl['revision'], | 50 Makes sure suspected_cls from heuristic or try_job have the same format. |
| 45 'commit_position': suspected_cl['commit_position'], | 51 """ |
| 46 'url': suspected_cl['url'] | 52 simplified_suspected_cls = [] |
| 47 } | 53 for cl in suspected_cls: |
| 48 if cl_info not in suspected_cls: | 54 simplified_cl = { |
| 49 suspected_cls.append(cl_info) | 55 'repo_name': cl['repo_name'], |
| 50 return suspected_cls | 56 'revision': cl['revision'], |
| 57 'commit_position': cl['commit_position'], |
| 58 'url': cl['url'] |
| 59 } |
| 60 simplified_suspected_cls.append(simplified_cl) |
| 61 return simplified_suspected_cls |
| 51 | 62 |
| 52 | 63 |
| 53 class IdentifyCulpritPipeline(BasePipeline): | 64 class IdentifyCulpritPipeline(BasePipeline): |
| 54 """A pipeline to identify culprit CLs for a build failure.""" | 65 """A pipeline to identify culprit CLs for a build failure.""" |
| 55 | 66 |
| 56 # Arguments number differs from overridden method - pylint: disable=W0221 | 67 # Arguments number differs from overridden method - pylint: disable=W0221 |
| 57 def run(self, failure_info, change_logs, deps_info, signals, build_completed): | 68 def run(self, failure_info, change_logs, deps_info, signals, build_completed): |
| 58 """Identifies culprit CL. | 69 """Identifies culprit CL. |
| 59 | 70 |
| 60 Args: | 71 Args: |
| 61 failure_info (dict): Output of pipeline DetectFirstFailurePipeline. | 72 failure_info (dict): Output of pipeline DetectFirstFailurePipeline. |
| 62 change_logs (dict): Output of pipeline PullChangelogPipeline. | 73 change_logs (dict): Output of pipeline PullChangelogPipeline. |
| 63 signals (dict): Output of pipeline ExtractSignalPipeline. | 74 signals (dict): Output of pipeline ExtractSignalPipeline. |
| 64 | 75 |
| 65 Returns: | 76 Returns: |
| 66 The same dict as the returned value of function | 77 analysis_result returned by build_failure_analysis.AnalyzeBuildFailure. |
| 67 build_failure_analysis.AnalyzeBuildFailure. | |
| 68 """ | 78 """ |
| 69 master_name = failure_info['master_name'] | 79 master_name = failure_info['master_name'] |
| 70 builder_name = failure_info['builder_name'] | 80 builder_name = failure_info['builder_name'] |
| 71 build_number = failure_info['build_number'] | 81 build_number = failure_info['build_number'] |
| 72 | 82 |
| 73 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 83 analysis_result, suspected_cls = build_failure_analysis.AnalyzeBuildFailure( |
| 74 failure_info, change_logs, deps_info, signals) | 84 failure_info, change_logs, deps_info, signals) |
| 75 analysis = WfAnalysis.Get(master_name, builder_name, build_number) | 85 analysis = WfAnalysis.Get(master_name, builder_name, build_number) |
| 76 analysis.build_completed = build_completed | 86 analysis.build_completed = build_completed |
| 77 analysis.result = analysis_result | 87 analysis.result = analysis_result |
| 78 analysis.status = analysis_status.COMPLETED | 88 analysis.status = analysis_status.COMPLETED |
| 79 analysis.result_status = _GetResultAnalysisStatus(analysis_result) | 89 analysis.result_status = _GetResultAnalysisStatus(analysis_result) |
| 80 analysis.suspected_cls = _GetSuspectedCLs(analysis_result) | 90 analysis.suspected_cls = _GetSuspectedCLsWithOnlyCLInfo(suspected_cls) |
| 81 analysis.end_time = time_util.GetUTCNow() | 91 analysis.end_time = time_util.GetUTCNow() |
| 82 analysis.put() | 92 analysis.put() |
| 83 | 93 |
| 94 # Save suspected_cls to data_store. |
| 95 _SaveSuspectedCLs( |
| 96 suspected_cls, failure_info['master_name'], |
| 97 failure_info['builder_name'], failure_info['build_number'], |
| 98 failure_info['failure_type']) |
| 84 return analysis_result | 99 return analysis_result |
| OLD | NEW |