blob: e2fa261e09a5324a42bc69bbac623dcbd7879601 [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
bijia093fdb62013-11-28 09:19:22 +080092review.URL.autoreviewer:
93
94To automatically append a user or mailing list to reviews, you can set
95a per-project or global Git option to do so.
96
Ben Komalo08a3f682010-07-15 16:03:02 -070097review.URL.autocopy:
98
99To automatically copy a user or mailing list to all uploaded reviews,
100you can set a per-project or global Git option to do so. Specifically,
101review.URL.autocopy can be set to a comma separated list of reviewers
102who you always want copied on all uploads with a non-empty --re
103argument.
104
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700105review.URL.username:
106
107Override the username used to connect to Gerrit Code Review.
108By default the local part of the email address is used.
109
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700110The URL must match the review URL listed in the manifest XML file,
111or in the .git/config within the project. For example:
112
113 [remote "origin"]
114 url = git://git.example.com/project.git
115 review = http://review.example.com/
116
117 [review "http://review.example.com/"]
118 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700119 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700120
Anthony Russellod666e932012-06-01 00:48:22 -0400121review.URL.uploadtopic:
122
123To add a topic branch whenever uploading a commit, you can set a
124per-project or global Git option to do so. If review.URL.uploadtopic
125is set to "true" then repo will assume you always want the equivalent
126of the -t option to the repo command. If unset or set to "false" then
127repo will make use of only the command line option.
128
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700129References
130----------
131
132Gerrit Code Review: http://code.google.com/p/gerrit/
133
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700134"""
135
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800136 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700137 p.add_option('-t',
138 dest='auto_topic', action='store_true',
139 help='Send local branch name to Gerrit Code Review')
Joe Onorato2896a792008-11-17 16:56:36 -0500140 p.add_option('--re', '--reviewers',
141 type='string', action='append', dest='reviewers',
142 help='Request reviews from these people.')
143 p.add_option('--cc',
144 type='string', action='append', dest='cc',
145 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700146 p.add_option('--br',
147 type='string', action='store', dest='branch',
148 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400149 p.add_option('--cbr', '--current-branch',
150 dest='current_branch', action='store_true',
151 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700152 p.add_option('-d', '--draft',
153 action='store_true', dest='draft', default=False,
154 help='If specified, upload as a draft.')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400155 p.add_option('-D', '--destination', '--dest',
156 type='string', action='store', dest='dest_branch',
157 metavar='BRANCH',
158 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800159
Doug Anderson37282b42011-03-04 11:54:18 -0800160 # Options relating to upload hook. Note that verify and no-verify are NOT
161 # opposites of each other, which is why they store to different locations.
162 # We are using them to match 'git commit' syntax.
163 #
164 # Combinations:
165 # - no-verify=False, verify=False (DEFAULT):
166 # If stdout is a tty, can prompt about running upload hooks if needed.
167 # If user denies running hooks, the upload is cancelled. If stdout is
168 # not a tty and we would need to prompt about upload hooks, upload is
169 # cancelled.
170 # - no-verify=False, verify=True:
171 # Always run upload hooks with no prompt.
172 # - no-verify=True, verify=False:
173 # Never run upload hooks, but upload anyway (AKA bypass hooks).
174 # - no-verify=True, verify=True:
175 # Invalid
176 p.add_option('--no-verify',
177 dest='bypass_hooks', action='store_true',
178 help='Do not run the upload hook.')
179 p.add_option('--verify',
180 dest='allow_all_hooks', action='store_true',
181 help='Run the upload hook without prompting.')
182
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700183 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700184 project = branch.project
185 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700186 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700187
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700188 key = 'review.%s.autoupload' % remote.review
189 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700190
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700191 if answer is False:
192 _die("upload blocked by %s = false" % key)
193
194 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700195 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900196 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700197
Chirayu Desai610d3c42013-06-24 14:02:12 +0530198 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Bryan Jacobsf609f912013-05-06 13:36:24 -0400199 print('Upload project %s/ to remote branch %s:' % (project.relpath, destination))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700200 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700201 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900202 len(commit_list),
203 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700204 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900205 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700206 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700207
Mike Frysingere9311272011-08-11 15:46:43 -0400208 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900209 answer = sys.stdin.readline().strip().lower()
210 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700211
212 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700213 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
214 answer = _ConfirmManyUploads()
215
216 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700217 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700218 else:
219 _die("upload aborted by user")
220
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700221 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700222 projects = {}
223 branches = {}
224
225 script = []
226 script.append('# Uncomment the branches to upload:')
227 for project, avail in pending:
228 script.append('#')
229 script.append('# project %s/:' % project.relpath)
230
231 b = {}
232 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400233 if branch is None:
234 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700235 name = branch.name
236 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900237 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700238
239 if b:
240 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400241 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200242 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700243 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900244 len(commit_list),
245 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200246 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400247 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900248 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700249 script.append('# %s' % commit)
250 b[name] = branch
251
252 projects[project.relpath] = project
253 branches[project.name] = b
254 script.append('')
255
chenguodong605a9a42011-08-22 18:42:47 +0800256 script = [ x.encode('utf-8')
257 if issubclass(type(x), unicode)
258 else x
259 for x in script ]
260
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700261 script = Editor.EditString("\n".join(script)).split("\n")
262
263 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
264 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
265
266 project = None
267 todo = []
268
269 for line in script:
270 m = project_re.match(line)
271 if m:
272 name = m.group(1)
273 project = projects.get(name)
274 if not project:
275 _die('project %s not available for upload', name)
276 continue
277
278 m = branch_re.match(line)
279 if m:
280 name = m.group(1)
281 if not project:
282 _die('project for branch %s not in script', name)
283 branch = branches[project.name].get(name)
284 if not branch:
285 _die('branch %s not in %s', name, project.relpath)
286 todo.append(branch)
287 if not todo:
288 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700289
290 many_commits = False
291 for branch in todo:
292 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
293 many_commits = True
294 break
295 if many_commits:
296 if not _ConfirmManyUploads(multiple_branches=True):
297 _die("upload aborted by user")
298
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700299 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700300
bijia093fdb62013-11-28 09:19:22 +0800301 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700302 """
bijia093fdb62013-11-28 09:19:22 +0800303 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700304 Appends the list of users in the CC list in the git project's config if a
305 non-empty reviewer list was found.
306 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700307 name = branch.name
308 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800309
310 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
311 raw_list = project.config.GetString(key)
312 if not raw_list is None:
313 people[0].extend([entry.strip() for entry in raw_list.split(',')])
314
Ben Komalo08a3f682010-07-15 16:03:02 -0700315 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
316 raw_list = project.config.GetString(key)
317 if not raw_list is None and len(people[0]) > 0:
318 people[1].extend([entry.strip() for entry in raw_list.split(',')])
319
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700320 def _FindGerritChange(self, branch):
321 last_pub = branch.project.WasPublished(branch.name)
322 if last_pub is None:
323 return ""
324
325 refs = branch.GetPublishedRefs()
326 try:
327 # refs/changes/XYZ/N --> XYZ
328 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900329 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700330 return ""
331
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700332 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700333 have_errors = False
334 for branch in todo:
335 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700336 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800337 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700338
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500339 # Check if there are local changes that may have been forgotten
340 if branch.project.HasChanges():
David Pursehousec1b86a22012-11-14 11:36:51 +0900341 key = 'review.%s.autoupload' % branch.project.remote.review
342 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500343
David Pursehousec1b86a22012-11-14 11:36:51 +0900344 # if they want to auto upload, let's not ask because it could be automated
345 if answer is None:
346 sys.stdout.write('Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/N) ')
347 a = sys.stdin.readline().strip().lower()
348 if a not in ('y', 'yes', 't', 'true', 'on'):
349 print("skipping upload", file=sys.stderr)
350 branch.uploaded = False
351 branch.error = 'User aborted'
352 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500353
Anthony Russellod666e932012-06-01 00:48:22 -0400354 # Check if topic branches should be sent to the server during upload
355 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900356 key = 'review.%s.uploadtopic' % branch.project.remote.review
357 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400358
Colin Cross59b31cb2013-10-08 23:10:52 -0700359 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700360
361 # Make sure our local branch is not setup to track a different remote branch
362 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700363 if destination:
364 full_dest = 'refs/heads/%s' % destination
365 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
366 print('merge branch %s does not match destination branch %s'
367 % (merge_branch, full_dest))
368 print('skipping upload.')
369 print('Please use `--destination %s` if this is intentional'
370 % destination)
371 branch.uploaded = False
372 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700373
Bryan Jacobs691a7592013-05-31 15:45:28 -0400374 branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft, dest_branch=destination)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700375 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700376 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700377 branch.error = e
378 branch.uploaded = False
379 have_errors = True
380
Sarah Owenscecd1d82012-11-01 22:59:27 -0700381 print(file=sys.stderr)
382 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700383
384 if have_errors:
385 for branch in todo:
386 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700387 if len(str(branch.error)) <= 30:
388 fmt = ' (%s)'
389 else:
390 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700391 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700392 branch.project.relpath + '/', \
393 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700394 str(branch.error)),
395 file=sys.stderr)
396 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700397
398 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900399 if branch.uploaded:
400 print('[OK ] %-15s %s' % (
401 branch.project.relpath + '/',
402 branch.name),
403 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700404
405 if have_errors:
406 sys.exit(1)
407
Conley Owens3bfd7212013-09-30 15:54:38 -0700408 def _GetMergeBranch(self, project):
409 p = GitCommand(project,
410 ['rev-parse', '--abbrev-ref', 'HEAD'],
411 capture_stdout = True,
412 capture_stderr = True)
413 p.Wait()
414 local_branch = p.stdout.strip()
415 p = GitCommand(project,
416 ['config', '--get', 'branch.%s.merge' % local_branch],
417 capture_stdout = True,
418 capture_stderr = True)
419 p.Wait()
420 merge_branch = p.stdout.strip()
421 return merge_branch
422
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700423 def Execute(self, opt, args):
424 project_list = self.GetProjects(args)
425 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500426 reviewers = []
427 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700428 branch = None
429
430 if opt.branch:
431 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500432
Doug Anderson37282b42011-03-04 11:54:18 -0800433 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400434 if opt.current_branch:
435 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800436 up_branch = project.GetUploadableBranch(cbr)
437 if up_branch:
438 avail = [up_branch]
439 else:
440 avail = None
441 print('ERROR: Current branch (%s) not uploadable. '
442 'You may be able to type '
443 '"git branch --set-upstream-to m/master" to fix '
444 'your branch.' % str(cbr),
445 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400446 else:
447 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800448 if avail:
449 pending.append((project, avail))
450
451 if pending and (not opt.bypass_hooks):
452 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
453 self.manifest.topdir, abort_if_user_denies=True)
454 pending_proj_names = [project.name for (project, avail) in pending]
David James8d201162013-10-11 17:03:19 -0700455 pending_worktrees = [project.worktree for (project, avail) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800456 try:
David James8d201162013-10-11 17:03:19 -0700457 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
458 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700459 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700460 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800461 return
462
Joe Onorato2896a792008-11-17 16:56:36 -0500463 if opt.reviewers:
464 reviewers = _SplitEmails(opt.reviewers)
465 if opt.cc:
466 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900467 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700468
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700469 if not pending:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700470 print("no branches ready for upload", file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700471 elif len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700472 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700473 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700474 self._MultipleBranches(opt, pending, people)