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 |
| 11 |
10 from distutils.version import LooseVersion | 12 from distutils.version import LooseVersion |
11 from multiprocessing.pool import ThreadPool | 13 from multiprocessing.pool import ThreadPool |
12 import base64 | 14 import base64 |
13 import collections | 15 import collections |
14 import glob | 16 import glob |
15 import httplib | 17 import httplib |
16 import json | 18 import json |
17 import logging | 19 import logging |
18 import multiprocessing | 20 import multiprocessing |
19 import optparse | 21 import optparse |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 DEFAULT_LINT_IGNORE_REGEX = r"$^" | 78 DEFAULT_LINT_IGNORE_REGEX = r"$^" |
77 | 79 |
78 # Shortcut since it quickly becomes redundant. | 80 # Shortcut since it quickly becomes redundant. |
79 Fore = colorama.Fore | 81 Fore = colorama.Fore |
80 | 82 |
81 # Initialized in main() | 83 # Initialized in main() |
82 settings = None | 84 settings = None |
83 | 85 |
84 | 86 |
85 def DieWithError(message): | 87 def DieWithError(message): |
86 print >> sys.stderr, message | 88 print(message, file=sys.stderr) |
87 sys.exit(1) | 89 sys.exit(1) |
88 | 90 |
89 | 91 |
90 def GetNoGitPagerEnv(): | 92 def GetNoGitPagerEnv(): |
91 env = os.environ.copy() | 93 env = os.environ.copy() |
92 # 'cat' is a magical git string that disables pagers on all platforms. | 94 # 'cat' is a magical git string that disables pagers on all platforms. |
93 env['GIT_PAGER'] = 'cat' | 95 env['GIT_PAGER'] = 'cat' |
94 return env | 96 return env |
95 | 97 |
96 | 98 |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 _buildbucket_retry( | 361 _buildbucket_retry( |
360 'triggering tryjobs', | 362 'triggering tryjobs', |
361 http, | 363 http, |
362 buildbucket_put_url, | 364 buildbucket_put_url, |
363 'PUT', | 365 'PUT', |
364 body=json.dumps(batch_req_body), | 366 body=json.dumps(batch_req_body), |
365 headers={'Content-Type': 'application/json'} | 367 headers={'Content-Type': 'application/json'} |
366 ) | 368 ) |
367 print_text.append('To see results here, run: git cl try-results') | 369 print_text.append('To see results here, run: git cl try-results') |
368 print_text.append('To see results in browser, run: git cl web') | 370 print_text.append('To see results in browser, run: git cl web') |
369 print '\n'.join(print_text) | 371 print('\n'.join(print_text)) |
370 | 372 |
371 | 373 |
372 def fetch_try_jobs(auth_config, changelist, options): | 374 def fetch_try_jobs(auth_config, changelist, options): |
373 """Fetches tryjobs from buildbucket. | 375 """Fetches tryjobs from buildbucket. |
374 | 376 |
375 Returns a map from build id to build info as json dictionary. | 377 Returns a map from build id to build info as json dictionary. |
376 """ | 378 """ |
377 rietveld_url = settings.GetDefaultServerUrl() | 379 rietveld_url = settings.GetDefaultServerUrl() |
378 rietveld_host = urlparse.urlparse(rietveld_url).hostname | 380 rietveld_host = urlparse.urlparse(rietveld_url).hostname |
379 authenticator = auth.get_authenticator_for_host(rietveld_host, auth_config) | 381 authenticator = auth.get_authenticator_for_host(rietveld_host, auth_config) |
380 if authenticator.has_cached_credentials(): | 382 if authenticator.has_cached_credentials(): |
381 http = authenticator.authorize(httplib2.Http()) | 383 http = authenticator.authorize(httplib2.Http()) |
382 else: | 384 else: |
383 print ('Warning: Some results might be missing because %s' % | 385 print('Warning: Some results might be missing because %s' % |
384 # Get the message on how to login. | 386 # Get the message on how to login. |
385 auth.LoginRequiredError(rietveld_host).message) | 387 (auth.LoginRequiredError(rietveld_host).message,)) |
386 http = httplib2.Http() | 388 http = httplib2.Http() |
387 | 389 |
388 http.force_exception_to_status_code = True | 390 http.force_exception_to_status_code = True |
389 | 391 |
390 buildset = 'patch/rietveld/{hostname}/{issue}/{patch}'.format( | 392 buildset = 'patch/rietveld/{hostname}/{issue}/{patch}'.format( |
391 hostname=rietveld_host, | 393 hostname=rietveld_host, |
392 issue=changelist.GetIssue(), | 394 issue=changelist.GetIssue(), |
393 patch=options.patchset) | 395 patch=options.patchset) |
394 params = {'tag': 'buildset:%s' % buildset} | 396 params = {'tag': 'buildset:%s' % buildset} |
395 | 397 |
396 builds = {} | 398 builds = {} |
397 while True: | 399 while True: |
398 url = 'https://{hostname}/_ah/api/buildbucket/v1/search?{params}'.format( | 400 url = 'https://{hostname}/_ah/api/buildbucket/v1/search?{params}'.format( |
399 hostname=options.buildbucket_host, | 401 hostname=options.buildbucket_host, |
400 params=urllib.urlencode(params)) | 402 params=urllib.urlencode(params)) |
401 content = _buildbucket_retry('fetching tryjobs', http, url, 'GET') | 403 content = _buildbucket_retry('fetching tryjobs', http, url, 'GET') |
402 for build in content.get('builds', []): | 404 for build in content.get('builds', []): |
403 builds[build['id']] = build | 405 builds[build['id']] = build |
404 if 'next_cursor' in content: | 406 if 'next_cursor' in content: |
405 params['start_cursor'] = content['next_cursor'] | 407 params['start_cursor'] = content['next_cursor'] |
406 else: | 408 else: |
407 break | 409 break |
408 return builds | 410 return builds |
409 | 411 |
410 | 412 |
411 def print_tryjobs(options, builds): | 413 def print_tryjobs(options, builds): |
412 """Prints nicely result of fetch_try_jobs.""" | 414 """Prints nicely result of fetch_try_jobs.""" |
413 if not builds: | 415 if not builds: |
414 print 'No tryjobs scheduled' | 416 print('No tryjobs scheduled') |
415 return | 417 return |
416 | 418 |
417 # Make a copy, because we'll be modifying builds dictionary. | 419 # Make a copy, because we'll be modifying builds dictionary. |
418 builds = builds.copy() | 420 builds = builds.copy() |
419 builder_names_cache = {} | 421 builder_names_cache = {} |
420 | 422 |
421 def get_builder(b): | 423 def get_builder(b): |
422 try: | 424 try: |
423 return builder_names_cache[b['id']] | 425 return builder_names_cache[b['id']] |
424 except KeyError: | 426 except KeyError: |
425 try: | 427 try: |
426 parameters = json.loads(b['parameters_json']) | 428 parameters = json.loads(b['parameters_json']) |
427 name = parameters['builder_name'] | 429 name = parameters['builder_name'] |
428 except (ValueError, KeyError) as error: | 430 except (ValueError, KeyError) as error: |
429 print 'WARNING: failed to get builder name for build %s: %s' % ( | 431 print('WARNING: failed to get builder name for build %s: %s' % ( |
430 b['id'], error) | 432 b['id'], error)) |
431 name = None | 433 name = None |
432 builder_names_cache[b['id']] = name | 434 builder_names_cache[b['id']] = name |
433 return name | 435 return name |
434 | 436 |
435 def get_bucket(b): | 437 def get_bucket(b): |
436 bucket = b['bucket'] | 438 bucket = b['bucket'] |
437 if bucket.startswith('master.'): | 439 if bucket.startswith('master.'): |
438 return bucket[len('master.'):] | 440 return bucket[len('master.'):] |
439 return bucket | 441 return bucket |
440 | 442 |
(...skipping 19 matching lines...) Expand all Loading... |
460 colorize = str | 462 colorize = str |
461 else: | 463 else: |
462 colorize = lambda x: '%s%s%s' % (color, x, Fore.RESET) | 464 colorize = lambda x: '%s%s%s' % (color, x, Fore.RESET) |
463 | 465 |
464 result = [] | 466 result = [] |
465 for b in builds.values(): | 467 for b in builds.values(): |
466 if all(b.get(k) == v for k, v in kwargs.iteritems()): | 468 if all(b.get(k) == v for k, v in kwargs.iteritems()): |
467 builds.pop(b['id']) | 469 builds.pop(b['id']) |
468 result.append(b) | 470 result.append(b) |
469 if result: | 471 if result: |
470 print colorize(title) | 472 print(colorize(title)) |
471 for b in sorted(result, key=sort_key): | 473 for b in sorted(result, key=sort_key): |
472 print ' ', colorize('\t'.join(map(str, f(b)))) | 474 print(' ', colorize('\t'.join(map(str, f(b))))) |
473 | 475 |
474 total = len(builds) | 476 total = len(builds) |
475 pop(status='COMPLETED', result='SUCCESS', | 477 pop(status='COMPLETED', result='SUCCESS', |
476 title='Successes:', color=Fore.GREEN, | 478 title='Successes:', color=Fore.GREEN, |
477 f=lambda b: (get_name(b), b.get('url'))) | 479 f=lambda b: (get_name(b), b.get('url'))) |
478 pop(status='COMPLETED', result='FAILURE', failure_reason='INFRA_FAILURE', | 480 pop(status='COMPLETED', result='FAILURE', failure_reason='INFRA_FAILURE', |
479 title='Infra Failures:', color=Fore.MAGENTA, | 481 title='Infra Failures:', color=Fore.MAGENTA, |
480 f=lambda b: (get_name(b), b.get('url'))) | 482 f=lambda b: (get_name(b), b.get('url'))) |
481 pop(status='COMPLETED', result='FAILURE', failure_reason='BUILD_FAILURE', | 483 pop(status='COMPLETED', result='FAILURE', failure_reason='BUILD_FAILURE', |
482 title='Failures:', color=Fore.RED, | 484 title='Failures:', color=Fore.RED, |
(...skipping 14 matching lines...) Expand all Loading... |
497 pop(status='STARTED', | 499 pop(status='STARTED', |
498 title='Started:', color=Fore.YELLOW, | 500 title='Started:', color=Fore.YELLOW, |
499 f=lambda b: (get_name(b), b.get('url'))) | 501 f=lambda b: (get_name(b), b.get('url'))) |
500 pop(status='SCHEDULED', | 502 pop(status='SCHEDULED', |
501 title='Scheduled:', | 503 title='Scheduled:', |
502 f=lambda b: (get_name(b), 'id=%s' % b['id'])) | 504 f=lambda b: (get_name(b), 'id=%s' % b['id'])) |
503 # The last section is just in case buildbucket API changes OR there is a bug. | 505 # The last section is just in case buildbucket API changes OR there is a bug. |
504 pop(title='Other:', | 506 pop(title='Other:', |
505 f=lambda b: (get_name(b), 'id=%s' % b['id'])) | 507 f=lambda b: (get_name(b), 'id=%s' % b['id'])) |
506 assert len(builds) == 0 | 508 assert len(builds) == 0 |
507 print 'Total: %d tryjobs' % total | 509 print('Total: %d tryjobs' % total) |
508 | 510 |
509 | 511 |
510 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 512 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
511 """Return the corresponding git ref if |base_url| together with |glob_spec| | 513 """Return the corresponding git ref if |base_url| together with |glob_spec| |
512 matches the full |url|. | 514 matches the full |url|. |
513 | 515 |
514 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). | 516 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). |
515 """ | 517 """ |
516 fetch_suburl, as_ref = glob_spec.split(':') | 518 fetch_suburl, as_ref = glob_spec.split(':') |
517 if allow_wildcards: | 519 if allow_wildcards: |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) | 1116 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) |
1115 else: | 1117 else: |
1116 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) | 1118 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) |
1117 return self._remote | 1119 return self._remote |
1118 | 1120 |
1119 def GitSanityChecks(self, upstream_git_obj): | 1121 def GitSanityChecks(self, upstream_git_obj): |
1120 """Checks git repo status and ensures diff is from local commits.""" | 1122 """Checks git repo status and ensures diff is from local commits.""" |
1121 | 1123 |
1122 if upstream_git_obj is None: | 1124 if upstream_git_obj is None: |
1123 if self.GetBranch() is None: | 1125 if self.GetBranch() is None: |
1124 print >> sys.stderr, ( | 1126 print('ERROR: unable to determine current branch (detached HEAD?)', |
1125 'ERROR: unable to determine current branch (detached HEAD?)') | 1127 file=sys.stderr) |
1126 else: | 1128 else: |
1127 print >> sys.stderr, ( | 1129 print('ERROR: no upstream branch', file=sys.stderr) |
1128 'ERROR: no upstream branch') | |
1129 return False | 1130 return False |
1130 | 1131 |
1131 # Verify the commit we're diffing against is in our current branch. | 1132 # Verify the commit we're diffing against is in our current branch. |
1132 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip() | 1133 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip() |
1133 common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip() | 1134 common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip() |
1134 if upstream_sha != common_ancestor: | 1135 if upstream_sha != common_ancestor: |
1135 print >> sys.stderr, ( | 1136 print('ERROR: %s is not in the current branch. You may need to rebase ' |
1136 'ERROR: %s is not in the current branch. You may need to rebase ' | 1137 'your tracking branch' % upstream_sha, file=sys.stderr) |
1137 'your tracking branch' % upstream_sha) | |
1138 return False | 1138 return False |
1139 | 1139 |
1140 # List the commits inside the diff, and verify they are all local. | 1140 # List the commits inside the diff, and verify they are all local. |
1141 commits_in_diff = RunGit( | 1141 commits_in_diff = RunGit( |
1142 ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines() | 1142 ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines() |
1143 code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch']) | 1143 code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch']) |
1144 remote_branch = remote_branch.strip() | 1144 remote_branch = remote_branch.strip() |
1145 if code != 0: | 1145 if code != 0: |
1146 _, remote_branch = self.GetRemoteBranch() | 1146 _, remote_branch = self.GetRemoteBranch() |
1147 | 1147 |
1148 commits_in_remote = RunGit( | 1148 commits_in_remote = RunGit( |
1149 ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines() | 1149 ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines() |
1150 | 1150 |
1151 common_commits = set(commits_in_diff) & set(commits_in_remote) | 1151 common_commits = set(commits_in_diff) & set(commits_in_remote) |
1152 if common_commits: | 1152 if common_commits: |
1153 print >> sys.stderr, ( | 1153 print('ERROR: Your diff contains %d commits already in %s.\n' |
1154 'ERROR: Your diff contains %d commits already in %s.\n' | 1154 'Run "git log --oneline %s..HEAD" to get a list of commits in ' |
1155 'Run "git log --oneline %s..HEAD" to get a list of commits in ' | 1155 'the diff. If you are using a custom git flow, you can override' |
1156 'the diff. If you are using a custom git flow, you can override' | 1156 ' the reference used for this check with "git config ' |
1157 ' the reference used for this check with "git config ' | 1157 'gitcl.remotebranch <git-ref>".' % ( |
1158 'gitcl.remotebranch <git-ref>".' % ( | 1158 len(common_commits), remote_branch, upstream_git_obj), |
1159 len(common_commits), remote_branch, upstream_git_obj)) | 1159 file=sys.stderr) |
1160 return False | 1160 return False |
1161 return True | 1161 return True |
1162 | 1162 |
1163 def GetGitBaseUrlFromConfig(self): | 1163 def GetGitBaseUrlFromConfig(self): |
1164 """Return the configured base URL from branch.<branchname>.baseurl. | 1164 """Return the configured base URL from branch.<branchname>.baseurl. |
1165 | 1165 |
1166 Returns None if it is not set. | 1166 Returns None if it is not set. |
1167 """ | 1167 """ |
1168 return RunGit(['config', 'branch.%s.base-url' % self.GetBranch()], | 1168 return RunGit(['config', 'branch.%s.base-url' % self.GetBranch()], |
1169 error_ok=True).strip() | 1169 error_ok=True).strip() |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 if not hook_results.should_continue(): | 1382 if not hook_results.should_continue(): |
1383 return 1 | 1383 return 1 |
1384 if not options.reviewers and hook_results.reviewers: | 1384 if not options.reviewers and hook_results.reviewers: |
1385 options.reviewers = hook_results.reviewers.split(',') | 1385 options.reviewers = hook_results.reviewers.split(',') |
1386 | 1386 |
1387 if self.GetIssue(): | 1387 if self.GetIssue(): |
1388 latest_patchset = self.GetMostRecentPatchset() | 1388 latest_patchset = self.GetMostRecentPatchset() |
1389 local_patchset = self.GetPatchset() | 1389 local_patchset = self.GetPatchset() |
1390 if (latest_patchset and local_patchset and | 1390 if (latest_patchset and local_patchset and |
1391 local_patchset != latest_patchset): | 1391 local_patchset != latest_patchset): |
1392 print ('The last upload made from this repository was patchset #%d but ' | 1392 print('The last upload made from this repository was patchset #%d but ' |
1393 'the most recent patchset on the server is #%d.' | 1393 'the most recent patchset on the server is #%d.' |
1394 % (local_patchset, latest_patchset)) | 1394 % (local_patchset, latest_patchset)) |
1395 print ('Uploading will still work, but if you\'ve uploaded to this ' | 1395 print('Uploading will still work, but if you\'ve uploaded to this ' |
1396 'issue from another machine or branch the patch you\'re ' | 1396 'issue from another machine or branch the patch you\'re ' |
1397 'uploading now might not include those changes.') | 1397 'uploading now might not include those changes.') |
1398 ask_for_data('About to upload; enter to confirm.') | 1398 ask_for_data('About to upload; enter to confirm.') |
1399 | 1399 |
1400 print_stats(options.similarity, options.find_copies, git_diff_args) | 1400 print_stats(options.similarity, options.find_copies, git_diff_args) |
1401 ret = self.CMDUploadChange(options, git_diff_args, change) | 1401 ret = self.CMDUploadChange(options, git_diff_args, change) |
1402 if not ret: | 1402 if not ret: |
1403 git_set_branch_value('last-upload-hash', | 1403 git_set_branch_value('last-upload-hash', |
1404 RunGit(['rev-parse', 'HEAD']).strip()) | 1404 RunGit(['rev-parse', 'HEAD']).strip()) |
1405 # Run post upload hooks, if specified. | 1405 # Run post upload hooks, if specified. |
1406 if settings.GetRunPostUploadHook(): | 1406 if settings.GetRunPostUploadHook(): |
1407 presubmit_support.DoPostUploadExecuter( | 1407 presubmit_support.DoPostUploadExecuter( |
1408 change, | 1408 change, |
1409 self, | 1409 self, |
1410 settings.GetRoot(), | 1410 settings.GetRoot(), |
1411 options.verbose, | 1411 options.verbose, |
1412 sys.stdout) | 1412 sys.stdout) |
1413 | 1413 |
1414 # Upload all dependencies if specified. | 1414 # Upload all dependencies if specified. |
1415 if options.dependencies: | 1415 if options.dependencies: |
1416 print | 1416 print() |
1417 print '--dependencies has been specified.' | 1417 print('--dependencies has been specified.') |
1418 print 'All dependent local branches will be re-uploaded.' | 1418 print('All dependent local branches will be re-uploaded.') |
1419 print | 1419 print() |
1420 # Remove the dependencies flag from args so that we do not end up in a | 1420 # Remove the dependencies flag from args so that we do not end up in a |
1421 # loop. | 1421 # loop. |
1422 orig_args.remove('--dependencies') | 1422 orig_args.remove('--dependencies') |
1423 ret = upload_branch_deps(self, orig_args) | 1423 ret = upload_branch_deps(self, orig_args) |
1424 return ret | 1424 return ret |
1425 | 1425 |
1426 def SetCQState(self, new_state): | 1426 def SetCQState(self, new_state): |
1427 """Update the CQ state for latest patchset. | 1427 """Update the CQ state for latest patchset. |
1428 | 1428 |
1429 Issue must have been already uploaded and known. | 1429 Issue must have been already uploaded and known. |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1618 'error. It is likely that you deleted this ' | 1618 'error. It is likely that you deleted this ' |
1619 'issue on the server. If this is the\n' | 1619 'issue on the server. If this is the\n' |
1620 'case, please run\n\n' | 1620 'case, please run\n\n' |
1621 ' git cl issue 0\n\n' | 1621 ' git cl issue 0\n\n' |
1622 'to clear the association with the deleted issue. Then run ' | 1622 'to clear the association with the deleted issue. Then run ' |
1623 'this command again.') % issue) | 1623 'this command again.') % issue) |
1624 else: | 1624 else: |
1625 DieWithError( | 1625 DieWithError( |
1626 '\nFailed to fetch issue description. HTTP error %d' % e.code) | 1626 '\nFailed to fetch issue description. HTTP error %d' % e.code) |
1627 except urllib2.URLError as e: | 1627 except urllib2.URLError as e: |
1628 print >> sys.stderr, ( | 1628 print('Warning: Failed to retrieve CL description due to network ' |
1629 'Warning: Failed to retrieve CL description due to network ' | 1629 'failure.', file=sys.stderr) |
1630 'failure.') | |
1631 return '' | 1630 return '' |
1632 | 1631 |
1633 def GetMostRecentPatchset(self): | 1632 def GetMostRecentPatchset(self): |
1634 return self.GetIssueProperties()['patchsets'][-1] | 1633 return self.GetIssueProperties()['patchsets'][-1] |
1635 | 1634 |
1636 def GetPatchSetDiff(self, issue, patchset): | 1635 def GetPatchSetDiff(self, issue, patchset): |
1637 return self.RpcServer().get( | 1636 return self.RpcServer().get( |
1638 '/download/issue%s_%s.diff' % (issue, patchset)) | 1637 '/download/issue%s_%s.diff' % (issue, patchset)) |
1639 | 1638 |
1640 def GetIssueProperties(self): | 1639 def GetIssueProperties(self): |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1812 if directory: | 1811 if directory: |
1813 cmd.extend(('--directory', directory)) | 1812 cmd.extend(('--directory', directory)) |
1814 if reject: | 1813 if reject: |
1815 cmd.append('--reject') | 1814 cmd.append('--reject') |
1816 elif IsGitVersionAtLeast('1.7.12'): | 1815 elif IsGitVersionAtLeast('1.7.12'): |
1817 cmd.append('--3way') | 1816 cmd.append('--3way') |
1818 try: | 1817 try: |
1819 subprocess2.check_call(cmd, env=GetNoGitPagerEnv(), | 1818 subprocess2.check_call(cmd, env=GetNoGitPagerEnv(), |
1820 stdin=patch_data, stdout=subprocess2.VOID) | 1819 stdin=patch_data, stdout=subprocess2.VOID) |
1821 except subprocess2.CalledProcessError: | 1820 except subprocess2.CalledProcessError: |
1822 print 'Failed to apply the patch' | 1821 print('Failed to apply the patch') |
1823 return 1 | 1822 return 1 |
1824 | 1823 |
1825 # If we had an issue, commit the current state and register the issue. | 1824 # If we had an issue, commit the current state and register the issue. |
1826 if not nocommit: | 1825 if not nocommit: |
1827 RunGit(['commit', '-m', (self.GetDescription() + '\n\n' + | 1826 RunGit(['commit', '-m', (self.GetDescription() + '\n\n' + |
1828 'patch from issue %(i)s at patchset ' | 1827 'patch from issue %(i)s at patchset ' |
1829 '%(p)s (http://crrev.com/%(i)s#ps%(p)s)' | 1828 '%(p)s (http://crrev.com/%(i)s#ps%(p)s)' |
1830 % {'i': self.GetIssue(), 'p': patchset})]) | 1829 % {'i': self.GetIssue(), 'p': patchset})]) |
1831 self.SetIssue(self.GetIssue()) | 1830 self.SetIssue(self.GetIssue()) |
1832 self.SetPatchset(patchset) | 1831 self.SetPatchset(patchset) |
1833 print "Committed patch locally." | 1832 print('Committed patch locally.') |
1834 else: | 1833 else: |
1835 print "Patch applied to index." | 1834 print('Patch applied to index.') |
1836 return 0 | 1835 return 0 |
1837 | 1836 |
1838 @staticmethod | 1837 @staticmethod |
1839 def ParseIssueURL(parsed_url): | 1838 def ParseIssueURL(parsed_url): |
1840 if not parsed_url.scheme or not parsed_url.scheme.startswith('http'): | 1839 if not parsed_url.scheme or not parsed_url.scheme.startswith('http'): |
1841 return None | 1840 return None |
1842 # Typical url: https://domain/<issue_number>[/[other]] | 1841 # Typical url: https://domain/<issue_number>[/[other]] |
1843 match = re.match('/(\d+)(/.*)?$', parsed_url.path) | 1842 match = re.match('/(\d+)(/.*)?$', parsed_url.path) |
1844 if match: | 1843 if match: |
1845 return _RietveldParsedIssueNumberArgument( | 1844 return _RietveldParsedIssueNumberArgument( |
(...skipping 21 matching lines...) Expand all Loading... |
1867 | 1866 |
1868 if options.email is not None: | 1867 if options.email is not None: |
1869 upload_args.extend(['--email', options.email]) | 1868 upload_args.extend(['--email', options.email]) |
1870 | 1869 |
1871 if self.GetIssue(): | 1870 if self.GetIssue(): |
1872 if options.title: | 1871 if options.title: |
1873 upload_args.extend(['--title', options.title]) | 1872 upload_args.extend(['--title', options.title]) |
1874 if options.message: | 1873 if options.message: |
1875 upload_args.extend(['--message', options.message]) | 1874 upload_args.extend(['--message', options.message]) |
1876 upload_args.extend(['--issue', str(self.GetIssue())]) | 1875 upload_args.extend(['--issue', str(self.GetIssue())]) |
1877 print ('This branch is associated with issue %s. ' | 1876 print('This branch is associated with issue %s. ' |
1878 'Adding patch to that issue.' % self.GetIssue()) | 1877 'Adding patch to that issue.' % self.GetIssue()) |
1879 else: | 1878 else: |
1880 if options.title: | 1879 if options.title: |
1881 upload_args.extend(['--title', options.title]) | 1880 upload_args.extend(['--title', options.title]) |
1882 message = (options.title or options.message or | 1881 message = (options.title or options.message or |
1883 CreateDescriptionFromLog(args)) | 1882 CreateDescriptionFromLog(args)) |
1884 change_desc = ChangeDescription(message) | 1883 change_desc = ChangeDescription(message) |
1885 if options.reviewers or options.tbr_owners: | 1884 if options.reviewers or options.tbr_owners: |
1886 change_desc.update_reviewers(options.reviewers, | 1885 change_desc.update_reviewers(options.reviewers, |
1887 options.tbr_owners, | 1886 options.tbr_owners, |
1888 change) | 1887 change) |
1889 if not options.force: | 1888 if not options.force: |
1890 change_desc.prompt() | 1889 change_desc.prompt() |
1891 | 1890 |
1892 if not change_desc.description: | 1891 if not change_desc.description: |
1893 print "Description is empty; aborting." | 1892 print('Description is empty; aborting.') |
1894 return 1 | 1893 return 1 |
1895 | 1894 |
1896 upload_args.extend(['--message', change_desc.description]) | 1895 upload_args.extend(['--message', change_desc.description]) |
1897 if change_desc.get_reviewers(): | 1896 if change_desc.get_reviewers(): |
1898 upload_args.append('--reviewers=%s' % ','.join( | 1897 upload_args.append('--reviewers=%s' % ','.join( |
1899 change_desc.get_reviewers())) | 1898 change_desc.get_reviewers())) |
1900 if options.send_mail: | 1899 if options.send_mail: |
1901 if not change_desc.get_reviewers(): | 1900 if not change_desc.get_reviewers(): |
1902 DieWithError("Must specify reviewers to send email.") | 1901 DieWithError("Must specify reviewers to send email.") |
1903 upload_args.append('--send_mail') | 1902 upload_args.append('--send_mail') |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1941 if target_ref: | 1940 if target_ref: |
1942 upload_args.extend(['--target_ref', target_ref]) | 1941 upload_args.extend(['--target_ref', target_ref]) |
1943 | 1942 |
1944 # Look for dependent patchsets. See crbug.com/480453 for more details. | 1943 # Look for dependent patchsets. See crbug.com/480453 for more details. |
1945 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) | 1944 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) |
1946 upstream_branch = ShortBranchName(upstream_branch) | 1945 upstream_branch = ShortBranchName(upstream_branch) |
1947 if remote is '.': | 1946 if remote is '.': |
1948 # A local branch is being tracked. | 1947 # A local branch is being tracked. |
1949 local_branch = upstream_branch | 1948 local_branch = upstream_branch |
1950 if settings.GetIsSkipDependencyUpload(local_branch): | 1949 if settings.GetIsSkipDependencyUpload(local_branch): |
1951 print | 1950 print() |
1952 print ('Skipping dependency patchset upload because git config ' | 1951 print('Skipping dependency patchset upload because git config ' |
1953 'branch.%s.skip-deps-uploads is set to True.' % local_branch) | 1952 'branch.%s.skip-deps-uploads is set to True.' % local_branch) |
1954 print | 1953 print() |
1955 else: | 1954 else: |
1956 auth_config = auth.extract_auth_config_from_options(options) | 1955 auth_config = auth.extract_auth_config_from_options(options) |
1957 branch_cl = Changelist(branchref='refs/heads/'+local_branch, | 1956 branch_cl = Changelist(branchref='refs/heads/'+local_branch, |
1958 auth_config=auth_config) | 1957 auth_config=auth_config) |
1959 branch_cl_issue_url = branch_cl.GetIssueURL() | 1958 branch_cl_issue_url = branch_cl.GetIssueURL() |
1960 branch_cl_issue = branch_cl.GetIssue() | 1959 branch_cl_issue = branch_cl.GetIssue() |
1961 branch_cl_patchset = branch_cl.GetPatchset() | 1960 branch_cl_patchset = branch_cl.GetPatchset() |
1962 if branch_cl_issue_url and branch_cl_issue and branch_cl_patchset: | 1961 if branch_cl_issue_url and branch_cl_issue and branch_cl_patchset: |
1963 upload_args.extend( | 1962 upload_args.extend( |
1964 ['--depends_on_patchset', '%s:%s' % ( | 1963 ['--depends_on_patchset', '%s:%s' % ( |
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2569 | 2568 |
2570 def _AddChangeIdToCommitMessage(self, options, args): | 2569 def _AddChangeIdToCommitMessage(self, options, args): |
2571 """Re-commits using the current message, assumes the commit hook is in | 2570 """Re-commits using the current message, assumes the commit hook is in |
2572 place. | 2571 place. |
2573 """ | 2572 """ |
2574 log_desc = options.message or CreateDescriptionFromLog(args) | 2573 log_desc = options.message or CreateDescriptionFromLog(args) |
2575 git_command = ['commit', '--amend', '-m', log_desc] | 2574 git_command = ['commit', '--amend', '-m', log_desc] |
2576 RunGit(git_command) | 2575 RunGit(git_command) |
2577 new_log_desc = CreateDescriptionFromLog(args) | 2576 new_log_desc = CreateDescriptionFromLog(args) |
2578 if git_footers.get_footer_change_id(new_log_desc): | 2577 if git_footers.get_footer_change_id(new_log_desc): |
2579 print 'git-cl: Added Change-Id to commit message.' | 2578 print('git-cl: Added Change-Id to commit message.') |
2580 return new_log_desc | 2579 return new_log_desc |
2581 else: | 2580 else: |
2582 DieWithError('ERROR: Gerrit commit-msg hook not installed.') | 2581 DieWithError('ERROR: Gerrit commit-msg hook not installed.') |
2583 | 2582 |
2584 def SetCQState(self, new_state): | 2583 def SetCQState(self, new_state): |
2585 """Sets the Commit-Queue label assuming canonical CQ config for Gerrit.""" | 2584 """Sets the Commit-Queue label assuming canonical CQ config for Gerrit.""" |
2586 # TODO(tandrii): maybe allow configurability in codereview.settings or by | 2585 # TODO(tandrii): maybe allow configurability in codereview.settings or by |
2587 # self-discovery of label config for this CL using REST API. | 2586 # self-discovery of label config for this CL using REST API. |
2588 vote_map = { | 2587 vote_map = { |
2589 _CQState.NONE: 0, | 2588 _CQState.NONE: 0, |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2973 LoadCodereviewSettingsFromFile(urllib2.urlopen(url)) | 2972 LoadCodereviewSettingsFromFile(urllib2.urlopen(url)) |
2974 return 0 | 2973 return 0 |
2975 | 2974 |
2976 | 2975 |
2977 def CMDbaseurl(parser, args): | 2976 def CMDbaseurl(parser, args): |
2978 """Gets or sets base-url for this branch.""" | 2977 """Gets or sets base-url for this branch.""" |
2979 branchref = RunGit(['symbolic-ref', 'HEAD']).strip() | 2978 branchref = RunGit(['symbolic-ref', 'HEAD']).strip() |
2980 branch = ShortBranchName(branchref) | 2979 branch = ShortBranchName(branchref) |
2981 _, args = parser.parse_args(args) | 2980 _, args = parser.parse_args(args) |
2982 if not args: | 2981 if not args: |
2983 print("Current base-url:") | 2982 print('Current base-url:') |
2984 return RunGit(['config', 'branch.%s.base-url' % branch], | 2983 return RunGit(['config', 'branch.%s.base-url' % branch], |
2985 error_ok=False).strip() | 2984 error_ok=False).strip() |
2986 else: | 2985 else: |
2987 print("Setting base-url to %s" % args[0]) | 2986 print('Setting base-url to %s' % args[0]) |
2988 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]], | 2987 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]], |
2989 error_ok=False).strip() | 2988 error_ok=False).strip() |
2990 | 2989 |
2991 | 2990 |
2992 def color_for_status(status): | 2991 def color_for_status(status): |
2993 """Maps a Changelist status to color, for CMDstatus and other tools.""" | 2992 """Maps a Changelist status to color, for CMDstatus and other tools.""" |
2994 return { | 2993 return { |
2995 'unsent': Fore.RED, | 2994 'unsent': Fore.RED, |
2996 'waiting': Fore.BLUE, | 2995 'waiting': Fore.BLUE, |
2997 'reply': Fore.YELLOW, | 2996 'reply': Fore.YELLOW, |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3092 | 3091 |
3093 # Create a dictionary of all local branches to the branches that are dependent | 3092 # Create a dictionary of all local branches to the branches that are dependent |
3094 # on it. | 3093 # on it. |
3095 tracked_to_dependents = collections.defaultdict(list) | 3094 tracked_to_dependents = collections.defaultdict(list) |
3096 for b in branches.splitlines(): | 3095 for b in branches.splitlines(): |
3097 tokens = b.split() | 3096 tokens = b.split() |
3098 if len(tokens) == 2: | 3097 if len(tokens) == 2: |
3099 branch_name, tracked = tokens | 3098 branch_name, tracked = tokens |
3100 tracked_to_dependents[tracked].append(branch_name) | 3099 tracked_to_dependents[tracked].append(branch_name) |
3101 | 3100 |
3102 print | 3101 print() |
3103 print 'The dependent local branches of %s are:' % root_branch | 3102 print('The dependent local branches of %s are:' % root_branch) |
3104 dependents = [] | 3103 dependents = [] |
3105 def traverse_dependents_preorder(branch, padding=''): | 3104 def traverse_dependents_preorder(branch, padding=''): |
3106 dependents_to_process = tracked_to_dependents.get(branch, []) | 3105 dependents_to_process = tracked_to_dependents.get(branch, []) |
3107 padding += ' ' | 3106 padding += ' ' |
3108 for dependent in dependents_to_process: | 3107 for dependent in dependents_to_process: |
3109 print '%s%s' % (padding, dependent) | 3108 print('%s%s' % (padding, dependent)) |
3110 dependents.append(dependent) | 3109 dependents.append(dependent) |
3111 traverse_dependents_preorder(dependent, padding) | 3110 traverse_dependents_preorder(dependent, padding) |
3112 traverse_dependents_preorder(root_branch) | 3111 traverse_dependents_preorder(root_branch) |
3113 print | 3112 print() |
3114 | 3113 |
3115 if not dependents: | 3114 if not dependents: |
3116 print 'There are no dependent local branches for %s' % root_branch | 3115 print('There are no dependent local branches for %s' % root_branch) |
3117 return 0 | 3116 return 0 |
3118 | 3117 |
3119 print ('This command will checkout all dependent branches and run ' | 3118 print('This command will checkout all dependent branches and run ' |
3120 '"git cl upload".') | 3119 '"git cl upload".') |
3121 ask_for_data('[Press enter to continue or ctrl-C to quit]') | 3120 ask_for_data('[Press enter to continue or ctrl-C to quit]') |
3122 | 3121 |
3123 # Add a default patchset title to all upload calls in Rietveld. | 3122 # Add a default patchset title to all upload calls in Rietveld. |
3124 if not cl.IsGerrit(): | 3123 if not cl.IsGerrit(): |
3125 args.extend(['-t', 'Updated patchset dependency']) | 3124 args.extend(['-t', 'Updated patchset dependency']) |
3126 | 3125 |
3127 # Record all dependents that failed to upload. | 3126 # Record all dependents that failed to upload. |
3128 failures = {} | 3127 failures = {} |
3129 # Go through all dependents, checkout the branch and upload. | 3128 # Go through all dependents, checkout the branch and upload. |
3130 try: | 3129 try: |
3131 for dependent_branch in dependents: | 3130 for dependent_branch in dependents: |
3132 print | 3131 print() |
3133 print '--------------------------------------' | 3132 print('--------------------------------------') |
3134 print 'Running "git cl upload" from %s:' % dependent_branch | 3133 print('Running "git cl upload" from %s:' % dependent_branch) |
3135 RunGit(['checkout', '-q', dependent_branch]) | 3134 RunGit(['checkout', '-q', dependent_branch]) |
3136 print | 3135 print() |
3137 try: | 3136 try: |
3138 if CMDupload(OptionParser(), args) != 0: | 3137 if CMDupload(OptionParser(), args) != 0: |
3139 print 'Upload failed for %s!' % dependent_branch | 3138 print('Upload failed for %s!' % dependent_branch) |
3140 failures[dependent_branch] = 1 | 3139 failures[dependent_branch] = 1 |
3141 except: # pylint: disable=W0702 | 3140 except: # pylint: disable=W0702 |
3142 failures[dependent_branch] = 1 | 3141 failures[dependent_branch] = 1 |
3143 print | 3142 print() |
3144 finally: | 3143 finally: |
3145 # Swap back to the original root branch. | 3144 # Swap back to the original root branch. |
3146 RunGit(['checkout', '-q', root_branch]) | 3145 RunGit(['checkout', '-q', root_branch]) |
3147 | 3146 |
3148 print | 3147 print() |
3149 print 'Upload complete for dependent branches!' | 3148 print('Upload complete for dependent branches!') |
3150 for dependent_branch in dependents: | 3149 for dependent_branch in dependents: |
3151 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded' | 3150 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded' |
3152 print ' %s : %s' % (dependent_branch, upload_status) | 3151 print(' %s : %s' % (dependent_branch, upload_status)) |
3153 print | 3152 print() |
3154 | 3153 |
3155 return 0 | 3154 return 0 |
3156 | 3155 |
3157 | 3156 |
3158 def CMDarchive(parser, args): | 3157 def CMDarchive(parser, args): |
3159 """Archives and deletes branches associated with closed changelists.""" | 3158 """Archives and deletes branches associated with closed changelists.""" |
3160 parser.add_option( | 3159 parser.add_option( |
3161 '-j', '--maxjobs', action='store', type=int, | 3160 '-j', '--maxjobs', action='store', type=int, |
3162 help='The maximum number of jobs to use when retrieving review status') | 3161 help='The maximum number of jobs to use when retrieving review status') |
3163 parser.add_option( | 3162 parser.add_option( |
3164 '-f', '--force', action='store_true', | 3163 '-f', '--force', action='store_true', |
3165 help='Bypasses the confirmation prompt.') | 3164 help='Bypasses the confirmation prompt.') |
3166 | 3165 |
3167 auth.add_auth_options(parser) | 3166 auth.add_auth_options(parser) |
3168 options, args = parser.parse_args(args) | 3167 options, args = parser.parse_args(args) |
3169 if args: | 3168 if args: |
3170 parser.error('Unsupported args: %s' % ' '.join(args)) | 3169 parser.error('Unsupported args: %s' % ' '.join(args)) |
3171 auth_config = auth.extract_auth_config_from_options(options) | 3170 auth_config = auth.extract_auth_config_from_options(options) |
3172 | 3171 |
3173 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) | 3172 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) |
3174 if not branches: | 3173 if not branches: |
3175 return 0 | 3174 return 0 |
3176 | 3175 |
3177 print 'Finding all branches associated with closed issues...' | 3176 print('Finding all branches associated with closed issues...') |
3178 changes = [Changelist(branchref=b, auth_config=auth_config) | 3177 changes = [Changelist(branchref=b, auth_config=auth_config) |
3179 for b in branches.splitlines()] | 3178 for b in branches.splitlines()] |
3180 alignment = max(5, max(len(c.GetBranch()) for c in changes)) | 3179 alignment = max(5, max(len(c.GetBranch()) for c in changes)) |
3181 statuses = get_cl_statuses(changes, | 3180 statuses = get_cl_statuses(changes, |
3182 fine_grained=True, | 3181 fine_grained=True, |
3183 max_processes=options.maxjobs) | 3182 max_processes=options.maxjobs) |
3184 proposal = [(cl.GetBranch(), | 3183 proposal = [(cl.GetBranch(), |
3185 'git-cl-archived-%s-%s' % (cl.GetIssue(), cl.GetBranch())) | 3184 'git-cl-archived-%s-%s' % (cl.GetIssue(), cl.GetBranch())) |
3186 for cl, status in statuses | 3185 for cl, status in statuses |
3187 if status == 'closed'] | 3186 if status == 'closed'] |
3188 proposal.sort() | 3187 proposal.sort() |
3189 | 3188 |
3190 if not proposal: | 3189 if not proposal: |
3191 print 'No branches with closed codereview issues found.' | 3190 print('No branches with closed codereview issues found.') |
3192 return 0 | 3191 return 0 |
3193 | 3192 |
3194 current_branch = GetCurrentBranch() | 3193 current_branch = GetCurrentBranch() |
3195 | 3194 |
3196 print '\nBranches with closed issues that will be archived:\n' | 3195 print('\nBranches with closed issues that will be archived:\n') |
3197 print '%*s | %s' % (alignment, 'Branch name', 'Archival tag name') | 3196 print('%*s | %s' % (alignment, 'Branch name', 'Archival tag name')) |
3198 for next_item in proposal: | 3197 for next_item in proposal: |
3199 print '%*s %s' % (alignment, next_item[0], next_item[1]) | 3198 print('%*s %s' % (alignment, next_item[0], next_item[1])) |
3200 | 3199 |
3201 if any(branch == current_branch for branch, _ in proposal): | 3200 if any(branch == current_branch for branch, _ in proposal): |
3202 print('You are currently on a branch \'%s\' which is associated with a ' | 3201 print('You are currently on a branch \'%s\' which is associated with a ' |
3203 'closed codereview issue, so archive cannot proceed. Please ' | 3202 'closed codereview issue, so archive cannot proceed. Please ' |
3204 'checkout another branch and run this command again.' % | 3203 'checkout another branch and run this command again.' % |
3205 current_branch) | 3204 current_branch) |
3206 return 1 | 3205 return 1 |
3207 | 3206 |
3208 if not options.force: | 3207 if not options.force: |
3209 if ask_for_data('\nProceed with deletion (Y/N)? ').lower() != 'y': | 3208 if ask_for_data('\nProceed with deletion (Y/N)? ').lower() != 'y': |
3210 print 'Aborted.' | 3209 print('Aborted.') |
3211 return 1 | 3210 return 1 |
3212 | 3211 |
3213 for branch, tagname in proposal: | 3212 for branch, tagname in proposal: |
3214 RunGit(['tag', tagname, branch]) | 3213 RunGit(['tag', tagname, branch]) |
3215 RunGit(['branch', '-D', branch]) | 3214 RunGit(['branch', '-D', branch]) |
3216 print '\nJob\'s done!' | 3215 print('\nJob\'s done!') |
3217 | 3216 |
3218 return 0 | 3217 return 0 |
3219 | 3218 |
3220 | 3219 |
3221 def CMDstatus(parser, args): | 3220 def CMDstatus(parser, args): |
3222 """Show status of changelists. | 3221 """Show status of changelists. |
3223 | 3222 |
3224 Colors are used to tell the state of the CL unless --fast is used: | 3223 Colors are used to tell the state of the CL unless --fast is used: |
3225 - Red not sent for review or broken | 3224 - Red not sent for review or broken |
3226 - Blue waiting for review | 3225 - Blue waiting for review |
(...skipping 14 matching lines...) Expand all Loading... |
3241 | 3240 |
3242 auth.add_auth_options(parser) | 3241 auth.add_auth_options(parser) |
3243 options, args = parser.parse_args(args) | 3242 options, args = parser.parse_args(args) |
3244 if args: | 3243 if args: |
3245 parser.error('Unsupported args: %s' % args) | 3244 parser.error('Unsupported args: %s' % args) |
3246 auth_config = auth.extract_auth_config_from_options(options) | 3245 auth_config = auth.extract_auth_config_from_options(options) |
3247 | 3246 |
3248 if options.field: | 3247 if options.field: |
3249 cl = Changelist(auth_config=auth_config) | 3248 cl = Changelist(auth_config=auth_config) |
3250 if options.field.startswith('desc'): | 3249 if options.field.startswith('desc'): |
3251 print cl.GetDescription() | 3250 print(cl.GetDescription()) |
3252 elif options.field == 'id': | 3251 elif options.field == 'id': |
3253 issueid = cl.GetIssue() | 3252 issueid = cl.GetIssue() |
3254 if issueid: | 3253 if issueid: |
3255 print issueid | 3254 print(issueid) |
3256 elif options.field == 'patch': | 3255 elif options.field == 'patch': |
3257 patchset = cl.GetPatchset() | 3256 patchset = cl.GetPatchset() |
3258 if patchset: | 3257 if patchset: |
3259 print patchset | 3258 print(patchset) |
3260 elif options.field == 'url': | 3259 elif options.field == 'url': |
3261 url = cl.GetIssueURL() | 3260 url = cl.GetIssueURL() |
3262 if url: | 3261 if url: |
3263 print url | 3262 print(url) |
3264 return 0 | 3263 return 0 |
3265 | 3264 |
3266 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) | 3265 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) |
3267 if not branches: | 3266 if not branches: |
3268 print('No local branch found.') | 3267 print('No local branch found.') |
3269 return 0 | 3268 return 0 |
3270 | 3269 |
3271 changes = [ | 3270 changes = [ |
3272 Changelist(branchref=b, auth_config=auth_config) | 3271 Changelist(branchref=b, auth_config=auth_config) |
3273 for b in branches.splitlines()] | 3272 for b in branches.splitlines()] |
3274 print 'Branches associated with reviews:' | 3273 print('Branches associated with reviews:') |
3275 output = get_cl_statuses(changes, | 3274 output = get_cl_statuses(changes, |
3276 fine_grained=not options.fast, | 3275 fine_grained=not options.fast, |
3277 max_processes=options.maxjobs) | 3276 max_processes=options.maxjobs) |
3278 | 3277 |
3279 branch_statuses = {} | 3278 branch_statuses = {} |
3280 alignment = max(5, max(len(ShortBranchName(c.GetBranch())) for c in changes)) | 3279 alignment = max(5, max(len(ShortBranchName(c.GetBranch())) for c in changes)) |
3281 for cl in sorted(changes, key=lambda c: c.GetBranch()): | 3280 for cl in sorted(changes, key=lambda c: c.GetBranch()): |
3282 branch = cl.GetBranch() | 3281 branch = cl.GetBranch() |
3283 while branch not in branch_statuses: | 3282 while branch not in branch_statuses: |
3284 c, status = output.next() | 3283 c, status = output.next() |
3285 branch_statuses[c.GetBranch()] = status | 3284 branch_statuses[c.GetBranch()] = status |
3286 status = branch_statuses.pop(branch) | 3285 status = branch_statuses.pop(branch) |
3287 url = cl.GetIssueURL() | 3286 url = cl.GetIssueURL() |
3288 if url and (not status or status == 'error'): | 3287 if url and (not status or status == 'error'): |
3289 # The issue probably doesn't exist anymore. | 3288 # The issue probably doesn't exist anymore. |
3290 url += ' (broken)' | 3289 url += ' (broken)' |
3291 | 3290 |
3292 color = color_for_status(status) | 3291 color = color_for_status(status) |
3293 reset = Fore.RESET | 3292 reset = Fore.RESET |
3294 if not setup_color.IS_TTY: | 3293 if not setup_color.IS_TTY: |
3295 color = '' | 3294 color = '' |
3296 reset = '' | 3295 reset = '' |
3297 status_str = '(%s)' % status if status else '' | 3296 status_str = '(%s)' % status if status else '' |
3298 print ' %*s : %s%s %s%s' % ( | 3297 print(' %*s : %s%s %s%s' % ( |
3299 alignment, ShortBranchName(branch), color, url, | 3298 alignment, ShortBranchName(branch), color, url, |
3300 status_str, reset) | 3299 status_str, reset)) |
3301 | 3300 |
3302 cl = Changelist(auth_config=auth_config) | 3301 cl = Changelist(auth_config=auth_config) |
3303 print | 3302 print() |
3304 print 'Current branch:', | 3303 print('Current branch:',) |
3305 print cl.GetBranch() | 3304 print(cl.GetBranch()) |
3306 if not cl.GetIssue(): | 3305 if not cl.GetIssue(): |
3307 print 'No issue assigned.' | 3306 print('No issue assigned.') |
3308 return 0 | 3307 return 0 |
3309 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) | 3308 print('Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL())) |
3310 if not options.fast: | 3309 if not options.fast: |
3311 print 'Issue description:' | 3310 print('Issue description:') |
3312 print cl.GetDescription(pretty=True) | 3311 print(cl.GetDescription(pretty=True)) |
3313 return 0 | 3312 return 0 |
3314 | 3313 |
3315 | 3314 |
3316 def colorize_CMDstatus_doc(): | 3315 def colorize_CMDstatus_doc(): |
3317 """To be called once in main() to add colors to git cl status help.""" | 3316 """To be called once in main() to add colors to git cl status help.""" |
3318 colors = [i for i in dir(Fore) if i[0].isupper()] | 3317 colors = [i for i in dir(Fore) if i[0].isupper()] |
3319 | 3318 |
3320 def colorize_line(line): | 3319 def colorize_line(line): |
3321 for color in colors: | 3320 for color in colors: |
3322 if color in line.upper(): | 3321 if color in line.upper(): |
(...skipping 27 matching lines...) Expand all Loading... |
3350 # Reverse issue lookup. | 3349 # Reverse issue lookup. |
3351 issue_branch_map = {} | 3350 issue_branch_map = {} |
3352 for branch in branches: | 3351 for branch in branches: |
3353 cl = Changelist(branchref=branch) | 3352 cl = Changelist(branchref=branch) |
3354 issue_branch_map.setdefault(cl.GetIssue(), []).append(branch) | 3353 issue_branch_map.setdefault(cl.GetIssue(), []).append(branch) |
3355 if not args: | 3354 if not args: |
3356 args = sorted(issue_branch_map.iterkeys()) | 3355 args = sorted(issue_branch_map.iterkeys()) |
3357 for issue in args: | 3356 for issue in args: |
3358 if not issue: | 3357 if not issue: |
3359 continue | 3358 continue |
3360 print 'Branch for issue number %s: %s' % ( | 3359 print('Branch for issue number %s: %s' % ( |
3361 issue, ', '.join(issue_branch_map.get(int(issue)) or ('None',))) | 3360 issue, ', '.join(issue_branch_map.get(int(issue)) or ('None',)))) |
3362 else: | 3361 else: |
3363 cl = Changelist(codereview=options.forced_codereview) | 3362 cl = Changelist(codereview=options.forced_codereview) |
3364 if len(args) > 0: | 3363 if len(args) > 0: |
3365 try: | 3364 try: |
3366 issue = int(args[0]) | 3365 issue = int(args[0]) |
3367 except ValueError: | 3366 except ValueError: |
3368 DieWithError('Pass a number to set the issue or none to list it.\n' | 3367 DieWithError('Pass a number to set the issue or none to list it.\n' |
3369 'Maybe you want to run git cl status?') | 3368 'Maybe you want to run git cl status?') |
3370 cl.SetIssue(issue) | 3369 cl.SetIssue(issue) |
3371 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) | 3370 print('Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL())) |
3372 return 0 | 3371 return 0 |
3373 | 3372 |
3374 | 3373 |
3375 def CMDcomments(parser, args): | 3374 def CMDcomments(parser, args): |
3376 """Shows or posts review comments for any changelist.""" | 3375 """Shows or posts review comments for any changelist.""" |
3377 parser.add_option('-a', '--add-comment', dest='comment', | 3376 parser.add_option('-a', '--add-comment', dest='comment', |
3378 help='comment to add to an issue') | 3377 help='comment to add to an issue') |
3379 parser.add_option('-i', dest='issue', | 3378 parser.add_option('-i', dest='issue', |
3380 help="review issue id (defaults to current issue)") | 3379 help="review issue id (defaults to current issue)") |
3381 parser.add_option('-j', '--json-file', | 3380 parser.add_option('-j', '--json-file', |
(...skipping 28 matching lines...) Expand all Loading... |
3410 if message['disapproval']: | 3409 if message['disapproval']: |
3411 color = Fore.RED | 3410 color = Fore.RED |
3412 summary[-1]['not lgtm'] = True | 3411 summary[-1]['not lgtm'] = True |
3413 elif message['approval']: | 3412 elif message['approval']: |
3414 color = Fore.GREEN | 3413 color = Fore.GREEN |
3415 summary[-1]['lgtm'] = True | 3414 summary[-1]['lgtm'] = True |
3416 elif message['sender'] == data['owner_email']: | 3415 elif message['sender'] == data['owner_email']: |
3417 color = Fore.MAGENTA | 3416 color = Fore.MAGENTA |
3418 else: | 3417 else: |
3419 color = Fore.BLUE | 3418 color = Fore.BLUE |
3420 print '\n%s%s %s%s' % ( | 3419 print('\n%s%s %s%s' % ( |
3421 color, message['date'].split('.', 1)[0], message['sender'], | 3420 color, message['date'].split('.', 1)[0], message['sender'], |
3422 Fore.RESET) | 3421 Fore.RESET)) |
3423 if message['text'].strip(): | 3422 if message['text'].strip(): |
3424 print '\n'.join(' ' + l for l in message['text'].splitlines()) | 3423 print('\n'.join(' ' + l for l in message['text'].splitlines())) |
3425 if options.json_file: | 3424 if options.json_file: |
3426 with open(options.json_file, 'wb') as f: | 3425 with open(options.json_file, 'wb') as f: |
3427 json.dump(summary, f) | 3426 json.dump(summary, f) |
3428 return 0 | 3427 return 0 |
3429 | 3428 |
3430 | 3429 |
3431 @subcommand.usage('[codereview url or issue id]') | 3430 @subcommand.usage('[codereview url or issue id]') |
3432 def CMDdescription(parser, args): | 3431 def CMDdescription(parser, args): |
3433 """Brings up the editor for the current CL's description.""" | 3432 """Brings up the editor for the current CL's description.""" |
3434 parser.add_option('-d', '--display', action='store_true', | 3433 parser.add_option('-d', '--display', action='store_true', |
(...skipping 18 matching lines...) Expand all Loading... |
3453 | 3452 |
3454 cl = Changelist( | 3453 cl = Changelist( |
3455 auth_config=auth_config, issue=target_issue, | 3454 auth_config=auth_config, issue=target_issue, |
3456 codereview=options.forced_codereview) | 3455 codereview=options.forced_codereview) |
3457 | 3456 |
3458 if not cl.GetIssue(): | 3457 if not cl.GetIssue(): |
3459 DieWithError('This branch has no associated changelist.') | 3458 DieWithError('This branch has no associated changelist.') |
3460 description = ChangeDescription(cl.GetDescription()) | 3459 description = ChangeDescription(cl.GetDescription()) |
3461 | 3460 |
3462 if options.display: | 3461 if options.display: |
3463 print description.description | 3462 print(description.description) |
3464 return 0 | 3463 return 0 |
3465 | 3464 |
3466 if options.new_description: | 3465 if options.new_description: |
3467 text = options.new_description | 3466 text = options.new_description |
3468 if text == '-': | 3467 if text == '-': |
3469 text = '\n'.join(l.rstrip() for l in sys.stdin) | 3468 text = '\n'.join(l.rstrip() for l in sys.stdin) |
3470 | 3469 |
3471 description.set_description(text) | 3470 description.set_description(text) |
3472 else: | 3471 else: |
3473 description.prompt() | 3472 description.prompt() |
(...skipping 24 matching lines...) Expand all Loading... |
3498 auth.add_auth_options(parser) | 3497 auth.add_auth_options(parser) |
3499 options, args = parser.parse_args(args) | 3498 options, args = parser.parse_args(args) |
3500 auth_config = auth.extract_auth_config_from_options(options) | 3499 auth_config = auth.extract_auth_config_from_options(options) |
3501 | 3500 |
3502 # Access to a protected member _XX of a client class | 3501 # Access to a protected member _XX of a client class |
3503 # pylint: disable=W0212 | 3502 # pylint: disable=W0212 |
3504 try: | 3503 try: |
3505 import cpplint | 3504 import cpplint |
3506 import cpplint_chromium | 3505 import cpplint_chromium |
3507 except ImportError: | 3506 except ImportError: |
3508 print "Your depot_tools is missing cpplint.py and/or cpplint_chromium.py." | 3507 print('Your depot_tools is missing cpplint.py and/or cpplint_chromium.py.') |
3509 return 1 | 3508 return 1 |
3510 | 3509 |
3511 # Change the current working directory before calling lint so that it | 3510 # Change the current working directory before calling lint so that it |
3512 # shows the correct base. | 3511 # shows the correct base. |
3513 previous_cwd = os.getcwd() | 3512 previous_cwd = os.getcwd() |
3514 os.chdir(settings.GetRoot()) | 3513 os.chdir(settings.GetRoot()) |
3515 try: | 3514 try: |
3516 cl = Changelist(auth_config=auth_config) | 3515 cl = Changelist(auth_config=auth_config) |
3517 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) | 3516 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) |
3518 files = [f.LocalPath() for f in change.AffectedFiles()] | 3517 files = [f.LocalPath() for f in change.AffectedFiles()] |
3519 if not files: | 3518 if not files: |
3520 print "Cannot lint an empty CL" | 3519 print('Cannot lint an empty CL') |
3521 return 1 | 3520 return 1 |
3522 | 3521 |
3523 # Process cpplints arguments if any. | 3522 # Process cpplints arguments if any. |
3524 command = args + files | 3523 command = args + files |
3525 if options.filter: | 3524 if options.filter: |
3526 command = ['--filter=' + ','.join(options.filter)] + command | 3525 command = ['--filter=' + ','.join(options.filter)] + command |
3527 filenames = cpplint.ParseArguments(command) | 3526 filenames = cpplint.ParseArguments(command) |
3528 | 3527 |
3529 white_regex = re.compile(settings.GetLintRegex()) | 3528 white_regex = re.compile(settings.GetLintRegex()) |
3530 black_regex = re.compile(settings.GetLintIgnoreRegex()) | 3529 black_regex = re.compile(settings.GetLintIgnoreRegex()) |
3531 extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace] | 3530 extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace] |
3532 for filename in filenames: | 3531 for filename in filenames: |
3533 if white_regex.match(filename): | 3532 if white_regex.match(filename): |
3534 if black_regex.match(filename): | 3533 if black_regex.match(filename): |
3535 print "Ignoring file %s" % filename | 3534 print('Ignoring file %s' % filename) |
3536 else: | 3535 else: |
3537 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level, | 3536 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level, |
3538 extra_check_functions) | 3537 extra_check_functions) |
3539 else: | 3538 else: |
3540 print "Skipping file %s" % filename | 3539 print('Skipping file %s' % filename) |
3541 finally: | 3540 finally: |
3542 os.chdir(previous_cwd) | 3541 os.chdir(previous_cwd) |
3543 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count | 3542 print('Total errors found: %d\n' % cpplint._cpplint_state.error_count) |
3544 if cpplint._cpplint_state.error_count != 0: | 3543 if cpplint._cpplint_state.error_count != 0: |
3545 return 1 | 3544 return 1 |
3546 return 0 | 3545 return 0 |
3547 | 3546 |
3548 | 3547 |
3549 def CMDpresubmit(parser, args): | 3548 def CMDpresubmit(parser, args): |
3550 """Runs presubmit tests on the current changelist.""" | 3549 """Runs presubmit tests on the current changelist.""" |
3551 parser.add_option('-u', '--upload', action='store_true', | 3550 parser.add_option('-u', '--upload', action='store_true', |
3552 help='Run upload hook instead of the push/dcommit hook') | 3551 help='Run upload hook instead of the push/dcommit hook') |
3553 parser.add_option('-f', '--force', action='store_true', | 3552 parser.add_option('-f', '--force', action='store_true', |
3554 help='Run checks even if tree is dirty') | 3553 help='Run checks even if tree is dirty') |
3555 auth.add_auth_options(parser) | 3554 auth.add_auth_options(parser) |
3556 options, args = parser.parse_args(args) | 3555 options, args = parser.parse_args(args) |
3557 auth_config = auth.extract_auth_config_from_options(options) | 3556 auth_config = auth.extract_auth_config_from_options(options) |
3558 | 3557 |
3559 if not options.force and git_common.is_dirty_git_tree('presubmit'): | 3558 if not options.force and git_common.is_dirty_git_tree('presubmit'): |
3560 print 'use --force to check even if tree is dirty.' | 3559 print('use --force to check even if tree is dirty.') |
3561 return 1 | 3560 return 1 |
3562 | 3561 |
3563 cl = Changelist(auth_config=auth_config) | 3562 cl = Changelist(auth_config=auth_config) |
3564 if args: | 3563 if args: |
3565 base_branch = args[0] | 3564 base_branch = args[0] |
3566 else: | 3565 else: |
3567 # Default to diffing against the common ancestor of the upstream branch. | 3566 # Default to diffing against the common ancestor of the upstream branch. |
3568 base_branch = cl.GetCommonAncestorWithUpstream() | 3567 base_branch = cl.GetCommonAncestorWithUpstream() |
3569 | 3568 |
3570 cl.RunHook( | 3569 cl.RunHook( |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3802 'Before uploading a commit to Gerrit, ensure it\'s author field is ' | 3801 'Before uploading a commit to Gerrit, ensure it\'s author field is ' |
3803 'the contributor\'s "name <email>". If you can\'t upload such a ' | 3802 'the contributor\'s "name <email>". If you can\'t upload such a ' |
3804 'commit for review, contact your repository admin and request' | 3803 'commit for review, contact your repository admin and request' |
3805 '"Forge-Author" permission.') | 3804 '"Forge-Author" permission.') |
3806 return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks, | 3805 return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks, |
3807 options.verbose) | 3806 options.verbose) |
3808 | 3807 |
3809 current = cl.GetBranch() | 3808 current = cl.GetBranch() |
3810 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 3809 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
3811 if not settings.GetIsGitSvn() and remote == '.': | 3810 if not settings.GetIsGitSvn() and remote == '.': |
3812 print | 3811 print() |
3813 print 'Attempting to push branch %r into another local branch!' % current | 3812 print('Attempting to push branch %r into another local branch!' % current) |
3814 print | 3813 print() |
3815 print 'Either reparent this branch on top of origin/master:' | 3814 print('Either reparent this branch on top of origin/master:') |
3816 print ' git reparent-branch --root' | 3815 print(' git reparent-branch --root') |
3817 print | 3816 print() |
3818 print 'OR run `git rebase-update` if you think the parent branch is already' | 3817 print('OR run `git rebase-update` if you think the parent branch is ') |
3819 print 'committed.' | 3818 print('already committed.') |
3820 print | 3819 print() |
3821 print ' Current parent: %r' % upstream_branch | 3820 print(' Current parent: %r' % upstream_branch) |
3822 return 1 | 3821 return 1 |
3823 | 3822 |
3824 if not args or cmd == 'land': | 3823 if not args or cmd == 'land': |
3825 # Default to merging against our best guess of the upstream branch. | 3824 # Default to merging against our best guess of the upstream branch. |
3826 args = [cl.GetUpstreamBranch()] | 3825 args = [cl.GetUpstreamBranch()] |
3827 | 3826 |
3828 if options.contributor: | 3827 if options.contributor: |
3829 if not re.match('^.*\s<\S+@\S+>$', options.contributor): | 3828 if not re.match('^.*\s<\S+@\S+>$', options.contributor): |
3830 print "Please provide contibutor as 'First Last <email@example.com>'" | 3829 print("Please provide contibutor as 'First Last <email@example.com>'") |
3831 return 1 | 3830 return 1 |
3832 | 3831 |
3833 base_branch = args[0] | 3832 base_branch = args[0] |
3834 base_has_submodules = IsSubmoduleMergeCommit(base_branch) | 3833 base_has_submodules = IsSubmoduleMergeCommit(base_branch) |
3835 | 3834 |
3836 if git_common.is_dirty_git_tree(cmd): | 3835 if git_common.is_dirty_git_tree(cmd): |
3837 return 1 | 3836 return 1 |
3838 | 3837 |
3839 # This rev-list syntax means "show all commits not in my branch that | 3838 # This rev-list syntax means "show all commits not in my branch that |
3840 # are in base_branch". | 3839 # are in base_branch". |
3841 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), | 3840 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), |
3842 base_branch]).splitlines() | 3841 base_branch]).splitlines() |
3843 if upstream_commits: | 3842 if upstream_commits: |
3844 print ('Base branch "%s" has %d commits ' | 3843 print('Base branch "%s" has %d commits ' |
3845 'not in this branch.' % (base_branch, len(upstream_commits))) | 3844 'not in this branch.' % (base_branch, len(upstream_commits))) |
3846 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd) | 3845 print('Run "git merge %s" before attempting to %s.' % (base_branch, cmd)) |
3847 return 1 | 3846 return 1 |
3848 | 3847 |
3849 # This is the revision `svn dcommit` will commit on top of. | 3848 # This is the revision `svn dcommit` will commit on top of. |
3850 svn_head = None | 3849 svn_head = None |
3851 if cmd == 'dcommit' or base_has_submodules: | 3850 if cmd == 'dcommit' or base_has_submodules: |
3852 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', | 3851 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', |
3853 '--pretty=format:%H']) | 3852 '--pretty=format:%H']) |
3854 | 3853 |
3855 if cmd == 'dcommit': | 3854 if cmd == 'dcommit': |
3856 # If the base_head is a submodule merge commit, the first parent of the | 3855 # If the base_head is a submodule merge commit, the first parent of the |
3857 # base_head should be a git-svn commit, which is what we're interested in. | 3856 # base_head should be a git-svn commit, which is what we're interested in. |
3858 base_svn_head = base_branch | 3857 base_svn_head = base_branch |
3859 if base_has_submodules: | 3858 if base_has_submodules: |
3860 base_svn_head += '^1' | 3859 base_svn_head += '^1' |
3861 | 3860 |
3862 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) | 3861 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) |
3863 if extra_commits: | 3862 if extra_commits: |
3864 print ('This branch has %d additional commits not upstreamed yet.' | 3863 print('This branch has %d additional commits not upstreamed yet.' |
3865 % len(extra_commits.splitlines())) | 3864 % len(extra_commits.splitlines())) |
3866 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' | 3865 print('Upstream "%s" or rebase this branch on top of the upstream trunk ' |
3867 'before attempting to %s.' % (base_branch, cmd)) | 3866 'before attempting to %s.' % (base_branch, cmd)) |
3868 return 1 | 3867 return 1 |
3869 | 3868 |
3870 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() | 3869 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() |
3871 if not options.bypass_hooks: | 3870 if not options.bypass_hooks: |
3872 author = None | 3871 author = None |
3873 if options.contributor: | 3872 if options.contributor: |
3874 author = re.search(r'\<(.*)\>', options.contributor).group(1) | 3873 author = re.search(r'\<(.*)\>', options.contributor).group(1) |
3875 hook_results = cl.RunHook( | 3874 hook_results = cl.RunHook( |
3876 committing=True, | 3875 committing=True, |
3877 may_prompt=not options.force, | 3876 may_prompt=not options.force, |
(...skipping 14 matching lines...) Expand all Loading... |
3892 return 1 | 3891 return 1 |
3893 | 3892 |
3894 change_desc = ChangeDescription(options.message) | 3893 change_desc = ChangeDescription(options.message) |
3895 if not change_desc.description and cl.GetIssue(): | 3894 if not change_desc.description and cl.GetIssue(): |
3896 change_desc = ChangeDescription(cl.GetDescription()) | 3895 change_desc = ChangeDescription(cl.GetDescription()) |
3897 | 3896 |
3898 if not change_desc.description: | 3897 if not change_desc.description: |
3899 if not cl.GetIssue() and options.bypass_hooks: | 3898 if not cl.GetIssue() and options.bypass_hooks: |
3900 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) | 3899 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) |
3901 else: | 3900 else: |
3902 print 'No description set.' | 3901 print('No description set.') |
3903 print 'Visit %s/edit to set it.' % (cl.GetIssueURL()) | 3902 print('Visit %s/edit to set it.' % (cl.GetIssueURL())) |
3904 return 1 | 3903 return 1 |
3905 | 3904 |
3906 # Keep a separate copy for the commit message, because the commit message | 3905 # Keep a separate copy for the commit message, because the commit message |
3907 # contains the link to the Rietveld issue, while the Rietveld message contains | 3906 # contains the link to the Rietveld issue, while the Rietveld message contains |
3908 # the commit viewvc url. | 3907 # the commit viewvc url. |
3909 # Keep a separate copy for the commit message. | 3908 # Keep a separate copy for the commit message. |
3910 if cl.GetIssue(): | 3909 if cl.GetIssue(): |
3911 change_desc.update_reviewers(cl.GetApprovingReviewers()) | 3910 change_desc.update_reviewers(cl.GetApprovingReviewers()) |
3912 | 3911 |
3913 commit_desc = ChangeDescription(change_desc.description) | 3912 commit_desc = ChangeDescription(change_desc.description) |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4011 '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) | 4010 '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) |
4012 logging.debug(output) | 4011 logging.debug(output) |
4013 finally: | 4012 finally: |
4014 # And then swap back to the original branch and clean up. | 4013 # And then swap back to the original branch and clean up. |
4015 RunGit(['checkout', '-q', cl.GetBranch()]) | 4014 RunGit(['checkout', '-q', cl.GetBranch()]) |
4016 RunGit(['branch', '-D', MERGE_BRANCH]) | 4015 RunGit(['branch', '-D', MERGE_BRANCH]) |
4017 if base_has_submodules: | 4016 if base_has_submodules: |
4018 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) | 4017 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) |
4019 | 4018 |
4020 if not revision: | 4019 if not revision: |
4021 print 'Failed to push. If this persists, please file a bug.' | 4020 print('Failed to push. If this persists, please file a bug.') |
4022 return 1 | 4021 return 1 |
4023 | 4022 |
4024 killed = False | 4023 killed = False |
4025 if pushed_to_pending: | 4024 if pushed_to_pending: |
4026 try: | 4025 try: |
4027 revision = WaitForRealCommit(remote, revision, base_branch, branch) | 4026 revision = WaitForRealCommit(remote, revision, base_branch, branch) |
4028 # We set pushed_to_pending to False, since it made it all the way to the | 4027 # We set pushed_to_pending to False, since it made it all the way to the |
4029 # real ref. | 4028 # real ref. |
4030 pushed_to_pending = False | 4029 pushed_to_pending = False |
4031 except KeyboardInterrupt: | 4030 except KeyboardInterrupt: |
4032 killed = True | 4031 killed = True |
4033 | 4032 |
4034 if cl.GetIssue(): | 4033 if cl.GetIssue(): |
4035 to_pending = ' to pending queue' if pushed_to_pending else '' | 4034 to_pending = ' to pending queue' if pushed_to_pending else '' |
4036 viewvc_url = settings.GetViewVCUrl() | 4035 viewvc_url = settings.GetViewVCUrl() |
4037 if not to_pending: | 4036 if not to_pending: |
4038 if viewvc_url and revision: | 4037 if viewvc_url and revision: |
4039 change_desc.append_footer( | 4038 change_desc.append_footer( |
4040 'Committed: %s%s' % (viewvc_url, revision)) | 4039 'Committed: %s%s' % (viewvc_url, revision)) |
4041 elif revision: | 4040 elif revision: |
4042 change_desc.append_footer('Committed: %s' % (revision,)) | 4041 change_desc.append_footer('Committed: %s' % (revision,)) |
4043 print ('Closing issue ' | 4042 print('Closing issue ' |
4044 '(you may be prompted for your codereview password)...') | 4043 '(you may be prompted for your codereview password)...') |
4045 cl.UpdateDescription(change_desc.description) | 4044 cl.UpdateDescription(change_desc.description) |
4046 cl.CloseIssue() | 4045 cl.CloseIssue() |
4047 props = cl.GetIssueProperties() | 4046 props = cl.GetIssueProperties() |
4048 patch_num = len(props['patchsets']) | 4047 patch_num = len(props['patchsets']) |
4049 comment = "Committed patchset #%d (id:%d)%s manually as %s" % ( | 4048 comment = "Committed patchset #%d (id:%d)%s manually as %s" % ( |
4050 patch_num, props['patchsets'][-1], to_pending, revision) | 4049 patch_num, props['patchsets'][-1], to_pending, revision) |
4051 if options.bypass_hooks: | 4050 if options.bypass_hooks: |
4052 comment += ' (tree was closed).' if GetTreeStatus() == 'closed' else '.' | 4051 comment += ' (tree was closed).' if GetTreeStatus() == 'closed' else '.' |
4053 else: | 4052 else: |
4054 comment += ' (presubmit successful).' | 4053 comment += ' (presubmit successful).' |
4055 cl.RpcServer().add_comment(cl.GetIssue(), comment) | 4054 cl.RpcServer().add_comment(cl.GetIssue(), comment) |
4056 cl.SetIssue(None) | 4055 cl.SetIssue(None) |
4057 | 4056 |
4058 if pushed_to_pending: | 4057 if pushed_to_pending: |
4059 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 4058 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
4060 print 'The commit is in the pending queue (%s).' % pending_ref | 4059 print('The commit is in the pending queue (%s).' % pending_ref) |
4061 print ( | 4060 print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' |
4062 'It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' | 4061 'footer.' % branch) |
4063 'footer.' % branch) | |
4064 | 4062 |
4065 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 4063 hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
4066 if os.path.isfile(hook): | 4064 if os.path.isfile(hook): |
4067 RunCommand([hook, merge_base], error_ok=True) | 4065 RunCommand([hook, merge_base], error_ok=True) |
4068 | 4066 |
4069 return 1 if killed else 0 | 4067 return 1 if killed else 0 |
4070 | 4068 |
4071 | 4069 |
4072 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): | 4070 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): |
4073 print | 4071 print() |
4074 print 'Waiting for commit to be landed on %s...' % real_ref | 4072 print('Waiting for commit to be landed on %s...' % real_ref) |
4075 print '(If you are impatient, you may Ctrl-C once without harm)' | 4073 print('(If you are impatient, you may Ctrl-C once without harm)') |
4076 target_tree = RunGit(['rev-parse', '%s:' % pushed_commit]).strip() | 4074 target_tree = RunGit(['rev-parse', '%s:' % pushed_commit]).strip() |
4077 current_rev = RunGit(['rev-parse', local_base_ref]).strip() | 4075 current_rev = RunGit(['rev-parse', local_base_ref]).strip() |
4078 mirror = settings.GetGitMirror(remote) | 4076 mirror = settings.GetGitMirror(remote) |
4079 | 4077 |
4080 loop = 0 | 4078 loop = 0 |
4081 while True: | 4079 while True: |
4082 sys.stdout.write('fetching (%d)... \r' % loop) | 4080 sys.stdout.write('fetching (%d)... \r' % loop) |
4083 sys.stdout.flush() | 4081 sys.stdout.flush() |
4084 loop += 1 | 4082 loop += 1 |
4085 | 4083 |
4086 if mirror: | 4084 if mirror: |
4087 mirror.populate() | 4085 mirror.populate() |
4088 RunGit(['retry', 'fetch', remote, real_ref], stderr=subprocess2.VOID) | 4086 RunGit(['retry', 'fetch', remote, real_ref], stderr=subprocess2.VOID) |
4089 to_rev = RunGit(['rev-parse', 'FETCH_HEAD']).strip() | 4087 to_rev = RunGit(['rev-parse', 'FETCH_HEAD']).strip() |
4090 commits = RunGit(['rev-list', '%s..%s' % (current_rev, to_rev)]) | 4088 commits = RunGit(['rev-list', '%s..%s' % (current_rev, to_rev)]) |
4091 for commit in commits.splitlines(): | 4089 for commit in commits.splitlines(): |
4092 if RunGit(['rev-parse', '%s:' % commit]).strip() == target_tree: | 4090 if RunGit(['rev-parse', '%s:' % commit]).strip() == target_tree: |
4093 print 'Found commit on %s' % real_ref | 4091 print('Found commit on %s' % real_ref) |
4094 return commit | 4092 return commit |
4095 | 4093 |
4096 current_rev = to_rev | 4094 current_rev = to_rev |
4097 | 4095 |
4098 | 4096 |
4099 def PushToGitPending(remote, pending_ref, upstream_ref): | 4097 def PushToGitPending(remote, pending_ref, upstream_ref): |
4100 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes. | 4098 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes. |
4101 | 4099 |
4102 Returns: | 4100 Returns: |
4103 (retcode of last operation, output log of last operation). | 4101 (retcode of last operation, output log of last operation). |
4104 """ | 4102 """ |
4105 assert pending_ref.startswith('refs/'), pending_ref | 4103 assert pending_ref.startswith('refs/'), pending_ref |
4106 local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):] | 4104 local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):] |
4107 cherry = RunGit(['rev-parse', 'HEAD']).strip() | 4105 cherry = RunGit(['rev-parse', 'HEAD']).strip() |
4108 code = 0 | 4106 code = 0 |
4109 out = '' | 4107 out = '' |
4110 max_attempts = 3 | 4108 max_attempts = 3 |
4111 attempts_left = max_attempts | 4109 attempts_left = max_attempts |
4112 while attempts_left: | 4110 while attempts_left: |
4113 if attempts_left != max_attempts: | 4111 if attempts_left != max_attempts: |
4114 print 'Retrying, %d attempts left...' % (attempts_left - 1,) | 4112 print('Retrying, %d attempts left...' % (attempts_left - 1,)) |
4115 attempts_left -= 1 | 4113 attempts_left -= 1 |
4116 | 4114 |
4117 # Fetch. Retry fetch errors. | 4115 # Fetch. Retry fetch errors. |
4118 print 'Fetching pending ref %s...' % pending_ref | 4116 print('Fetching pending ref %s...' % pending_ref) |
4119 code, out = RunGitWithCode( | 4117 code, out = RunGitWithCode( |
4120 ['retry', 'fetch', remote, '+%s:%s' % (pending_ref, local_pending_ref)]) | 4118 ['retry', 'fetch', remote, '+%s:%s' % (pending_ref, local_pending_ref)]) |
4121 if code: | 4119 if code: |
4122 print 'Fetch failed with exit code %d.' % code | 4120 print('Fetch failed with exit code %d.' % code) |
4123 if out.strip(): | 4121 if out.strip(): |
4124 print out.strip() | 4122 print(out.strip()) |
4125 continue | 4123 continue |
4126 | 4124 |
4127 # Try to cherry pick. Abort on merge conflicts. | 4125 # Try to cherry pick. Abort on merge conflicts. |
4128 print 'Cherry-picking commit on top of pending ref...' | 4126 print('Cherry-picking commit on top of pending ref...') |
4129 RunGitWithCode(['checkout', local_pending_ref], suppress_stderr=True) | 4127 RunGitWithCode(['checkout', local_pending_ref], suppress_stderr=True) |
4130 code, out = RunGitWithCode(['cherry-pick', cherry]) | 4128 code, out = RunGitWithCode(['cherry-pick', cherry]) |
4131 if code: | 4129 if code: |
4132 print ( | 4130 print('Your patch doesn\'t apply cleanly to ref \'%s\', ' |
4133 'Your patch doesn\'t apply cleanly to ref \'%s\', ' | 4131 'the following files have merge conflicts:' % pending_ref) |
4134 'the following files have merge conflicts:' % pending_ref) | 4132 print(RunGit(['diff', '--name-status', '--diff-filter=U']).strip()) |
4135 print RunGit(['diff', '--name-status', '--diff-filter=U']).strip() | 4133 print('Please rebase your patch and try again.') |
4136 print 'Please rebase your patch and try again.' | |
4137 RunGitWithCode(['cherry-pick', '--abort']) | 4134 RunGitWithCode(['cherry-pick', '--abort']) |
4138 return code, out | 4135 return code, out |
4139 | 4136 |
4140 # Applied cleanly, try to push now. Retry on error (flake or non-ff push). | 4137 # Applied cleanly, try to push now. Retry on error (flake or non-ff push). |
4141 print 'Pushing commit to %s... It can take a while.' % pending_ref | 4138 print('Pushing commit to %s... It can take a while.' % pending_ref) |
4142 code, out = RunGitWithCode( | 4139 code, out = RunGitWithCode( |
4143 ['retry', 'push', '--porcelain', remote, 'HEAD:%s' % pending_ref]) | 4140 ['retry', 'push', '--porcelain', remote, 'HEAD:%s' % pending_ref]) |
4144 if code == 0: | 4141 if code == 0: |
4145 # Success. | 4142 # Success. |
4146 print 'Commit pushed to pending ref successfully!' | 4143 print('Commit pushed to pending ref successfully!') |
4147 return code, out | 4144 return code, out |
4148 | 4145 |
4149 print 'Push failed with exit code %d.' % code | 4146 print('Push failed with exit code %d.' % code) |
4150 if out.strip(): | 4147 if out.strip(): |
4151 print out.strip() | 4148 print(out.strip()) |
4152 if IsFatalPushFailure(out): | 4149 if IsFatalPushFailure(out): |
4153 print ( | 4150 print('Fatal push error. Make sure your .netrc credentials and git ' |
4154 'Fatal push error. Make sure your .netrc credentials and git ' | 4151 'user.email are correct and you have push access to the repo.') |
4155 'user.email are correct and you have push access to the repo.') | |
4156 return code, out | 4152 return code, out |
4157 | 4153 |
4158 print 'All attempts to push to pending ref failed.' | 4154 print('All attempts to push to pending ref failed.') |
4159 return code, out | 4155 return code, out |
4160 | 4156 |
4161 | 4157 |
4162 def IsFatalPushFailure(push_stdout): | 4158 def IsFatalPushFailure(push_stdout): |
4163 """True if retrying push won't help.""" | 4159 """True if retrying push won't help.""" |
4164 return '(prohibited by Gerrit)' in push_stdout | 4160 return '(prohibited by Gerrit)' in push_stdout |
4165 | 4161 |
4166 | 4162 |
4167 @subcommand.usage('[upstream branch to apply against]') | 4163 @subcommand.usage('[upstream branch to apply against]') |
4168 def CMDdcommit(parser, args): | 4164 def CMDdcommit(parser, args): |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4350 elif result_master != cur_master: | 4346 elif result_master != cur_master: |
4351 return None, 'The builders do not belong to the same master.' | 4347 return None, 'The builders do not belong to the same master.' |
4352 return result_master, None | 4348 return result_master, None |
4353 | 4349 |
4354 | 4350 |
4355 def CMDtree(parser, args): | 4351 def CMDtree(parser, args): |
4356 """Shows the status of the tree.""" | 4352 """Shows the status of the tree.""" |
4357 _, args = parser.parse_args(args) | 4353 _, args = parser.parse_args(args) |
4358 status = GetTreeStatus() | 4354 status = GetTreeStatus() |
4359 if 'unset' == status: | 4355 if 'unset' == status: |
4360 print 'You must configure your tree status URL by running "git cl config".' | 4356 print('You must configure your tree status URL by running "git cl config".') |
4361 return 2 | 4357 return 2 |
4362 | 4358 |
4363 print "The tree is %s" % status | 4359 print('The tree is %s' % status) |
4364 print | 4360 print() |
4365 print GetTreeStatusReason() | 4361 print(GetTreeStatusReason()) |
4366 if status != 'open': | 4362 if status != 'open': |
4367 return 1 | 4363 return 1 |
4368 return 0 | 4364 return 0 |
4369 | 4365 |
4370 | 4366 |
4371 def CMDtry(parser, args): | 4367 def CMDtry(parser, args): |
4372 """Triggers try jobs through BuildBucket.""" | 4368 """Triggers try jobs through BuildBucket.""" |
4373 group = optparse.OptionGroup(parser, "Try job options") | 4369 group = optparse.OptionGroup(parser, "Try job options") |
4374 group.add_option( | 4370 group.add_option( |
4375 "-b", "--bot", action="append", | 4371 "-b", "--bot", action="append", |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4522 | 4518 |
4523 # Return a master map with one master to be backwards compatible. The | 4519 # Return a master map with one master to be backwards compatible. The |
4524 # master name defaults to an empty string, which will cause the master | 4520 # master name defaults to an empty string, which will cause the master |
4525 # not to be set on rietveld (deprecated). | 4521 # not to be set on rietveld (deprecated). |
4526 return {options.master: builders_and_tests} | 4522 return {options.master: builders_and_tests} |
4527 | 4523 |
4528 masters = GetMasterMap() | 4524 masters = GetMasterMap() |
4529 | 4525 |
4530 for builders in masters.itervalues(): | 4526 for builders in masters.itervalues(): |
4531 if any('triggered' in b for b in builders): | 4527 if any('triggered' in b for b in builders): |
4532 print >> sys.stderr, ( | 4528 print('ERROR You are trying to send a job to a triggered bot. This type ' |
4533 'ERROR You are trying to send a job to a triggered bot. This type of' | 4529 'of bot requires an\ninitial job from a parent (usually a builder).' |
4534 ' bot requires an\ninitial job from a parent (usually a builder). ' | 4530 ' Instead send your job to the parent.\n' |
4535 'Instead send your job to the parent.\n' | 4531 'Bot list: %s' % builders, file=sys.stderr) |
4536 'Bot list: %s' % builders) | |
4537 return 1 | 4532 return 1 |
4538 | 4533 |
4539 patchset = cl.GetMostRecentPatchset() | 4534 patchset = cl.GetMostRecentPatchset() |
4540 if patchset and patchset != cl.GetPatchset(): | 4535 if patchset and patchset != cl.GetPatchset(): |
4541 print( | 4536 print( |
4542 '\nWARNING Mismatch between local config and server. Did a previous ' | 4537 '\nWARNING Mismatch between local config and server. Did a previous ' |
4543 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' | 4538 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' |
4544 'Continuing using\npatchset %s.\n' % patchset) | 4539 'Continuing using\npatchset %s.\n' % patchset) |
4545 if options.luci: | 4540 if options.luci: |
4546 trigger_luci_job(cl, masters, options) | 4541 trigger_luci_job(cl, masters, options) |
4547 elif not options.use_rietveld: | 4542 elif not options.use_rietveld: |
4548 try: | 4543 try: |
4549 trigger_try_jobs(auth_config, cl, options, masters, 'git_cl_try') | 4544 trigger_try_jobs(auth_config, cl, options, masters, 'git_cl_try') |
4550 except BuildbucketResponseException as ex: | 4545 except BuildbucketResponseException as ex: |
4551 print 'ERROR: %s' % ex | 4546 print('ERROR: %s' % ex) |
4552 return 1 | 4547 return 1 |
4553 except Exception as e: | 4548 except Exception as e: |
4554 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) | 4549 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) |
4555 print 'ERROR: Exception when trying to trigger tryjobs: %s\n%s' % ( | 4550 print('ERROR: Exception when trying to trigger tryjobs: %s\n%s' % |
4556 e, stacktrace) | 4551 (e, stacktrace)) |
4557 return 1 | 4552 return 1 |
4558 else: | 4553 else: |
4559 try: | 4554 try: |
4560 cl.RpcServer().trigger_distributed_try_jobs( | 4555 cl.RpcServer().trigger_distributed_try_jobs( |
4561 cl.GetIssue(), patchset, options.name, options.clobber, | 4556 cl.GetIssue(), patchset, options.name, options.clobber, |
4562 options.revision, masters) | 4557 options.revision, masters) |
4563 except urllib2.HTTPError as e: | 4558 except urllib2.HTTPError as e: |
4564 if e.code == 404: | 4559 if e.code == 404: |
4565 print('404 from rietveld; ' | 4560 print('404 from rietveld; ' |
4566 'did you mean to use "git try" instead of "git cl try"?') | 4561 'did you mean to use "git try" instead of "git cl try"?') |
4567 return 1 | 4562 return 1 |
4568 print('Tried jobs on:') | 4563 print('Tried jobs on:') |
4569 | 4564 |
4570 for (master, builders) in sorted(masters.iteritems()): | 4565 for (master, builders) in sorted(masters.iteritems()): |
4571 if master: | 4566 if master: |
4572 print 'Master: %s' % master | 4567 print('Master: %s' % master) |
4573 length = max(len(builder) for builder in builders) | 4568 length = max(len(builder) for builder in builders) |
4574 for builder in sorted(builders): | 4569 for builder in sorted(builders): |
4575 print ' %*s: %s' % (length, builder, ','.join(builders[builder])) | 4570 print(' %*s: %s' % (length, builder, ','.join(builders[builder]))) |
4576 return 0 | 4571 return 0 |
4577 | 4572 |
4578 | 4573 |
4579 def CMDtry_results(parser, args): | 4574 def CMDtry_results(parser, args): |
4580 group = optparse.OptionGroup(parser, "Try job results options") | 4575 group = optparse.OptionGroup(parser, "Try job results options") |
4581 group.add_option( | 4576 group.add_option( |
4582 "-p", "--patchset", type=int, help="patchset number if not current.") | 4577 "-p", "--patchset", type=int, help="patchset number if not current.") |
4583 group.add_option( | 4578 group.add_option( |
4584 "--print-master", action='store_true', help="print master name as well.") | 4579 "--print-master", action='store_true', help="print master name as well.") |
4585 group.add_option( | 4580 group.add_option( |
(...skipping 16 matching lines...) Expand all Loading... |
4602 if not options.patchset: | 4597 if not options.patchset: |
4603 options.patchset = cl.GetMostRecentPatchset() | 4598 options.patchset = cl.GetMostRecentPatchset() |
4604 if options.patchset and options.patchset != cl.GetPatchset(): | 4599 if options.patchset and options.patchset != cl.GetPatchset(): |
4605 print( | 4600 print( |
4606 '\nWARNING Mismatch between local config and server. Did a previous ' | 4601 '\nWARNING Mismatch between local config and server. Did a previous ' |
4607 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' | 4602 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' |
4608 'Continuing using\npatchset %s.\n' % options.patchset) | 4603 'Continuing using\npatchset %s.\n' % options.patchset) |
4609 try: | 4604 try: |
4610 jobs = fetch_try_jobs(auth_config, cl, options) | 4605 jobs = fetch_try_jobs(auth_config, cl, options) |
4611 except BuildbucketResponseException as ex: | 4606 except BuildbucketResponseException as ex: |
4612 print 'Buildbucket error: %s' % ex | 4607 print('Buildbucket error: %s' % ex) |
4613 return 1 | 4608 return 1 |
4614 except Exception as e: | 4609 except Exception as e: |
4615 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) | 4610 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) |
4616 print 'ERROR: Exception when trying to fetch tryjobs: %s\n%s' % ( | 4611 print('ERROR: Exception when trying to fetch tryjobs: %s\n%s' % |
4617 e, stacktrace) | 4612 (e, stacktrace)) |
4618 return 1 | 4613 return 1 |
4619 print_tryjobs(options, jobs) | 4614 print_tryjobs(options, jobs) |
4620 return 0 | 4615 return 0 |
4621 | 4616 |
4622 | 4617 |
4623 @subcommand.usage('[new upstream branch]') | 4618 @subcommand.usage('[new upstream branch]') |
4624 def CMDupstream(parser, args): | 4619 def CMDupstream(parser, args): |
4625 """Prints or sets the name of the upstream branch, if any.""" | 4620 """Prints or sets the name of the upstream branch, if any.""" |
4626 _, args = parser.parse_args(args) | 4621 _, args = parser.parse_args(args) |
4627 if len(args) > 1: | 4622 if len(args) > 1: |
4628 parser.error('Unrecognized args: %s' % ' '.join(args)) | 4623 parser.error('Unrecognized args: %s' % ' '.join(args)) |
4629 | 4624 |
4630 cl = Changelist() | 4625 cl = Changelist() |
4631 if args: | 4626 if args: |
4632 # One arg means set upstream branch. | 4627 # One arg means set upstream branch. |
4633 branch = cl.GetBranch() | 4628 branch = cl.GetBranch() |
4634 RunGit(['branch', '--set-upstream', branch, args[0]]) | 4629 RunGit(['branch', '--set-upstream', branch, args[0]]) |
4635 cl = Changelist() | 4630 cl = Changelist() |
4636 print "Upstream branch set to " + cl.GetUpstreamBranch() | 4631 print('Upstream branch set to %s' % (cl.GetUpstreamBranch(),)) |
4637 | 4632 |
4638 # Clear configured merge-base, if there is one. | 4633 # Clear configured merge-base, if there is one. |
4639 git_common.remove_merge_base(branch) | 4634 git_common.remove_merge_base(branch) |
4640 else: | 4635 else: |
4641 print cl.GetUpstreamBranch() | 4636 print(cl.GetUpstreamBranch()) |
4642 return 0 | 4637 return 0 |
4643 | 4638 |
4644 | 4639 |
4645 def CMDweb(parser, args): | 4640 def CMDweb(parser, args): |
4646 """Opens the current CL in the web browser.""" | 4641 """Opens the current CL in the web browser.""" |
4647 _, args = parser.parse_args(args) | 4642 _, args = parser.parse_args(args) |
4648 if args: | 4643 if args: |
4649 parser.error('Unrecognized args: %s' % ' '.join(args)) | 4644 parser.error('Unrecognized args: %s' % ' '.join(args)) |
4650 | 4645 |
4651 issue_url = Changelist().GetIssueURL() | 4646 issue_url = Changelist().GetIssueURL() |
4652 if not issue_url: | 4647 if not issue_url: |
4653 print >> sys.stderr, 'ERROR No issue to open' | 4648 print('ERROR No issue to open', file=sys.stderr) |
4654 return 1 | 4649 return 1 |
4655 | 4650 |
4656 webbrowser.open(issue_url) | 4651 webbrowser.open(issue_url) |
4657 return 0 | 4652 return 0 |
4658 | 4653 |
4659 | 4654 |
4660 def CMDset_commit(parser, args): | 4655 def CMDset_commit(parser, args): |
4661 """Sets the commit bit to trigger the Commit Queue.""" | 4656 """Sets the commit bit to trigger the Commit Queue.""" |
4662 parser.add_option('-d', '--dry-run', action='store_true', | 4657 parser.add_option('-d', '--dry-run', action='store_true', |
4663 help='trigger in dry run mode') | 4658 help='trigger in dry run mode') |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4909 try: | 4904 try: |
4910 command = [dart_format.FindDartFmtToolInChromiumTree()] | 4905 command = [dart_format.FindDartFmtToolInChromiumTree()] |
4911 if not opts.dry_run and not opts.diff: | 4906 if not opts.dry_run and not opts.diff: |
4912 command.append('-w') | 4907 command.append('-w') |
4913 command.extend(dart_diff_files) | 4908 command.extend(dart_diff_files) |
4914 | 4909 |
4915 stdout = RunCommand(command, cwd=top_dir) | 4910 stdout = RunCommand(command, cwd=top_dir) |
4916 if opts.dry_run and stdout: | 4911 if opts.dry_run and stdout: |
4917 return_value = 2 | 4912 return_value = 2 |
4918 except dart_format.NotFoundError as e: | 4913 except dart_format.NotFoundError as e: |
4919 print ('Warning: Unable to check Dart code formatting. Dart SDK not ' + | 4914 print('Warning: Unable to check Dart code formatting. Dart SDK not ' |
4920 'found in this checkout. Files in other languages are still ' + | 4915 'found in this checkout. Files in other languages are still ' |
4921 'formatted.') | 4916 'formatted.') |
4922 | 4917 |
4923 # Format GN build files. Always run on full build files for canonical form. | 4918 # Format GN build files. Always run on full build files for canonical form. |
4924 if gn_diff_files: | 4919 if gn_diff_files: |
4925 cmd = ['gn', 'format'] | 4920 cmd = ['gn', 'format'] |
4926 if not opts.dry_run and not opts.diff: | 4921 if not opts.dry_run and not opts.diff: |
4927 cmd.append('--in-place') | 4922 cmd.append('--in-place') |
4928 for gn_diff_file in gn_diff_files: | 4923 for gn_diff_file in gn_diff_files: |
4929 stdout = RunCommand(cmd + [gn_diff_file], | 4924 stdout = RunCommand(cmd + [gn_diff_file], |
4930 shell=sys.platform == 'win32', | 4925 shell=sys.platform == 'win32', |
4931 cwd=top_dir) | 4926 cwd=top_dir) |
(...skipping 23 matching lines...) Expand all Loading... |
4955 r'branch\..*\.%s' % issueprefix], | 4950 r'branch\..*\.%s' % issueprefix], |
4956 error_ok=True) | 4951 error_ok=True) |
4957 for key, issue in [x.split() for x in output.splitlines()]: | 4952 for key, issue in [x.split() for x in output.splitlines()]: |
4958 if issue == target_issue: | 4953 if issue == target_issue: |
4959 yield re.sub(r'branch\.(.*)\.%s' % issueprefix, r'\1', key) | 4954 yield re.sub(r'branch\.(.*)\.%s' % issueprefix, r'\1', key) |
4960 | 4955 |
4961 branches = [] | 4956 branches = [] |
4962 for cls in _CODEREVIEW_IMPLEMENTATIONS.values(): | 4957 for cls in _CODEREVIEW_IMPLEMENTATIONS.values(): |
4963 branches.extend(find_issues(cls.IssueSettingSuffix())) | 4958 branches.extend(find_issues(cls.IssueSettingSuffix())) |
4964 if len(branches) == 0: | 4959 if len(branches) == 0: |
4965 print 'No branch found for issue %s.' % target_issue | 4960 print('No branch found for issue %s.' % target_issue) |
4966 return 1 | 4961 return 1 |
4967 if len(branches) == 1: | 4962 if len(branches) == 1: |
4968 RunGit(['checkout', branches[0]]) | 4963 RunGit(['checkout', branches[0]]) |
4969 else: | 4964 else: |
4970 print 'Multiple branches match issue %s:' % target_issue | 4965 print('Multiple branches match issue %s:' % target_issue) |
4971 for i in range(len(branches)): | 4966 for i in range(len(branches)): |
4972 print '%d: %s' % (i, branches[i]) | 4967 print('%d: %s' % (i, branches[i])) |
4973 which = raw_input('Choose by index: ') | 4968 which = raw_input('Choose by index: ') |
4974 try: | 4969 try: |
4975 RunGit(['checkout', branches[int(which)]]) | 4970 RunGit(['checkout', branches[int(which)]]) |
4976 except (IndexError, ValueError): | 4971 except (IndexError, ValueError): |
4977 print 'Invalid selection, not checking out any branch.' | 4972 print('Invalid selection, not checking out any branch.') |
4978 return 1 | 4973 return 1 |
4979 | 4974 |
4980 return 0 | 4975 return 0 |
4981 | 4976 |
4982 | 4977 |
4983 def CMDlol(parser, args): | 4978 def CMDlol(parser, args): |
4984 # This command is intentionally undocumented. | 4979 # This command is intentionally undocumented. |
4985 print zlib.decompress(base64.b64decode( | 4980 print(zlib.decompress(base64.b64decode( |
4986 'eNptkLEOwyAMRHe+wupCIqW57v0Vq84WqWtXyrcXnCBsmgMJ+/SSAxMZgRB6NzE' | 4981 'eNptkLEOwyAMRHe+wupCIqW57v0Vq84WqWtXyrcXnCBsmgMJ+/SSAxMZgRB6NzE' |
4987 'E2ObgCKJooYdu4uAQVffUEoE1sRQLxAcqzd7uK2gmStrll1ucV3uZyaY5sXyDd9' | 4982 'E2ObgCKJooYdu4uAQVffUEoE1sRQLxAcqzd7uK2gmStrll1ucV3uZyaY5sXyDd9' |
4988 'JAnN+lAXsOMJ90GANAi43mq5/VeeacylKVgi8o6F1SC63FxnagHfJUTfUYdCR/W' | 4983 'JAnN+lAXsOMJ90GANAi43mq5/VeeacylKVgi8o6F1SC63FxnagHfJUTfUYdCR/W' |
4989 'Ofe+0dHL7PicpytKP750Fh1q2qnLVof4w8OZWNY')) | 4984 'Ofe+0dHL7PicpytKP750Fh1q2qnLVof4w8OZWNY'))) |
4990 return 0 | 4985 return 0 |
4991 | 4986 |
4992 | 4987 |
4993 class OptionParser(optparse.OptionParser): | 4988 class OptionParser(optparse.OptionParser): |
4994 """Creates the option parse and add --verbose support.""" | 4989 """Creates the option parse and add --verbose support.""" |
4995 def __init__(self, *args, **kwargs): | 4990 def __init__(self, *args, **kwargs): |
4996 optparse.OptionParser.__init__( | 4991 optparse.OptionParser.__init__( |
4997 self, *args, prog='git cl', version=__version__, **kwargs) | 4992 self, *args, prog='git cl', version=__version__, **kwargs) |
4998 self.add_option( | 4993 self.add_option( |
4999 '-v', '--verbose', action='count', default=0, | 4994 '-v', '--verbose', action='count', default=0, |
5000 help='Use 2 times for more debugging info') | 4995 help='Use 2 times for more debugging info') |
5001 | 4996 |
5002 def parse_args(self, args=None, values=None): | 4997 def parse_args(self, args=None, values=None): |
5003 options, args = optparse.OptionParser.parse_args(self, args, values) | 4998 options, args = optparse.OptionParser.parse_args(self, args, values) |
5004 levels = [logging.WARNING, logging.INFO, logging.DEBUG] | 4999 levels = [logging.WARNING, logging.INFO, logging.DEBUG] |
5005 logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)]) | 5000 logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)]) |
5006 return options, args | 5001 return options, args |
5007 | 5002 |
5008 | 5003 |
5009 def main(argv): | 5004 def main(argv): |
5010 if sys.hexversion < 0x02060000: | 5005 if sys.hexversion < 0x02060000: |
5011 print >> sys.stderr, ( | 5006 print('\nYour python version %s is unsupported, please upgrade.\n' % |
5012 '\nYour python version %s is unsupported, please upgrade.\n' % | 5007 (sys.version.split(' ', 1)[0],), file=sys.stderr) |
5013 sys.version.split(' ', 1)[0]) | |
5014 return 2 | 5008 return 2 |
5015 | 5009 |
5016 # Reload settings. | 5010 # Reload settings. |
5017 global settings | 5011 global settings |
5018 settings = Settings() | 5012 settings = Settings() |
5019 | 5013 |
5020 colorize_CMDstatus_doc() | 5014 colorize_CMDstatus_doc() |
5021 dispatcher = subcommand.CommandDispatcher(__name__) | 5015 dispatcher = subcommand.CommandDispatcher(__name__) |
5022 try: | 5016 try: |
5023 return dispatcher.execute(OptionParser(), argv) | 5017 return dispatcher.execute(OptionParser(), argv) |
(...skipping 11 matching lines...) Expand all Loading... |
5035 if __name__ == '__main__': | 5029 if __name__ == '__main__': |
5036 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5030 # These affect sys.stdout so do it outside of main() to simplify mocks in |
5037 # unit testing. | 5031 # unit testing. |
5038 fix_encoding.fix_encoding() | 5032 fix_encoding.fix_encoding() |
5039 setup_color.init() | 5033 setup_color.init() |
5040 try: | 5034 try: |
5041 sys.exit(main(sys.argv[1:])) | 5035 sys.exit(main(sys.argv[1:])) |
5042 except KeyboardInterrupt: | 5036 except KeyboardInterrupt: |
5043 sys.stderr.write('interrupted\n') | 5037 sys.stderr.write('interrupted\n') |
5044 sys.exit(1) | 5038 sys.exit(1) |
OLD | NEW |