Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 import collections | 5 import collections |
| 6 import hashlib | 6 import hashlib |
| 7 import json | 7 import json |
| 8 import re | 8 import re |
| 9 | 9 |
| 10 from recipe_engine import recipe_api | 10 from recipe_engine import recipe_api |
| 11 | 11 |
| 12 RECIPE_TRYJOB_BYPASS_REASON_TAG = "Recipe-Tryjob-Bypass-Reason" | |
| 13 | |
| 12 #TODO(martiniss): make the recipe engine be able to dump the package as JSON so | 14 #TODO(martiniss): make the recipe engine be able to dump the package as JSON so |
| 13 # we don't have to do this weird parsing. | 15 # we don't have to do this weird parsing. |
| 14 def parse_protobuf(lines): | 16 def parse_protobuf(lines): |
| 15 """Parse the protobuf text format just well enough to understand recipes.cfg. | 17 """Parse the protobuf text format just well enough to understand recipes.cfg. |
| 16 | 18 |
| 17 We don't use the protobuf library because we want to be as self-contained | 19 We don't use the protobuf library because we want to be as self-contained |
| 18 as possible in this bootstrap, so it can be simply vendored into a client | 20 as possible in this bootstrap, so it can be simply vendored into a client |
| 19 repo. | 21 repo. |
| 20 | 22 |
| 21 We assume all fields are repeated since we don't have a proto spec to work | 23 We assume all fields are repeated since we don't have a proto spec to work |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 if patch: | 231 if patch: |
| 230 kwargs['rietveld'] = patch.server | 232 kwargs['rietveld'] = patch.server |
| 231 kwargs['issue'] = patch.issue | 233 kwargs['issue'] = patch.issue |
| 232 kwargs['patchset'] = patch.patchset | 234 kwargs['patchset'] = patch.patchset |
| 233 else: | 235 else: |
| 234 kwargs['patch'] = False | 236 kwargs['patch'] = False |
| 235 | 237 |
| 236 self.m.bot_update.ensure_checkout(**kwargs) | 238 self.m.bot_update.ensure_checkout(**kwargs) |
| 237 return repo_path | 239 return repo_path |
| 238 | 240 |
| 241 def get_fail_build_info(self, downstream_projects, patches): | |
| 242 fail_build = collections.defaultdict(lambda: True) | |
| 243 | |
| 244 for proj, patch in patches.items(): | |
| 245 patch_url = "%s/%s" % (patch.server, patch.issue) | |
| 246 desc = self.m.git_cl.get_description( | |
| 247 patch=patch_url, codereview='rietveld', suffix=proj) | |
| 248 | |
| 249 assert desc.stdout is not None, "CL %s had no description!" % patch_url | |
| 250 | |
| 251 bypass_reason = self.m.tryserver.get_footer( | |
| 252 RECIPE_TRYJOB_BYPASS_REASON_TAG, patch_text=desc.stdout) | |
| 253 | |
| 254 fail_build[proj] = not bool(bypass_reason) | |
| 255 | |
| 256 # Propogate Falses down the deps tree | |
| 257 queue = list(patches.keys()) | |
| 258 while queue: | |
| 259 item = queue.pop(0) | |
| 260 | |
| 261 if not fail_build[item]: | |
| 262 for downstream in downstream_projects.get(item, []): | |
| 263 fail_build[downstream] = False | |
| 264 queue.append(downstream) | |
| 265 | |
| 266 return fail_build | |
| 239 | 267 |
| 240 def simulation_test(self, proj, proj_config, repo_path, deps): | 268 def simulation_test(self, proj, proj_config, repo_path, deps): |
| 241 """ | 269 """ |
| 242 Args: | 270 Args: |
| 243 proj: The luci-config project to simulation_test. | 271 proj: The luci-config project to simulation_test. |
| 244 proj_config: The recipes.cfg configuration for the project. | 272 proj_config: The recipes.cfg configuration for the project. |
| 245 repo_path: The path to the repository on disk. | 273 repo_path: The path to the repository on disk. |
| 246 deps: Mapping from project name to Path. Passed into the recipes.py | 274 deps: Mapping from project name to Path. Passed into the recipes.py |
| 247 invocation via the "-O" options. | 275 invocation via the "-O" options. |
| 248 | 276 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 # luci config project name to recipe config namedtuple | 316 # luci config project name to recipe config namedtuple |
| 289 recipe_configs = {} | 317 recipe_configs = {} |
| 290 | 318 |
| 291 # List of all the projects we care about testing. luci-config names | 319 # List of all the projects we care about testing. luci-config names |
| 292 all_projects = set(p for p in url_mapping if p in PROJECTS_TO_TRY) | 320 all_projects = set(p for p in url_mapping if p in PROJECTS_TO_TRY) |
| 293 | 321 |
| 294 recipe_configs = { | 322 recipe_configs = { |
| 295 p: self._get_project_config(p) for p in all_projects} | 323 p: self._get_project_config(p) for p in all_projects} |
| 296 | 324 |
| 297 deps, downstream_projects = get_deps_info(all_projects, recipe_configs) | 325 deps, downstream_projects = get_deps_info(all_projects, recipe_configs) |
| 326 should_fail_build_mapping = self.get_fail_build_info( | |
| 327 downstream_projects, patches) | |
| 298 | 328 |
| 299 projs_to_test, locations = self._checkout_projects( | 329 projs_to_test, locations = self._checkout_projects( |
| 300 root_dir, url_mapping, deps, downstream_projects, patches) | 330 root_dir, url_mapping, deps, downstream_projects, patches) |
| 301 | 331 |
| 302 with self.m.step.defer_results(): | 332 failures = [] |
| 303 for proj in projs_to_test: | 333 try: |
| 304 deps_locs = {dep: locations[dep] for dep in deps[proj]} | 334 with self.m.step.defer_results(): |
| 335 for proj in projs_to_test: | |
| 336 deps_locs = {dep: locations[dep] for dep in deps[proj]} | |
| 305 | 337 |
| 306 self.simulation_test( | 338 simulation_result = self.simulation_test( |
| 307 proj, recipe_configs[proj], locations[proj], deps_locs) | 339 proj, recipe_configs[proj], locations[proj], deps_locs) |
| 340 | |
| 341 try: | |
| 342 simulation_result.get_result() | |
| 343 except recipe_api.StepFailure as f: | |
| 344 if should_fail_build_mapping.get(proj): | |
|
Paweł Hajdan Jr.
2016/05/25 00:51:55
Shouldn't we re-raise the exception here?
It's no
martiniss
2016/05/25 17:36:30
Re-raising the exception here would mean we don't
Paweł Hajdan Jr.
2016/05/25 17:58:10
I think I understand this now.
defer_results resu
| |
| 345 failures.append(f) | |
| 346 except recipe_api.AggregatedStepFailure: | |
| 347 if failures: | |
| 348 raise | |
| 349 | |
| 350 | |
| 351 | |
| 352 | |
| OLD | NEW |