blob: 02b43b400662c4c58786570fa3c635acc628478b [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():
Chirayu Desai217ea7d2013-03-01 19:14:38 +053029 input = raw_input
Anthony Kingd792f792014-05-05 22:01:07 +010030else:
31 unicode = str
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
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040081# Configuration
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070082
83review.URL.autoupload:
84
Mike Frysingere9311272011-08-11 15:46:43 -040085To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070086or global Git configuration option. If review.URL.autoupload is set
87to "true" then repo will assume you always answer "y" at the prompt,
88and will not prompt you further. If it is set to "false" then repo
89will assume you always answer "n", and will abort.
90
bijia093fdb62013-11-28 09:19:22 +080091review.URL.autoreviewer:
92
93To automatically append a user or mailing list to reviews, you can set
94a per-project or global Git option to do so.
95
Ben Komalo08a3f682010-07-15 16:03:02 -070096review.URL.autocopy:
97
98To automatically copy a user or mailing list to all uploaded reviews,
99you can set a per-project or global Git option to do so. Specifically,
100review.URL.autocopy can be set to a comma separated list of reviewers
101who you always want copied on all uploads with a non-empty --re
102argument.
103
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700104review.URL.username:
105
106Override the username used to connect to Gerrit Code Review.
107By default the local part of the email address is used.
108
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700109The URL must match the review URL listed in the manifest XML file,
110or in the .git/config within the project. For example:
111
112 [remote "origin"]
113 url = git://git.example.com/project.git
114 review = http://review.example.com/
115
116 [review "http://review.example.com/"]
117 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700118 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700119
Anthony Russellod666e932012-06-01 00:48:22 -0400120review.URL.uploadtopic:
121
122To add a topic branch whenever uploading a commit, you can set a
123per-project or global Git option to do so. If review.URL.uploadtopic
124is set to "true" then repo will assume you always want the equivalent
125of the -t option to the repo command. If unset or set to "false" then
126repo will make use of only the command line option.
127
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400128# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700129
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400130Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700131
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700132"""
133
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800134 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700135 p.add_option('-t',
136 dest='auto_topic', action='store_true',
137 help='Send local branch name to Gerrit Code Review')
Joe Onorato2896a792008-11-17 16:56:36 -0500138 p.add_option('--re', '--reviewers',
139 type='string', action='append', dest='reviewers',
140 help='Request reviews from these people.')
141 p.add_option('--cc',
142 type='string', action='append', dest='cc',
143 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700144 p.add_option('--br',
145 type='string', action='store', dest='branch',
146 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400147 p.add_option('--cbr', '--current-branch',
148 dest='current_branch', action='store_true',
149 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700150 p.add_option('-d', '--draft',
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000151 action='store_true', dest='draft', default=False,
152 help='If specified, upload as a draft.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200153 p.add_option('-p', '--private',
154 action='store_true', dest='private', default=False,
155 help='If specified, upload as a private change.')
156 p.add_option('-w', '--wip',
157 action='store_true', dest='wip', default=False,
158 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800159 p.add_option('-o', '--push-option',
160 type='string', action='append', dest='push_options',
161 default=[],
162 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400163 p.add_option('-D', '--destination', '--dest',
164 type='string', action='store', dest='dest_branch',
165 metavar='BRANCH',
166 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800167
Doug Anderson37282b42011-03-04 11:54:18 -0800168 # Options relating to upload hook. Note that verify and no-verify are NOT
169 # opposites of each other, which is why they store to different locations.
170 # We are using them to match 'git commit' syntax.
171 #
172 # Combinations:
173 # - no-verify=False, verify=False (DEFAULT):
174 # If stdout is a tty, can prompt about running upload hooks if needed.
175 # If user denies running hooks, the upload is cancelled. If stdout is
176 # not a tty and we would need to prompt about upload hooks, upload is
177 # cancelled.
178 # - no-verify=False, verify=True:
179 # Always run upload hooks with no prompt.
180 # - no-verify=True, verify=False:
181 # Never run upload hooks, but upload anyway (AKA bypass hooks).
182 # - no-verify=True, verify=True:
183 # Invalid
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200184 p.add_option('--no-cert-checks',
185 dest='validate_certs', action='store_false', default=True,
186 help='Disable verifying ssl certs (unsafe).')
Doug Anderson37282b42011-03-04 11:54:18 -0800187 p.add_option('--no-verify',
188 dest='bypass_hooks', action='store_true',
189 help='Do not run the upload hook.')
190 p.add_option('--verify',
191 dest='allow_all_hooks', action='store_true',
192 help='Run the upload hook without prompting.')
193
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700194 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700195 project = branch.project
196 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700197 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700198
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700199 key = 'review.%s.autoupload' % remote.review
200 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700201
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700202 if answer is False:
203 _die("upload blocked by %s = false" % key)
204
205 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700206 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900207 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700208
Chirayu Desai610d3c42013-06-24 14:02:12 +0530209 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200210 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000211 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700212 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700213 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900214 len(commit_list),
215 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700216 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900217 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700218 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700219
Mike Frysingere9311272011-08-11 15:46:43 -0400220 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900221 answer = sys.stdin.readline().strip().lower()
222 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700223
224 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700225 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
226 answer = _ConfirmManyUploads()
227
228 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700229 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700230 else:
231 _die("upload aborted by user")
232
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700233 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700234 projects = {}
235 branches = {}
236
237 script = []
238 script.append('# Uncomment the branches to upload:')
239 for project, avail in pending:
240 script.append('#')
241 script.append('# project %s/:' % project.relpath)
242
243 b = {}
244 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400245 if branch is None:
246 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700247 name = branch.name
248 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900249 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700250
251 if b:
252 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400253 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200254 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700255 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900256 len(commit_list),
257 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200258 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400259 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900260 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700261 script.append('# %s' % commit)
262 b[name] = branch
263
264 projects[project.relpath] = project
265 branches[project.name] = b
266 script.append('')
267
chenguodong605a9a42011-08-22 18:42:47 +0800268 script = [ x.encode('utf-8')
269 if issubclass(type(x), unicode)
270 else x
271 for x in script ]
272
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700273 script = Editor.EditString("\n".join(script)).split("\n")
274
275 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
276 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
277
278 project = None
279 todo = []
280
281 for line in script:
282 m = project_re.match(line)
283 if m:
284 name = m.group(1)
285 project = projects.get(name)
286 if not project:
287 _die('project %s not available for upload', name)
288 continue
289
290 m = branch_re.match(line)
291 if m:
292 name = m.group(1)
293 if not project:
294 _die('project for branch %s not in script', name)
295 branch = branches[project.name].get(name)
296 if not branch:
297 _die('branch %s not in %s', name, project.relpath)
298 todo.append(branch)
299 if not todo:
300 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700301
302 many_commits = False
303 for branch in todo:
304 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
305 many_commits = True
306 break
307 if many_commits:
308 if not _ConfirmManyUploads(multiple_branches=True):
309 _die("upload aborted by user")
310
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700311 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700312
bijia093fdb62013-11-28 09:19:22 +0800313 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700314 """
bijia093fdb62013-11-28 09:19:22 +0800315 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700316 Appends the list of users in the CC list in the git project's config if a
317 non-empty reviewer list was found.
318 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700319 name = branch.name
320 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800321
322 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
323 raw_list = project.config.GetString(key)
324 if not raw_list is None:
325 people[0].extend([entry.strip() for entry in raw_list.split(',')])
326
Ben Komalo08a3f682010-07-15 16:03:02 -0700327 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
328 raw_list = project.config.GetString(key)
329 if not raw_list is None and len(people[0]) > 0:
330 people[1].extend([entry.strip() for entry in raw_list.split(',')])
331
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700332 def _FindGerritChange(self, branch):
333 last_pub = branch.project.WasPublished(branch.name)
334 if last_pub is None:
335 return ""
336
337 refs = branch.GetPublishedRefs()
338 try:
339 # refs/changes/XYZ/N --> XYZ
340 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900341 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700342 return ""
343
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700344 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700345 have_errors = False
346 for branch in todo:
347 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700348 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800349 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700350
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500351 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700352 changes = branch.project.UncommitedFiles()
353 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900354 key = 'review.%s.autoupload' % branch.project.remote.review
355 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500356
David Pursehousec1b86a22012-11-14 11:36:51 +0900357 # if they want to auto upload, let's not ask because it could be automated
358 if answer is None:
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700359 sys.stdout.write('Uncommitted changes in ' + branch.project.name)
360 sys.stdout.write(' (did you forget to amend?):\n')
361 sys.stdout.write('\n'.join(changes) + '\n')
362 sys.stdout.write('Continue uploading? (y/N) ')
David Pursehousec1b86a22012-11-14 11:36:51 +0900363 a = sys.stdin.readline().strip().lower()
364 if a not in ('y', 'yes', 't', 'true', 'on'):
365 print("skipping upload", file=sys.stderr)
366 branch.uploaded = False
367 branch.error = 'User aborted'
368 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500369
Anthony Russellod666e932012-06-01 00:48:22 -0400370 # Check if topic branches should be sent to the server during upload
371 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900372 key = 'review.%s.uploadtopic' % branch.project.remote.review
373 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400374
Colin Cross59b31cb2013-10-08 23:10:52 -0700375 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700376
377 # Make sure our local branch is not setup to track a different remote branch
378 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700379 if destination:
380 full_dest = 'refs/heads/%s' % destination
381 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
382 print('merge branch %s does not match destination branch %s'
383 % (merge_branch, full_dest))
384 print('skipping upload.')
385 print('Please use `--destination %s` if this is intentional'
386 % destination)
387 branch.uploaded = False
388 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700389
Changcheng Xiao87984c62017-08-02 16:55:03 +0200390 branch.UploadForReview(people,
391 auto_topic=opt.auto_topic,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000392 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200393 private=opt.private,
394 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200395 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800396 validate_certs=opt.validate_certs,
397 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200398
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700399 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700400 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700401 branch.error = e
402 branch.uploaded = False
403 have_errors = True
404
Sarah Owenscecd1d82012-11-01 22:59:27 -0700405 print(file=sys.stderr)
406 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700407
408 if have_errors:
409 for branch in todo:
410 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700411 if len(str(branch.error)) <= 30:
412 fmt = ' (%s)'
413 else:
414 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700415 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700416 branch.project.relpath + '/', \
417 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700418 str(branch.error)),
419 file=sys.stderr)
420 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700421
422 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900423 if branch.uploaded:
424 print('[OK ] %-15s %s' % (
425 branch.project.relpath + '/',
426 branch.name),
427 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700428
429 if have_errors:
430 sys.exit(1)
431
Conley Owens3bfd7212013-09-30 15:54:38 -0700432 def _GetMergeBranch(self, project):
433 p = GitCommand(project,
434 ['rev-parse', '--abbrev-ref', 'HEAD'],
435 capture_stdout = True,
436 capture_stderr = True)
437 p.Wait()
438 local_branch = p.stdout.strip()
439 p = GitCommand(project,
440 ['config', '--get', 'branch.%s.merge' % local_branch],
441 capture_stdout = True,
442 capture_stderr = True)
443 p.Wait()
444 merge_branch = p.stdout.strip()
445 return merge_branch
446
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700447 def Execute(self, opt, args):
448 project_list = self.GetProjects(args)
449 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500450 reviewers = []
451 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700452 branch = None
453
454 if opt.branch:
455 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500456
Doug Anderson37282b42011-03-04 11:54:18 -0800457 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400458 if opt.current_branch:
459 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800460 up_branch = project.GetUploadableBranch(cbr)
461 if up_branch:
462 avail = [up_branch]
463 else:
464 avail = None
465 print('ERROR: Current branch (%s) not uploadable. '
466 'You may be able to type '
467 '"git branch --set-upstream-to m/master" to fix '
468 'your branch.' % str(cbr),
469 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400470 else:
471 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800472 if avail:
473 pending.append((project, avail))
474
Mike Frysinger163a3be2016-04-04 17:31:32 -0400475 if not pending:
476 print("no branches ready for upload", file=sys.stderr)
477 return
478
479 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800480 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400481 self.manifest.topdir,
482 self.manifest.manifestProject.GetRemote('origin').url,
483 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900484 pending_proj_names = [project.name for (project, available) in pending]
485 pending_worktrees = [project.worktree for (project, available) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800486 try:
David James8d201162013-10-11 17:03:19 -0700487 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
488 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700489 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700490 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800491 return
492
Joe Onorato2896a792008-11-17 16:56:36 -0500493 if opt.reviewers:
494 reviewers = _SplitEmails(opt.reviewers)
495 if opt.cc:
496 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900497 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700498
Mike Frysinger163a3be2016-04-04 17:31:32 -0400499 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700500 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700501 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700502 self._MultipleBranches(opt, pending, people)