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

Side by Side Diff: appengine/findit/waterfall/identify_try_job_culprit_pipeline.py

Issue 1591003002: [Findit] Modify tryjob pipelines to trigger try jobs for test failure. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: . Created 4 years, 10 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 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 from common.git_repository import GitRepository 5 from common.git_repository import GitRepository
6 from common.http_client_appengine import HttpClientAppengine as HttpClient 6 from common.http_client_appengine import HttpClientAppengine as HttpClient
7 from model import wf_analysis_status 7 from model import wf_analysis_status
8 from model.wf_try_job import WfTryJob 8 from model.wf_try_job import WfTryJob
9 from pipeline_wrapper import BasePipeline 9 from pipeline_wrapper import BasePipeline
10 from waterfall.try_job_type import TryJobType
11
12
13 GIT_REPO = GitRepository(
14 'https://chromium.googlesource.com/chromium/src.git', HttpClient())
10 15
11 16
12 class IdentifyTryJobCulpritPipeline(BasePipeline): 17 class IdentifyTryJobCulpritPipeline(BasePipeline):
13 """A pipeline to identify culprit CL info based on try job compile results.""" 18 """A pipeline to identify culprit CL info based on try job compile results."""
14 19
20 def _GetCulpritInfo(self, failed_revisions):
21 """Gets commit_positions and review_urls for revisions."""
22 culprits = {}
23 for failed_revision in failed_revisions:
24 culprits[failed_revision] = {
25 'revision': failed_revision
26 }
27 change_log = GIT_REPO.GetChangeLog(failed_revision)
28 if change_log:
29 culprits[failed_revision]['commit_position'] = (
30 change_log.commit_position)
31 culprits[failed_revision]['review_url'] = change_log.code_review_url
32
33 return culprits
34
15 @staticmethod 35 @staticmethod
16 def _GetFailedRevisionFromResultsDict(results_dict): 36 def _GetFailedRevisionFromResultsDict(results_dict):
17 """Finds the failed revision from the given dict of revisions. 37 """Finds the failed revision from the given dict of revisions.
18 38
19 Args: 39 Args:
20 results_dict: (dict) A dict that maps revisions to their results. For 40 results_dict: (dict) A dict that maps revisions to their results. For
21 example: 41 example:
22 42
23 { 43 {
24 'rev1': 'passed', 44 'rev1': 'passed',
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 result_for_last_checked_revision[0] if 114 result_for_last_checked_revision[0] if
95 result_for_last_checked_revision[1].lower() == 'failed' else None) 115 result_for_last_checked_revision[1].lower() == 'failed' else None)
96 else: 116 else:
97 revision_results = report.get('result', {}) 117 revision_results = report.get('result', {})
98 failed_revision = ( 118 failed_revision = (
99 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict( 119 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict(
100 revision_results)) 120 revision_results))
101 121
102 return failed_revision 122 return failed_revision
103 123
104 @staticmethod 124 def _FindCulpritForEachTestFailure(self, blame_list, result):
105 def _GetCulpritFromFailedRevision(failed_revision): 125 # For test failures, the try job will run against every revision,
106 """Returns a culprit (dict) using failed_revision, or None.""" 126 # so we need to traverse the result dict in chronological order to identify
107 if not failed_revision: 127 # the culprits for each failed step or test.
108 return None 128 culprit_map = {}
129 failed_revisions = []
130 for revision in blame_list:
131 for step, step_result in result['report'][revision].iteritems():
132 if step_result['valid'] and step_result['status'] == 'failed':
qyearsley 2016/02/03 18:55:14 Optional change if you want to use one less level
chanli 2016/02/03 23:44:13 Done.
133 if revision not in failed_revisions:
134 failed_revisions.append(revision)
109 135
110 git_repo = GitRepository( 136 if step not in culprit_map:
111 'https://chromium.googlesource.com/chromium/src.git', HttpClient()) 137 culprit_map[step] = {
112 change_log = git_repo.GetChangeLog(failed_revision) 138 'tests': {}
139 }
113 140
114 if not change_log: 141 if (not step_result['failures'] and
115 return None 142 not culprit_map[step].get('revision')):
143 # Non swarming test failures, only have step level failure info.
144 culprit_map[step]['revision'] = revision
116 145
117 return { 146 for failed_test in step_result['failures']:
118 'revision': failed_revision, 147 # Swarming tests, gets first failed revision for each test.
119 'commit_position': change_log.commit_position, 148 if failed_test not in culprit_map[step]['tests']:
120 'review_url': change_log.code_review_url 149 culprit_map[step]['tests'][failed_test] = {
121 } 150 'revision': revision
151 }
152 return culprit_map, failed_revisions
153
154 def _UpdateCulpritMapWithCulpritInfo(self, culprit_map, culprits):
155 """Fills in commit_position and review_url for each failed rev in map."""
156 for step_culprit in culprit_map.values():
157 if step_culprit.get('revision'):
158 culprit = culprits[step_culprit['revision']]
159 step_culprit['commit_position'] = culprit['commit_position']
160 step_culprit['review_url'] = culprit['review_url']
161 for test_culprit in step_culprit.get('tests', {}).values():
162 test_revision = test_culprit['revision']
163 test_culprit.update(culprits[test_revision])
122 164
123 # Arguments number differs from overridden method - pylint: disable=W0221 165 # Arguments number differs from overridden method - pylint: disable=W0221
124 def run(self, master_name, builder_name, build_number, try_job_id, 166 def run(
125 compile_result): 167 self, master_name, builder_name, build_number, blame_list, try_job_type,
126 culprit = None 168 try_job_id, result):
127 failed_revision = self._GetFailedRevisionFromCompileResult(compile_result) 169 """Identifies the information for failed revisions.
128 culprit = self._GetCulpritFromFailedRevision(failed_revision) 170
171 Please refer to try_job_result_format.md for format check.
172 """
173 culprits = None
174 if result and result.get('report'):
175 if try_job_type == TryJobType.COMPILE:
176 # For compile failures, the try job will stop if one revision fails, so
177 # the culprit will be the last revision in the result.
178 failed_revision = self._GetFailedRevisionFromCompileResult(
179 result)
180 failed_revisions = [failed_revision] if failed_revision else []
181 culprits = self._GetCulpritInfo(failed_revisions)
182 if culprits:
183 result['culprit'] = culprits[failed_revision]
184 else: # try_job_type is 'test'.
185 culprit_map, failed_revisions = self._FindCulpritForEachTestFailure(
186 blame_list, result)
187 culprits = self._GetCulpritInfo(failed_revisions)
188 if culprits:
189 self._UpdateCulpritMapWithCulpritInfo(culprit_map, culprits)
190 result['culprit'] = culprit_map
129 191
130 # Store try job results. 192 # Store try job results.
131 try_job_result = WfTryJob.Get(master_name, builder_name, build_number) 193 try_job_result = WfTryJob.Get(master_name, builder_name, build_number)
132 if culprit: 194 if culprits:
133 compile_result['culprit'] = culprit 195 result_to_update = (
134 if (try_job_result.compile_results and 196 try_job_result.compile_results if
135 try_job_result.compile_results[-1]['try_job_id'] == try_job_id): 197 try_job_type == TryJobType.COMPILE else
136 try_job_result.compile_results[-1].update(compile_result) 198 try_job_result.test_results)
199 if (result_to_update and
200 result_to_update[-1]['try_job_id'] == try_job_id):
201 result_to_update[-1].update(result)
202
137 else: # pragma: no cover 203 else: # pragma: no cover
138 try_job_result.compile_results.append(compile_result) 204 result_to_update.append(result)
139 205
140 try_job_result.status = wf_analysis_status.ANALYZED 206 try_job_result.status = wf_analysis_status.ANALYZED
141 try_job_result.put() 207 try_job_result.put()
142 208
143 return culprit 209 return result.get('culprit', None) if result else None
qyearsley 2016/02/03 18:55:14 Equivalent to `result.get('culprit') if result els
chanli 2016/02/03 23:44:13 Done.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698