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

Side by Side Diff: git_cl.py

Issue 13843002: Make git-cl accepts multiple --reviewers and --cc arguments. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: with strip Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # Copyright (C) 2008 Evan Martin <martine@danga.com> 6 # Copyright (C) 2008 Evan Martin <martine@danga.com>
7 7
8 """A git-command for integrating reviews on Rietveld.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 import json 10 import json
(...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() 821 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip()
822 if not content.strip(): 822 if not content.strip():
823 DieWithError('No CL description, aborting') 823 DieWithError('No CL description, aborting')
824 self.description = content 824 self.description = content
825 825
826 def ParseDescription(self): 826 def ParseDescription(self):
827 """Updates the list of reviewers and subject from the description.""" 827 """Updates the list of reviewers and subject from the description."""
828 self.description = self.description.strip('\n') + '\n' 828 self.description = self.description.strip('\n') + '\n'
829 # Retrieves all reviewer lines 829 # Retrieves all reviewer lines
830 regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE) 830 regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE)
831 reviewers = ','.join( 831 reviewers = ', '.join(
832 i.group(2).strip() for i in regexp.finditer(self.description)) 832 i.group(2).strip() for i in regexp.finditer(self.description))
833 if reviewers: 833 if reviewers:
834 self.reviewers = reviewers 834 self.reviewers = reviewers
835 835
836 def IsEmpty(self): 836 def IsEmpty(self):
837 return not self.description 837 return not self.description
838 838
839 839
840 def FindCodereviewSettingsFile(filename='codereview.settings'): 840 def FindCodereviewSettingsFile(filename='codereview.settings'):
841 """Finds the given file starting in the cwd and going up. 841 """Finds the given file starting in the cwd and going up.
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
1099 # It is probably not worthwhile to support different workflows. 1099 # It is probably not worthwhile to support different workflows.
1100 remote = 'origin' 1100 remote = 'origin'
1101 branch = 'master' 1101 branch = 'master'
1102 if options.target_branch: 1102 if options.target_branch:
1103 branch = options.target_branch 1103 branch = options.target_branch
1104 1104
1105 log_desc = options.message or CreateDescriptionFromLog(args) 1105 log_desc = options.message or CreateDescriptionFromLog(args)
1106 if CHANGE_ID not in log_desc: 1106 if CHANGE_ID not in log_desc:
1107 AddChangeIdToCommitMessage(options, args) 1107 AddChangeIdToCommitMessage(options, args)
1108 if options.reviewers: 1108 if options.reviewers:
1109 log_desc += '\nR=' + options.reviewers 1109 log_desc += '\nR=' + ', '.join(options.reviewers)
1110 change_desc = ChangeDescription(log_desc, options.reviewers) 1110 change_desc = ChangeDescription(log_desc, ', '.join(options.reviewers))
1111 change_desc.ParseDescription() 1111 change_desc.ParseDescription()
1112 if change_desc.IsEmpty(): 1112 if change_desc.IsEmpty():
1113 print "Description is empty; aborting." 1113 print "Description is empty; aborting."
1114 return 1 1114 return 1
1115 1115
1116 receive_options = [] 1116 receive_options = []
1117 cc = cl.GetCCList().split(',') 1117 cc = cl.GetCCList().split(',')
1118 if options.cc: 1118 if options.cc:
1119 cc += options.cc.split(',') 1119 cc.extend(options.cc)
1120 cc = filter(None, cc) 1120 cc = filter(None, cc)
1121 if cc: 1121 if cc:
1122 receive_options += ['--cc=' + email for email in cc] 1122 receive_options += ['--cc=' + email for email in cc]
1123 if change_desc.reviewers: 1123 if change_desc.reviewers:
1124 reviewers = filter(None, change_desc.reviewers.split(',')) 1124 reviewers = filter(
1125 None, (r.strip() for r in change_desc.reviewers.split(',')))
1125 if reviewers: 1126 if reviewers:
1126 receive_options += ['--reviewer=' + email for email in reviewers] 1127 receive_options += ['--reviewer=' + email for email in reviewers]
1127 1128
1128 git_command = ['push'] 1129 git_command = ['push']
1129 if receive_options: 1130 if receive_options:
1130 git_command.append('--receive-pack=git receive-pack %s' % 1131 git_command.append('--receive-pack=git receive-pack %s' %
1131 ' '.join(receive_options)) 1132 ' '.join(receive_options))
1132 git_command += [remote, 'HEAD:refs/for/' + branch] 1133 git_command += [remote, 'HEAD:refs/for/' + branch]
1133 RunGit(git_command) 1134 RunGit(git_command)
1134 # TODO(ukai): parse Change-Id: and set issue number? 1135 # TODO(ukai): parse Change-Id: and set issue number?
(...skipping 17 matching lines...) Expand all
1152 # for upload.py. Soon this will be changed to set the --message option. 1153 # 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. 1154 # Will wait until people are used to typing -t instead of -m.
1154 upload_args.extend(['--title', options.message]) 1155 upload_args.extend(['--title', options.message])
1155 upload_args.extend(['--issue', str(cl.GetIssue())]) 1156 upload_args.extend(['--issue', str(cl.GetIssue())])
1156 print ("This branch is associated with issue %s. " 1157 print ("This branch is associated with issue %s. "
1157 "Adding patch to that issue." % cl.GetIssue()) 1158 "Adding patch to that issue." % cl.GetIssue())
1158 else: 1159 else:
1159 if options.title: 1160 if options.title:
1160 upload_args.extend(['--title', options.title]) 1161 upload_args.extend(['--title', options.title])
1161 message = options.title or options.message or CreateDescriptionFromLog(args) 1162 message = options.title or options.message or CreateDescriptionFromLog(args)
1162 change_desc = ChangeDescription(message, options.reviewers) 1163 change_desc = ChangeDescription(message, ','.join(options.reviewers))
1163 if not options.force: 1164 if not options.force:
1164 change_desc.Prompt() 1165 change_desc.Prompt()
1165 change_desc.ParseDescription() 1166 change_desc.ParseDescription()
1166 1167
1167 if change_desc.IsEmpty(): 1168 if change_desc.IsEmpty():
1168 print "Description is empty; aborting." 1169 print "Description is empty; aborting."
1169 return 1 1170 return 1
1170 1171
1171 upload_args.extend(['--message', change_desc.description]) 1172 upload_args.extend(['--message', change_desc.description])
1172 if change_desc.reviewers: 1173 if change_desc.reviewers:
1173 upload_args.extend(['--reviewers', change_desc.reviewers]) 1174 upload_args.extend(
1175 [
1176 '--reviewers',
1177 ','.join(r.strip() for r in change_desc.reviewers.split(',')),
1178 ])
1174 if options.send_mail: 1179 if options.send_mail:
1175 if not change_desc.reviewers: 1180 if not change_desc.reviewers:
1176 DieWithError("Must specify reviewers to send email.") 1181 DieWithError("Must specify reviewers to send email.")
1177 upload_args.append('--send_mail') 1182 upload_args.append('--send_mail')
1178 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) 1183 cc = ','.join(filter(None, (cl.GetCCList(), ','.join(options.cc))))
1179 if cc: 1184 if cc:
1180 upload_args.extend(['--cc', cc]) 1185 upload_args.extend(['--cc', cc])
1181 1186
1182 upload_args.extend(['--git_similarity', str(options.similarity)]) 1187 upload_args.extend(['--git_similarity', str(options.similarity)])
1183 if not options.find_copies: 1188 if not options.find_copies:
1184 upload_args.extend(['--git_no_find_copies']) 1189 upload_args.extend(['--git_no_find_copies'])
1185 1190
1186 # Include the upstream repo's URL in the change -- this is useful for 1191 # Include the upstream repo's URL in the change -- this is useful for
1187 # projects that have their source spread across multiple repos. 1192 # projects that have their source spread across multiple repos.
1188 remote_url = cl.GetGitBaseUrlFromConfig() 1193 remote_url = cl.GetGitBaseUrlFromConfig()
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1221 1226
1222 if not cl.GetIssue(): 1227 if not cl.GetIssue():
1223 cl.SetIssue(issue) 1228 cl.SetIssue(issue)
1224 cl.SetPatchset(patchset) 1229 cl.SetPatchset(patchset)
1225 1230
1226 if options.use_commit_queue: 1231 if options.use_commit_queue:
1227 cl.SetFlag('commit', '1') 1232 cl.SetFlag('commit', '1')
1228 return 0 1233 return 0
1229 1234
1230 1235
1236 def cleanup_list(l):
1237 """Fixes a list so that comma separated items are put as individual items.
1238
1239 So that "--reviewers joe@c,john@c --reviewers joa@c" results in
1240 options.reviewers == sorted(['joe@c', 'john@c', 'joa@c']).
1241 """
1242 items = sum((i.split(',') for i in l), [])
1243 stripped_items = (i.strip() for i in items)
1244 return sorted(filter(None, stripped_items))
1245
1246
1231 @usage('[args to "git diff"]') 1247 @usage('[args to "git diff"]')
1232 def CMDupload(parser, args): 1248 def CMDupload(parser, args):
1233 """upload the current changelist to codereview""" 1249 """upload the current changelist to codereview"""
1234 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', 1250 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks',
1235 help='bypass upload presubmit hook') 1251 help='bypass upload presubmit hook')
1236 parser.add_option('-f', action='store_true', dest='force', 1252 parser.add_option('-f', action='store_true', dest='force',
1237 help="force yes to questions (don't prompt)") 1253 help="force yes to questions (don't prompt)")
1238 parser.add_option('-m', dest='message', help='message for patchset') 1254 parser.add_option('-m', dest='message', help='message for patchset')
1239 parser.add_option('-t', dest='title', help='title for patchset') 1255 parser.add_option('-t', dest='title', help='title for patchset')
1240 parser.add_option('-r', '--reviewers', 1256 parser.add_option('-r', '--reviewers',
1257 action='append', default=[],
1241 help='reviewer email addresses') 1258 help='reviewer email addresses')
1242 parser.add_option('--cc', 1259 parser.add_option('--cc',
1260 action='append', default=[],
1243 help='cc email addresses') 1261 help='cc email addresses')
1244 parser.add_option('-s', '--send-mail', action='store_true', 1262 parser.add_option('-s', '--send-mail', action='store_true',
1245 help='send email to reviewer immediately') 1263 help='send email to reviewer immediately')
1246 parser.add_option("--emulate_svn_auto_props", action="store_true", 1264 parser.add_option("--emulate_svn_auto_props", action="store_true",
1247 dest="emulate_svn_auto_props", 1265 dest="emulate_svn_auto_props",
1248 help="Emulate Subversion's auto properties feature.") 1266 help="Emulate Subversion's auto properties feature.")
1249 parser.add_option('-c', '--use-commit-queue', action='store_true', 1267 parser.add_option('-c', '--use-commit-queue', action='store_true',
1250 help='tell the commit queue to commit this patchset') 1268 help='tell the commit queue to commit this patchset')
1251 parser.add_option('--target_branch', 1269 parser.add_option('--target_branch',
1252 help='When uploading to gerrit, remote branch to ' 1270 help='When uploading to gerrit, remote branch to '
1253 'use for CL. Default: master') 1271 'use for CL. Default: master')
1254 add_git_similarity(parser) 1272 add_git_similarity(parser)
1255 (options, args) = parser.parse_args(args) 1273 (options, args) = parser.parse_args(args)
1256 1274
1257 if options.target_branch and not settings.GetIsGerrit(): 1275 if options.target_branch and not settings.GetIsGerrit():
1258 parser.error('Use --target_branch for non gerrit repository.') 1276 parser.error('Use --target_branch for non gerrit repository.')
1259 1277
1260 # Print warning if the user used the -m/--message argument. This will soon 1278 # Print warning if the user used the -m/--message argument. This will soon
1261 # change to -t/--title. 1279 # change to -t/--title.
1262 if options.message: 1280 if options.message:
1263 print >> sys.stderr, ( 1281 print >> sys.stderr, (
1264 '\nWARNING: Use -t or --title to set the title of the patchset.\n' 1282 '\nWARNING: Use -t or --title to set the title of the patchset.\n'
1265 'In the near future, -m or --message will send a message instead.\n' 1283 'In the near future, -m or --message will send a message instead.\n'
1266 'See http://goo.gl/JGg0Z for details.\n') 1284 'See http://goo.gl/JGg0Z for details.\n')
1267 1285
1268 if is_dirty_git_tree('upload'): 1286 if is_dirty_git_tree('upload'):
1269 return 1 1287 return 1
1270 1288
1289 options.reviewers = cleanup_list(options.reviewers)
1290 options.cc = cleanup_list(options.cc)
1291
1271 cl = Changelist() 1292 cl = Changelist()
1272 if args: 1293 if args:
1273 # TODO(ukai): is it ok for gerrit case? 1294 # TODO(ukai): is it ok for gerrit case?
1274 base_branch = args[0] 1295 base_branch = args[0]
1275 else: 1296 else:
1276 # Default to diffing against common ancestor of upstream branch 1297 # Default to diffing against common ancestor of upstream branch
1277 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() 1298 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip()
1278 args = [base_branch, 'HEAD'] 1299 args = [base_branch, 'HEAD']
1279 1300
1280 # Apply watchlists on upload. 1301 # Apply watchlists on upload.
1281 change = cl.GetChange(base_branch, None) 1302 change = cl.GetChange(base_branch, None)
1282 watchlist = watchlists.Watchlists(change.RepositoryRoot()) 1303 watchlist = watchlists.Watchlists(change.RepositoryRoot())
1283 files = [f.LocalPath() for f in change.AffectedFiles()] 1304 files = [f.LocalPath() for f in change.AffectedFiles()]
1284 cl.SetWatchers(watchlist.GetWatchersForPaths(files)) 1305 cl.SetWatchers(watchlist.GetWatchersForPaths(files))
1285 1306
1286 if not options.bypass_hooks: 1307 if not options.bypass_hooks:
1287 hook_results = cl.RunHook(committing=False, 1308 hook_results = cl.RunHook(committing=False,
1288 may_prompt=not options.force, 1309 may_prompt=not options.force,
1289 verbose=options.verbose, 1310 verbose=options.verbose,
1290 change=change) 1311 change=change)
1291 if not hook_results.should_continue(): 1312 if not hook_results.should_continue():
1292 return 1 1313 return 1
1293 if not options.reviewers and hook_results.reviewers: 1314 if not options.reviewers and hook_results.reviewers:
1294 options.reviewers = hook_results.reviewers 1315 options.reviewers = hook_results.reviewers.split(',')
1295 1316
1296 if cl.GetIssue(): 1317 if cl.GetIssue():
1297 latest_patchset = cl.GetMostRecentPatchset(cl.GetIssue()) 1318 latest_patchset = cl.GetMostRecentPatchset(cl.GetIssue())
1298 local_patchset = cl.GetPatchset() 1319 local_patchset = cl.GetPatchset()
1299 if latest_patchset and local_patchset and local_patchset != latest_patchset: 1320 if latest_patchset and local_patchset and local_patchset != latest_patchset:
1300 print ('The last upload made from this repository was patchset #%d but ' 1321 print ('The last upload made from this repository was patchset #%d but '
1301 'the most recent patchset on the server is #%d.' 1322 'the most recent patchset on the server is #%d.'
1302 % (local_patchset, latest_patchset)) 1323 % (local_patchset, latest_patchset))
1303 ask_for_data('About to upload; enter to confirm.') 1324 ask_for_data('About to upload; enter to confirm.')
1304 1325
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
1905 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) 1926 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)))
1906 1927
1907 # Not a known command. Default to help. 1928 # Not a known command. Default to help.
1908 GenUsage(parser, 'help') 1929 GenUsage(parser, 'help')
1909 return CMDhelp(parser, argv) 1930 return CMDhelp(parser, argv)
1910 1931
1911 1932
1912 if __name__ == '__main__': 1933 if __name__ == '__main__':
1913 fix_encoding.fix_encoding() 1934 fix_encoding.fix_encoding()
1914 sys.exit(main(sys.argv[1:])) 1935 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698