| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
| 7 | 7 |
| 8 """A git-command for integrating reviews on Rietveld and Gerrit.""" | 8 """A git-command for integrating reviews on Rietveld and Gerrit.""" |
| 9 | 9 |
| 10 from __future__ import print_function | 10 from __future__ import print_function |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 default_presubmit=None, | 356 default_presubmit=None, |
| 357 project=None, | 357 project=None, |
| 358 verbose=options.verbose, | 358 verbose=options.verbose, |
| 359 output_stream=sys.stdout) | 359 output_stream=sys.stdout) |
| 360 | 360 |
| 361 if masters: | 361 if masters: |
| 362 return masters | 362 return masters |
| 363 | 363 |
| 364 # Fall back to deprecated method: get try slaves from PRESUBMIT.py | 364 # Fall back to deprecated method: get try slaves from PRESUBMIT.py |
| 365 # files. | 365 # files. |
| 366 # TODO(qyearsley): Remove this. |
| 366 options.bot = presubmit_support.DoGetTrySlaves( | 367 options.bot = presubmit_support.DoGetTrySlaves( |
| 367 change=change, | 368 change=change, |
| 368 changed_files=change.LocalPaths(), | 369 changed_files=change.LocalPaths(), |
| 369 repository_root=settings.GetRoot(), | 370 repository_root=settings.GetRoot(), |
| 370 default_presubmit=None, | 371 default_presubmit=None, |
| 371 project=None, | 372 project=None, |
| 372 verbose=options.verbose, | 373 verbose=options.verbose, |
| 373 output_stream=sys.stdout) | 374 output_stream=sys.stdout) |
| 374 | 375 |
| 375 if not options.bot: | 376 if not options.bot: |
| 376 return {} | 377 return {} |
| 377 | 378 |
| 378 if options.bucket: | 379 if options.bucket: |
| 379 return {options.bucket: {b: [] for b in options.bot}} | 380 return {options.bucket: {b: [] for b in options.bot}} |
| 380 | 381 |
| 382 if not options.master: |
| 383 bucket_map, error_message = _get_bucket_map_for_builders(options.bot) |
| 384 if error_message: |
| 385 option_parser.error( |
| 386 'Tryserver master cannot be found because: %s\n' |
| 387 'Please manually specify the tryserver master, e.g. ' |
| 388 '"-m tryserver.chromium.linux".' % error_message) |
| 389 return bucket_map |
| 390 |
| 381 builders_and_tests = {} | 391 builders_and_tests = {} |
| 382 | 392 |
| 383 # TODO(machenbach): The old style command-line options don't support | 393 # TODO(machenbach): The old style command-line options don't support |
| 384 # multiple try masters yet. | 394 # multiple try masters yet. |
| 395 # TODO(qyearsley): If options.bot is always a list of strings, then |
| 396 # "new_style" never applies, and so we should remove support for Specifying |
| 397 # test filters completely. |
| 385 old_style = filter(lambda x: isinstance(x, basestring), options.bot) | 398 old_style = filter(lambda x: isinstance(x, basestring), options.bot) |
| 386 new_style = filter(lambda x: isinstance(x, tuple), options.bot) | 399 new_style = filter(lambda x: isinstance(x, tuple), options.bot) |
| 387 | 400 |
| 388 for bot in old_style: | 401 for bot in old_style: |
| 389 if ':' in bot: | 402 if ':' in bot: |
| 390 option_parser.error('Specifying testfilter is no longer supported') | 403 option_parser.error('Specifying testfilter is no longer supported') |
| 391 elif ',' in bot: | 404 elif ',' in bot: |
| 392 option_parser.error('Specify one bot per --bot flag') | 405 option_parser.error('Specify one bot per --bot flag') |
| 393 else: | 406 else: |
| 394 builders_and_tests.setdefault(bot, []) | 407 builders_and_tests.setdefault(bot, []) |
| 395 | 408 |
| 396 for bot, tests in new_style: | 409 for bot, tests in new_style: |
| 397 builders_and_tests.setdefault(bot, []).extend(tests) | 410 builders_and_tests.setdefault(bot, []).extend(tests) |
| 398 | 411 |
| 399 if not options.master: | 412 # Add the "master." prefix to the master name to obtain the bucket name. |
| 400 # TODO(qyearsley): crbug.com/640740 | 413 bucket = _prefix_master(options.master) |
| 401 options.master, error_message = _get_builder_master(options.bot) | |
| 402 if error_message: | |
| 403 option_parser.error( | |
| 404 'Tryserver master cannot be found because: %s\n' | |
| 405 'Please manually specify the tryserver master, e.g. ' | |
| 406 '"-m tryserver.chromium.linux".' % error_message) | |
| 407 | |
| 408 # Return a master map with one master to be backwards compatible. The | |
| 409 # master name defaults to an empty string, which will cause the master | |
| 410 # not to be set on rietveld (deprecated). | |
| 411 bucket = '' | |
| 412 if options.master: | |
| 413 # Add the "master." prefix to the master name to obtain the bucket name. | |
| 414 bucket = _prefix_master(options.master) | |
| 415 return {bucket: builders_and_tests} | 414 return {bucket: builders_and_tests} |
| 416 | 415 |
| 417 | 416 |
| 418 def _get_builder_master(bot_list): | 417 def _get_bucket_map_for_builders(builders): |
| 419 """Fetches a master for the given list of builders. | 418 """Returns a map of buckets to builders for the given builders.""" |
| 420 | |
| 421 Returns a pair (master, error_message), where either master or | |
| 422 error_message is None. | |
| 423 """ | |
| 424 map_url = 'https://builders-map.appspot.com/' | 419 map_url = 'https://builders-map.appspot.com/' |
| 425 try: | 420 try: |
| 426 master_map = json.load(urllib2.urlopen(map_url)) | 421 builders_map = json.load(urllib2.urlopen(map_url)) |
| 427 except urllib2.URLError as e: | 422 except urllib2.URLError as e: |
| 428 return None, ('Failed to fetch builder-to-master map from %s. Error: %s.' % | 423 return None, ('Failed to fetch builder-to-master map from %s. Error: %s.' % |
| 429 (map_url, e)) | 424 (map_url, e)) |
| 430 except ValueError as e: | 425 except ValueError as e: |
| 431 return None, ('Invalid json string from %s. Error: %s.' % (map_url, e)) | 426 return None, ('Invalid json string from %s. Error: %s.' % (map_url, e)) |
| 432 if not master_map: | 427 if not builders_map: |
| 433 return None, 'Failed to build master map.' | 428 return None, 'Failed to build master map.' |
| 434 | 429 |
| 435 result_master = '' | 430 bucket_map = {} |
| 436 for bot in bot_list: | 431 for builder in builders: |
| 437 builder = bot.split(':', 1)[0] | 432 builder = builder.split(':', 1)[0] |
| 438 master_list = master_map.get(builder, []) | 433 masters = builders_map.get(builder, []) |
| 439 if not master_list: | 434 if not masters: |
| 440 return None, ('No matching master for builder %s.' % builder) | 435 return None, ('No matching master for builder %s.' % builder) |
| 441 elif len(master_list) > 1: | 436 if len(masters) > 1: |
| 442 return None, ('The builder name %s exists in multiple masters %s.' % | 437 return None, ('The builder name %s exists in multiple masters %s.' % |
| 443 (builder, master_list)) | 438 (builder, masters)) |
| 444 else: | 439 bucket = _prefix_master(masters[0]) |
| 445 cur_master = master_list[0] | 440 bucket_map.setdefault(bucket, {})[builder] = [] |
| 446 if not result_master: | 441 |
| 447 result_master = cur_master | 442 return bucket_map, None |
| 448 elif result_master != cur_master: | |
| 449 return None, 'The builders do not belong to the same master.' | |
| 450 return result_master, None | |
| 451 | 443 |
| 452 | 444 |
| 453 def _trigger_try_jobs(auth_config, changelist, buckets, options, | 445 def _trigger_try_jobs(auth_config, changelist, buckets, options, |
| 454 category='git_cl_try', patchset=None): | 446 category='git_cl_try', patchset=None): |
| 455 """Sends a request to Buildbucket to trigger try jobs for a changelist. | 447 """Sends a request to Buildbucket to trigger try jobs for a changelist. |
| 456 | 448 |
| 457 Args: | 449 Args: |
| 458 auth_config: AuthConfig for Rietveld. | 450 auth_config: AuthConfig for Rietveld. |
| 459 changelist: Changelist that the try jobs are associated with. | 451 changelist: Changelist that the try jobs are associated with. |
| 460 buckets: A nested dict mapping bucket names to builders to tests. | 452 buckets: A nested dict mapping bucket names to builders to tests. |
| (...skipping 4949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5410 if __name__ == '__main__': | 5402 if __name__ == '__main__': |
| 5411 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5403 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 5412 # unit testing. | 5404 # unit testing. |
| 5413 fix_encoding.fix_encoding() | 5405 fix_encoding.fix_encoding() |
| 5414 setup_color.init() | 5406 setup_color.init() |
| 5415 try: | 5407 try: |
| 5416 sys.exit(main(sys.argv[1:])) | 5408 sys.exit(main(sys.argv[1:])) |
| 5417 except KeyboardInterrupt: | 5409 except KeyboardInterrupt: |
| 5418 sys.stderr.write('interrupted\n') | 5410 sys.stderr.write('interrupted\n') |
| 5419 sys.exit(1) | 5411 sys.exit(1) |
| OLD | NEW |