Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
| 7 | 7 |
| 8 """A git-command for integrating reviews on Rietveld.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
| 9 | 9 |
| 10 import difflib | 10 import difflib |
| 11 from distutils.version import LooseVersion | 11 from distutils.version import LooseVersion |
| 12 import json | 12 import json |
| 13 import logging | 13 import logging |
| 14 import optparse | 14 import optparse |
| 15 import os | 15 import os |
| 16 import Queue | |
| 16 import re | 17 import re |
| 17 import stat | 18 import stat |
| 18 import sys | 19 import sys |
| 19 import textwrap | 20 import textwrap |
| 21 import threading | |
| 20 import urllib2 | 22 import urllib2 |
| 21 import urlparse | 23 import urlparse |
| 22 | 24 |
| 23 try: | 25 try: |
| 24 import readline # pylint: disable=F0401,W0611 | 26 import readline # pylint: disable=F0401,W0611 |
| 25 except ImportError: | 27 except ImportError: |
| 26 pass | 28 pass |
| 27 | 29 |
| 28 | 30 |
| 29 from third_party import colorama | 31 from third_party import colorama |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 405 self.LazyUpdateIfNeeded() | 407 self.LazyUpdateIfNeeded() |
| 406 return RunGit(['config', param], **kwargs).strip() | 408 return RunGit(['config', param], **kwargs).strip() |
| 407 | 409 |
| 408 | 410 |
| 409 def ShortBranchName(branch): | 411 def ShortBranchName(branch): |
| 410 """Convert a name like 'refs/heads/foo' to just 'foo'.""" | 412 """Convert a name like 'refs/heads/foo' to just 'foo'.""" |
| 411 return branch.replace('refs/heads/', '') | 413 return branch.replace('refs/heads/', '') |
| 412 | 414 |
| 413 | 415 |
| 414 class Changelist(object): | 416 class Changelist(object): |
| 415 def __init__(self, branchref=None): | 417 def __init__(self, branchref=None, issue=None): |
| 416 # Poke settings so we get the "configure your server" message if necessary. | 418 # Poke settings so we get the "configure your server" message if necessary. |
| 417 global settings | 419 global settings |
| 418 if not settings: | 420 if not settings: |
| 419 # Happens when git_cl.py is used as a utility library. | 421 # Happens when git_cl.py is used as a utility library. |
| 420 settings = Settings() | 422 settings = Settings() |
| 421 settings.GetDefaultServerUrl() | 423 settings.GetDefaultServerUrl() |
| 422 self.branchref = branchref | 424 self.branchref = branchref |
| 423 if self.branchref: | 425 if self.branchref: |
| 424 self.branch = ShortBranchName(self.branchref) | 426 self.branch = ShortBranchName(self.branchref) |
| 425 else: | 427 else: |
| 426 self.branch = None | 428 self.branch = None |
| 427 self.rietveld_server = None | 429 self.rietveld_server = None |
| 428 self.upstream_branch = None | 430 self.upstream_branch = None |
| 429 self.has_issue = False | 431 self.lookedup_issue = False |
| 430 self.issue = None | 432 self.issue = issue or None |
| 431 self.has_description = False | 433 self.has_description = False |
| 432 self.description = None | 434 self.description = None |
| 433 self.has_patchset = False | 435 self.lookedup_patchset = False |
| 434 self.patchset = None | 436 self.patchset = None |
| 435 self._rpc_server = None | 437 self._rpc_server = None |
| 436 self.cc = None | 438 self.cc = None |
| 437 self.watchers = () | 439 self.watchers = () |
| 438 self._remote = None | 440 self._remote = None |
| 441 self._props = None | |
| 439 | 442 |
| 440 def GetCCList(self): | 443 def GetCCList(self): |
| 441 """Return the users cc'd on this CL. | 444 """Return the users cc'd on this CL. |
| 442 | 445 |
| 443 Return is a string suitable for passing to gcl with the --cc flag. | 446 Return is a string suitable for passing to gcl with the --cc flag. |
| 444 """ | 447 """ |
| 445 if self.cc is None: | 448 if self.cc is None: |
| 446 base_cc = settings .GetDefaultCCList() | 449 base_cc = settings .GetDefaultCCList() |
| 447 more_cc = ','.join(self.watchers) | 450 more_cc = ','.join(self.watchers) |
| 448 self.cc = ','.join(filter(None, (base_cc, more_cc))) or '' | 451 self.cc = ','.join(filter(None, (base_cc, more_cc))) or '' |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 594 def GetRemoteUrl(self): | 597 def GetRemoteUrl(self): |
| 595 """Return the configured remote URL, e.g. 'git://example.org/foo.git/'. | 598 """Return the configured remote URL, e.g. 'git://example.org/foo.git/'. |
| 596 | 599 |
| 597 Returns None if there is no remote. | 600 Returns None if there is no remote. |
| 598 """ | 601 """ |
| 599 remote, _ = self.GetRemoteBranch() | 602 remote, _ = self.GetRemoteBranch() |
| 600 return RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() | 603 return RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() |
| 601 | 604 |
| 602 def GetIssue(self): | 605 def GetIssue(self): |
| 603 """Returns the issue number as a int or None if not set.""" | 606 """Returns the issue number as a int or None if not set.""" |
| 604 if not self.has_issue: | 607 if self.issue is None and not self.lookedup_issue: |
| 605 issue = RunGit(['config', self._IssueSetting()], error_ok=True).strip() | 608 issue = RunGit(['config', self._IssueSetting()], error_ok=True).strip() |
| 606 if issue: | 609 self.issue = int(issue) or None if issue else None |
| 607 self.issue = int(issue) | 610 self.lookedup_issue = True |
| 608 else: | |
| 609 self.issue = None | |
| 610 self.has_issue = True | |
| 611 return self.issue | 611 return self.issue |
| 612 | 612 |
| 613 def GetRietveldServer(self): | 613 def GetRietveldServer(self): |
| 614 if not self.rietveld_server: | 614 if not self.rietveld_server: |
| 615 # If we're on a branch then get the server potentially associated | 615 # If we're on a branch then get the server potentially associated |
| 616 # with that branch. | 616 # with that branch. |
| 617 if self.GetIssue(): | 617 if self.GetIssue(): |
| 618 self.rietveld_server = gclient_utils.UpgradeToHttps(RunGit( | 618 self.rietveld_server = gclient_utils.UpgradeToHttps(RunGit( |
| 619 ['config', self._RietveldServer()], error_ok=True).strip()) | 619 ['config', self._RietveldServer()], error_ok=True).strip()) |
| 620 if not self.rietveld_server: | 620 if not self.rietveld_server: |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 649 '\nFailed to fetch issue description. HTTP error ' + e.code) | 649 '\nFailed to fetch issue description. HTTP error ' + e.code) |
| 650 self.has_description = True | 650 self.has_description = True |
| 651 if pretty: | 651 if pretty: |
| 652 wrapper = textwrap.TextWrapper() | 652 wrapper = textwrap.TextWrapper() |
| 653 wrapper.initial_indent = wrapper.subsequent_indent = ' ' | 653 wrapper.initial_indent = wrapper.subsequent_indent = ' ' |
| 654 return wrapper.fill(self.description) | 654 return wrapper.fill(self.description) |
| 655 return self.description | 655 return self.description |
| 656 | 656 |
| 657 def GetPatchset(self): | 657 def GetPatchset(self): |
| 658 """Returns the patchset number as a int or None if not set.""" | 658 """Returns the patchset number as a int or None if not set.""" |
| 659 if not self.has_patchset: | 659 if self.patchset is None and not self.lookedup_patchset: |
| 660 patchset = RunGit(['config', self._PatchsetSetting()], | 660 patchset = RunGit(['config', self._PatchsetSetting()], |
| 661 error_ok=True).strip() | 661 error_ok=True).strip() |
| 662 if patchset: | 662 self.patchset = int(patchset) or None if patchset else None |
| 663 self.patchset = int(patchset) | 663 self.lookedup_patchset = True |
| 664 else: | |
| 665 self.patchset = None | |
| 666 self.has_patchset = True | |
| 667 return self.patchset | 664 return self.patchset |
| 668 | 665 |
| 669 def SetPatchset(self, patchset): | 666 def SetPatchset(self, patchset): |
| 670 """Set this branch's patchset. If patchset=0, clears the patchset.""" | 667 """Set this branch's patchset. If patchset=0, clears the patchset.""" |
| 671 if patchset: | 668 if patchset: |
| 672 RunGit(['config', self._PatchsetSetting(), str(patchset)]) | 669 RunGit(['config', self._PatchsetSetting(), str(patchset)]) |
| 670 self.patchset = patchset | |
| 673 else: | 671 else: |
| 674 RunGit(['config', '--unset', self._PatchsetSetting()], | 672 RunGit(['config', '--unset', self._PatchsetSetting()], |
| 675 stderr=subprocess2.PIPE, error_ok=True) | 673 stderr=subprocess2.PIPE, error_ok=True) |
| 676 self.has_patchset = False | 674 self.patchset = None |
| 677 | 675 |
| 678 def GetMostRecentPatchset(self, issue): | 676 def GetMostRecentPatchset(self): |
| 679 return self.RpcServer().get_issue_properties( | 677 return self.GetIssueProperties()['patchsets'][-1] |
| 680 int(issue), False)['patchsets'][-1] | |
| 681 | 678 |
| 682 def GetPatchSetDiff(self, issue, patchset): | 679 def GetPatchSetDiff(self, issue, patchset): |
| 683 return self.RpcServer().get( | 680 return self.RpcServer().get( |
| 684 '/download/issue%s_%s.diff' % (issue, patchset)) | 681 '/download/issue%s_%s.diff' % (issue, patchset)) |
| 685 | 682 |
| 683 def GetIssueProperties(self): | |
| 684 if self._props is None: | |
| 685 issue = self.GetIssue() | |
| 686 if not issue: | |
| 687 self._props = {} | |
| 688 else: | |
| 689 self._props = self.RpcServer().get_issue_properties(issue, True) | |
| 690 return self._props | |
| 691 | |
| 686 def GetApprovingReviewers(self): | 692 def GetApprovingReviewers(self): |
| 687 return get_approving_reviewers( | 693 return get_approving_reviewers(self.GetIssueProperties()) |
| 688 self.RpcServer().get_issue_properties(self.GetIssue(), True)) | |
| 689 | 694 |
| 690 def SetIssue(self, issue): | 695 def SetIssue(self, issue): |
| 691 """Set this branch's issue. If issue=0, clears the issue.""" | 696 """Set this branch's issue. If issue=0, clears the issue.""" |
| 692 if issue: | 697 if issue: |
| 698 self.issue = issue | |
| 693 RunGit(['config', self._IssueSetting(), str(issue)]) | 699 RunGit(['config', self._IssueSetting(), str(issue)]) |
| 694 if self.rietveld_server: | 700 if self.rietveld_server: |
| 695 RunGit(['config', self._RietveldServer(), self.rietveld_server]) | 701 RunGit(['config', self._RietveldServer(), self.rietveld_server]) |
| 696 else: | 702 else: |
| 697 RunGit(['config', '--unset', self._IssueSetting()]) | 703 RunGit(['config', '--unset', self._IssueSetting()]) |
| 698 self.SetPatchset(0) | 704 self.issue = None |
| 699 self.has_issue = False | 705 self.SetPatchset(None) |
| 700 | 706 |
| 701 def GetChange(self, upstream_branch, author): | 707 def GetChange(self, upstream_branch, author): |
| 702 if not self.GitSanityChecks(upstream_branch): | 708 if not self.GitSanityChecks(upstream_branch): |
| 703 DieWithError('\nGit sanity check failure') | 709 DieWithError('\nGit sanity check failure') |
| 704 | 710 |
| 705 env = os.environ.copy() | 711 env = os.environ.copy() |
| 706 # 'cat' is a magical git string that disables pagers on all platforms. | 712 # 'cat' is a magical git string that disables pagers on all platforms. |
| 707 env['GIT_PAGER'] = 'cat' | 713 env['GIT_PAGER'] = 'cat' |
| 708 | 714 |
| 709 root = RunCommand(['git', 'rev-parse', '--show-cdup'], env=env).strip() | 715 root = RunCommand(['git', 'rev-parse', '--show-cdup'], env=env).strip() |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1057 else: | 1063 else: |
| 1058 print("Setting base-url to %s" % args[0]) | 1064 print("Setting base-url to %s" % args[0]) |
| 1059 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]], | 1065 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]], |
| 1060 error_ok=False).strip() | 1066 error_ok=False).strip() |
| 1061 | 1067 |
| 1062 | 1068 |
| 1063 def CMDstatus(parser, args): | 1069 def CMDstatus(parser, args): |
| 1064 """show status of changelists""" | 1070 """show status of changelists""" |
| 1065 parser.add_option('--field', | 1071 parser.add_option('--field', |
| 1066 help='print only specific field (desc|id|patch|url)') | 1072 help='print only specific field (desc|id|patch|url)') |
| 1073 parser.add_option('-f', '--fast', action='store_true', | |
| 1074 help='Do not retrieve review status') | |
| 1067 (options, args) = parser.parse_args(args) | 1075 (options, args) = parser.parse_args(args) |
| 1068 | 1076 |
| 1069 if options.field: | 1077 if options.field: |
| 1070 cl = Changelist() | 1078 cl = Changelist() |
| 1071 if options.field.startswith('desc'): | 1079 if options.field.startswith('desc'): |
| 1072 print cl.GetDescription() | 1080 print cl.GetDescription() |
| 1073 elif options.field == 'id': | 1081 elif options.field == 'id': |
| 1074 issueid = cl.GetIssue() | 1082 issueid = cl.GetIssue() |
| 1075 if issueid: | 1083 if issueid: |
| 1076 print issueid | 1084 print issueid |
| 1077 elif options.field == 'patch': | 1085 elif options.field == 'patch': |
| 1078 patchset = cl.GetPatchset() | 1086 patchset = cl.GetPatchset() |
| 1079 if patchset: | 1087 if patchset: |
| 1080 print patchset | 1088 print patchset |
| 1081 elif options.field == 'url': | 1089 elif options.field == 'url': |
| 1082 url = cl.GetIssueURL() | 1090 url = cl.GetIssueURL() |
| 1083 if url: | 1091 if url: |
| 1084 print url | 1092 print url |
| 1085 return 0 | 1093 return 0 |
| 1086 | 1094 |
| 1087 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) | 1095 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) |
| 1088 if not branches: | 1096 if not branches: |
| 1089 print('No local branch found.') | 1097 print('No local branch found.') |
| 1090 return 0 | 1098 return 0 |
| 1091 | 1099 |
| 1092 changes = (Changelist(branchref=b) for b in branches.splitlines()) | 1100 changes = (Changelist(branchref=b) for b in branches.splitlines()) |
| 1093 branches = dict((c.GetBranch(), c.GetIssueURL()) for c in changes) | 1101 branches = dict((c.GetBranch(), c.GetIssueURL()) for c in changes) |
| 1094 alignment = max(5, max(len(b) for b in branches)) | 1102 alignment = max(5, max(len(b) for b in branches)) |
| 1095 print 'Branches associated with reviews:' | 1103 print 'Branches associated with reviews:' |
| 1104 # Adhoc thread pool to request data concurrently. | |
| 1105 output = Queue.Queue() | |
| 1106 | |
| 1107 # Silence upload.py otherwise it becomes unweldly. | |
| 1108 upload.verbosity = 0 | |
| 1109 | |
| 1110 if not options.fast: | |
| 1111 def fetch(b): | |
| 1112 c = Changelist(branchref=b) | |
| 1113 i = c.GetIssueURL() | |
| 1114 try: | |
| 1115 props = c.GetIssueProperties() | |
| 1116 r = c.GetApprovingReviewers() if i else None | |
| 1117 if not props.get('messages'): | |
| 1118 r = None | |
| 1119 except urllib2.HTTPError: | |
| 1120 # The issue probably doesn't exist anymore. | |
| 1121 i += ' (broken)' | |
| 1122 r = None | |
| 1123 output.put((b, i, r)) | |
| 1124 | |
| 1125 threads = [threading.Thread(target=fetch, args=(b,)) for b in branches] | |
| 1126 for t in threads: | |
| 1127 t.daemon = True | |
| 1128 t.start() | |
| 1129 else: | |
| 1130 # Do not use GetApprovingReviewers(), since it requires an HTTP request. | |
| 1131 for b in branches: | |
| 1132 c = Changelist(branchref=b) | |
| 1133 output.put((b, c.GetIssue(), None)) | |
| 1134 | |
| 1135 tmp = {} | |
| 1136 alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) | |
| 1096 for branch in sorted(branches): | 1137 for branch in sorted(branches): |
| 1097 print " %*s: %s" % (alignment, branch, branches[branch]) | 1138 while branch not in tmp: |
| 1139 b, i, r = output.get() | |
| 1140 tmp[b] = (i, r) | |
| 1141 issue, reviewers = tmp.pop(branch) | |
| 1142 if not issue: | |
| 1143 color = Fore.WHITE | |
| 1144 elif reviewers: | |
| 1145 # Was approved. | |
| 1146 color = Fore.GREEN | |
| 1147 elif reviewers is None: | |
| 1148 # No message was sent. | |
| 1149 color = Fore.RED | |
| 1150 else: | |
| 1151 color = Fore.BLUE | |
| 1152 print ' %*s: %s%s%s' % ( | |
| 1153 alignment, ShortBranchName(branch), color, issue, Fore.RESET) | |
| 1154 | |
| 1098 cl = Changelist() | 1155 cl = Changelist() |
| 1099 print | 1156 print |
| 1100 print 'Current branch:', | 1157 print 'Current branch:', |
| 1101 if not cl.GetIssue(): | 1158 if not cl.GetIssue(): |
| 1102 print 'no issue assigned.' | 1159 print 'no issue assigned.' |
| 1103 return 0 | 1160 return 0 |
| 1104 print cl.GetBranch() | 1161 print cl.GetBranch() |
| 1105 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) | 1162 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) |
| 1106 print 'Issue description:' | 1163 print 'Issue description:' |
| 1107 print cl.GetDescription(pretty=True) | 1164 print cl.GetDescription(pretty=True) |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1129 | 1186 |
| 1130 | 1187 |
| 1131 def CMDcomments(parser, args): | 1188 def CMDcomments(parser, args): |
| 1132 """show review comments of the current changelist""" | 1189 """show review comments of the current changelist""" |
| 1133 (_, args) = parser.parse_args(args) | 1190 (_, args) = parser.parse_args(args) |
| 1134 if args: | 1191 if args: |
| 1135 parser.error('Unsupported argument: %s' % args) | 1192 parser.error('Unsupported argument: %s' % args) |
| 1136 | 1193 |
| 1137 cl = Changelist() | 1194 cl = Changelist() |
| 1138 if cl.GetIssue(): | 1195 if cl.GetIssue(): |
| 1139 data = cl.RpcServer().get_issue_properties(cl.GetIssue(), True) | 1196 data = cl.GetIssueProperties() |
| 1140 for message in sorted(data['messages'], key=lambda x: x['date']): | 1197 for message in sorted(data['messages'], key=lambda x: x['date']): |
| 1141 if message['disapproval']: | 1198 if message['disapproval']: |
| 1142 color = Fore.RED | 1199 color = Fore.RED |
| 1143 elif message['approval']: | 1200 elif message['approval']: |
| 1144 color = Fore.GREEN | 1201 color = Fore.GREEN |
| 1145 elif message['sender'] == data['owner_email']: | 1202 elif message['sender'] == data['owner_email']: |
| 1146 color = Fore.MAGENTA | 1203 color = Fore.MAGENTA |
| 1147 else: | 1204 else: |
| 1148 color = Fore.BLUE | 1205 color = Fore.BLUE |
| 1149 print '\n%s%s %s%s' % ( | 1206 print '\n%s%s %s%s' % ( |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1427 hook_results = cl.RunHook(committing=False, | 1484 hook_results = cl.RunHook(committing=False, |
| 1428 may_prompt=not options.force, | 1485 may_prompt=not options.force, |
| 1429 verbose=options.verbose, | 1486 verbose=options.verbose, |
| 1430 change=change) | 1487 change=change) |
| 1431 if not hook_results.should_continue(): | 1488 if not hook_results.should_continue(): |
| 1432 return 1 | 1489 return 1 |
| 1433 if not options.reviewers and hook_results.reviewers: | 1490 if not options.reviewers and hook_results.reviewers: |
| 1434 options.reviewers = hook_results.reviewers.split(',') | 1491 options.reviewers = hook_results.reviewers.split(',') |
| 1435 | 1492 |
| 1436 if cl.GetIssue(): | 1493 if cl.GetIssue(): |
| 1437 latest_patchset = cl.GetMostRecentPatchset(cl.GetIssue()) | 1494 latest_patchset = cl.GetMostRecentPatchset() |
| 1438 local_patchset = cl.GetPatchset() | 1495 local_patchset = cl.GetPatchset() |
| 1439 if latest_patchset and local_patchset and local_patchset != latest_patchset: | 1496 if latest_patchset and local_patchset and local_patchset != latest_patchset: |
| 1440 print ('The last upload made from this repository was patchset #%d but ' | 1497 print ('The last upload made from this repository was patchset #%d but ' |
| 1441 'the most recent patchset on the server is #%d.' | 1498 'the most recent patchset on the server is #%d.' |
| 1442 % (local_patchset, latest_patchset)) | 1499 % (local_patchset, latest_patchset)) |
| 1443 print ('Uploading will still work, but if you\'ve uploaded to this issue ' | 1500 print ('Uploading will still work, but if you\'ve uploaded to this issue ' |
| 1444 'from another machine or branch the patch you\'re uploading now ' | 1501 'from another machine or branch the patch you\'re uploading now ' |
| 1445 'might not include those changes.') | 1502 'might not include those changes.') |
| 1446 ask_for_data('About to upload; enter to confirm.') | 1503 ask_for_data('About to upload; enter to confirm.') |
| 1447 | 1504 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1666 return 1 | 1723 return 1 |
| 1667 viewvc_url = settings.GetViewVCUrl() | 1724 viewvc_url = settings.GetViewVCUrl() |
| 1668 if viewvc_url and revision: | 1725 if viewvc_url and revision: |
| 1669 change_desc.append_footer('Committed: ' + viewvc_url + revision) | 1726 change_desc.append_footer('Committed: ' + viewvc_url + revision) |
| 1670 elif revision: | 1727 elif revision: |
| 1671 change_desc.append_footer('Committed: ' + revision) | 1728 change_desc.append_footer('Committed: ' + revision) |
| 1672 print ('Closing issue ' | 1729 print ('Closing issue ' |
| 1673 '(you may be prompted for your codereview password)...') | 1730 '(you may be prompted for your codereview password)...') |
| 1674 cl.UpdateDescription(change_desc.description) | 1731 cl.UpdateDescription(change_desc.description) |
| 1675 cl.CloseIssue() | 1732 cl.CloseIssue() |
| 1676 props = cl.RpcServer().get_issue_properties(cl.GetIssue(), False) | 1733 props = cl.GetIssueProperties() |
| 1677 patch_num = len(props['patchsets']) | 1734 patch_num = len(props['patchsets']) |
| 1678 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) | 1735 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) |
| 1679 comment += ' (presubmit successful).' if not options.bypass_hooks else '.' | 1736 comment += ' (presubmit successful).' if not options.bypass_hooks else '.' |
| 1680 cl.RpcServer().add_comment(cl.GetIssue(), comment) | 1737 cl.RpcServer().add_comment(cl.GetIssue(), comment) |
| 1681 cl.SetIssue(0) | 1738 cl.SetIssue(None) |
|
iannucci
2013/07/23 21:19:25
if you git cl issue 0, will that still do the righ
M-A Ruel
2013/07/23 23:22:29
Yes, tested.
| |
| 1682 | 1739 |
| 1683 if retcode == 0: | 1740 if retcode == 0: |
| 1684 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 1741 hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
| 1685 if os.path.isfile(hook): | 1742 if os.path.isfile(hook): |
| 1686 RunCommand([hook, base_branch], error_ok=True) | 1743 RunCommand([hook, base_branch], error_ok=True) |
| 1687 | 1744 |
| 1688 return 0 | 1745 return 0 |
| 1689 | 1746 |
| 1690 | 1747 |
| 1691 @usage('[upstream branch to apply against]') | 1748 @usage('[upstream branch to apply against]') |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1730 if len(args) != 1: | 1787 if len(args) != 1: |
| 1731 parser.print_help() | 1788 parser.print_help() |
| 1732 return 1 | 1789 return 1 |
| 1733 issue_arg = args[0] | 1790 issue_arg = args[0] |
| 1734 | 1791 |
| 1735 # TODO(maruel): Use apply_issue.py | 1792 # TODO(maruel): Use apply_issue.py |
| 1736 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? | 1793 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? |
| 1737 | 1794 |
| 1738 if issue_arg.isdigit(): | 1795 if issue_arg.isdigit(): |
| 1739 # Input is an issue id. Figure out the URL. | 1796 # Input is an issue id. Figure out the URL. |
| 1740 cl = Changelist() | |
| 1741 issue = int(issue_arg) | 1797 issue = int(issue_arg) |
| 1742 patchset = cl.GetMostRecentPatchset(issue) | 1798 cl = Changelist(issue) |
| 1799 patchset = cl.GetMostRecentPatchset() | |
| 1743 patch_data = cl.GetPatchSetDiff(issue, patchset) | 1800 patch_data = cl.GetPatchSetDiff(issue, patchset) |
| 1744 else: | 1801 else: |
| 1745 # Assume it's a URL to the patch. Default to https. | 1802 # Assume it's a URL to the patch. Default to https. |
| 1746 issue_url = gclient_utils.UpgradeToHttps(issue_arg) | 1803 issue_url = gclient_utils.UpgradeToHttps(issue_arg) |
| 1747 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) | 1804 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) |
| 1748 if not match: | 1805 if not match: |
| 1749 DieWithError('Must pass an issue ID or full URL for ' | 1806 DieWithError('Must pass an issue ID or full URL for ' |
| 1750 '\'Download raw patch set\'') | 1807 '\'Download raw patch set\'') |
| 1751 issue = int(match.group(1)) | 1808 issue = int(match.group(1)) |
| 1752 patchset = int(match.group(2)) | 1809 patchset = int(match.group(2)) |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1939 if any('triggered' in b for b in builders_and_tests): | 1996 if any('triggered' in b for b in builders_and_tests): |
| 1940 print >> sys.stderr, ( | 1997 print >> sys.stderr, ( |
| 1941 'ERROR You are trying to send a job to a triggered bot. This type of' | 1998 'ERROR You are trying to send a job to a triggered bot. This type of' |
| 1942 ' bot requires an\ninitial job from a parent (usually a builder). ' | 1999 ' bot requires an\ninitial job from a parent (usually a builder). ' |
| 1943 'Instead send your job to the parent.\n' | 2000 'Instead send your job to the parent.\n' |
| 1944 'Bot list: %s' % builders_and_tests) | 2001 'Bot list: %s' % builders_and_tests) |
| 1945 return 1 | 2002 return 1 |
| 1946 | 2003 |
| 1947 patchset = cl.GetPatchset() | 2004 patchset = cl.GetPatchset() |
| 1948 if not cl.GetPatchset(): | 2005 if not cl.GetPatchset(): |
| 1949 patchset = cl.GetMostRecentPatchset(cl.GetIssue()) | 2006 patchset = cl.GetMostRecentPatchset() |
| 1950 | 2007 |
| 1951 cl.RpcServer().trigger_try_jobs( | 2008 cl.RpcServer().trigger_try_jobs( |
| 1952 cl.GetIssue(), patchset, options.name, options.clobber, options.revision, | 2009 cl.GetIssue(), patchset, options.name, options.clobber, options.revision, |
| 1953 builders_and_tests) | 2010 builders_and_tests) |
| 1954 print('Tried jobs on:') | 2011 print('Tried jobs on:') |
| 1955 length = max(len(builder) for builder in builders_and_tests) | 2012 length = max(len(builder) for builder in builders_and_tests) |
| 1956 for builder in sorted(builders_and_tests): | 2013 for builder in sorted(builders_and_tests): |
| 1957 print ' %*s: %s' % (length, builder, ','.join(builders_and_tests[builder])) | 2014 print ' %*s: %s' % (length, builder, ','.join(builders_and_tests[builder])) |
| 1958 return 0 | 2015 return 0 |
| 1959 | 2016 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2177 GenUsage(parser, 'help') | 2234 GenUsage(parser, 'help') |
| 2178 return CMDhelp(parser, argv) | 2235 return CMDhelp(parser, argv) |
| 2179 | 2236 |
| 2180 | 2237 |
| 2181 if __name__ == '__main__': | 2238 if __name__ == '__main__': |
| 2182 # These affect sys.stdout so do it outside of main() to simplify mocks in | 2239 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 2183 # unit testing. | 2240 # unit testing. |
| 2184 fix_encoding.fix_encoding() | 2241 fix_encoding.fix_encoding() |
| 2185 colorama.init() | 2242 colorama.init() |
| 2186 sys.exit(main(sys.argv[1:])) | 2243 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |