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 json | 10 import json |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 | 47 |
| 48 | 48 |
| 49 def DieWithError(message): | 49 def DieWithError(message): |
| 50 print >> sys.stderr, message | 50 print >> sys.stderr, message |
| 51 sys.exit(1) | 51 sys.exit(1) |
| 52 | 52 |
| 53 | 53 |
| 54 def RunCommand(args, error_ok=False, error_message=None, **kwargs): | 54 def RunCommand(args, error_ok=False, error_message=None, **kwargs): |
| 55 try: | 55 try: |
| 56 return subprocess2.check_output(args, shell=False, **kwargs) | 56 return subprocess2.check_output(args, shell=False, **kwargs) |
| 57 except subprocess2.CalledProcessError, e: | 57 except subprocess2.CalledProcessError as e: |
| 58 logging.debug('Failed running %s', args) | |
| 58 if not error_ok: | 59 if not error_ok: |
| 59 DieWithError( | 60 DieWithError( |
| 60 'Command "%s" failed.\n%s' % ( | 61 'Command "%s" failed.\n%s' % ( |
| 61 ' '.join(args), error_message or e.stdout or '')) | 62 ' '.join(args), error_message or e.stdout or '')) |
| 62 return e.stdout | 63 return e.stdout |
| 63 | 64 |
| 64 | 65 |
| 65 def RunGit(args, **kwargs): | 66 def RunGit(args, **kwargs): |
| 66 """Returns stdout.""" | 67 """Returns stdout.""" |
| 67 return RunCommand(['git'] + args, **kwargs) | 68 return RunCommand(['git'] + args, **kwargs) |
| (...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 790 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', | 791 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', |
| 791 'tree-status-url', False) | 792 'tree-status-url', False) |
| 792 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) | 793 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) |
| 793 | 794 |
| 794 # TODO: configure a default branch to diff against, rather than this | 795 # TODO: configure a default branch to diff against, rather than this |
| 795 # svn-based hackery. | 796 # svn-based hackery. |
| 796 | 797 |
| 797 | 798 |
| 798 class ChangeDescription(object): | 799 class ChangeDescription(object): |
| 799 """Contains a parsed form of the change description.""" | 800 """Contains a parsed form of the change description.""" |
| 800 def __init__(self, log_desc, reviewers): | 801 R_LINE = r'^\s*(TBR|R)\s*=\s*(.+)\s*$' |
| 801 self.log_desc = log_desc | |
| 802 self.reviewers = reviewers | |
| 803 self.description = self.log_desc | |
| 804 | 802 |
| 805 def Prompt(self): | 803 def __init__(self, description): |
| 806 content = """# Enter a description of the change. | 804 self._description = (description or '').strip() |
| 807 # This will displayed on the codereview site. | 805 |
| 808 # The first line will also be used as the subject of the review. | 806 @property |
| 809 """ | 807 def description(self): |
| 810 content += self.description | 808 return self._description |
| 811 if ('\nR=' not in self.description and | 809 |
| 812 '\nTBR=' not in self.description and | 810 def update_reviewers(self, reviewers): |
|
iannucci
2013/04/08 22:49:40
Can we make reviewers a list of reviewers instead
Dirk Pranke
2013/04/09 00:07:52
I don't think we can easily do this without pushin
M-A Ruel
2013/04/11 00:01:38
So reviewers is now a list all the time.
| |
| 813 self.reviewers): | 811 """Rewrites the R=/TBR= line(s) as a single line.""" |
| 814 content += '\nR=' + self.reviewers | 812 if not reviewers: |
| 813 return | |
| 814 regexp = re.compile(self.R_LINE, re.MULTILINE) | |
| 815 matches = list(regexp.finditer(self.description)) | |
| 816 is_tbr = any(m.group(1) == 'TBR' for m in matches) | |
| 817 if len(matches) > 1: | |
| 818 # Erase all except the first one. | |
| 819 for i in xrange(len(matches) - 1, 0, -1): | |
| 820 self._description = ( | |
| 821 self.description[:matches[i].start()] + | |
| 822 self.description[matches[i].end()+1:]) | |
|
Dirk Pranke
2013/04/09 00:07:52
switching back and forth between self._description
M-A Ruel
2013/04/11 00:01:38
Done.
| |
| 823 | |
| 824 if is_tbr: | |
| 825 new_r_line = 'TBR=' + reviewers | |
| 826 else: | |
| 827 new_r_line = 'R=' + reviewers | |
| 828 | |
| 829 if matches: | |
| 830 self._description = ( | |
| 831 self.description[:matches[0].start()] + new_r_line + | |
| 832 self.description[matches[0].end()+1:]) | |
| 833 else: | |
| 834 self.append_line(new_r_line) | |
| 835 | |
| 836 def prompt(self): | |
| 837 """Asks the user to update the description.""" | |
| 838 self._description = ( | |
| 839 '# Enter a description of the change.\n' | |
| 840 '# This will displayed on the codereview site.\n' | |
| 841 '# The first line will also be used as the subject of the review.\n' | |
| 842 ) + self.description | |
| 843 | |
| 815 if '\nBUG=' not in self.description: | 844 if '\nBUG=' not in self.description: |
| 816 content += '\nBUG=' | 845 self.append_line('BUG=') |
| 817 content = content.rstrip('\n') + '\n' | 846 content = gclient_utils.RunEditor(self.description, True) |
| 818 content = gclient_utils.RunEditor(content, True) | |
| 819 if not content: | 847 if not content: |
| 820 DieWithError('Running editor failed') | 848 DieWithError('Running editor failed') |
| 849 | |
| 850 # Strip off comments. | |
| 821 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() | 851 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() |
| 822 if not content.strip(): | 852 if not content: |
| 823 DieWithError('No CL description, aborting') | 853 DieWithError('No CL description, aborting') |
| 824 self.description = content | 854 self._description = content |
| 825 | 855 |
| 826 def ParseDescription(self): | 856 def append_line(self, line): |
|
Dirk Pranke
2013/04/09 00:07:52
I would probably call this something like add_keyw
| |
| 827 """Updates the list of reviewers and subject from the description.""" | 857 # Adds a LF if the last line did not have 'FOO=BAR' or if the new one isn't. |
| 828 self.description = self.description.strip('\n') + '\n' | 858 if self.description: |
| 829 # Retrieves all reviewer lines | 859 if '\n' not in self.description: |
| 830 regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE) | 860 self._description += '\n' |
| 831 reviewers = ','.join( | 861 else: |
| 832 i.group(2).strip() for i in regexp.finditer(self.description)) | 862 last_line = self.description.rsplit('\n', 1)[1] |
| 833 if reviewers: | 863 if (not presubmit_support.Change.TAG_LINE_RE.match(last_line) or |
| 834 self.reviewers = reviewers | 864 not presubmit_support.Change.TAG_LINE_RE.match(line)): |
| 865 self._description += '\n' | |
| 866 self._description += '\n' + line | |
| 835 | 867 |
| 836 def IsEmpty(self): | 868 def get_reviewers(self): |
| 837 return not self.description | 869 """Retrieves the list of reviewers.""" |
| 870 regexp = re.compile(self.R_LINE, re.MULTILINE) | |
| 871 reviewers = sum( | |
| 872 (i.group(2).split(',') for i in regexp.finditer(self.description)), | |
| 873 []) | |
| 874 reviewers = (i.strip() for i in reviewers) | |
| 875 return sorted(i for i in reviewers if i) | |
| 838 | 876 |
| 839 | 877 |
| 840 def FindCodereviewSettingsFile(filename='codereview.settings'): | 878 def FindCodereviewSettingsFile(filename='codereview.settings'): |
| 841 """Finds the given file starting in the cwd and going up. | 879 """Finds the given file starting in the cwd and going up. |
| 842 | 880 |
| 843 Only looks up to the top of the repository unless an | 881 Only looks up to the top of the repository unless an |
| 844 'inherit-review-settings-ok' file exists in the root of the repository. | 882 'inherit-review-settings-ok' file exists in the root of the repository. |
| 845 """ | 883 """ |
| 846 inherit_ok_file = 'inherit-review-settings-ok' | 884 inherit_ok_file = 'inherit-review-settings-ok' |
| 847 cwd = os.getcwd() | 885 cwd = os.getcwd() |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1095 | 1133 |
| 1096 def GerritUpload(options, args, cl): | 1134 def GerritUpload(options, args, cl): |
| 1097 """upload the current branch to gerrit.""" | 1135 """upload the current branch to gerrit.""" |
| 1098 # We assume the remote called "origin" is the one we want. | 1136 # We assume the remote called "origin" is the one we want. |
| 1099 # It is probably not worthwhile to support different workflows. | 1137 # It is probably not worthwhile to support different workflows. |
| 1100 remote = 'origin' | 1138 remote = 'origin' |
| 1101 branch = 'master' | 1139 branch = 'master' |
| 1102 if options.target_branch: | 1140 if options.target_branch: |
| 1103 branch = options.target_branch | 1141 branch = options.target_branch |
| 1104 | 1142 |
| 1105 log_desc = options.message or CreateDescriptionFromLog(args) | 1143 change_desc = ChangeDescription( |
| 1106 if CHANGE_ID not in log_desc: | 1144 options.message or CreateDescriptionFromLog(args)) |
| 1145 if not change_desc.description: | |
| 1146 print "Description is empty; aborting." | |
| 1147 return 1 | |
| 1148 if CHANGE_ID not in change_desc.description: | |
|
Dirk Pranke
2013/04/09 00:07:52
I wonder if we should restructure this so that we
M-A Ruel
2013/04/11 00:01:38
I prefer to keep this out of this CL since it invo
| |
| 1107 AddChangeIdToCommitMessage(options, args) | 1149 AddChangeIdToCommitMessage(options, args) |
| 1108 if options.reviewers: | 1150 if options.reviewers: |
| 1109 log_desc += '\nR=' + options.reviewers | 1151 change_desc.update_reviewers(options.reviewers) |
| 1110 change_desc = ChangeDescription(log_desc, options.reviewers) | |
| 1111 change_desc.ParseDescription() | |
| 1112 if change_desc.IsEmpty(): | |
| 1113 print "Description is empty; aborting." | |
| 1114 return 1 | |
| 1115 | 1152 |
| 1116 receive_options = [] | 1153 receive_options = [] |
| 1117 cc = cl.GetCCList().split(',') | 1154 cc = cl.GetCCList().split(',') |
| 1118 if options.cc: | 1155 if options.cc: |
| 1119 cc += options.cc.split(',') | 1156 cc += options.cc.split(',') |
| 1120 cc = filter(None, cc) | 1157 cc = filter(None, cc) |
| 1121 if cc: | 1158 if cc: |
| 1122 receive_options += ['--cc=' + email for email in cc] | 1159 receive_options += ['--cc=' + email for email in cc] |
| 1123 if change_desc.reviewers: | 1160 if change_desc.get_reviewers(): |
| 1124 reviewers = filter(None, change_desc.reviewers.split(',')) | 1161 receive_options.extend( |
| 1125 if reviewers: | 1162 '--reviewer=' + email for email in change_desc.get_reviewers()) |
| 1126 receive_options += ['--reviewer=' + email for email in reviewers] | |
| 1127 | 1163 |
| 1128 git_command = ['push'] | 1164 git_command = ['push'] |
| 1129 if receive_options: | 1165 if receive_options: |
| 1130 git_command.append('--receive-pack=git receive-pack %s' % | 1166 git_command.append('--receive-pack=git receive-pack %s' % |
| 1131 ' '.join(receive_options)) | 1167 ' '.join(receive_options)) |
| 1132 git_command += [remote, 'HEAD:refs/for/' + branch] | 1168 git_command += [remote, 'HEAD:refs/for/' + branch] |
| 1133 RunGit(git_command) | 1169 RunGit(git_command) |
| 1134 # TODO(ukai): parse Change-Id: and set issue number? | 1170 # TODO(ukai): parse Change-Id: and set issue number? |
| 1135 return 0 | 1171 return 0 |
| 1136 | 1172 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1152 # for upload.py. Soon this will be changed to set the --message option. | 1188 # for upload.py. Soon this will be changed to set the --message option. |
| 1153 # Will wait until people are used to typing -t instead of -m. | 1189 # Will wait until people are used to typing -t instead of -m. |
| 1154 upload_args.extend(['--title', options.message]) | 1190 upload_args.extend(['--title', options.message]) |
| 1155 upload_args.extend(['--issue', str(cl.GetIssue())]) | 1191 upload_args.extend(['--issue', str(cl.GetIssue())]) |
| 1156 print ("This branch is associated with issue %s. " | 1192 print ("This branch is associated with issue %s. " |
| 1157 "Adding patch to that issue." % cl.GetIssue()) | 1193 "Adding patch to that issue." % cl.GetIssue()) |
| 1158 else: | 1194 else: |
| 1159 if options.title: | 1195 if options.title: |
| 1160 upload_args.extend(['--title', options.title]) | 1196 upload_args.extend(['--title', options.title]) |
| 1161 message = options.title or options.message or CreateDescriptionFromLog(args) | 1197 message = options.title or options.message or CreateDescriptionFromLog(args) |
| 1162 change_desc = ChangeDescription(message, options.reviewers) | 1198 change_desc = ChangeDescription(message) |
| 1199 if options.reviewers: | |
| 1200 change_desc.update_reviewers(options.reviewers) | |
| 1163 if not options.force: | 1201 if not options.force: |
| 1164 change_desc.Prompt() | 1202 change_desc.prompt() |
| 1165 change_desc.ParseDescription() | |
| 1166 | 1203 |
| 1167 if change_desc.IsEmpty(): | 1204 if not change_desc.description: |
| 1168 print "Description is empty; aborting." | 1205 print "Description is empty; aborting." |
| 1169 return 1 | 1206 return 1 |
| 1170 | 1207 |
| 1171 upload_args.extend(['--message', change_desc.description]) | 1208 upload_args.extend(['--message', change_desc.description]) |
| 1172 if change_desc.reviewers: | 1209 if change_desc.get_reviewers(): |
| 1173 upload_args.extend(['--reviewers', change_desc.reviewers]) | 1210 upload_args.append('--reviewers=' + ','.join(change_desc.get_reviewers())) |
| 1174 if options.send_mail: | 1211 if options.send_mail: |
| 1175 if not change_desc.reviewers: | 1212 if not change_desc.get_reviewers(): |
| 1176 DieWithError("Must specify reviewers to send email.") | 1213 DieWithError("Must specify reviewers to send email.") |
| 1177 upload_args.append('--send_mail') | 1214 upload_args.append('--send_mail') |
| 1178 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) | 1215 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) |
| 1179 if cc: | 1216 if cc: |
| 1180 upload_args.extend(['--cc', cc]) | 1217 upload_args.extend(['--cc', cc]) |
| 1181 | 1218 |
| 1182 upload_args.extend(['--git_similarity', str(options.similarity)]) | 1219 upload_args.extend(['--git_similarity', str(options.similarity)]) |
| 1183 if not options.find_copies: | 1220 if not options.find_copies: |
| 1184 upload_args.extend(['--git_no_find_copies']) | 1221 upload_args.extend(['--git_no_find_copies']) |
| 1185 | 1222 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1409 elif 'unknown' == status: | 1446 elif 'unknown' == status: |
| 1410 print('Unable to determine tree status. Please verify manually and ' | 1447 print('Unable to determine tree status. Please verify manually and ' |
| 1411 'use "git cl dcommit --bypass-hooks" to commit on a closed tree.') | 1448 'use "git cl dcommit --bypass-hooks" to commit on a closed tree.') |
| 1412 else: | 1449 else: |
| 1413 breakpad.SendStack( | 1450 breakpad.SendStack( |
| 1414 'GitClHooksBypassedCommit', | 1451 'GitClHooksBypassedCommit', |
| 1415 'Issue %s/%s bypassed hook when committing' % | 1452 'Issue %s/%s bypassed hook when committing' % |
| 1416 (cl.GetRietveldServer(), cl.GetIssue()), | 1453 (cl.GetRietveldServer(), cl.GetIssue()), |
| 1417 verbose=False) | 1454 verbose=False) |
| 1418 | 1455 |
| 1419 description = options.message | 1456 change_desc = ChangeDescription(options.message) |
| 1420 if not description and cl.GetIssue(): | 1457 if not change_desc.description and cl.GetIssue(): |
| 1421 description = cl.GetDescription() | 1458 change_desc = ChangeDescription(cl.GetDescription()) |
| 1422 | 1459 |
| 1423 if not description: | 1460 if not change_desc.description: |
| 1424 if not cl.GetIssue() and options.bypass_hooks: | 1461 if not cl.GetIssue() and options.bypass_hooks: |
| 1425 description = CreateDescriptionFromLog([base_branch]) | 1462 change_desc = ChangeDescription(CreateDescriptionFromLog([base_branch])) |
| 1426 else: | 1463 else: |
| 1427 print 'No description set.' | 1464 print 'No description set.' |
| 1428 print 'Visit %s/edit to set it.' % (cl.GetIssueURL()) | 1465 print 'Visit %s/edit to set it.' % (cl.GetIssueURL()) |
| 1429 return 1 | 1466 return 1 |
| 1430 | 1467 |
| 1468 # Keep a separate copy for the commit message. | |
|
Dirk Pranke
2013/04/09 00:07:52
Can you clarify *why* we need a separate copy here
M-A Ruel
2013/04/11 00:01:38
Done.
| |
| 1469 commit_desc = ChangeDescription(change_desc.description) | |
| 1431 if cl.GetIssue(): | 1470 if cl.GetIssue(): |
| 1432 description += "\n\nReview URL: %s" % cl.GetIssueURL() | 1471 commit_desc.append_line('Review URL: %s' % cl.GetIssueURL()) |
| 1472 if options.contributor: | |
| 1473 commit_desc.append_line('Patch from %s.' % options.contributor) | |
| 1433 | 1474 |
| 1434 if options.contributor: | 1475 print 'Description:', repr(commit_desc.description) |
| 1435 description += "\nPatch from %s." % options.contributor | |
| 1436 print 'Description:', repr(description) | |
| 1437 | 1476 |
| 1438 branches = [base_branch, cl.GetBranchRef()] | 1477 branches = [base_branch, cl.GetBranchRef()] |
| 1439 if not options.force: | 1478 if not options.force: |
| 1440 print_stats(options.similarity, options.find_copies, branches) | 1479 print_stats(options.similarity, options.find_copies, branches) |
| 1441 ask_for_data('About to commit; enter to confirm.') | 1480 ask_for_data('About to commit; enter to confirm.') |
| 1442 | 1481 |
| 1443 # We want to squash all this branch's commits into one commit with the proper | 1482 # We want to squash all this branch's commits into one commit with the proper |
| 1444 # description. We do this by doing a "reset --soft" to the base branch (which | 1483 # description. We do this by doing a "reset --soft" to the base branch (which |
| 1445 # keeps the working copy the same), then dcommitting that. If origin/master | 1484 # keeps the working copy the same), then dcommitting that. If origin/master |
| 1446 # has a submodule merge commit, we'll also need to cherry-pick the squashed | 1485 # has a submodule merge commit, we'll also need to cherry-pick the squashed |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1462 os.chdir(rel_base_path) | 1501 os.chdir(rel_base_path) |
| 1463 | 1502 |
| 1464 # Stuff our change into the merge branch. | 1503 # Stuff our change into the merge branch. |
| 1465 # We wrap in a try...finally block so if anything goes wrong, | 1504 # We wrap in a try...finally block so if anything goes wrong, |
| 1466 # we clean up the branches. | 1505 # we clean up the branches. |
| 1467 retcode = -1 | 1506 retcode = -1 |
| 1468 try: | 1507 try: |
| 1469 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) | 1508 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) |
| 1470 RunGit(['reset', '--soft', base_branch]) | 1509 RunGit(['reset', '--soft', base_branch]) |
| 1471 if options.contributor: | 1510 if options.contributor: |
| 1472 RunGit(['commit', '--author', options.contributor, '-m', description]) | 1511 RunGit( |
| 1512 [ | |
| 1513 'commit', '--author', options.contributor, | |
| 1514 '-m', commit_desc.description, | |
| 1515 ]) | |
| 1473 else: | 1516 else: |
| 1474 RunGit(['commit', '-m', description]) | 1517 RunGit(['commit', '-m', commit_desc.description]) |
| 1475 if base_has_submodules: | 1518 if base_has_submodules: |
| 1476 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() | 1519 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() |
| 1477 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) | 1520 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) |
| 1478 RunGit(['checkout', CHERRY_PICK_BRANCH]) | 1521 RunGit(['checkout', CHERRY_PICK_BRANCH]) |
| 1479 RunGit(['cherry-pick', cherry_pick_commit]) | 1522 RunGit(['cherry-pick', cherry_pick_commit]) |
| 1480 if cmd == 'push': | 1523 if cmd == 'push': |
| 1481 # push the merge branch. | 1524 # push the merge branch. |
| 1482 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 1525 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 1483 retcode, output = RunGitWithCode( | 1526 retcode, output = RunGitWithCode( |
| 1484 ['push', '--porcelain', remote, 'HEAD:%s' % branch]) | 1527 ['push', '--porcelain', remote, 'HEAD:%s' % branch]) |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1503 for l in output.splitlines(False)) | 1546 for l in output.splitlines(False)) |
| 1504 match = filter(None, match) | 1547 match = filter(None, match) |
| 1505 if len(match) != 1: | 1548 if len(match) != 1: |
| 1506 DieWithError("Couldn't parse ouput to extract the committed hash:\n%s" % | 1549 DieWithError("Couldn't parse ouput to extract the committed hash:\n%s" % |
| 1507 output) | 1550 output) |
| 1508 revision = match[0].group(2) | 1551 revision = match[0].group(2) |
| 1509 else: | 1552 else: |
| 1510 return 1 | 1553 return 1 |
| 1511 viewvc_url = settings.GetViewVCUrl() | 1554 viewvc_url = settings.GetViewVCUrl() |
| 1512 if viewvc_url and revision: | 1555 if viewvc_url and revision: |
| 1513 cl.description += ('\n\nCommitted: ' + viewvc_url + revision) | 1556 change_desc.append_line('Committed: ' + viewvc_url + revision) |
| 1514 elif revision: | 1557 elif revision: |
| 1515 cl.description += ('\n\nCommitted: ' + revision) | 1558 change_desc.append_line('Committed: ' + revision) |
| 1516 print ('Closing issue ' | 1559 print ('Closing issue ' |
| 1517 '(you may be prompted for your codereview password)...') | 1560 '(you may be prompted for your codereview password)...') |
| 1518 cl.UpdateDescription(cl.description) | 1561 cl.UpdateDescription(change_desc.description) |
| 1519 cl.CloseIssue() | 1562 cl.CloseIssue() |
| 1520 props = cl.RpcServer().get_issue_properties(cl.GetIssue(), False) | 1563 props = cl.RpcServer().get_issue_properties(cl.GetIssue(), False) |
| 1521 patch_num = len(props['patchsets']) | 1564 patch_num = len(props['patchsets']) |
| 1522 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) | 1565 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) |
| 1523 comment += ' (presubmit successful).' if not options.bypass_hooks else '.' | 1566 comment += ' (presubmit successful).' if not options.bypass_hooks else '.' |
| 1524 cl.RpcServer().add_comment(cl.GetIssue(), comment) | 1567 cl.RpcServer().add_comment(cl.GetIssue(), comment) |
| 1525 cl.SetIssue(0) | 1568 cl.SetIssue(0) |
| 1526 | 1569 |
| 1527 if retcode == 0: | 1570 if retcode == 0: |
| 1528 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 1571 hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1905 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1948 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1906 | 1949 |
| 1907 # Not a known command. Default to help. | 1950 # Not a known command. Default to help. |
| 1908 GenUsage(parser, 'help') | 1951 GenUsage(parser, 'help') |
| 1909 return CMDhelp(parser, argv) | 1952 return CMDhelp(parser, argv) |
| 1910 | 1953 |
| 1911 | 1954 |
| 1912 if __name__ == '__main__': | 1955 if __name__ == '__main__': |
| 1913 fix_encoding.fix_encoding() | 1956 fix_encoding.fix_encoding() |
| 1914 sys.exit(main(sys.argv[1:])) | 1957 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |