| 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 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 'parameters_json': json.dumps(parameters), | 376 'parameters_json': json.dumps(parameters), |
| 377 'client_operation_id': str(uuid.uuid4()), | 377 'client_operation_id': str(uuid.uuid4()), |
| 378 'tags': ['builder:%s' % builder, | 378 'tags': ['builder:%s' % builder, |
| 379 'buildset:%s' % buildset, | 379 'buildset:%s' % buildset, |
| 380 'master:%s' % master, | 380 'master:%s' % master, |
| 381 'user_agent:git_cl_try'] | 381 'user_agent:git_cl_try'] |
| 382 } | 382 } |
| 383 ) | 383 ) |
| 384 | 384 |
| 385 _buildbucket_retry( | 385 _buildbucket_retry( |
| 386 'triggering tryjobs', | 386 'triggering try jobs', |
| 387 http, | 387 http, |
| 388 buildbucket_put_url, | 388 buildbucket_put_url, |
| 389 'PUT', | 389 'PUT', |
| 390 body=json.dumps(batch_req_body), | 390 body=json.dumps(batch_req_body), |
| 391 headers={'Content-Type': 'application/json'} | 391 headers={'Content-Type': 'application/json'} |
| 392 ) | 392 ) |
| 393 print_text.append('To see results here, run: git cl try-results') | 393 print_text.append('To see results here, run: git cl try-results') |
| 394 print_text.append('To see results in browser, run: git cl web') | 394 print_text.append('To see results in browser, run: git cl web') |
| 395 print('\n'.join(print_text)) | 395 print('\n'.join(print_text)) |
| 396 | 396 |
| 397 | 397 |
| 398 def fetch_try_jobs(auth_config, changelist, options): | 398 def fetch_try_jobs(auth_config, changelist, options): |
| 399 """Fetches tryjobs from buildbucket. | 399 """Fetches try jobs from buildbucket. |
| 400 | 400 |
| 401 Returns a map from build id to build info as json dictionary. | 401 Returns a map from build id to build info as json dictionary. |
| 402 """ | 402 """ |
| 403 rietveld_url = settings.GetDefaultServerUrl() | 403 rietveld_url = settings.GetDefaultServerUrl() |
| 404 rietveld_host = urlparse.urlparse(rietveld_url).hostname | 404 rietveld_host = urlparse.urlparse(rietveld_url).hostname |
| 405 authenticator = auth.get_authenticator_for_host(rietveld_host, auth_config) | 405 authenticator = auth.get_authenticator_for_host(rietveld_host, auth_config) |
| 406 if authenticator.has_cached_credentials(): | 406 if authenticator.has_cached_credentials(): |
| 407 http = authenticator.authorize(httplib2.Http()) | 407 http = authenticator.authorize(httplib2.Http()) |
| 408 else: | 408 else: |
| 409 print('Warning: Some results might be missing because %s' % | 409 print('Warning: Some results might be missing because %s' % |
| 410 # Get the message on how to login. | 410 # Get the message on how to login. |
| 411 (auth.LoginRequiredError(rietveld_host).message,)) | 411 (auth.LoginRequiredError(rietveld_host).message,)) |
| 412 http = httplib2.Http() | 412 http = httplib2.Http() |
| 413 | 413 |
| 414 http.force_exception_to_status_code = True | 414 http.force_exception_to_status_code = True |
| 415 | 415 |
| 416 buildset = 'patch/rietveld/{hostname}/{issue}/{patch}'.format( | 416 buildset = 'patch/rietveld/{hostname}/{issue}/{patch}'.format( |
| 417 hostname=rietveld_host, | 417 hostname=rietveld_host, |
| 418 issue=changelist.GetIssue(), | 418 issue=changelist.GetIssue(), |
| 419 patch=options.patchset) | 419 patch=options.patchset) |
| 420 params = {'tag': 'buildset:%s' % buildset} | 420 params = {'tag': 'buildset:%s' % buildset} |
| 421 | 421 |
| 422 builds = {} | 422 builds = {} |
| 423 while True: | 423 while True: |
| 424 url = 'https://{hostname}/_ah/api/buildbucket/v1/search?{params}'.format( | 424 url = 'https://{hostname}/_ah/api/buildbucket/v1/search?{params}'.format( |
| 425 hostname=options.buildbucket_host, | 425 hostname=options.buildbucket_host, |
| 426 params=urllib.urlencode(params)) | 426 params=urllib.urlencode(params)) |
| 427 content = _buildbucket_retry('fetching tryjobs', http, url, 'GET') | 427 content = _buildbucket_retry('fetching try jobs', http, url, 'GET') |
| 428 for build in content.get('builds', []): | 428 for build in content.get('builds', []): |
| 429 builds[build['id']] = build | 429 builds[build['id']] = build |
| 430 if 'next_cursor' in content: | 430 if 'next_cursor' in content: |
| 431 params['start_cursor'] = content['next_cursor'] | 431 params['start_cursor'] = content['next_cursor'] |
| 432 else: | 432 else: |
| 433 break | 433 break |
| 434 return builds | 434 return builds |
| 435 | 435 |
| 436 | 436 |
| 437 def print_tryjobs(options, builds): | 437 def print_try_jobs(options, builds): |
| 438 """Prints nicely result of fetch_try_jobs.""" | 438 """Prints nicely result of fetch_try_jobs.""" |
| 439 if not builds: | 439 if not builds: |
| 440 print('No tryjobs scheduled') | 440 print('No try jobs scheduled') |
| 441 return | 441 return |
| 442 | 442 |
| 443 # Make a copy, because we'll be modifying builds dictionary. | 443 # Make a copy, because we'll be modifying builds dictionary. |
| 444 builds = builds.copy() | 444 builds = builds.copy() |
| 445 builder_names_cache = {} | 445 builder_names_cache = {} |
| 446 | 446 |
| 447 def get_builder(b): | 447 def get_builder(b): |
| 448 try: | 448 try: |
| 449 return builder_names_cache[b['id']] | 449 return builder_names_cache[b['id']] |
| 450 except KeyError: | 450 except KeyError: |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 pop(status='STARTED', | 523 pop(status='STARTED', |
| 524 title='Started:', color=Fore.YELLOW, | 524 title='Started:', color=Fore.YELLOW, |
| 525 f=lambda b: (get_name(b), b.get('url'))) | 525 f=lambda b: (get_name(b), b.get('url'))) |
| 526 pop(status='SCHEDULED', | 526 pop(status='SCHEDULED', |
| 527 title='Scheduled:', | 527 title='Scheduled:', |
| 528 f=lambda b: (get_name(b), 'id=%s' % b['id'])) | 528 f=lambda b: (get_name(b), 'id=%s' % b['id'])) |
| 529 # The last section is just in case buildbucket API changes OR there is a bug. | 529 # The last section is just in case buildbucket API changes OR there is a bug. |
| 530 pop(title='Other:', | 530 pop(title='Other:', |
| 531 f=lambda b: (get_name(b), 'id=%s' % b['id'])) | 531 f=lambda b: (get_name(b), 'id=%s' % b['id'])) |
| 532 assert len(builds) == 0 | 532 assert len(builds) == 0 |
| 533 print('Total: %d tryjobs' % total) | 533 print('Total: %d try jobs' % total) |
| 534 | 534 |
| 535 | 535 |
| 536 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 536 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
| 537 """Return the corresponding git ref if |base_url| together with |glob_spec| | 537 """Return the corresponding git ref if |base_url| together with |glob_spec| |
| 538 matches the full |url|. | 538 matches the full |url|. |
| 539 | 539 |
| 540 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). | 540 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). |
| 541 """ | 541 """ |
| 542 fetch_suburl, as_ref = glob_spec.split(':') | 542 fetch_suburl, as_ref = glob_spec.split(':') |
| 543 if allow_wildcards: | 543 if allow_wildcards: |
| (...skipping 4057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4601 if cl.IsGerrit(): | 4601 if cl.IsGerrit(): |
| 4602 parser.error( | 4602 parser.error( |
| 4603 'Not yet supported for Gerrit (http://crbug.com/599931).\n' | 4603 'Not yet supported for Gerrit (http://crbug.com/599931).\n' |
| 4604 'If your project has Commit Queue, dry run is a workaround:\n' | 4604 'If your project has Commit Queue, dry run is a workaround:\n' |
| 4605 ' git cl set-commit --dry-run') | 4605 ' git cl set-commit --dry-run') |
| 4606 # Code below assumes Rietveld issue. | 4606 # Code below assumes Rietveld issue. |
| 4607 # TODO(tandrii): actually implement for Gerrit http://crbug.com/599931. | 4607 # TODO(tandrii): actually implement for Gerrit http://crbug.com/599931. |
| 4608 | 4608 |
| 4609 props = cl.GetIssueProperties() | 4609 props = cl.GetIssueProperties() |
| 4610 if props.get('closed'): | 4610 if props.get('closed'): |
| 4611 parser.error('Cannot send tryjobs for a closed CL') | 4611 parser.error('Cannot send try jobs for a closed CL') |
| 4612 | 4612 |
| 4613 if props.get('private'): | 4613 if props.get('private'): |
| 4614 parser.error('Cannot use trybots with private issue') | 4614 parser.error('Cannot use try bots with private issue') |
| 4615 | 4615 |
| 4616 if not options.name: | 4616 if not options.name: |
| 4617 options.name = cl.GetBranch() | 4617 options.name = cl.GetBranch() |
| 4618 | 4618 |
| 4619 if options.bot and not options.master: | 4619 if options.bot and not options.master: |
| 4620 options.master, err_msg = GetBuilderMaster(options.bot) | 4620 options.master, err_msg = GetBuilderMaster(options.bot) |
| 4621 if err_msg: | 4621 if err_msg: |
| 4622 parser.error('Tryserver master cannot be found because: %s\n' | 4622 parser.error('Tryserver master cannot be found because: %s\n' |
| 4623 'Please manually specify the tryserver master' | 4623 'Please manually specify the tryserver master' |
| 4624 ', e.g. "-m tryserver.chromium.linux".' % err_msg) | 4624 ', e.g. "-m tryserver.chromium.linux".' % err_msg) |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4714 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' | 4714 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' |
| 4715 'Continuing using\npatchset %s.\n' % patchset) | 4715 'Continuing using\npatchset %s.\n' % patchset) |
| 4716 if not options.use_rietveld: | 4716 if not options.use_rietveld: |
| 4717 try: | 4717 try: |
| 4718 trigger_try_jobs(auth_config, cl, options, masters, 'git_cl_try') | 4718 trigger_try_jobs(auth_config, cl, options, masters, 'git_cl_try') |
| 4719 except BuildbucketResponseException as ex: | 4719 except BuildbucketResponseException as ex: |
| 4720 print('ERROR: %s' % ex) | 4720 print('ERROR: %s' % ex) |
| 4721 return 1 | 4721 return 1 |
| 4722 except Exception as e: | 4722 except Exception as e: |
| 4723 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) | 4723 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) |
| 4724 print('ERROR: Exception when trying to trigger tryjobs: %s\n%s' % | 4724 print('ERROR: Exception when trying to trigger try jobs: %s\n%s' % |
| 4725 (e, stacktrace)) | 4725 (e, stacktrace)) |
| 4726 return 1 | 4726 return 1 |
| 4727 else: | 4727 else: |
| 4728 try: | 4728 try: |
| 4729 cl.RpcServer().trigger_distributed_try_jobs( | 4729 cl.RpcServer().trigger_distributed_try_jobs( |
| 4730 cl.GetIssue(), patchset, options.name, options.clobber, | 4730 cl.GetIssue(), patchset, options.name, options.clobber, |
| 4731 options.revision, masters) | 4731 options.revision, masters) |
| 4732 except urllib2.HTTPError as e: | 4732 except urllib2.HTTPError as e: |
| 4733 if e.code == 404: | 4733 if e.code == 404: |
| 4734 print('404 from rietveld; ' | 4734 print('404 from rietveld; ' |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4775 '\nWARNING Mismatch between local config and server. Did a previous ' | 4775 '\nWARNING Mismatch between local config and server. Did a previous ' |
| 4776 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' | 4776 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' |
| 4777 'Continuing using\npatchset %s.\n' % options.patchset) | 4777 'Continuing using\npatchset %s.\n' % options.patchset) |
| 4778 try: | 4778 try: |
| 4779 jobs = fetch_try_jobs(auth_config, cl, options) | 4779 jobs = fetch_try_jobs(auth_config, cl, options) |
| 4780 except BuildbucketResponseException as ex: | 4780 except BuildbucketResponseException as ex: |
| 4781 print('Buildbucket error: %s' % ex) | 4781 print('Buildbucket error: %s' % ex) |
| 4782 return 1 | 4782 return 1 |
| 4783 except Exception as e: | 4783 except Exception as e: |
| 4784 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) | 4784 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) |
| 4785 print('ERROR: Exception when trying to fetch tryjobs: %s\n%s' % | 4785 print('ERROR: Exception when trying to fetch try jobs: %s\n%s' % |
| 4786 (e, stacktrace)) | 4786 (e, stacktrace)) |
| 4787 return 1 | 4787 return 1 |
| 4788 print_tryjobs(options, jobs) | 4788 print_try_jobs(options, jobs) |
| 4789 return 0 | 4789 return 0 |
| 4790 | 4790 |
| 4791 | 4791 |
| 4792 @subcommand.usage('[new upstream branch]') | 4792 @subcommand.usage('[new upstream branch]') |
| 4793 def CMDupstream(parser, args): | 4793 def CMDupstream(parser, args): |
| 4794 """Prints or sets the name of the upstream branch, if any.""" | 4794 """Prints or sets the name of the upstream branch, if any.""" |
| 4795 _, args = parser.parse_args(args) | 4795 _, args = parser.parse_args(args) |
| 4796 if len(args) > 1: | 4796 if len(args) > 1: |
| 4797 parser.error('Unrecognized args: %s' % ' '.join(args)) | 4797 parser.error('Unrecognized args: %s' % ' '.join(args)) |
| 4798 | 4798 |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5218 if __name__ == '__main__': | 5218 if __name__ == '__main__': |
| 5219 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5219 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 5220 # unit testing. | 5220 # unit testing. |
| 5221 fix_encoding.fix_encoding() | 5221 fix_encoding.fix_encoding() |
| 5222 setup_color.init() | 5222 setup_color.init() |
| 5223 try: | 5223 try: |
| 5224 sys.exit(main(sys.argv[1:])) | 5224 sys.exit(main(sys.argv[1:])) |
| 5225 except KeyboardInterrupt: | 5225 except KeyboardInterrupt: |
| 5226 sys.stderr.write('interrupted\n') | 5226 sys.stderr.write('interrupted\n') |
| 5227 sys.exit(1) | 5227 sys.exit(1) |
| OLD | NEW |