OLD | NEW |
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2013 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 """Miscellaneous utilities needed by the Skia buildbot master.""" | 6 """Miscellaneous utilities needed by the Skia buildbot master.""" |
7 | 7 |
8 | 8 |
9 import httplib2 | 9 import httplib2 |
10 import re | 10 import re |
11 | 11 |
12 # requires Google APIs client library for Python; see | 12 # requires Google APIs client library for Python; see |
13 # https://code.google.com/p/google-api-python-client/wiki/Installation | 13 # https://code.google.com/p/google-api-python-client/wiki/Installation |
14 from apiclient.discovery import build | 14 from apiclient.discovery import build |
15 from buildbot.scheduler import AnyBranchScheduler | 15 from buildbot.scheduler import AnyBranchScheduler |
16 from buildbot.schedulers import timed | 16 from buildbot.schedulers import timed |
17 from buildbot.schedulers.filter import ChangeFilter | 17 from buildbot.schedulers.filter import ChangeFilter |
18 from buildbot.util import NotABranch | 18 from buildbot.util import NotABranch |
19 from config_private import TRY_SVN_BASEURL | 19 from config_private import TRY_SVN_BASEURL |
20 from master import master_config | 20 from master import master_config |
21 from master import try_job_svn | 21 from master import try_job_svn |
22 from master import try_job_rietveld | 22 from master import try_job_rietveld |
23 from master.builders_pools import BuildersPools | 23 from master.builders_pools import BuildersPools |
24 from oauth2client.client import SignedJwtAssertionCredentials | 24 from oauth2client.client import SignedJwtAssertionCredentials |
25 | 25 |
26 from skia_master_scripts import android_factory | |
27 from skia_master_scripts import chromeos_factory | |
28 from skia_master_scripts import factory as skia_factory | |
29 from skia_master_scripts import housekeeping_percommit_factory, \ | |
30 housekeeping_periodic_factory | |
31 from skia_master_scripts import ios_factory | |
32 from skia_master_scripts import nacl_factory | |
33 | |
34 import config_private | 26 import config_private |
35 | 27 |
36 | 28 |
37 CATEGORY_BUILD = ' Build' | 29 BUILDER_NAME_SEP = '-' |
38 TRYBOT_NAME_SUFFIX = '_Trybot' | 30 |
| 31 # Patterns for creating builder names, based on the role of the builder. |
| 32 # TODO(borenet): Extract these into a separate file (JSON?) so that they can be |
| 33 # read by other users. |
| 34 BUILDER_ROLE_COMPILE = 'Build' |
| 35 BUILDER_ROLE_PERF = 'Perf' |
| 36 BUILDER_ROLE_TEST = 'Test' |
| 37 BUILDER_ROLE_HOUSEKEEPER = 'Housekeeper' |
| 38 BUILDER_NAME_DEFAULT_ATTRS = ['os', 'model', 'gpu', 'arch', 'configuration'] |
| 39 BUILDER_NAME_SCHEMA = { |
| 40 BUILDER_ROLE_COMPILE: ['os', 'compiler', 'target_arch', 'configuration'], |
| 41 BUILDER_ROLE_TEST: BUILDER_NAME_DEFAULT_ATTRS, |
| 42 BUILDER_ROLE_PERF: BUILDER_NAME_DEFAULT_ATTRS, |
| 43 BUILDER_ROLE_HOUSEKEEPER: ['frequency'], |
| 44 } |
| 45 |
| 46 TRYBOT_NAME_SUFFIX = 'Trybot' |
39 TRY_SCHEDULER_SVN = 'skia_try_svn' | 47 TRY_SCHEDULER_SVN = 'skia_try_svn' |
40 TRY_SCHEDULER_RIETVELD = 'skia_try_rietveld' | 48 TRY_SCHEDULER_RIETVELD = 'skia_try_rietveld' |
41 TRY_SCHEDULERS = [TRY_SCHEDULER_SVN, TRY_SCHEDULER_RIETVELD] | 49 TRY_SCHEDULERS = [TRY_SCHEDULER_SVN, TRY_SCHEDULER_RIETVELD] |
42 TRY_SCHEDULERS_STR = '|'.join(TRY_SCHEDULERS) | 50 TRY_SCHEDULERS_STR = '|'.join(TRY_SCHEDULERS) |
43 | 51 |
44 | 52 |
45 def IsTrybot(builder_name): | 53 def IsTrybot(builder_name): |
46 return builder_name.endswith(TRYBOT_NAME_SUFFIX) | 54 return builder_name.endswith(TRYBOT_NAME_SUFFIX) |
47 | 55 |
48 | 56 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 # Skip buildbot runs of a CL if its commit log message contains the following | 204 # Skip buildbot runs of a CL if its commit log message contains the following |
197 # substring. | 205 # substring. |
198 SKIP_BUILDBOT_SUBSTRING = '(SkipBuildbotRuns)' | 206 SKIP_BUILDBOT_SUBSTRING = '(SkipBuildbotRuns)' |
199 | 207 |
200 # If the below regex is found in a CL's commit log message, only run the | 208 # If the below regex is found in a CL's commit log message, only run the |
201 # builders specified therein. | 209 # builders specified therein. |
202 RUN_BUILDERS_REGEX = '\(RunBuilders:(.+)\)' | 210 RUN_BUILDERS_REGEX = '\(RunBuilders:(.+)\)' |
203 RUN_BUILDERS_RE_COMPILED = re.compile(RUN_BUILDERS_REGEX) | 211 RUN_BUILDERS_RE_COMPILED = re.compile(RUN_BUILDERS_REGEX) |
204 | 212 |
205 | 213 |
| 214 def AndroidModelToDevice(android_model): |
| 215 name_parts = [] |
| 216 for part in re.split('(\d+)', android_model): |
| 217 if re.match('(\d+)', part): |
| 218 name_parts.append(part) |
| 219 else: |
| 220 name_parts.extend(re.findall('[A-Z][a-z]*', part)) |
| 221 return '_'.join([part.lower() for part in name_parts]) |
| 222 |
| 223 |
206 # Since we can't modify the existing Helper class, we subclass it here, | 224 # Since we can't modify the existing Helper class, we subclass it here, |
207 # overriding the necessary parts to get things working as we want. | 225 # overriding the necessary parts to get things working as we want. |
208 # Specifically, the Helper class hardcodes each registered scheduler to be | 226 # Specifically, the Helper class hardcodes each registered scheduler to be |
209 # instantiated as a 'Scheduler,' which aliases 'SingleBranchScheduler.' We add | 227 # instantiated as a 'Scheduler,' which aliases 'SingleBranchScheduler.' We add |
210 # an 'AnyBranchScheduler' method and change the implementation of Update() to | 228 # an 'AnyBranchScheduler' method and change the implementation of Update() to |
211 # instantiate the proper type. | 229 # instantiate the proper type. |
212 | 230 |
213 # TODO(borenet): modify this code upstream so that we don't need this override. | 231 # TODO(borenet): modify this code upstream so that we don't need this override. |
214 # BUG: http://code.google.com/p/skia/issues/detail?id=761 | 232 # BUG: http://code.google.com/p/skia/issues/detail?id=761 |
215 class SkiaHelper(master_config.Helper): | 233 class SkiaHelper(master_config.Helper): |
216 | 234 |
217 def Builder(self, name, factory, gatekeeper=None, scheduler=None, | 235 def Builder(self, name, factory, gatekeeper=None, scheduler=None, |
218 builddir=None, auto_reboot=False, notify_on_missing=False, | 236 builddir=None, auto_reboot=False, notify_on_missing=False): |
219 override_category=None): | |
220 if override_category: | |
221 old_category = self._defaults.get('category') | |
222 self._defaults['category'] = override_category | |
223 super(SkiaHelper, self).Builder(name=name, factory=factory, | 237 super(SkiaHelper, self).Builder(name=name, factory=factory, |
224 gatekeeper=gatekeeper, scheduler=scheduler, | 238 gatekeeper=gatekeeper, scheduler=scheduler, |
225 builddir=builddir, auto_reboot=auto_reboot, | 239 builddir=builddir, auto_reboot=auto_reboot, |
226 notify_on_missing=notify_on_missing) | 240 notify_on_missing=notify_on_missing) |
227 if override_category: | |
228 self._defaults['category'] = old_category | |
229 | 241 |
230 def AnyBranchScheduler(self, name, branches, treeStableTimer=60, | 242 def AnyBranchScheduler(self, name, branches, treeStableTimer=60, |
231 categories=None): | 243 categories=None): |
232 if name in self._schedulers: | 244 if name in self._schedulers: |
233 raise ValueError('Scheduler %s already exist' % name) | 245 raise ValueError('Scheduler %s already exist' % name) |
234 self._schedulers[name] = {'type': 'AnyBranchScheduler', | 246 self._schedulers[name] = {'type': 'AnyBranchScheduler', |
235 'branches': branches, | 247 'branches': branches, |
236 'treeStableTimer': treeStableTimer, | 248 'treeStableTimer': treeStableTimer, |
237 'builders': [], | 249 'builders': [], |
238 'categories': categories} | 250 'categories': categories} |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 # been defined. | 372 # been defined. |
361 # pylint: disable=W0601 | 373 # pylint: disable=W0601 |
362 global skia_all_subdirs | 374 global skia_all_subdirs |
363 try: | 375 try: |
364 if skia_all_subdirs: | 376 if skia_all_subdirs: |
365 raise Exception('skia_all_subdirs has already been defined!') | 377 raise Exception('skia_all_subdirs has already been defined!') |
366 except NameError: | 378 except NameError: |
367 skia_all_subdirs = all_subdirs | 379 skia_all_subdirs = all_subdirs |
368 | 380 |
369 | 381 |
370 def MakeBuilderName(builder_base_name, config): | 382 def MakeBuilderName(role, extra_config=None, is_trybot=False, **kwargs): |
371 """ Inserts config into builder_base_name at '%s', or if builder_base_name | 383 schema = BUILDER_NAME_SCHEMA.get(role) |
372 does not contain '%s', appends config to the end of builder_base_name, | 384 if not schema: |
373 separated by an underscore. """ | 385 raise ValueError('%s is not a recognized role.' % role) |
374 try: | 386 for k, v in kwargs.iteritems(): |
375 return builder_base_name % config | 387 if BUILDER_NAME_SEP in v: |
376 except TypeError: | 388 raise ValueError('%s not allowed in %s.' % (v, BUILDER_NAME_SEP)) |
377 # If builder_base_name does not contain '%s' | 389 if not k in schema: |
378 return '%s_%s' % (builder_base_name, config) | 390 raise ValueError('Schema does not contain "%s": %s' %(k, schema)) |
| 391 if extra_config and BUILDER_NAME_SEP in extra_config: |
| 392 raise ValueError('%s not allowed in %s.' % (extra_config, |
| 393 BUILDER_NAME_SEP)) |
| 394 name_parts = [role] |
| 395 name_parts.extend([kwargs[attribute] for attribute in schema]) |
| 396 if extra_config: |
| 397 name_parts.append(extra_config) |
| 398 if is_trybot: |
| 399 name_parts.append(TRYBOT_NAME_SUFFIX) |
| 400 print BUILDER_NAME_SEP.join(name_parts) |
| 401 return BUILDER_NAME_SEP.join(name_parts) |
379 | 402 |
380 | 403 |
381 def MakeCompileBuilderName(builder_base_name, release=False): | 404 def _MakeBuilder(helper, role, os, model, gpu, configuration, arch, |
382 if release: | 405 gm_image_subdir, factory_type, extra_config=None, |
383 compile_name = 'Compile_Release' | 406 perf_output_basedir=None, extra_branches=None, is_trybot=False, |
384 else: | 407 **kwargs): |
385 compile_name = 'Compile_Debug' | 408 """ Creates a builder and scheduler. """ |
386 return MakeBuilderName(builder_base_name, compile_name) | |
387 | |
388 | |
389 def MakeDebugBuilderName(builder_base_name): | |
390 return MakeBuilderName(builder_base_name, skia_factory.CONFIG_DEBUG) | |
391 | |
392 | |
393 def MakeReleaseBuilderName(builder_base_name): | |
394 return MakeBuilderName(builder_base_name, skia_factory.CONFIG_RELEASE) | |
395 | |
396 | |
397 def MakeBenchBuilderName(builder_base_name): | |
398 return MakeBuilderName(builder_base_name, skia_factory.CONFIG_BENCH) | |
399 | |
400 | |
401 def MakeSchedulerName(builder_base_name): | |
402 return MakeBuilderName(builder_base_name, 'Scheduler') | |
403 | |
404 | |
405 def _MakeBuilderSet(helper, builder_base_name, gm_image_subdir, | |
406 perf_output_basedir=None, extra_branches=None, | |
407 factory_type=None, do_compile=True, do_debug=True, | |
408 do_release=True, do_bench=True, try_schedulers=None, | |
409 compile_bot_warnings_as_errors=True, | |
410 **kwargs): | |
411 """ Creates a trio of builders for a given platform: | |
412 1. Debug mode builder which runs all steps | |
413 2. Release mode builder which runs all steps EXCEPT benchmarks | |
414 3. Release mode builder which runs ONLY benchmarks. | |
415 """ | |
416 B = helper.Builder | 409 B = helper.Builder |
417 F = helper.Factory | 410 F = helper.Factory |
418 | 411 |
419 if not extra_branches: | 412 if not extra_branches: |
420 extra_branches = [] | 413 extra_branches = [] |
421 subdirs_to_checkout = set(extra_branches) | 414 subdirs_to_checkout = set(extra_branches) |
422 if gm_image_subdir: | 415 if gm_image_subdir: |
423 gm_image_branch = 'gm-expected/%s' % gm_image_subdir | 416 gm_image_branch = 'gm-expected/%s' % gm_image_subdir |
424 subdirs_to_checkout.add(gm_image_branch) | 417 subdirs_to_checkout.add(gm_image_branch) |
425 | 418 |
426 if try_schedulers: | 419 builder_name = MakeBuilderName( |
427 scheduler_name = '|'.join(try_schedulers) | 420 role=role, |
428 builder_base_name = builder_base_name + TRYBOT_NAME_SUFFIX | 421 os=os, |
| 422 model=model, |
| 423 gpu=gpu, |
| 424 configuration=configuration, |
| 425 arch=arch, |
| 426 extra_config=extra_config, |
| 427 is_trybot=is_trybot) |
| 428 |
| 429 if is_trybot: |
| 430 scheduler_name = TRY_SCHEDULERS_STR |
429 else: | 431 else: |
430 scheduler_name = MakeSchedulerName(builder_base_name) | 432 scheduler_name = builder_name + BUILDER_NAME_SEP + 'Scheduler' |
431 branches = list(subdirs_to_checkout.union(SKIA_PRIMARY_SUBDIRS)) | 433 branches = list(subdirs_to_checkout.union(SKIA_PRIMARY_SUBDIRS)) |
432 helper.AnyBranchScheduler(scheduler_name, branches=branches) | 434 helper.AnyBranchScheduler(scheduler_name, branches=branches) |
433 | 435 |
434 if do_compile: | 436 B(builder_name, 'f_%s' % builder_name, scheduler=scheduler_name) |
435 compile_debug_builder_name = MakeCompileBuilderName(builder_base_name, | 437 F('f_%s' % builder_name, factory_type( |
436 release=False) | 438 builder_name=builder_name, |
437 B(compile_debug_builder_name, 'f_%s' % compile_debug_builder_name, | 439 other_subdirs=subdirs_to_checkout, |
438 # Do not add gatekeeper for trybots. | 440 configuration=configuration, |
439 gatekeeper='GateKeeper' if try_schedulers is None else None, | 441 gm_image_subdir=gm_image_subdir, |
440 scheduler=scheduler_name, override_category=CATEGORY_BUILD) | 442 do_patch_step=is_trybot, |
441 F('f_%s' % compile_debug_builder_name, factory_type( | 443 perf_output_basedir=perf_output_basedir, |
442 builder_name=compile_debug_builder_name, | 444 **kwargs |
443 other_subdirs=subdirs_to_checkout, | 445 ).Build(role=role)) |
444 configuration=skia_factory.CONFIG_DEBUG, | |
445 gm_image_subdir=gm_image_subdir, | |
446 do_patch_step=(try_schedulers is not None), | |
447 perf_output_basedir=None, | |
448 compile_warnings_as_errors=compile_bot_warnings_as_errors, | |
449 **kwargs | |
450 ).BuildCompileOnly()) | |
451 compile_release_builder_name = MakeCompileBuilderName(builder_base_name, | |
452 release=True) | |
453 B(compile_release_builder_name, 'f_%s' % compile_release_builder_name, | |
454 # Do not add gatekeeper for trybots. | |
455 gatekeeper='GateKeeper' if try_schedulers is None else None, | |
456 scheduler=scheduler_name, override_category=CATEGORY_BUILD) | |
457 F('f_%s' % compile_release_builder_name, factory_type( | |
458 builder_name=compile_release_builder_name, | |
459 other_subdirs=subdirs_to_checkout, | |
460 configuration=skia_factory.CONFIG_RELEASE, | |
461 gm_image_subdir=gm_image_subdir, | |
462 do_patch_step=(try_schedulers is not None), | |
463 perf_output_basedir=None, | |
464 compile_warnings_as_errors=compile_bot_warnings_as_errors, | |
465 **kwargs | |
466 ).BuildCompileOnly()) | |
467 | |
468 if do_debug: | |
469 debug_builder_name = MakeDebugBuilderName(builder_base_name) | |
470 B(debug_builder_name, 'f_%s' % debug_builder_name, | |
471 scheduler=scheduler_name) | |
472 F('f_%s' % debug_builder_name, factory_type( | |
473 builder_name=debug_builder_name, | |
474 other_subdirs=subdirs_to_checkout, | |
475 configuration=skia_factory.CONFIG_DEBUG, | |
476 gm_image_subdir=gm_image_subdir, | |
477 do_patch_step=(try_schedulers is not None), | |
478 perf_output_basedir=None, | |
479 compile_warnings_as_errors=False, | |
480 **kwargs | |
481 ).Build()) | |
482 | |
483 if do_release: | |
484 no_perf_builder_name = MakeReleaseBuilderName(builder_base_name) | |
485 B(no_perf_builder_name, 'f_%s' % no_perf_builder_name, | |
486 scheduler=scheduler_name) | |
487 F('f_%s' % no_perf_builder_name, factory_type( | |
488 builder_name=no_perf_builder_name, | |
489 other_subdirs=subdirs_to_checkout, | |
490 configuration=skia_factory.CONFIG_RELEASE, | |
491 gm_image_subdir=gm_image_subdir, | |
492 do_patch_step=(try_schedulers is not None), | |
493 perf_output_basedir=None, | |
494 compile_warnings_as_errors=False, | |
495 **kwargs | |
496 ).BuildNoPerf()) | |
497 | |
498 if do_bench: | |
499 perf_builder_name = MakeBenchBuilderName(builder_base_name) | |
500 B(perf_builder_name, 'f_%s' % perf_builder_name, | |
501 scheduler=scheduler_name) | |
502 F('f_%s' % perf_builder_name, factory_type( | |
503 builder_name=perf_builder_name, | |
504 other_subdirs=subdirs_to_checkout, | |
505 configuration=skia_factory.CONFIG_RELEASE, | |
506 gm_image_subdir=gm_image_subdir, | |
507 do_patch_step=(try_schedulers is not None), | |
508 perf_output_basedir=perf_output_basedir, | |
509 compile_warnings_as_errors=False, | |
510 **kwargs | |
511 ).BuildPerfOnly()) | |
512 | 446 |
513 | 447 |
514 def _MakeBuilderAndMaybeTrybotSet(do_trybots=True, **kwargs): | 448 def _MakeBuilderAndMaybeTrybotSet(do_trybots=True, **kwargs): |
515 _MakeBuilderSet(try_schedulers=None, **kwargs) | 449 _MakeBuilder(**kwargs) |
516 if do_trybots: | 450 if do_trybots: |
517 _MakeBuilderSet(try_schedulers=TRY_SCHEDULERS, **kwargs) | 451 _MakeBuilder(is_trybot=True, **kwargs) |
518 | 452 |
519 | 453 |
520 def MakeBuilderSet(**kwargs): | 454 def MakeBuilderSet(**kwargs): |
521 _MakeBuilderAndMaybeTrybotSet(factory_type=skia_factory.SkiaFactory, **kwargs) | 455 _MakeBuilderAndMaybeTrybotSet(**kwargs) |
522 | 456 |
523 | 457 |
524 def MakeHousekeeperBuilderSet(helper, do_trybots, do_upload_results): | 458 def _MakeCompileBuilder(helper, scheduler, os, compiler, configuration, |
525 B = helper.Builder | 459 target_arch, factory_type, is_trybot, |
526 F = helper.Factory | 460 extra_config=None, **kwargs): |
527 | 461 builder_name = MakeBuilderName(role=BUILDER_ROLE_COMPILE, |
528 builder_factory_scheduler = [ | 462 os=os, |
529 # The Percommit housekeeper | 463 compiler=compiler, |
530 ('Skia_PerCommit_House_Keeping', | 464 configuration=configuration, |
531 housekeeping_percommit_factory.HouseKeepingPerCommitFactory, | 465 target_arch=target_arch, |
532 'skia_rel'), | 466 extra_config=extra_config, |
533 # The Periodic housekeeper | 467 is_trybot=is_trybot) |
534 ('Skia_Periodic_House_Keeping', | 468 helper.Builder(builder_name, 'f_%s' % builder_name, |
535 housekeeping_periodic_factory.HouseKeepingPeriodicFactory, | 469 # Do not add gatekeeper for trybots. |
536 'skia_periodic'), | 470 gatekeeper='GateKeeper' if is_trybot else None, |
537 ] | 471 scheduler=scheduler) |
538 if do_trybots: | 472 helper.Factory('f_%s' % builder_name, factory_type( |
539 # Add the corresponding trybot builders to the above list. | 473 builder_name=builder_name, |
540 builder_factory_scheduler.extend([ | 474 do_patch_step=is_trybot, |
541 (builder + TRYBOT_NAME_SUFFIX, factory, TRY_SCHEDULERS_STR) | 475 configuration=configuration, |
542 for (builder, factory, _scheduler) in builder_factory_scheduler]) | 476 **kwargs |
543 | 477 ).Build(role=BUILDER_ROLE_COMPILE)) |
544 for (builder_name, factory, scheduler) in builder_factory_scheduler: | 478 return builder_name |
545 B(builder_name, 'f_%s' % builder_name, scheduler=scheduler) | |
546 F('f_%s' % builder_name, | |
547 factory( | |
548 do_upload_results=do_upload_results, | |
549 target_platform=skia_factory.TARGET_PLATFORM_LINUX, | |
550 builder_name=builder_name, | |
551 do_patch_step=(scheduler == TRY_SCHEDULERS_STR), | |
552 ).Build()) | |
553 | 479 |
554 | 480 |
555 def MakeAndroidBuilderSet(extra_branches=None, **kwargs): | 481 def MakeCompileBuilderSet(scheduler, do_trybots=True, **kwargs): |
556 if not extra_branches: | 482 if do_trybots: |
557 extra_branches = [] | 483 _MakeCompileBuilder(scheduler=scheduler, is_trybot=True, **kwargs) |
558 extra_branches.append('android') | 484 _MakeCompileBuilder(scheduler=TRY_SCHEDULERS_STR, is_trybot=False, **kwargs) |
559 _MakeBuilderAndMaybeTrybotSet(factory_type=android_factory.AndroidFactory, | |
560 extra_branches=extra_branches, | |
561 **kwargs) | |
562 | |
563 | |
564 def MakeChromeOSBuilderSet(**kwargs): | |
565 _MakeBuilderAndMaybeTrybotSet(factory_type=chromeos_factory.ChromeOSFactory, | |
566 **kwargs) | |
567 | |
568 | |
569 def MakeIOSBuilderSet(**kwargs): | |
570 _MakeBuilderAndMaybeTrybotSet(factory_type=ios_factory.iOSFactory, **kwargs) | |
571 | |
572 | |
573 def MakeNaClBuilderSet(**kwargs): | |
574 _MakeBuilderAndMaybeTrybotSet(factory_type=nacl_factory.NaClFactory, **kwargs) | |
575 | 485 |
576 | 486 |
577 def CanMergeBuildRequests(req1, req2): | 487 def CanMergeBuildRequests(req1, req2): |
578 """ Determine whether or not two BuildRequests can be merged. Note that the | 488 """ Determine whether or not two BuildRequests can be merged. Note that the |
579 call to buildbot.sourcestamp.SourceStamp.canBeMergedWith() is conspicuously | 489 call to buildbot.sourcestamp.SourceStamp.canBeMergedWith() is conspicuously |
580 missing. This is because that method verifies that: | 490 missing. This is because that method verifies that: |
581 1. req1.source.repository == req2.source.repository | 491 1. req1.source.repository == req2.source.repository |
582 2. req1.source.project == req2.source.project | 492 2. req1.source.project == req2.source.project |
583 3. req1.source.branch == req2.source.branch | 493 3. req1.source.branch == req2.source.branch |
584 4. req1.patch == None and req2.patch = None | 494 4. req1.patch == None and req2.patch = None |
(...skipping 29 matching lines...) Expand all Loading... |
614 # request is associated with a change but the revisions match (#5 above). | 524 # request is associated with a change but the revisions match (#5 above). |
615 if req1.source.changes and not req2.source.changes: | 525 if req1.source.changes and not req2.source.changes: |
616 return False | 526 return False |
617 if not req1.source.changes and req2.source.changes: | 527 if not req1.source.changes and req2.source.changes: |
618 return False | 528 return False |
619 if not (req1.source.changes and req2.source.changes): | 529 if not (req1.source.changes and req2.source.changes): |
620 if req1.source.revision != req2.source.revision: | 530 if req1.source.revision != req2.source.revision: |
621 return False | 531 return False |
622 | 532 |
623 return True | 533 return True |
OLD | NEW |