Chromium Code Reviews| 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 from collections import defaultdict | 5 from collections import defaultdict |
| 6 import logging | 6 import logging |
| 7 | 7 |
| 8 from google.appengine.ext import ndb | 8 from google.appengine.ext import ndb |
| 9 | 9 |
| 10 from common.git_repository import GitRepository | 10 from common.git_repository import GitRepository |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 for failed_test in test_result['failures']: | 175 for failed_test in test_result['failures']: |
| 176 # Swarming tests, gets first failed revision for each test. | 176 # Swarming tests, gets first failed revision for each test. |
| 177 if failed_test not in culprit_map[step]['tests']: | 177 if failed_test not in culprit_map[step]['tests']: |
| 178 culprit_map[step]['tests'][failed_test] = { | 178 culprit_map[step]['tests'][failed_test] = { |
| 179 'revision': revision | 179 'revision': revision |
| 180 } | 180 } |
| 181 | 181 |
| 182 return culprit_map, list(failed_revisions) | 182 return culprit_map, list(failed_revisions) |
| 183 | 183 |
| 184 | 184 |
| 185 def _NotifyCulprits(master_name, builder_name, build_number, culprits): | 185 def _GetSuspectedCLFoundByHeuristicForCompile(analysis): |
| 186 """For compile failure, gets the suspected revision found by heuristic.""" | |
| 187 if not analysis or not analysis.result: | |
| 188 return None | |
| 189 for failure in analysis.result.get('failures', []): | |
| 190 if (failure['step_name'].lower() == 'compile' and | |
| 191 len(failure['suspected_cls']) == 1): | |
| 192 # Based on confidence calculation, suspected_cl found by heuristic for | |
| 193 # compile is very likely to be the culprit. | |
| 194 # Since the current confidence calculation is for results with single | |
| 195 # suspected_cl, we might need to have the same regulation here. | |
| 196 return failure['suspected_cls'][0] | |
| 197 return None | |
| 198 | |
| 199 | |
| 200 def _GetHeuristicSuspectedCLs(analysis): | |
| 201 """Gets revisions of suspected cls found by heuristic approach.""" | |
| 202 if analysis and analysis.suspected_cls: | |
| 203 return [(cl['repo_name'], cl['revision']) for cl in analysis.suspected_cls] | |
| 204 return [] | |
| 205 | |
| 206 | |
| 207 def _StartSendNotificationPipeline( | |
| 208 master_name, builder_name, build_number, repo_name, revision): | |
| 209 try: | |
| 210 pipeline = SendNotificationForCulpritPipeline( | |
| 211 master_name, builder_name, build_number, repo_name, revision) | |
| 212 pipeline.start() | |
| 213 except Exception: # pragma: no cover. | |
| 214 logging.exception( | |
| 215 'Failed to notify culprits which was found by both approaches.') | |
| 216 | |
| 217 | |
| 218 def _NotifyCulprits(master_name, builder_name, build_number, culprits, | |
| 219 heuristic_cls, compile_suspected_cl): | |
| 186 """Sends notifications to the identified culprits.""" | 220 """Sends notifications to the identified culprits.""" |
| 187 try: | 221 |
| 188 for culprit in (culprits or {}).itervalues(): | 222 if culprits: |
|
Sharu Jiang
2016/09/02 18:00:22
If culprits mean try_job_cls, I think rename it to
chanli
2016/09/02 18:25:59
It is a convention to call a suspected_cl found by
| |
| 189 pipeline = SendNotificationForCulpritPipeline( | 223 # There is try job result, we need to check if any of the culprit |
| 190 master_name, builder_name, build_number, | 224 # was also found by heuristic. |
| 191 culprit['repo_name'], culprit['revision']) | 225 for culprit in culprits.itervalues(): |
| 192 pipeline.start() | 226 if (culprit['repo_name'], culprit['revision']) in heuristic_cls: |
| 193 except Exception: # pragma: no cover. | 227 _StartSendNotificationPipeline( |
| 194 logging.exception('Failed to notify culprits.') | 228 master_name, builder_name, build_number, |
| 229 culprit['repo_name'], culprit['revision']) | |
| 230 elif compile_suspected_cl: | |
| 231 # Need to check if the failure is compile and heuristic found a culprit. | |
| 232 _StartSendNotificationPipeline( | |
| 233 master_name, builder_name, build_number, | |
| 234 compile_suspected_cl['repo_name'], compile_suspected_cl['revision']) | |
| 195 | 235 |
| 196 | 236 |
| 197 class IdentifyTryJobCulpritPipeline(BasePipeline): | 237 class IdentifyTryJobCulpritPipeline(BasePipeline): |
| 198 """A pipeline to identify culprit CL info based on try job compile results.""" | 238 """A pipeline to identify culprit CL info based on try job compile results.""" |
| 199 | 239 |
| 200 def _GetCulpritInfo(self, failed_revisions): | 240 def _GetCulpritInfo(self, failed_revisions): |
| 201 """Gets commit_positions and review urls for revisions.""" | 241 """Gets commit_positions and review urls for revisions.""" |
| 202 culprits = {} | 242 culprits = {} |
| 203 # TODO(lijeffrey): remove hard-coded 'chromium' when DEPS file parsing is | 243 # TODO(lijeffrey): remove hard-coded 'chromium' when DEPS file parsing is |
| 204 # supported. | 244 # supported. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 try_job_result.status = analysis_status.COMPLETED | 357 try_job_result.status = analysis_status.COMPLETED |
| 318 try_job_result.put() | 358 try_job_result.put() |
| 319 | 359 |
| 320 @ndb.transactional | 360 @ndb.transactional |
| 321 def UpdateWfAnalysisWithTryJobResult(): | 361 def UpdateWfAnalysisWithTryJobResult(): |
| 322 if not culprits: | 362 if not culprits: |
| 323 return | 363 return |
| 324 | 364 |
| 325 # Update analysis result and suspected CLs with results of this try job if | 365 # Update analysis result and suspected CLs with results of this try job if |
| 326 # culprits were found. | 366 # culprits were found. |
| 327 analysis = WfAnalysis.Get(master_name, builder_name, build_number) | |
| 328 updated_result_status = _GetResultAnalysisStatus(analysis, result) | 367 updated_result_status = _GetResultAnalysisStatus(analysis, result) |
| 329 updated_suspected_cls = _GetSuspectedCLs(analysis, result) | 368 updated_suspected_cls = _GetSuspectedCLs(analysis, result) |
| 330 | 369 |
| 331 if (analysis.result_status != updated_result_status or | 370 if (analysis.result_status != updated_result_status or |
| 332 analysis.suspected_cls != updated_suspected_cls): | 371 analysis.suspected_cls != updated_suspected_cls): |
| 333 analysis.result_status = updated_result_status | 372 analysis.result_status = updated_result_status |
| 334 analysis.suspected_cls = updated_suspected_cls | 373 analysis.suspected_cls = updated_suspected_cls |
| 335 analysis.put() | 374 analysis.put() |
| 336 | 375 |
| 337 # Store try-job results. | 376 # Store try-job results. |
| 338 UpdateTryJobResult() | 377 UpdateTryJobResult() |
| 378 | |
| 379 | |
|
Sharu Jiang
2016/09/02 18:00:22
nit: delete one empty line.
chanli
2016/09/02 18:25:59
Done.
| |
| 380 analysis = WfAnalysis.Get(master_name, builder_name, build_number) | |
| 381 heuristic_cls = _GetHeuristicSuspectedCLs(analysis) | |
| 382 compile_suspected_cl = ( | |
| 383 _GetSuspectedCLFoundByHeuristicForCompile(analysis) | |
| 384 if try_job_type == failure_type.COMPILE else None) | |
| 385 | |
| 339 # Add try-job results to WfAnalysis. | 386 # Add try-job results to WfAnalysis. |
| 340 UpdateWfAnalysisWithTryJobResult() | 387 UpdateWfAnalysisWithTryJobResult() |
| 341 | 388 |
| 342 _NotifyCulprits(master_name, builder_name, build_number, culprits) | 389 _NotifyCulprits(master_name, builder_name, build_number, culprits, |
| 343 return result.get('culprit') if result else None | 390 heuristic_cls, compile_suspected_cl) |
| 391 return result.get('culprit') if result else None | |
| OLD | NEW |