blob: 674fc17dfc34d87874a3b9d071d291b7e48f0227 [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
Anthony Kingd792f792014-05-05 22:01:07 +010028# pylint:disable=W0622
David Pursehouse59bbb582013-05-17 10:49:33 +090029if not is_python3():
Chirayu Desai217ea7d2013-03-01 19:14:38 +053030 input = raw_input
Anthony Kingd792f792014-05-05 22:01:07 +010031else:
32 unicode = str
33# pylint:enable=W0622
Chirayu Desai217ea7d2013-03-01 19:14:38 +053034
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070035UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070036
37def _ConfirmManyUploads(multiple_branches=False):
38 if multiple_branches:
David Pursehouse2f9e7e42013-03-05 17:26:46 +090039 print('ATTENTION: One or more branches has an unusually high number '
Sarah Owenscecd1d82012-11-01 22:59:27 -070040 'of commits.')
Dan Morrill879a9a52010-05-04 16:56:07 -070041 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -070042 print('ATTENTION: You are uploading an unusually high number of commits.')
David Pursehouse2f9e7e42013-03-05 17:26:46 +090043 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
Sarah Owenscecd1d82012-11-01 22:59:27 -070044 'branches?)')
Chirayu Desai217ea7d2013-03-01 19:14:38 +053045 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
Dan Morrill879a9a52010-05-04 16:56:07 -070046 return answer == "yes"
47
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070048def _die(fmt, *args):
49 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070050 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070051 sys.exit(1)
52
Joe Onorato2896a792008-11-17 16:56:36 -050053def _SplitEmails(values):
54 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090055 for value in values:
56 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050057 return result
58
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070059class Upload(InteractiveCommand):
60 common = True
61 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090062 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070063%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070064"""
65 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070066The '%prog' command is used to send changes to the Gerrit Code
67Review system. It searches for topic branches in local projects
68that have not yet been published for review. If multiple topic
69branches are found, '%prog' opens an editor to allow the user to
70select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070071
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070072'%prog' searches for uploadable changes in all projects listed at
73the command line. Projects can be specified either by name, or by
74a relative or absolute path to the project's local directory. If no
75projects are specified, '%prog' will search for uploadable changes
76in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050077
78If the --reviewers or --cc options are passed, those emails are
79added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070080new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050081with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080082
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070083Configuration
84-------------
85
86review.URL.autoupload:
87
Mike Frysingere9311272011-08-11 15:46:43 -040088To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070089or global Git configuration option. If review.URL.autoupload is set
90to "true" then repo will assume you always answer "y" at the prompt,
91and will not prompt you further. If it is set to "false" then repo
92will assume you always answer "n", and will abort.
93
bijia093fdb62013-11-28 09:19:22 +080094review.URL.autoreviewer:
95
96To automatically append a user or mailing list to reviews, you can set
97a per-project or global Git option to do so.
98
Ben Komalo08a3f682010-07-15 16:03:02 -070099review.URL.autocopy:
100
101To automatically copy a user or mailing list to all uploaded reviews,
102you can set a per-project or global Git option to do so. Specifically,
103review.URL.autocopy can be set to a comma separated list of reviewers
104who you always want copied on all uploads with a non-empty --re
105argument.
106
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700107review.URL.username:
108
109Override the username used to connect to Gerrit Code Review.
110By default the local part of the email address is used.
111
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700112The URL must match the review URL listed in the manifest XML file,
113or in the .git/config within the project. For example:
114
115 [remote "origin"]
116 url = git://git.example.com/project.git
117 review = http://review.example.com/
118
119 [review "http://review.example.com/"]
120 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700121 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700122
Anthony Russellod666e932012-06-01 00:48:22 -0400123review.URL.uploadtopic:
124
125To add a topic branch whenever uploading a commit, you can set a
126per-project or global Git option to do so. If review.URL.uploadtopic
127is set to "true" then repo will assume you always want the equivalent
128of the -t option to the repo command. If unset or set to "false" then
129repo will make use of only the command line option.
130
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700131References
132----------
133
134Gerrit Code Review: http://code.google.com/p/gerrit/
135
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700136"""
137
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800138 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700139 p.add_option('-t',
140 dest='auto_topic', action='store_true',
141 help='Send local branch name to Gerrit Code Review')
Joe Onorato2896a792008-11-17 16:56:36 -0500142 p.add_option('--re', '--reviewers',
143 type='string', action='append', dest='reviewers',
144 help='Request reviews from these people.')
145 p.add_option('--cc',
146 type='string', action='append', dest='cc',
147 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700148 p.add_option('--br',
149 type='string', action='store', dest='branch',
150 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400151 p.add_option('--cbr', '--current-branch',
152 dest='current_branch', action='store_true',
153 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700154 p.add_option('-d', '--draft',
155 action='store_true', dest='draft', default=False,
156 help='If specified, upload as a draft.')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400157 p.add_option('-D', '--destination', '--dest',
158 type='string', action='store', dest='dest_branch',
159 metavar='BRANCH',
160 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800161
Doug Anderson37282b42011-03-04 11:54:18 -0800162 # Options relating to upload hook. Note that verify and no-verify are NOT
163 # opposites of each other, which is why they store to different locations.
164 # We are using them to match 'git commit' syntax.
165 #
166 # Combinations:
167 # - no-verify=False, verify=False (DEFAULT):
168 # If stdout is a tty, can prompt about running upload hooks if needed.
169 # If user denies running hooks, the upload is cancelled. If stdout is
170 # not a tty and we would need to prompt about upload hooks, upload is
171 # cancelled.
172 # - no-verify=False, verify=True:
173 # Always run upload hooks with no prompt.
174 # - no-verify=True, verify=False:
175 # Never run upload hooks, but upload anyway (AKA bypass hooks).
176 # - no-verify=True, verify=True:
177 # Invalid
178 p.add_option('--no-verify',
179 dest='bypass_hooks', action='store_true',
180 help='Do not run the upload hook.')
181 p.add_option('--verify',
182 dest='allow_all_hooks', action='store_true',
183 help='Run the upload hook without prompting.')
184
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700185 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700186 project = branch.project
187 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700188 remote = project.GetBranch(name).remote
189
190 key = 'review.%s.autoupload' % remote.review
191 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700192
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700193 if answer is False:
194 _die("upload blocked by %s = false" % key)
195
196 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700197 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900198 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700199
Chirayu Desai610d3c42013-06-24 14:02:12 +0530200 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Bryan Jacobsf609f912013-05-06 13:36:24 -0400201 print('Upload project %s/ to remote branch %s:' % (project.relpath, destination))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700202 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700203 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900204 len(commit_list),
205 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700206 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900207 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700208 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700209
Mike Frysingere9311272011-08-11 15:46:43 -0400210 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900211 answer = sys.stdin.readline().strip().lower()
212 answer = answer in ('y', 'yes', '1', 'true', 't')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700213
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700214 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700215 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
216 answer = _ConfirmManyUploads()
217
218 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700219 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700220 else:
221 _die("upload aborted by user")
222
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700223 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700224 projects = {}
225 branches = {}
226
227 script = []
228 script.append('# Uncomment the branches to upload:')
229 for project, avail in pending:
230 script.append('#')
231 script.append('# project %s/:' % project.relpath)
232
233 b = {}
234 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400235 if branch is None:
236 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700237 name = branch.name
238 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900239 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700240
241 if b:
242 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400243 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200244 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700245 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900246 len(commit_list),
247 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200248 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400249 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900250 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700251 script.append('# %s' % commit)
252 b[name] = branch
253
254 projects[project.relpath] = project
255 branches[project.name] = b
256 script.append('')
257
chenguodong605a9a42011-08-22 18:42:47 +0800258 script = [ x.encode('utf-8')
259 if issubclass(type(x), unicode)
260 else x
261 for x in script ]
262
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700263 script = Editor.EditString("\n".join(script)).split("\n")
264
265 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
266 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
267
268 project = None
269 todo = []
270
271 for line in script:
272 m = project_re.match(line)
273 if m:
274 name = m.group(1)
275 project = projects.get(name)
276 if not project:
277 _die('project %s not available for upload', name)
278 continue
279
280 m = branch_re.match(line)
281 if m:
282 name = m.group(1)
283 if not project:
284 _die('project for branch %s not in script', name)
285 branch = branches[project.name].get(name)
286 if not branch:
287 _die('branch %s not in %s', name, project.relpath)
288 todo.append(branch)
289 if not todo:
290 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700291
292 many_commits = False
293 for branch in todo:
294 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
295 many_commits = True
296 break
297 if many_commits:
298 if not _ConfirmManyUploads(multiple_branches=True):
299 _die("upload aborted by user")
300
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700301 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700302
bijia093fdb62013-11-28 09:19:22 +0800303 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700304 """
bijia093fdb62013-11-28 09:19:22 +0800305 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700306 Appends the list of users in the CC list in the git project's config if a
307 non-empty reviewer list was found.
308 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700309 name = branch.name
310 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800311
312 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
313 raw_list = project.config.GetString(key)
314 if not raw_list is None:
315 people[0].extend([entry.strip() for entry in raw_list.split(',')])
316
Ben Komalo08a3f682010-07-15 16:03:02 -0700317 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
318 raw_list = project.config.GetString(key)
319 if not raw_list is None and len(people[0]) > 0:
320 people[1].extend([entry.strip() for entry in raw_list.split(',')])
321
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700322 def _FindGerritChange(self, branch):
323 last_pub = branch.project.WasPublished(branch.name)
324 if last_pub is None:
325 return ""
326
327 refs = branch.GetPublishedRefs()
328 try:
329 # refs/changes/XYZ/N --> XYZ
330 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900331 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700332 return ""
333
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700334 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700335 have_errors = False
336 for branch in todo:
337 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700338 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800339 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700340
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500341 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700342 changes = branch.project.UncommitedFiles()
343 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900344 key = 'review.%s.autoupload' % branch.project.remote.review
345 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500346
David Pursehousec1b86a22012-11-14 11:36:51 +0900347 # if they want to auto upload, let's not ask because it could be automated
348 if answer is None:
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700349 sys.stdout.write('Uncommitted changes in ' + branch.project.name)
350 sys.stdout.write(' (did you forget to amend?):\n')
351 sys.stdout.write('\n'.join(changes) + '\n')
352 sys.stdout.write('Continue uploading? (y/N) ')
David Pursehousec1b86a22012-11-14 11:36:51 +0900353 a = sys.stdin.readline().strip().lower()
354 if a not in ('y', 'yes', 't', 'true', 'on'):
355 print("skipping upload", file=sys.stderr)
356 branch.uploaded = False
357 branch.error = 'User aborted'
358 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500359
Anthony Russellod666e932012-06-01 00:48:22 -0400360 # Check if topic branches should be sent to the server during upload
361 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900362 key = 'review.%s.uploadtopic' % branch.project.remote.review
363 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400364
Colin Cross59b31cb2013-10-08 23:10:52 -0700365 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700366
367 # Make sure our local branch is not setup to track a different remote branch
368 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700369 if destination:
370 full_dest = 'refs/heads/%s' % destination
371 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
372 print('merge branch %s does not match destination branch %s'
373 % (merge_branch, full_dest))
374 print('skipping upload.')
375 print('Please use `--destination %s` if this is intentional'
376 % destination)
377 branch.uploaded = False
378 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700379
Bryan Jacobs691a7592013-05-31 15:45:28 -0400380 branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft, dest_branch=destination)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700381 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700382 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700383 branch.error = e
384 branch.uploaded = False
385 have_errors = True
386
Sarah Owenscecd1d82012-11-01 22:59:27 -0700387 print(file=sys.stderr)
388 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700389
390 if have_errors:
391 for branch in todo:
392 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700393 if len(str(branch.error)) <= 30:
394 fmt = ' (%s)'
395 else:
396 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700397 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700398 branch.project.relpath + '/', \
399 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700400 str(branch.error)),
401 file=sys.stderr)
402 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700403
404 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900405 if branch.uploaded:
406 print('[OK ] %-15s %s' % (
407 branch.project.relpath + '/',
408 branch.name),
409 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700410
411 if have_errors:
412 sys.exit(1)
413
Conley Owens3bfd7212013-09-30 15:54:38 -0700414 def _GetMergeBranch(self, project):
415 p = GitCommand(project,
416 ['rev-parse', '--abbrev-ref', 'HEAD'],
417 capture_stdout = True,
418 capture_stderr = True)
419 p.Wait()
420 local_branch = p.stdout.strip()
421 p = GitCommand(project,
422 ['config', '--get', 'branch.%s.merge' % local_branch],
423 capture_stdout = True,
424 capture_stderr = True)
425 p.Wait()
426 merge_branch = p.stdout.strip()
427 return merge_branch
428
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700429 def Execute(self, opt, args):
430 project_list = self.GetProjects(args)
431 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500432 reviewers = []
433 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700434 branch = None
435
436 if opt.branch:
437 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500438
Doug Anderson37282b42011-03-04 11:54:18 -0800439 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400440 if opt.current_branch:
441 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800442 up_branch = project.GetUploadableBranch(cbr)
443 if up_branch:
444 avail = [up_branch]
445 else:
446 avail = None
447 print('ERROR: Current branch (%s) not uploadable. '
448 'You may be able to type '
449 '"git branch --set-upstream-to m/master" to fix '
450 'your branch.' % str(cbr),
451 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400452 else:
453 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800454 if avail:
455 pending.append((project, avail))
456
457 if pending and (not opt.bypass_hooks):
458 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
459 self.manifest.topdir, abort_if_user_denies=True)
460 pending_proj_names = [project.name for (project, avail) in pending]
David James8d201162013-10-11 17:03:19 -0700461 pending_worktrees = [project.worktree for (project, avail) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800462 try:
David James8d201162013-10-11 17:03:19 -0700463 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
464 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700465 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700466 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800467 return
468
Joe Onorato2896a792008-11-17 16:56:36 -0500469 if opt.reviewers:
470 reviewers = _SplitEmails(opt.reviewers)
471 if opt.cc:
472 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900473 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700474
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700475 if not pending:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700476 print("no branches ready for upload", file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700477 elif len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700478 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700479 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700480 self._MultipleBranches(opt, pending, people)