Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(226)

Side by Side Diff: git_cl.py

Issue 2419113002: Add -B/--bucket flag to git-cl try (Closed)
Patch Set: Move a line Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 GIT_INSTRUCTIONS_URL = 'http://code.google.com/p/chromium/wiki/UsingGit' 69 GIT_INSTRUCTIONS_URL = 'http://code.google.com/p/chromium/wiki/UsingGit'
70 REFS_THAT_ALIAS_TO_OTHER_REFS = { 70 REFS_THAT_ALIAS_TO_OTHER_REFS = {
71 'refs/remotes/origin/lkgr': 'refs/remotes/origin/master', 71 'refs/remotes/origin/lkgr': 'refs/remotes/origin/master',
72 'refs/remotes/origin/lkcr': 'refs/remotes/origin/master', 72 'refs/remotes/origin/lkcr': 'refs/remotes/origin/master',
73 } 73 }
74 74
75 # Valid extensions for files we want to lint. 75 # Valid extensions for files we want to lint.
76 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" 76 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)"
77 DEFAULT_LINT_IGNORE_REGEX = r"$^" 77 DEFAULT_LINT_IGNORE_REGEX = r"$^"
78 78
79 # Buildbucket master name prefix.
80 MASTER_PREFIX = 'master.'
81
79 # Shortcut since it quickly becomes redundant. 82 # Shortcut since it quickly becomes redundant.
80 Fore = colorama.Fore 83 Fore = colorama.Fore
81 84
82 # Initialized in main() 85 # Initialized in main()
83 settings = None 86 settings = None
84 87
85 88
86 def DieWithError(message): 89 def DieWithError(message):
87 print(message, file=sys.stderr) 90 print(message, file=sys.stderr)
88 sys.exit(1) 91 sys.exit(1)
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 271
269 272
270 def _prefix_master(master): 273 def _prefix_master(master):
271 """Convert user-specified master name to full master name. 274 """Convert user-specified master name to full master name.
272 275
273 Buildbucket uses full master name(master.tryserver.chromium.linux) as bucket 276 Buildbucket uses full master name(master.tryserver.chromium.linux) as bucket
274 name, while the developers always use shortened master name 277 name, while the developers always use shortened master name
275 (tryserver.chromium.linux) by stripping off the prefix 'master.'. This 278 (tryserver.chromium.linux) by stripping off the prefix 'master.'. This
276 function does the conversion for buildbucket migration. 279 function does the conversion for buildbucket migration.
277 """ 280 """
278 prefix = 'master.' 281 if master.startswith(MASTER_PREFIX):
279 if master.startswith(prefix):
280 return master 282 return master
281 return '%s%s' % (prefix, master) 283 return '%s%s' % (MASTER_PREFIX, master)
284
285
286 def _unprefix_master(bucket):
287 """Convert bucket name to shortened master name.
288
289 Buildbucket uses full master name(master.tryserver.chromium.linux) as bucket
290 name, while the developers always use shortened master name
291 (tryserver.chromium.linux) by stripping off the prefix 'master.'. This
292 function does the conversion for buildbucket migration.
293 """
294 if bucket.startswith(MASTER_PREFIX):
295 return bucket[len(MASTER_PREFIX):]
296 return bucket
282 297
283 298
284 def _buildbucket_retry(operation_name, http, *args, **kwargs): 299 def _buildbucket_retry(operation_name, http, *args, **kwargs):
285 """Retries requests to buildbucket service and returns parsed json content.""" 300 """Retries requests to buildbucket service and returns parsed json content."""
286 try_count = 0 301 try_count = 0
287 while True: 302 while True:
288 response, content = http.request(*args, **kwargs) 303 response, content = http.request(*args, **kwargs)
289 try: 304 try:
290 content_json = json.loads(content) 305 content_json = json.loads(content)
291 except ValueError: 306 except ValueError:
(...skipping 19 matching lines...) Expand all
311 if response.status < 500 or try_count >= 2: 326 if response.status < 500 or try_count >= 2:
312 raise httplib2.HttpLib2Error(content) 327 raise httplib2.HttpLib2Error(content)
313 328
314 # status >= 500 means transient failures. 329 # status >= 500 means transient failures.
315 logging.debug('Transient errors when %s. Will retry.', operation_name) 330 logging.debug('Transient errors when %s. Will retry.', operation_name)
316 time.sleep(0.5 + 1.5*try_count) 331 time.sleep(0.5 + 1.5*try_count)
317 try_count += 1 332 try_count += 1
318 assert False, 'unreachable' 333 assert False, 'unreachable'
319 334
320 335
321 def _trigger_try_jobs(auth_config, changelist, masters, options, 336 def _trigger_try_jobs(auth_config, changelist, buckets, options,
322 category='git_cl_try', patchset=None): 337 category='git_cl_try', patchset=None):
323 assert changelist.GetIssue(), 'CL must be uploaded first' 338 assert changelist.GetIssue(), 'CL must be uploaded first'
324 codereview_url = changelist.GetCodereviewServer() 339 codereview_url = changelist.GetCodereviewServer()
325 assert codereview_url, 'CL must be uploaded first' 340 assert codereview_url, 'CL must be uploaded first'
326 patchset = patchset or changelist.GetMostRecentPatchset() 341 patchset = patchset or changelist.GetMostRecentPatchset()
327 assert patchset, 'CL must be uploaded first' 342 assert patchset, 'CL must be uploaded first'
328 343
329 codereview_host = urlparse.urlparse(codereview_url).hostname 344 codereview_host = urlparse.urlparse(codereview_url).hostname
330 authenticator = auth.get_authenticator_for_host(codereview_host, auth_config) 345 authenticator = auth.get_authenticator_for_host(codereview_host, auth_config)
331 http = authenticator.authorize(httplib2.Http()) 346 http = authenticator.authorize(httplib2.Http())
(...skipping 11 matching lines...) Expand all
343 buildset = 'patch/{codereview}/{hostname}/{issue}/{patch}'.format( 358 buildset = 'patch/{codereview}/{hostname}/{issue}/{patch}'.format(
344 codereview='gerrit' if changelist.IsGerrit() else 'rietveld', 359 codereview='gerrit' if changelist.IsGerrit() else 'rietveld',
345 hostname=codereview_host, 360 hostname=codereview_host,
346 issue=changelist.GetIssue(), 361 issue=changelist.GetIssue(),
347 patch=patchset) 362 patch=patchset)
348 extra_properties = _get_properties_from_options(options) 363 extra_properties = _get_properties_from_options(options)
349 364
350 batch_req_body = {'builds': []} 365 batch_req_body = {'builds': []}
351 print_text = [] 366 print_text = []
352 print_text.append('Tried jobs on:') 367 print_text.append('Tried jobs on:')
353 for master, builders_and_tests in sorted(masters.iteritems()): 368 for bucket, builders_and_tests in sorted(buckets.iteritems()):
354 print_text.append('Master: %s' % master) 369 print_text.append('Bucket: %s' % bucket)
355 bucket = _prefix_master(master) 370 master = _unprefix_master(bucket)
356 for builder, tests in sorted(builders_and_tests.iteritems()): 371 for builder, tests in sorted(builders_and_tests.iteritems()):
357 print_text.append(' %s: %s' % (builder, tests)) 372 print_text.append(' %s: %s' % (builder, tests))
358 parameters = { 373 parameters = {
359 'builder_name': builder, 374 'builder_name': builder,
360 'changes': [{ 375 'changes': [{
361 'author': {'email': owner_email}, 376 'author': {'email': owner_email},
362 'revision': options.revision, 377 'revision': options.revision,
363 }], 378 }],
364 'properties': { 379 'properties': {
365 'category': category, 380 'category': category,
(...skipping 4332 matching lines...) Expand 10 before | Expand all | Expand 10 after
4698 """ 4713 """
4699 group = optparse.OptionGroup(parser, 'Try job options') 4714 group = optparse.OptionGroup(parser, 'Try job options')
4700 group.add_option( 4715 group.add_option(
4701 '-b', '--bot', action='append', 4716 '-b', '--bot', action='append',
4702 help=('IMPORTANT: specify ONE builder per --bot flag. Use it multiple ' 4717 help=('IMPORTANT: specify ONE builder per --bot flag. Use it multiple '
4703 'times to specify multiple builders. ex: ' 4718 'times to specify multiple builders. ex: '
4704 '"-b win_rel -b win_layout". See ' 4719 '"-b win_rel -b win_layout". See '
4705 'the try server waterfall for the builders name and the tests ' 4720 'the try server waterfall for the builders name and the tests '
4706 'available.')) 4721 'available.'))
4707 group.add_option( 4722 group.add_option(
4723 '-B', '--bucket', default='',
4724 help=('Buildbucket bucket to send the try requests.'))
4725 group.add_option(
4708 '-m', '--master', default='', 4726 '-m', '--master', default='',
4709 help=('Specify a try master where to run the tries.')) 4727 help=('Specify a try master where to run the tries.'))
4710 # TODO(tandrii,nodir): add -B --bucket flag.
4711 group.add_option( 4728 group.add_option(
4712 '-r', '--revision', 4729 '-r', '--revision',
4713 help='Revision to use for the try job; default: the revision will ' 4730 help='Revision to use for the try job; default: the revision will '
4714 'be determined by the try recipe that builder runs, which usually ' 4731 'be determined by the try recipe that builder runs, which usually '
4715 'defaults to HEAD of origin/master') 4732 'defaults to HEAD of origin/master')
4716 group.add_option( 4733 group.add_option(
4717 '-c', '--clobber', action='store_true', default=False, 4734 '-c', '--clobber', action='store_true', default=False,
4718 help='Force a clobber before building; that is don\'t do an ' 4735 help='Force a clobber before building; that is don\'t do an '
4719 'incremental build') 4736 'incremental build')
4720 group.add_option( 4737 group.add_option(
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
4758 'If your project has Commit Queue, dry run is a workaround:\n' 4775 'If your project has Commit Queue, dry run is a workaround:\n'
4759 ' git cl set-commit --dry-run') 4776 ' git cl set-commit --dry-run')
4760 4777
4761 error_message = cl.CannotTriggerTryJobReason() 4778 error_message = cl.CannotTriggerTryJobReason()
4762 if error_message: 4779 if error_message:
4763 parser.error('Can\'t trigger try jobs: %s') 4780 parser.error('Can\'t trigger try jobs: %s')
4764 4781
4765 if not options.name: 4782 if not options.name:
4766 options.name = cl.GetBranch() 4783 options.name = cl.GetBranch()
4767 4784
4768 if options.bot and not options.master: 4785 if options.bucket and options.master:
4786 parser.error('Only one of --bucket and --master may be used.')
4787
4788 if options.bot and not options.master and not options.bucket:
4769 options.master, err_msg = GetBuilderMaster(options.bot) 4789 options.master, err_msg = GetBuilderMaster(options.bot)
4770 if err_msg: 4790 if err_msg:
4771 parser.error('Tryserver master cannot be found because: %s\n' 4791 parser.error('Tryserver master cannot be found because: %s\n'
4772 'Please manually specify the tryserver master' 4792 'Please manually specify the tryserver master'
4773 ', e.g. "-m tryserver.chromium.linux".' % err_msg) 4793 ', e.g. "-m tryserver.chromium.linux".' % err_msg)
4774 4794
4795 def GetBotsMap(bots):
4796 builders_and_tests = {}
4797
4798 # TODO(machenbach): The old style command-line options don't support
4799 # multiple try masters yet.
4800 old_style = filter(lambda x: isinstance(x, basestring), bots)
4801 new_style = filter(lambda x: isinstance(x, tuple), bots)
4802
4803 for bot in old_style:
nodir 2016/10/14 18:41:18 let's not support old style stuff in new code path
borenet 2016/10/14 18:46:42 Unfortunately the old code path goes through here
nodir 2016/10/14 18:54:16 I think it is better copy-paste code that is neede
borenet 2016/10/17 14:25:00 Done. It seems that when using "-b <bot>" we get t
4804 if ':' in bot:
4805 parser.error('Specifying testfilter is no longer supported')
4806 elif ',' in bot:
4807 parser.error('Specify one bot per --bot flag')
4808 else:
4809 builders_and_tests.setdefault(bot, [])
4810
4811 for bot, tests in new_style:
4812 builders_and_tests.setdefault(bot, []).extend(tests)
4813 return builders_and_tests
4814
4775 def GetMasterMap(): 4815 def GetMasterMap():
4776 # Process --bot. 4816 # Process --bot.
4777 if not options.bot: 4817 if not options.bot:
4778 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) 4818 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None)
4779 4819
4780 # Get try masters from PRESUBMIT.py files. 4820 # Get try masters from PRESUBMIT.py files.
4781 masters = presubmit_support.DoGetTryMasters( 4821 masters = presubmit_support.DoGetTryMasters(
4782 change, 4822 change,
4783 change.LocalPaths(), 4823 change.LocalPaths(),
4784 settings.GetRoot(), 4824 settings.GetRoot(),
(...skipping 10 matching lines...) Expand all
4795 change.LocalPaths(), 4835 change.LocalPaths(),
4796 settings.GetRoot(), 4836 settings.GetRoot(),
4797 None, 4837 None,
4798 None, 4838 None,
4799 options.verbose, 4839 options.verbose,
4800 sys.stdout) 4840 sys.stdout)
4801 4841
4802 if not options.bot: 4842 if not options.bot:
4803 return {} 4843 return {}
4804 4844
4805 builders_and_tests = {} 4845 builders_and_tests = GetBotsMap(options.bot)
4806 # TODO(machenbach): The old style command-line options don't support
4807 # multiple try masters yet.
4808 old_style = filter(lambda x: isinstance(x, basestring), options.bot)
4809 new_style = filter(lambda x: isinstance(x, tuple), options.bot)
4810
4811 for bot in old_style:
4812 if ':' in bot:
4813 parser.error('Specifying testfilter is no longer supported')
4814 elif ',' in bot:
4815 parser.error('Specify one bot per --bot flag')
4816 else:
4817 builders_and_tests.setdefault(bot, [])
4818
4819 for bot, tests in new_style:
4820 builders_and_tests.setdefault(bot, []).extend(tests)
4821 4846
4822 # Return a master map with one master to be backwards compatible. The 4847 # Return a master map with one master to be backwards compatible. The
4823 # master name defaults to an empty string, which will cause the master 4848 # master name defaults to an empty string, which will cause the master
4824 # not to be set on rietveld (deprecated). 4849 # not to be set on rietveld (deprecated).
4825 return {options.master: builders_and_tests} 4850 bucket = ""
nodir 2016/10/14 18:41:17 use ''
borenet 2016/10/14 18:46:42 Done.
4851 if options.master:
4852 # Add the "master." prefix to the master name to obtain the bucket name.
4853 bucket = _prefix_master(options.master)
4854 return {bucket: builders_and_tests}
4826 4855
4827 masters = GetMasterMap() 4856 if options.bucket:
4828 if not masters: 4857 buckets = {options.bucket: GetBotsMap(options.bot or [])}
4829 # Default to triggering Dry Run (see http://crbug.com/625697). 4858 else:
4830 if options.verbose: 4859 buckets = GetMasterMap()
4831 print('git cl try with no bots now defaults to CQ Dry Run.') 4860 if not buckets:
4832 try: 4861 # Default to triggering Dry Run (see http://crbug.com/625697).
4833 cl.SetCQState(_CQState.DRY_RUN) 4862 if options.verbose:
4834 print('scheduled CQ Dry Run on %s' % cl.GetIssueURL()) 4863 print('git cl try with no bots now defaults to CQ Dry Run.')
4835 return 0 4864 try:
4836 except KeyboardInterrupt: 4865 cl.SetCQState(_CQState.DRY_RUN)
4837 raise 4866 print('scheduled CQ Dry Run on %s' % cl.GetIssueURL())
4838 except: 4867 return 0
4839 print('WARNING: failed to trigger CQ Dry Run.\n' 4868 except KeyboardInterrupt:
4840 'Either:\n' 4869 raise
4841 ' * your project has no CQ\n' 4870 except:
4842 ' * you don\'t have permission to trigger Dry Run\n' 4871 print('WARNING: failed to trigger CQ Dry Run.\n'
4843 ' * bug in this code (see stack trace below).\n' 4872 'Either:\n'
4844 'Consider specifying which bots to trigger manually ' 4873 ' * your project has no CQ\n'
4845 'or asking your project owners for permissions ' 4874 ' * you don\'t have permission to trigger Dry Run\n'
4846 'or contacting Chrome Infrastructure team at ' 4875 ' * bug in this code (see stack trace below).\n'
4847 'https://www.chromium.org/infra\n\n') 4876 'Consider specifying which bots to trigger manually '
4848 # Still raise exception so that stack trace is printed. 4877 'or asking your project owners for permissions '
4849 raise 4878 'or contacting Chrome Infrastructure team at '
4879 'https://www.chromium.org/infra\n\n')
4880 # Still raise exception so that stack trace is printed.
4881 raise
4850 4882
4851 for builders in masters.itervalues(): 4883 for builders in buckets.itervalues():
4852 if any('triggered' in b for b in builders): 4884 if any('triggered' in b for b in builders):
4853 print('ERROR You are trying to send a job to a triggered bot. This type ' 4885 print('ERROR You are trying to send a job to a triggered bot. This type '
4854 'of bot requires an initial job from a parent (usually a builder). ' 4886 'of bot requires an initial job from a parent (usually a builder). '
4855 'Instead send your job to the parent.\n' 4887 'Instead send your job to the parent.\n'
4856 'Bot list: %s' % builders, file=sys.stderr) 4888 'Bot list: %s' % builders, file=sys.stderr)
4857 return 1 4889 return 1
4858 4890
4859 patchset = cl.GetMostRecentPatchset() 4891 patchset = cl.GetMostRecentPatchset()
4860 if patchset != cl.GetPatchset(): 4892 if patchset != cl.GetPatchset():
4861 print('Warning: Codereview server has newer patchsets (%s) than most ' 4893 print('Warning: Codereview server has newer patchsets (%s) than most '
4862 'recent upload from local checkout (%s). Did a previous upload ' 4894 'recent upload from local checkout (%s). Did a previous upload '
4863 'fail?\n' 4895 'fail?\n'
4864 'By default, git cl try uses the latest patchset from ' 4896 'By default, git cl try uses the latest patchset from '
4865 'codereview, continuing to use patchset %s.\n' % 4897 'codereview, continuing to use patchset %s.\n' %
4866 (patchset, cl.GetPatchset(), patchset)) 4898 (patchset, cl.GetPatchset(), patchset))
4867 try: 4899 try:
4868 _trigger_try_jobs(auth_config, cl, masters, options, 'git_cl_try', 4900 _trigger_try_jobs(auth_config, cl, buckets, options, 'git_cl_try',
4869 patchset) 4901 patchset)
4870 except BuildbucketResponseException as ex: 4902 except BuildbucketResponseException as ex:
4871 print('ERROR: %s' % ex) 4903 print('ERROR: %s' % ex)
4872 return 1 4904 return 1
4873 return 0 4905 return 0
4874 4906
4875 4907
4876 def CMDtry_results(parser, args): 4908 def CMDtry_results(parser, args):
4877 """Prints info about try jobs associated with current CL.""" 4909 """Prints info about try jobs associated with current CL."""
4878 group = optparse.OptionGroup(parser, 'Try job results options') 4910 group = optparse.OptionGroup(parser, 'Try job results options')
4879 group.add_option( 4911 group.add_option(
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after
5365 if __name__ == '__main__': 5397 if __name__ == '__main__':
5366 # These affect sys.stdout so do it outside of main() to simplify mocks in 5398 # These affect sys.stdout so do it outside of main() to simplify mocks in
5367 # unit testing. 5399 # unit testing.
5368 fix_encoding.fix_encoding() 5400 fix_encoding.fix_encoding()
5369 setup_color.init() 5401 setup_color.init()
5370 try: 5402 try:
5371 sys.exit(main(sys.argv[1:])) 5403 sys.exit(main(sys.argv[1:]))
5372 except KeyboardInterrupt: 5404 except KeyboardInterrupt:
5373 sys.stderr.write('interrupted\n') 5405 sys.stderr.write('interrupted\n')
5374 sys.exit(1) 5406 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698