blob: 526dcd573d959ca86039b42177fd8e7a82b9df34 [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#
2# Copyright (C) 2008 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Sarah Owenscecd1d82012-11-01 22:59:27 -070016from __future__ import print_function
Ben Komalo08a3f682010-07-15 16:03:02 -070017import copy
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070018import re
19import sys
20
21from command import InteractiveCommand
22from editor import Editor
Doug Anderson37282b42011-03-04 11:54:18 -080023from error import HookError, UploadError
Conley Owens3bfd7212013-09-30 15:54:38 -070024from git_command import GitCommand
Doug Anderson37282b42011-03-04 11:54:18 -080025from project import RepoHook
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070026
David Pursehouse59bbb582013-05-17 10:49:33 +090027from pyversion import is_python3
28if not is_python3():
29 # pylint:disable=W0622
Chirayu Desai217ea7d2013-03-01 19:14:38 +053030 input = raw_input
David Pursehouse59bbb582013-05-17 10:49:33 +090031 # pylint:enable=W0622
Chirayu Desai217ea7d2013-03-01 19:14:38 +053032
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070033UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070034
35def _ConfirmManyUploads(multiple_branches=False):
36 if multiple_branches:
David Pursehouse2f9e7e42013-03-05 17:26:46 +090037 print('ATTENTION: One or more branches has an unusually high number '
Sarah Owenscecd1d82012-11-01 22:59:27 -070038 'of commits.')
Dan Morrill879a9a52010-05-04 16:56:07 -070039 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -070040 print('ATTENTION: You are uploading an unusually high number of commits.')
David Pursehouse2f9e7e42013-03-05 17:26:46 +090041 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
Sarah Owenscecd1d82012-11-01 22:59:27 -070042 'branches?)')
Chirayu Desai217ea7d2013-03-01 19:14:38 +053043 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
Dan Morrill879a9a52010-05-04 16:56:07 -070044 return answer == "yes"
45
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070046def _die(fmt, *args):
47 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070048 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070049 sys.exit(1)
50
Joe Onorato2896a792008-11-17 16:56:36 -050051def _SplitEmails(values):
52 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090053 for value in values:
54 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050055 return result
56
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070057class Upload(InteractiveCommand):
58 common = True
59 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090060 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070061%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070062"""
63 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070064The '%prog' command is used to send changes to the Gerrit Code
65Review system. It searches for topic branches in local projects
66that have not yet been published for review. If multiple topic
67branches are found, '%prog' opens an editor to allow the user to
68select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070069
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070070'%prog' searches for uploadable changes in all projects listed at
71the command line. Projects can be specified either by name, or by
72a relative or absolute path to the project's local directory. If no
73projects are specified, '%prog' will search for uploadable changes
74in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050075
76If the --reviewers or --cc options are passed, those emails are
77added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070078new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050079with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080080
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070081Configuration
82-------------
83
84review.URL.autoupload:
85
Mike Frysingere9311272011-08-11 15:46:43 -040086To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070087or global Git configuration option. If review.URL.autoupload is set
88to "true" then repo will assume you always answer "y" at the prompt,
89and will not prompt you further. If it is set to "false" then repo
90will assume you always answer "n", and will abort.
91
Ben Komalo08a3f682010-07-15 16:03:02 -070092review.URL.autocopy:
93
94To automatically copy a user or mailing list to all uploaded reviews,
95you can set a per-project or global Git option to do so. Specifically,
96review.URL.autocopy can be set to a comma separated list of reviewers
97who you always want copied on all uploads with a non-empty --re
98argument.
99
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700100review.URL.username:
101
102Override the username used to connect to Gerrit Code Review.
103By default the local part of the email address is used.
104
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700105The URL must match the review URL listed in the manifest XML file,
106or in the .git/config within the project. For example:
107
108 [remote "origin"]
109 url = git://git.example.com/project.git
110 review = http://review.example.com/
111
112 [review "http://review.example.com/"]
113 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700114 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700115
Anthony Russellod666e932012-06-01 00:48:22 -0400116review.URL.uploadtopic:
117
118To add a topic branch whenever uploading a commit, you can set a
119per-project or global Git option to do so. If review.URL.uploadtopic
120is set to "true" then repo will assume you always want the equivalent
121of the -t option to the repo command. If unset or set to "false" then
122repo will make use of only the command line option.
123
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700124References
125----------
126
127Gerrit Code Review: http://code.google.com/p/gerrit/
128
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700129"""
130
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800131 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700132 p.add_option('-t',
133 dest='auto_topic', action='store_true',
134 help='Send local branch name to Gerrit Code Review')
Joe Onorato2896a792008-11-17 16:56:36 -0500135 p.add_option('--re', '--reviewers',
136 type='string', action='append', dest='reviewers',
137 help='Request reviews from these people.')
138 p.add_option('--cc',
139 type='string', action='append', dest='cc',
140 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700141 p.add_option('--br',
142 type='string', action='store', dest='branch',
143 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400144 p.add_option('--cbr', '--current-branch',
145 dest='current_branch', action='store_true',
146 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700147 p.add_option('-d', '--draft',
148 action='store_true', dest='draft', default=False,
149 help='If specified, upload as a draft.')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400150 p.add_option('-D', '--destination', '--dest',
151 type='string', action='store', dest='dest_branch',
152 metavar='BRANCH',
153 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800154
Doug Anderson37282b42011-03-04 11:54:18 -0800155 # Options relating to upload hook. Note that verify and no-verify are NOT
156 # opposites of each other, which is why they store to different locations.
157 # We are using them to match 'git commit' syntax.
158 #
159 # Combinations:
160 # - no-verify=False, verify=False (DEFAULT):
161 # If stdout is a tty, can prompt about running upload hooks if needed.
162 # If user denies running hooks, the upload is cancelled. If stdout is
163 # not a tty and we would need to prompt about upload hooks, upload is
164 # cancelled.
165 # - no-verify=False, verify=True:
166 # Always run upload hooks with no prompt.
167 # - no-verify=True, verify=False:
168 # Never run upload hooks, but upload anyway (AKA bypass hooks).
169 # - no-verify=True, verify=True:
170 # Invalid
171 p.add_option('--no-verify',
172 dest='bypass_hooks', action='store_true',
173 help='Do not run the upload hook.')
174 p.add_option('--verify',
175 dest='allow_all_hooks', action='store_true',
176 help='Run the upload hook without prompting.')
177
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700178 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700179 project = branch.project
180 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700181 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700182
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700183 key = 'review.%s.autoupload' % remote.review
184 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700185
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700186 if answer is False:
187 _die("upload blocked by %s = false" % key)
188
189 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700190 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900191 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700192
Chirayu Desai610d3c42013-06-24 14:02:12 +0530193 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Bryan Jacobsf609f912013-05-06 13:36:24 -0400194 print('Upload project %s/ to remote branch %s:' % (project.relpath, destination))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700195 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700196 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900197 len(commit_list),
198 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700199 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900200 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700201 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700202
Mike Frysingere9311272011-08-11 15:46:43 -0400203 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900204 answer = sys.stdin.readline().strip().lower()
205 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700206
207 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700208 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
209 answer = _ConfirmManyUploads()
210
211 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700212 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700213 else:
214 _die("upload aborted by user")
215
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700216 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700217 projects = {}
218 branches = {}
219
220 script = []
221 script.append('# Uncomment the branches to upload:')
222 for project, avail in pending:
223 script.append('#')
224 script.append('# project %s/:' % project.relpath)
225
226 b = {}
227 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400228 if branch is None:
229 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700230 name = branch.name
231 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900232 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700233
234 if b:
235 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400236 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200237 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700238 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900239 len(commit_list),
240 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200241 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400242 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900243 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700244 script.append('# %s' % commit)
245 b[name] = branch
246
247 projects[project.relpath] = project
248 branches[project.name] = b
249 script.append('')
250
chenguodong605a9a42011-08-22 18:42:47 +0800251 script = [ x.encode('utf-8')
252 if issubclass(type(x), unicode)
253 else x
254 for x in script ]
255
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700256 script = Editor.EditString("\n".join(script)).split("\n")
257
258 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
259 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
260
261 project = None
262 todo = []
263
264 for line in script:
265 m = project_re.match(line)
266 if m:
267 name = m.group(1)
268 project = projects.get(name)
269 if not project:
270 _die('project %s not available for upload', name)
271 continue
272
273 m = branch_re.match(line)
274 if m:
275 name = m.group(1)
276 if not project:
277 _die('project for branch %s not in script', name)
278 branch = branches[project.name].get(name)
279 if not branch:
280 _die('branch %s not in %s', name, project.relpath)
281 todo.append(branch)
282 if not todo:
283 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700284
285 many_commits = False
286 for branch in todo:
287 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
288 many_commits = True
289 break
290 if many_commits:
291 if not _ConfirmManyUploads(multiple_branches=True):
292 _die("upload aborted by user")
293
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700294 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700295
Ben Komalo08a3f682010-07-15 16:03:02 -0700296 def _AppendAutoCcList(self, branch, people):
297 """
298 Appends the list of users in the CC list in the git project's config if a
299 non-empty reviewer list was found.
300 """
301
302 name = branch.name
303 project = branch.project
304 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
305 raw_list = project.config.GetString(key)
306 if not raw_list is None and len(people[0]) > 0:
307 people[1].extend([entry.strip() for entry in raw_list.split(',')])
308
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700309 def _FindGerritChange(self, branch):
310 last_pub = branch.project.WasPublished(branch.name)
311 if last_pub is None:
312 return ""
313
314 refs = branch.GetPublishedRefs()
315 try:
316 # refs/changes/XYZ/N --> XYZ
317 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900318 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700319 return ""
320
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700321 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700322 have_errors = False
323 for branch in todo:
324 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700325 people = copy.deepcopy(original_people)
326 self._AppendAutoCcList(branch, people)
327
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500328 # Check if there are local changes that may have been forgotten
329 if branch.project.HasChanges():
David Pursehousec1b86a22012-11-14 11:36:51 +0900330 key = 'review.%s.autoupload' % branch.project.remote.review
331 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500332
David Pursehousec1b86a22012-11-14 11:36:51 +0900333 # if they want to auto upload, let's not ask because it could be automated
334 if answer is None:
335 sys.stdout.write('Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/N) ')
336 a = sys.stdin.readline().strip().lower()
337 if a not in ('y', 'yes', 't', 'true', 'on'):
338 print("skipping upload", file=sys.stderr)
339 branch.uploaded = False
340 branch.error = 'User aborted'
341 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500342
Anthony Russellod666e932012-06-01 00:48:22 -0400343 # Check if topic branches should be sent to the server during upload
344 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900345 key = 'review.%s.uploadtopic' % branch.project.remote.review
346 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400347
Colin Cross59b31cb2013-10-08 23:10:52 -0700348 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700349
350 # Make sure our local branch is not setup to track a different remote branch
351 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700352 if destination:
353 full_dest = 'refs/heads/%s' % destination
354 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
355 print('merge branch %s does not match destination branch %s'
356 % (merge_branch, full_dest))
357 print('skipping upload.')
358 print('Please use `--destination %s` if this is intentional'
359 % destination)
360 branch.uploaded = False
361 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700362
Bryan Jacobs691a7592013-05-31 15:45:28 -0400363 branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft, dest_branch=destination)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700364 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700365 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700366 branch.error = e
367 branch.uploaded = False
368 have_errors = True
369
Sarah Owenscecd1d82012-11-01 22:59:27 -0700370 print(file=sys.stderr)
371 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700372
373 if have_errors:
374 for branch in todo:
375 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700376 if len(str(branch.error)) <= 30:
377 fmt = ' (%s)'
378 else:
379 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700380 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700381 branch.project.relpath + '/', \
382 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700383 str(branch.error)),
384 file=sys.stderr)
385 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700386
387 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900388 if branch.uploaded:
389 print('[OK ] %-15s %s' % (
390 branch.project.relpath + '/',
391 branch.name),
392 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700393
394 if have_errors:
395 sys.exit(1)
396
Conley Owens3bfd7212013-09-30 15:54:38 -0700397 def _GetMergeBranch(self, project):
398 p = GitCommand(project,
399 ['rev-parse', '--abbrev-ref', 'HEAD'],
400 capture_stdout = True,
401 capture_stderr = True)
402 p.Wait()
403 local_branch = p.stdout.strip()
404 p = GitCommand(project,
405 ['config', '--get', 'branch.%s.merge' % local_branch],
406 capture_stdout = True,
407 capture_stderr = True)
408 p.Wait()
409 merge_branch = p.stdout.strip()
410 return merge_branch
411
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700412 def Execute(self, opt, args):
413 project_list = self.GetProjects(args)
414 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500415 reviewers = []
416 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700417 branch = None
418
419 if opt.branch:
420 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500421
Doug Anderson37282b42011-03-04 11:54:18 -0800422 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400423 if opt.current_branch:
424 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800425 up_branch = project.GetUploadableBranch(cbr)
426 if up_branch:
427 avail = [up_branch]
428 else:
429 avail = None
430 print('ERROR: Current branch (%s) not uploadable. '
431 'You may be able to type '
432 '"git branch --set-upstream-to m/master" to fix '
433 'your branch.' % str(cbr),
434 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400435 else:
436 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800437 if avail:
438 pending.append((project, avail))
439
440 if pending and (not opt.bypass_hooks):
441 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
442 self.manifest.topdir, abort_if_user_denies=True)
443 pending_proj_names = [project.name for (project, avail) in pending]
David James8d201162013-10-11 17:03:19 -0700444 pending_worktrees = [project.worktree for (project, avail) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800445 try:
David James8d201162013-10-11 17:03:19 -0700446 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
447 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700448 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700449 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800450 return
451
Joe Onorato2896a792008-11-17 16:56:36 -0500452 if opt.reviewers:
453 reviewers = _SplitEmails(opt.reviewers)
454 if opt.cc:
455 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900456 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700457
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700458 if not pending:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700459 print("no branches ready for upload", file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700460 elif len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700461 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700462 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700463 self._MultipleBranches(opt, pending, people)