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

Side by Side Diff: git_cl.py

Issue 963953003: OAuth2 support in depot_tools (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: fix sorting Created 5 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | git_cl_oauth2.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.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 from distutils.version import LooseVersion 10 from distutils.version import LooseVersion
11 from multiprocessing.pool import ThreadPool 11 from multiprocessing.pool import ThreadPool
12 import base64 12 import base64
13 import glob 13 import glob
14 import httplib
14 import json 15 import json
15 import logging 16 import logging
16 import optparse 17 import optparse
17 import os 18 import os
18 import Queue 19 import Queue
19 import re 20 import re
20 import stat 21 import stat
21 import sys 22 import sys
22 import tempfile 23 import tempfile
23 import textwrap 24 import textwrap
25 import threading
26 import time
24 import urllib2 27 import urllib2
25 import urlparse 28 import urlparse
26 import webbrowser 29 import webbrowser
27 import zlib 30 import zlib
28 31
29 try: 32 try:
30 import readline # pylint: disable=F0401,W0611 33 import readline # pylint: disable=F0401,W0611
31 except ImportError: 34 except ImportError:
32 pass 35 pass
33 36
34 37
35 from third_party import colorama 38 from third_party import colorama
39 from third_party import httplib2
36 from third_party import upload 40 from third_party import upload
41 from third_party.google_api_python_client import apiclient
37 import breakpad # pylint: disable=W0611 42 import breakpad # pylint: disable=W0611
38 import clang_format 43 import clang_format
39 import dart_format 44 import dart_format
40 import fix_encoding 45 import fix_encoding
41 import gclient_utils 46 import gclient_utils
47 import git_cl_oauth2
42 import git_common 48 import git_common
43 import owners 49 import owners
44 import owners_finder 50 import owners_finder
45 import presubmit_support 51 import presubmit_support
46 import rietveld 52 import rietveld
47 import scm 53 import scm
48 import subcommand 54 import subcommand
49 import subprocess2 55 import subprocess2
50 import watchlists 56 import watchlists
51 57
52 __version__ = '1.0' 58 __version__ = '1.0'
53 59
54 DEFAULT_SERVER = 'https://codereview.appspot.com' 60 DEFAULT_SERVER = 'https://codereview.appspot.com'
55 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' 61 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s'
56 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' 62 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup'
57 GIT_INSTRUCTIONS_URL = 'http://code.google.com/p/chromium/wiki/UsingGit' 63 GIT_INSTRUCTIONS_URL = 'http://code.google.com/p/chromium/wiki/UsingGit'
58 CHANGE_ID = 'Change-Id:' 64 CHANGE_ID = 'Change-Id:'
59 REFS_THAT_ALIAS_TO_OTHER_REFS = { 65 REFS_THAT_ALIAS_TO_OTHER_REFS = {
60 'refs/remotes/origin/lkgr': 'refs/remotes/origin/master', 66 'refs/remotes/origin/lkgr': 'refs/remotes/origin/master',
61 'refs/remotes/origin/lkcr': 'refs/remotes/origin/master', 67 'refs/remotes/origin/lkcr': 'refs/remotes/origin/master',
62 } 68 }
63 69
70 # Buildbucket-related constants
71 DISCOVERY_URL = (
72 'https://cr-buildbucket.appspot.com/_ah/api/discovery/v1/apis/'
73 '{api}/{apiVersion}/rest')
74 DEFAULT_SCOPES = 'email'
75 BUILDSET_STR = 'patch/rietveld/{hostname}/{issue}/{patch}'
76
64 # Valid extensions for files we want to lint. 77 # Valid extensions for files we want to lint.
65 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" 78 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)"
66 DEFAULT_LINT_IGNORE_REGEX = r"$^" 79 DEFAULT_LINT_IGNORE_REGEX = r"$^"
67 80
68 # Shortcut since it quickly becomes redundant. 81 # Shortcut since it quickly becomes redundant.
69 Fore = colorama.Fore 82 Fore = colorama.Fore
70 83
71 # Initialized in main() 84 # Initialized in main()
72 settings = None 85 settings = None
73 86
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 if dirty: 221 if dirty:
209 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd 222 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd
210 print 'Uncommitted files: (git diff-index --name-status HEAD)' 223 print 'Uncommitted files: (git diff-index --name-status HEAD)'
211 print dirty[:4096] 224 print dirty[:4096]
212 if len(dirty) > 4096: 225 if len(dirty) > 4096:
213 print '... (run "git diff-index --name-status HEAD" to see full output).' 226 print '... (run "git diff-index --name-status HEAD" to see full output).'
214 return True 227 return True
215 return False 228 return False
216 229
217 230
231 def _prefix_master(master):
232 prefix = 'master.'
233 if master.startswith(prefix):
234 return master
235 else:
236 return '%s%s' % (prefix, master)
237
238
239 def _get_buildbucket(credentials):
240 http = httplib2.Http()
241 http = credentials.authorize(http)
242 return apiclient.discovery.build(
243 'buildbucket', 'v1',
244 http=http,
245 discoveryServiceUrl=DISCOVERY_URL,
246 )
247
248
249 def trigger_distributed_try_jobs(
250 credentials, changelist, options, masters, category):
251 buildbucket = _get_buildbucket(credentials)
252 creds_props = json.loads(credentials.to_json())
253 requester = creds_props['id_token']['email']
254 issue_props = changelist.GetIssueProperties()
255 rietveld_host = urlparse.urlparse(changelist.GetRietveldServer()).hostname
256 issue = changelist.GetIssue()
257 patchset = changelist.GetMostRecentPatchset()
258 buildset = BUILDSET_STR.format(
259 hostname=rietveld_host,
260 issue=str(issue),
261 patch=str(patchset))
262 print 'Tried jobs on:'
263 for (master, builders_and_tests) in masters.iteritems():
264 print 'Master: %s' % master
265 bucket = _prefix_master(master)
266 for builder, tests in builders_and_tests.iteritems():
267 req = buildbucket.put(body={
268 'bucket': bucket,
269 'parameters_json': json.dumps({
270 'builder_name': builder,
271 'changes':[
272 {'author': {'email': issue_props['owner_email']}},
273 ],
274 'properties': {
275 'category': category,
276 'clobber': options.clobber,
277 'issue': issue,
278 'master': master,
279 'patch_project': issue_props['project'],
280 'patch_storage': 'rietveld',
281 'patchset': patchset,
282 'reason': options.name,
283 'requester': requester,
284 'revision': options.revision,
285 'rietveld': changelist.GetRietveldServer(),
286 'testfilter': tests,
287 },
288 }),
289 'tags': ['buildset:%s' % buildset,
290 'master:%s' % master,
291 'builder:%s' % builder,
292 'requester:%s' % requester]
293 })
294 wait = 1
295 try_count = 3
296 while try_count > 0:
297 try:
298 try_count -= 1
299 response = req.execute()
300 if response.get('error'):
301 msg = 'Error in response. Reason: %s. Message: %s.' % (
302 response['error'].get('reason', ''),
303 response['error'].get('message', ''))
304 raise BuildbucketResponseException(msg)
305 break
306 except apiclient.errors.HttpError as ex:
307 status = ex.resp.status if ex.resp else None
308 if status >= 500:
309 logging.debug('Transient errors when triggering tryjobs. '
310 'Will retry in %d seconds.', wait)
311 time.sleep(wait)
312 wait *= 2
313 if try_count <= 0:
314 raise
315 else:
316 raise
317 print ' %s: %s' % (builder, tests)
318
319
218 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): 320 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards):
219 """Return the corresponding git ref if |base_url| together with |glob_spec| 321 """Return the corresponding git ref if |base_url| together with |glob_spec|
220 matches the full |url|. 322 matches the full |url|.
221 323
222 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). 324 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below).
223 """ 325 """
224 fetch_suburl, as_ref = glob_spec.split(':') 326 fetch_suburl, as_ref = glob_spec.split(':')
225 if allow_wildcards: 327 if allow_wildcards:
226 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) 328 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl)
227 if glob_match: 329 if glob_match:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 try: 377 try:
276 stdout = sys.stdout.fileno() 378 stdout = sys.stdout.fileno()
277 except AttributeError: 379 except AttributeError:
278 stdout = None 380 stdout = None
279 return subprocess2.call( 381 return subprocess2.call(
280 ['git', 382 ['git',
281 'diff', '--no-ext-diff', '--stat'] + similarity_options + args, 383 'diff', '--no-ext-diff', '--stat'] + similarity_options + args,
282 stdout=stdout, env=env) 384 stdout=stdout, env=env)
283 385
284 386
387 class BuildbucketResponseException(Exception):
388 pass
389
390
285 class Settings(object): 391 class Settings(object):
286 def __init__(self): 392 def __init__(self):
287 self.default_server = None 393 self.default_server = None
288 self.cc = None 394 self.cc = None
289 self.root = None 395 self.root = None
290 self.is_git_svn = None 396 self.is_git_svn = None
291 self.svn_branch = None 397 self.svn_branch = None
292 self.tree_status_url = None 398 self.tree_status_url = None
293 self.viewvc_url = None 399 self.viewvc_url = None
294 self.updated = False 400 self.updated = False
(...skipping 2417 matching lines...) Expand 10 before | Expand all | Expand 10 after
2712 "-c", "--clobber", action="store_true", default=False, 2818 "-c", "--clobber", action="store_true", default=False,
2713 help="Force a clobber before building; e.g. don't do an " 2819 help="Force a clobber before building; e.g. don't do an "
2714 "incremental build") 2820 "incremental build")
2715 group.add_option( 2821 group.add_option(
2716 "--project", 2822 "--project",
2717 help="Override which project to use. Projects are defined " 2823 help="Override which project to use. Projects are defined "
2718 "server-side to define what default bot set to use") 2824 "server-side to define what default bot set to use")
2719 group.add_option( 2825 group.add_option(
2720 "-n", "--name", help="Try job name; default to current branch name") 2826 "-n", "--name", help="Try job name; default to current branch name")
2721 parser.add_option_group(group) 2827 parser.add_option_group(group)
2828 git_cl_oauth2.add_oauth2_options(parser)
2722 options, args = parser.parse_args(args) 2829 options, args = parser.parse_args(args)
2723 2830
2724 if args: 2831 if args:
2725 parser.error('Unknown arguments: %s' % args) 2832 parser.error('Unknown arguments: %s' % args)
2726 2833
2727 cl = Changelist() 2834 cl = Changelist()
2728 if not cl.GetIssue(): 2835 if not cl.GetIssue():
2729 parser.error('Need to upload first') 2836 parser.error('Need to upload first')
2730 2837
2731 props = cl.GetIssueProperties() 2838 props = cl.GetIssueProperties()
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
2807 'Bot list: %s' % builders) 2914 'Bot list: %s' % builders)
2808 return 1 2915 return 1
2809 2916
2810 patchset = cl.GetMostRecentPatchset() 2917 patchset = cl.GetMostRecentPatchset()
2811 if patchset and patchset != cl.GetPatchset(): 2918 if patchset and patchset != cl.GetPatchset():
2812 print( 2919 print(
2813 '\nWARNING Mismatch between local config and server. Did a previous ' 2920 '\nWARNING Mismatch between local config and server. Did a previous '
2814 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' 2921 'upload fail?\ngit-cl try always uses latest patchset from rietveld. '
2815 'Continuing using\npatchset %s.\n' % patchset) 2922 'Continuing using\npatchset %s.\n' % patchset)
2816 try: 2923 try:
2817 cl.RpcServer().trigger_distributed_try_jobs( 2924 creds = git_cl_oauth2.get_oauth2_creds(
2818 cl.GetIssue(), patchset, options.name, options.clobber, 2925 options,
2819 options.revision, masters) 2926 urlparse.urlparse(cl.GetRietveldServer()).hostname)
2820 except urllib2.HTTPError, e: 2927 if not creds:
2821 if e.code == 404: 2928 print 'Failed to fetch credentials. Aborting...'
2822 print('404 from rietveld; '
2823 'did you mean to use "git try" instead of "git cl try"?')
2824 return 1 2929 return 1
2825 print('Tried jobs on:') 2930 trigger_distributed_try_jobs(creds, cl, options, masters, 'git cl try')
2826 2931 except apiclient.errors.HttpError as ex:
2827 for (master, builders) in masters.iteritems(): 2932 status = ex.resp.status if ex.resp else None
2828 if master: 2933 if status == httplib.FORBIDDEN:
2829 print 'Master: %s' % master 2934 print 'ERROR: Access denied. Please verify you have tryjob access.'
2830 length = max(len(builder) for builder in builders) 2935 else:
2831 for builder in sorted(builders): 2936 print 'ERROR: Tryjob request failed: %s.' % ex
2832 print ' %*s: %s' % (length, builder, ','.join(builders[builder])) 2937 return 1
2938 except BuildbucketResponseException as ex:
2939 print ex
2940 return 1
2941 except Exception as e:
2942 print 'Unexcpected error when trying to trigger tryjobs: %s.' % e
nodir 2015/03/18 23:49:15 typo: unexpected
sheyang 2015/03/24 00:36:30 Done.
2943 return 1
2833 return 0 2944 return 0
2834 2945
2835 2946
2836 @subcommand.usage('[new upstream branch]') 2947 @subcommand.usage('[new upstream branch]')
2837 def CMDupstream(parser, args): 2948 def CMDupstream(parser, args):
2838 """Prints or sets the name of the upstream branch, if any.""" 2949 """Prints or sets the name of the upstream branch, if any."""
2839 _, args = parser.parse_args(args) 2950 _, args = parser.parse_args(args)
2840 if len(args) > 1: 2951 if len(args) > 1:
2841 parser.error('Unrecognized args: %s' % ' '.join(args)) 2952 parser.error('Unrecognized args: %s' % ' '.join(args))
2842 2953
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
3134 if __name__ == '__main__': 3245 if __name__ == '__main__':
3135 # These affect sys.stdout so do it outside of main() to simplify mocks in 3246 # These affect sys.stdout so do it outside of main() to simplify mocks in
3136 # unit testing. 3247 # unit testing.
3137 fix_encoding.fix_encoding() 3248 fix_encoding.fix_encoding()
3138 colorama.init() 3249 colorama.init()
3139 try: 3250 try:
3140 sys.exit(main(sys.argv[1:])) 3251 sys.exit(main(sys.argv[1:]))
3141 except KeyboardInterrupt: 3252 except KeyboardInterrupt:
3142 sys.stderr.write('interrupted\n') 3253 sys.stderr.write('interrupted\n')
3143 sys.exit(1) 3254 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | git_cl_oauth2.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698