Chromium Code Reviews| 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 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 if response.status < 500 or try_count >= 2: | 333 if response.status < 500 or try_count >= 2: |
| 334 raise httplib2.HttpLib2Error(content) | 334 raise httplib2.HttpLib2Error(content) |
| 335 | 335 |
| 336 # status >= 500 means transient failures. | 336 # status >= 500 means transient failures. |
| 337 logging.debug('Transient errors when %s. Will retry.', operation_name) | 337 logging.debug('Transient errors when %s. Will retry.', operation_name) |
| 338 time_sleep(0.5 + 1.5*try_count) | 338 time_sleep(0.5 + 1.5*try_count) |
| 339 try_count += 1 | 339 try_count += 1 |
| 340 assert False, 'unreachable' | 340 assert False, 'unreachable' |
| 341 | 341 |
| 342 | 342 |
| 343 def _get_bucket_map(changelist, options, option_parser): | |
| 344 """Returns a dict mapping bucket names (or master names) to | |
| 345 builders and tests, for triggering try jobs. | |
| 346 """ | |
| 347 if not options.bot: | |
| 348 change = changelist.GetChange( | |
| 349 changelist.GetCommonAncestorWithUpstream(), None) | |
| 350 | |
| 351 # Get try masters from PRESUBMIT.py files. | |
| 352 masters = presubmit_support.DoGetTryMasters( | |
| 353 change=change, | |
| 354 changed_files=change.LocalPaths(), | |
| 355 repository_root=settings.GetRoot(), | |
| 356 default_presubmit=None, | |
| 357 project=None, | |
| 358 verbose=options.verbose, | |
| 359 output_stream=sys.stdout) | |
| 360 | |
| 361 if masters: | |
| 362 return masters | |
|
nodir
2016/11/04 21:49:40
this returns masters, not buckets. Caused https://
nodir
2016/11/04 21:55:42
https://codereview.chromium.org/2482523002
| |
| 363 | |
| 364 # Fall back to deprecated method: get try slaves from PRESUBMIT.py | |
| 365 # files. | |
| 366 options.bot = presubmit_support.DoGetTrySlaves( | |
| 367 change=change, | |
| 368 changed_files=change.LocalPaths(), | |
| 369 repository_root=settings.GetRoot(), | |
| 370 default_presubmit=None, | |
| 371 project=None, | |
| 372 verbose=options.verbose, | |
| 373 output_stream=sys.stdout) | |
| 374 | |
| 375 if not options.bot: | |
| 376 return {} | |
| 377 | |
| 378 if options.bucket: | |
| 379 return {options.bucket: {b: [] for b in options.bot}} | |
| 380 | |
| 381 builders_and_tests = {} | |
| 382 | |
| 383 # TODO(machenbach): The old style command-line options don't support | |
| 384 # multiple try masters yet. | |
| 385 old_style = filter(lambda x: isinstance(x, basestring), options.bot) | |
| 386 new_style = filter(lambda x: isinstance(x, tuple), options.bot) | |
| 387 | |
| 388 for bot in old_style: | |
| 389 if ':' in bot: | |
| 390 option_parser.error('Specifying testfilter is no longer supported') | |
| 391 elif ',' in bot: | |
| 392 option_parser.error('Specify one bot per --bot flag') | |
| 393 else: | |
| 394 builders_and_tests.setdefault(bot, []) | |
| 395 | |
| 396 for bot, tests in new_style: | |
| 397 builders_and_tests.setdefault(bot, []).extend(tests) | |
| 398 | |
| 399 if not options.master: | |
| 400 # TODO(qyearsley): crbug.com/640740 | |
| 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} | |
| 416 | |
| 417 | |
| 418 def _get_builder_master(bot_list): | |
| 419 """Fetches a master for the given list of 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/' | |
| 425 try: | |
| 426 master_map = json.load(urllib2.urlopen(map_url)) | |
| 427 except urllib2.URLError as e: | |
| 428 return None, ('Failed to fetch builder-to-master map from %s. Error: %s.' % | |
| 429 (map_url, e)) | |
| 430 except ValueError as e: | |
| 431 return None, ('Invalid json string from %s. Error: %s.' % (map_url, e)) | |
| 432 if not master_map: | |
| 433 return None, 'Failed to build master map.' | |
| 434 | |
| 435 result_master = '' | |
| 436 for bot in bot_list: | |
| 437 builder = bot.split(':', 1)[0] | |
| 438 master_list = master_map.get(builder, []) | |
| 439 if not master_list: | |
| 440 return None, ('No matching master for builder %s.' % builder) | |
| 441 elif len(master_list) > 1: | |
| 442 return None, ('The builder name %s exists in multiple masters %s.' % | |
| 443 (builder, master_list)) | |
| 444 else: | |
| 445 cur_master = master_list[0] | |
| 446 if not result_master: | |
| 447 result_master = cur_master | |
| 448 elif result_master != cur_master: | |
| 449 return None, 'The builders do not belong to the same master.' | |
| 450 return result_master, None | |
| 451 | |
| 452 | |
| 343 def _trigger_try_jobs(auth_config, changelist, buckets, options, | 453 def _trigger_try_jobs(auth_config, changelist, buckets, options, |
| 344 category='git_cl_try', patchset=None): | 454 category='git_cl_try', patchset=None): |
| 455 """Sends a request to Buildbucket to trigger try jobs for a changelist. | |
| 456 | |
| 457 Args: | |
| 458 auth_config: AuthConfig for Rietveld. | |
| 459 changelist: Changelist that the try jobs are associated with. | |
| 460 buckets: A nested dict mapping bucket names to builders to tests. | |
| 461 options: Command-line options. | |
| 462 """ | |
| 345 assert changelist.GetIssue(), 'CL must be uploaded first' | 463 assert changelist.GetIssue(), 'CL must be uploaded first' |
| 346 codereview_url = changelist.GetCodereviewServer() | 464 codereview_url = changelist.GetCodereviewServer() |
| 347 assert codereview_url, 'CL must be uploaded first' | 465 assert codereview_url, 'CL must be uploaded first' |
| 348 patchset = patchset or changelist.GetMostRecentPatchset() | 466 patchset = patchset or changelist.GetMostRecentPatchset() |
| 349 assert patchset, 'CL must be uploaded first' | 467 assert patchset, 'CL must be uploaded first' |
| 350 | 468 |
| 351 codereview_host = urlparse.urlparse(codereview_url).hostname | 469 codereview_host = urlparse.urlparse(codereview_url).hostname |
| 352 authenticator = auth.get_authenticator_for_host(codereview_host, auth_config) | 470 authenticator = auth.get_authenticator_for_host(codereview_host, auth_config) |
| 353 http = authenticator.authorize(httplib2.Http()) | 471 http = authenticator.authorize(httplib2.Http()) |
| 354 http.force_exception_to_status_code = True | 472 http.force_exception_to_status_code = True |
| (...skipping 1220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1575 | 1693 |
| 1576 def SetCQState(self, new_state): | 1694 def SetCQState(self, new_state): |
| 1577 """Update the CQ state for latest patchset. | 1695 """Update the CQ state for latest patchset. |
| 1578 | 1696 |
| 1579 Issue must have been already uploaded and known. | 1697 Issue must have been already uploaded and known. |
| 1580 """ | 1698 """ |
| 1581 assert new_state in _CQState.ALL_STATES | 1699 assert new_state in _CQState.ALL_STATES |
| 1582 assert self.GetIssue() | 1700 assert self.GetIssue() |
| 1583 return self._codereview_impl.SetCQState(new_state) | 1701 return self._codereview_impl.SetCQState(new_state) |
| 1584 | 1702 |
| 1703 def TriggerDryRun(self): | |
| 1704 """Triggers a dry run and prints a warning on failure.""" | |
| 1705 # TODO(qyearsley): Either re-use this method in CMDset_commit | |
| 1706 # and CMDupload, or change CMDtry to trigger dry runs with | |
| 1707 # just SetCQState, and catch keyboard interrupt and other | |
| 1708 # errors in that method. | |
| 1709 try: | |
| 1710 self.SetCQState(_CQState.DRY_RUN) | |
| 1711 print('scheduled CQ Dry Run on %s' % self.GetIssueURL()) | |
| 1712 return 0 | |
| 1713 except KeyboardInterrupt: | |
| 1714 raise | |
| 1715 except: | |
| 1716 print('WARNING: failed to trigger CQ Dry Run.\n' | |
| 1717 'Either:\n' | |
| 1718 ' * your project has no CQ\n' | |
| 1719 ' * you don\'t have permission to trigger Dry Run\n' | |
| 1720 ' * bug in this code (see stack trace below).\n' | |
| 1721 'Consider specifying which bots to trigger manually ' | |
| 1722 'or asking your project owners for permissions ' | |
| 1723 'or contacting Chrome Infrastructure team at ' | |
| 1724 'https://www.chromium.org/infra\n\n') | |
| 1725 # Still raise exception so that stack trace is printed. | |
| 1726 raise | |
| 1727 | |
| 1585 # Forward methods to codereview specific implementation. | 1728 # Forward methods to codereview specific implementation. |
| 1586 | 1729 |
| 1587 def CloseIssue(self): | 1730 def CloseIssue(self): |
| 1588 return self._codereview_impl.CloseIssue() | 1731 return self._codereview_impl.CloseIssue() |
| 1589 | 1732 |
| 1590 def GetStatus(self): | 1733 def GetStatus(self): |
| 1591 return self._codereview_impl.GetStatus() | 1734 return self._codereview_impl.GetStatus() |
| 1592 | 1735 |
| 1593 def GetCodereviewServer(self): | 1736 def GetCodereviewServer(self): |
| 1594 return self._codereview_impl.GetCodereviewServer() | 1737 return self._codereview_impl.GetCodereviewServer() |
| (...skipping 3046 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4641 """Fetches the tree status from a json url and returns the message | 4784 """Fetches the tree status from a json url and returns the message |
| 4642 with the reason for the tree to be opened or closed.""" | 4785 with the reason for the tree to be opened or closed.""" |
| 4643 url = settings.GetTreeStatusUrl() | 4786 url = settings.GetTreeStatusUrl() |
| 4644 json_url = urlparse.urljoin(url, '/current?format=json') | 4787 json_url = urlparse.urljoin(url, '/current?format=json') |
| 4645 connection = urllib2.urlopen(json_url) | 4788 connection = urllib2.urlopen(json_url) |
| 4646 status = json.loads(connection.read()) | 4789 status = json.loads(connection.read()) |
| 4647 connection.close() | 4790 connection.close() |
| 4648 return status['message'] | 4791 return status['message'] |
| 4649 | 4792 |
| 4650 | 4793 |
| 4651 def GetBuilderMaster(bot_list): | |
| 4652 """For a given builder, fetch the master from AE if available.""" | |
| 4653 map_url = 'https://builders-map.appspot.com/' | |
| 4654 try: | |
| 4655 master_map = json.load(urllib2.urlopen(map_url)) | |
| 4656 except urllib2.URLError as e: | |
| 4657 return None, ('Failed to fetch builder-to-master map from %s. Error: %s.' % | |
| 4658 (map_url, e)) | |
| 4659 except ValueError as e: | |
| 4660 return None, ('Invalid json string from %s. Error: %s.' % (map_url, e)) | |
| 4661 if not master_map: | |
| 4662 return None, 'Failed to build master map.' | |
| 4663 | |
| 4664 result_master = '' | |
| 4665 for bot in bot_list: | |
| 4666 builder = bot.split(':', 1)[0] | |
| 4667 master_list = master_map.get(builder, []) | |
| 4668 if not master_list: | |
| 4669 return None, ('No matching master for builder %s.' % builder) | |
| 4670 elif len(master_list) > 1: | |
| 4671 return None, ('The builder name %s exists in multiple masters %s.' % | |
| 4672 (builder, master_list)) | |
| 4673 else: | |
| 4674 cur_master = master_list[0] | |
| 4675 if not result_master: | |
| 4676 result_master = cur_master | |
| 4677 elif result_master != cur_master: | |
| 4678 return None, 'The builders do not belong to the same master.' | |
| 4679 return result_master, None | |
| 4680 | |
| 4681 | |
| 4682 def CMDtree(parser, args): | 4794 def CMDtree(parser, args): |
| 4683 """Shows the status of the tree.""" | 4795 """Shows the status of the tree.""" |
| 4684 _, args = parser.parse_args(args) | 4796 _, args = parser.parse_args(args) |
| 4685 status = GetTreeStatus() | 4797 status = GetTreeStatus() |
| 4686 if 'unset' == status: | 4798 if 'unset' == status: |
| 4687 print('You must configure your tree status URL by running "git cl config".') | 4799 print('You must configure your tree status URL by running "git cl config".') |
| 4688 return 2 | 4800 return 2 |
| 4689 | 4801 |
| 4690 print('The tree is %s' % status) | 4802 print('The tree is %s' % status) |
| 4691 print() | 4803 print() |
| 4692 print(GetTreeStatusReason()) | 4804 print(GetTreeStatusReason()) |
| 4693 if status != 'open': | 4805 if status != 'open': |
| 4694 return 1 | 4806 return 1 |
| 4695 return 0 | 4807 return 0 |
| 4696 | 4808 |
| 4697 | 4809 |
| 4698 def CMDtry(parser, args): | 4810 def CMDtry(parser, args): |
| 4699 """Triggers try jobs using CQ dry run or BuildBucket for individual builders. | 4811 """Triggers try jobs using either BuildBucket or CQ dry run.""" |
| 4700 """ | |
| 4701 group = optparse.OptionGroup(parser, 'Try job options') | 4812 group = optparse.OptionGroup(parser, 'Try job options') |
| 4702 group.add_option( | 4813 group.add_option( |
| 4703 '-b', '--bot', action='append', | 4814 '-b', '--bot', action='append', |
| 4704 help=('IMPORTANT: specify ONE builder per --bot flag. Use it multiple ' | 4815 help=('IMPORTANT: specify ONE builder per --bot flag. Use it multiple ' |
| 4705 'times to specify multiple builders. ex: ' | 4816 'times to specify multiple builders. ex: ' |
| 4706 '"-b win_rel -b win_layout". See ' | 4817 '"-b win_rel -b win_layout". See ' |
| 4707 'the try server waterfall for the builders name and the tests ' | 4818 'the try server waterfall for the builders name and the tests ' |
| 4708 'available.')) | 4819 'available.')) |
| 4709 group.add_option( | 4820 group.add_option( |
| 4710 '-B', '--bucket', default='', | 4821 '-B', '--bucket', default='', |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4765 error_message = cl.CannotTriggerTryJobReason() | 4876 error_message = cl.CannotTriggerTryJobReason() |
| 4766 if error_message: | 4877 if error_message: |
| 4767 parser.error('Can\'t trigger try jobs: %s' % error_message) | 4878 parser.error('Can\'t trigger try jobs: %s' % error_message) |
| 4768 | 4879 |
| 4769 if not options.name: | 4880 if not options.name: |
| 4770 options.name = cl.GetBranch() | 4881 options.name = cl.GetBranch() |
| 4771 | 4882 |
| 4772 if options.bucket and options.master: | 4883 if options.bucket and options.master: |
| 4773 parser.error('Only one of --bucket and --master may be used.') | 4884 parser.error('Only one of --bucket and --master may be used.') |
| 4774 | 4885 |
| 4775 if options.bot and not options.master and not options.bucket: | 4886 buckets = _get_bucket_map(cl, options, parser) |
| 4776 options.master, err_msg = GetBuilderMaster(options.bot) | |
| 4777 if err_msg: | |
| 4778 parser.error('Tryserver master cannot be found because: %s\n' | |
| 4779 'Please manually specify the tryserver master' | |
| 4780 ', e.g. "-m tryserver.chromium.linux".' % err_msg) | |
| 4781 | 4887 |
| 4782 def GetMasterMap(): | 4888 if not buckets: |
| 4783 """Returns {master: {builder_name: [test_names]}}. Not buckets!""" | 4889 # Default to triggering Dry Run (see http://crbug.com/625697). |
| 4784 # Process --bot. | 4890 if options.verbose: |
| 4785 if not options.bot: | 4891 print('git cl try with no bots now defaults to CQ Dry Run.') |
| 4786 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) | 4892 return cl.TriggerDryRun() |
| 4787 | |
| 4788 # Get try masters from PRESUBMIT.py files. | |
| 4789 masters = presubmit_support.DoGetTryMasters( | |
| 4790 change, | |
| 4791 change.LocalPaths(), | |
| 4792 settings.GetRoot(), | |
| 4793 None, | |
| 4794 None, | |
| 4795 options.verbose, | |
| 4796 sys.stdout) | |
| 4797 if masters: | |
| 4798 return masters | |
| 4799 | |
| 4800 # Fall back to deprecated method: get try slaves from PRESUBMIT.py files. | |
| 4801 options.bot = presubmit_support.DoGetTrySlaves( | |
| 4802 change, | |
| 4803 change.LocalPaths(), | |
| 4804 settings.GetRoot(), | |
| 4805 None, | |
| 4806 None, | |
| 4807 options.verbose, | |
| 4808 sys.stdout) | |
| 4809 | |
| 4810 if not options.bot: | |
| 4811 return {} | |
| 4812 | |
| 4813 builders_and_tests = {} | |
| 4814 # TODO(machenbach): The old style command-line options don't support | |
| 4815 # multiple try masters yet. | |
| 4816 old_style = filter(lambda x: isinstance(x, basestring), options.bot) | |
| 4817 new_style = filter(lambda x: isinstance(x, tuple), options.bot) | |
| 4818 | |
| 4819 for bot in old_style: | |
| 4820 if ':' in bot: | |
| 4821 parser.error('Specifying testfilter is no longer supported') | |
| 4822 elif ',' in bot: | |
| 4823 parser.error('Specify one bot per --bot flag') | |
| 4824 else: | |
| 4825 builders_and_tests.setdefault(bot, []) | |
| 4826 | |
| 4827 for bot, tests in new_style: | |
| 4828 builders_and_tests.setdefault(bot, []).extend(tests) | |
| 4829 | |
| 4830 # Return a master map with one master to be backwards compatible. The | |
| 4831 # master name defaults to an empty string, which will cause the master | |
| 4832 # not to be set on rietveld (deprecated). | |
| 4833 return {options.master: builders_and_tests} | |
| 4834 | |
| 4835 if options.bucket: | |
| 4836 buckets = {options.bucket: {b: [] for b in options.bot}} | |
| 4837 else: | |
| 4838 buckets = {} | |
| 4839 for master, data in GetMasterMap().iteritems(): | |
| 4840 # Add the "master." prefix to the master name to obtain the bucket name. | |
| 4841 bucket = _prefix_master(master) if master else '' | |
| 4842 buckets[bucket] = data | |
| 4843 | |
| 4844 if not buckets: | |
| 4845 # Default to triggering Dry Run (see http://crbug.com/625697). | |
| 4846 if options.verbose: | |
| 4847 print('git cl try with no bots now defaults to CQ Dry Run.') | |
| 4848 try: | |
| 4849 cl.SetCQState(_CQState.DRY_RUN) | |
| 4850 print('scheduled CQ Dry Run on %s' % cl.GetIssueURL()) | |
| 4851 return 0 | |
| 4852 except KeyboardInterrupt: | |
| 4853 raise | |
| 4854 except: | |
| 4855 print('WARNING: failed to trigger CQ Dry Run.\n' | |
| 4856 'Either:\n' | |
| 4857 ' * your project has no CQ\n' | |
| 4858 ' * you don\'t have permission to trigger Dry Run\n' | |
| 4859 ' * bug in this code (see stack trace below).\n' | |
| 4860 'Consider specifying which bots to trigger manually ' | |
| 4861 'or asking your project owners for permissions ' | |
| 4862 'or contacting Chrome Infrastructure team at ' | |
| 4863 'https://www.chromium.org/infra\n\n') | |
| 4864 # Still raise exception so that stack trace is printed. | |
| 4865 raise | |
| 4866 | 4893 |
| 4867 for builders in buckets.itervalues(): | 4894 for builders in buckets.itervalues(): |
| 4868 if any('triggered' in b for b in builders): | 4895 if any('triggered' in b for b in builders): |
| 4869 print('ERROR You are trying to send a job to a triggered bot. This type ' | 4896 print('ERROR You are trying to send a job to a triggered bot. This type ' |
| 4870 'of bot requires an initial job from a parent (usually a builder). ' | 4897 'of bot requires an initial job from a parent (usually a builder). ' |
| 4871 'Instead send your job to the parent.\n' | 4898 'Instead send your job to the parent.\n' |
| 4872 'Bot list: %s' % builders, file=sys.stderr) | 4899 'Bot list: %s' % builders, file=sys.stderr) |
| 4873 return 1 | 4900 return 1 |
| 4874 | 4901 |
| 4875 patchset = cl.GetMostRecentPatchset() | 4902 patchset = cl.GetMostRecentPatchset() |
| 4876 if patchset != cl.GetPatchset(): | 4903 if patchset != cl.GetPatchset(): |
| 4877 print('Warning: Codereview server has newer patchsets (%s) than most ' | 4904 print('Warning: Codereview server has newer patchsets (%s) than most ' |
| 4878 'recent upload from local checkout (%s). Did a previous upload ' | 4905 'recent upload from local checkout (%s). Did a previous upload ' |
| 4879 'fail?\n' | 4906 'fail?\n' |
| 4880 'By default, git cl try uses the latest patchset from ' | 4907 'By default, git cl try uses the latest patchset from ' |
| 4881 'codereview, continuing to use patchset %s.\n' % | 4908 'codereview, continuing to use patchset %s.\n' % |
| 4882 (patchset, cl.GetPatchset(), patchset)) | 4909 (patchset, cl.GetPatchset(), patchset)) |
| 4910 | |
| 4883 try: | 4911 try: |
| 4884 _trigger_try_jobs(auth_config, cl, buckets, options, 'git_cl_try', | 4912 _trigger_try_jobs(auth_config, cl, buckets, options, 'git_cl_try', |
| 4885 patchset) | 4913 patchset) |
| 4886 except BuildbucketResponseException as ex: | 4914 except BuildbucketResponseException as ex: |
| 4887 print('ERROR: %s' % ex) | 4915 print('ERROR: %s' % ex) |
| 4888 return 1 | 4916 return 1 |
| 4889 return 0 | 4917 return 0 |
| 4890 | 4918 |
| 4891 | 4919 |
| 4892 def CMDtry_results(parser, args): | 4920 def CMDtry_results(parser, args): |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4994 if args: | 5022 if args: |
| 4995 parser.error('Unrecognized args: %s' % ' '.join(args)) | 5023 parser.error('Unrecognized args: %s' % ' '.join(args)) |
| 4996 if options.dry_run and options.clear: | 5024 if options.dry_run and options.clear: |
| 4997 parser.error('Make up your mind: both --dry-run and --clear not allowed') | 5025 parser.error('Make up your mind: both --dry-run and --clear not allowed') |
| 4998 | 5026 |
| 4999 cl = Changelist(auth_config=auth_config, issue=options.issue, | 5027 cl = Changelist(auth_config=auth_config, issue=options.issue, |
| 5000 codereview=options.forced_codereview) | 5028 codereview=options.forced_codereview) |
| 5001 if options.clear: | 5029 if options.clear: |
| 5002 state = _CQState.NONE | 5030 state = _CQState.NONE |
| 5003 elif options.dry_run: | 5031 elif options.dry_run: |
| 5032 # TODO(qyearsley): Use cl.TriggerDryRun. | |
| 5004 state = _CQState.DRY_RUN | 5033 state = _CQState.DRY_RUN |
| 5005 else: | 5034 else: |
| 5006 state = _CQState.COMMIT | 5035 state = _CQState.COMMIT |
| 5007 if not cl.GetIssue(): | 5036 if not cl.GetIssue(): |
| 5008 parser.error('Must upload the issue first') | 5037 parser.error('Must upload the issue first') |
| 5009 cl.SetCQState(state) | 5038 cl.SetCQState(state) |
| 5010 return 0 | 5039 return 0 |
| 5011 | 5040 |
| 5012 | 5041 |
| 5013 def CMDset_close(parser, args): | 5042 def CMDset_close(parser, args): |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5381 if __name__ == '__main__': | 5410 if __name__ == '__main__': |
| 5382 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5411 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 5383 # unit testing. | 5412 # unit testing. |
| 5384 fix_encoding.fix_encoding() | 5413 fix_encoding.fix_encoding() |
| 5385 setup_color.init() | 5414 setup_color.init() |
| 5386 try: | 5415 try: |
| 5387 sys.exit(main(sys.argv[1:])) | 5416 sys.exit(main(sys.argv[1:])) |
| 5388 except KeyboardInterrupt: | 5417 except KeyboardInterrupt: |
| 5389 sys.stderr.write('interrupted\n') | 5418 sys.stderr.write('interrupted\n') |
| 5390 sys.exit(1) | 5419 sys.exit(1) |
| OLD | NEW |