blob: 77eaf81ab43cf5e71b2fd678ebb1fcc1c172e3b7 [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',
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000155 action='store_true', dest='draft', default=False,
156 help='If specified, upload as a draft.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200157 p.add_option('-p', '--private',
158 action='store_true', dest='private', default=False,
159 help='If specified, upload as a private change.')
160 p.add_option('-w', '--wip',
161 action='store_true', dest='wip', default=False,
162 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800163 p.add_option('-o', '--push-option',
164 type='string', action='append', dest='push_options',
165 default=[],
166 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400167 p.add_option('-D', '--destination', '--dest',
168 type='string', action='store', dest='dest_branch',
169 metavar='BRANCH',
170 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800171
Doug Anderson37282b42011-03-04 11:54:18 -0800172 # Options relating to upload hook. Note that verify and no-verify are NOT
173 # opposites of each other, which is why they store to different locations.
174 # We are using them to match 'git commit' syntax.
175 #
176 # Combinations:
177 # - no-verify=False, verify=False (DEFAULT):
178 # If stdout is a tty, can prompt about running upload hooks if needed.
179 # If user denies running hooks, the upload is cancelled. If stdout is
180 # not a tty and we would need to prompt about upload hooks, upload is
181 # cancelled.
182 # - no-verify=False, verify=True:
183 # Always run upload hooks with no prompt.
184 # - no-verify=True, verify=False:
185 # Never run upload hooks, but upload anyway (AKA bypass hooks).
186 # - no-verify=True, verify=True:
187 # Invalid
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200188 p.add_option('--no-cert-checks',
189 dest='validate_certs', action='store_false', default=True,
190 help='Disable verifying ssl certs (unsafe).')
Doug Anderson37282b42011-03-04 11:54:18 -0800191 p.add_option('--no-verify',
192 dest='bypass_hooks', action='store_true',
193 help='Do not run the upload hook.')
194 p.add_option('--verify',
195 dest='allow_all_hooks', action='store_true',
196 help='Run the upload hook without prompting.')
197
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700198 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700199 project = branch.project
200 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700201 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700202
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700203 key = 'review.%s.autoupload' % remote.review
204 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700205
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700206 if answer is False:
207 _die("upload blocked by %s = false" % key)
208
209 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700210 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900211 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700212
Chirayu Desai610d3c42013-06-24 14:02:12 +0530213 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200214 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000215 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700216 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700217 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900218 len(commit_list),
219 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700220 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900221 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700222 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700223
Mike Frysingere9311272011-08-11 15:46:43 -0400224 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900225 answer = sys.stdin.readline().strip().lower()
226 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700227
228 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700229 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
230 answer = _ConfirmManyUploads()
231
232 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700233 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700234 else:
235 _die("upload aborted by user")
236
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700237 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700238 projects = {}
239 branches = {}
240
241 script = []
242 script.append('# Uncomment the branches to upload:')
243 for project, avail in pending:
244 script.append('#')
245 script.append('# project %s/:' % project.relpath)
246
247 b = {}
248 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400249 if branch is None:
250 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700251 name = branch.name
252 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900253 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700254
255 if b:
256 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400257 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200258 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700259 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900260 len(commit_list),
261 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200262 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400263 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900264 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700265 script.append('# %s' % commit)
266 b[name] = branch
267
268 projects[project.relpath] = project
269 branches[project.name] = b
270 script.append('')
271
chenguodong605a9a42011-08-22 18:42:47 +0800272 script = [ x.encode('utf-8')
273 if issubclass(type(x), unicode)
274 else x
275 for x in script ]
276
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700277 script = Editor.EditString("\n".join(script)).split("\n")
278
279 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
280 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
281
282 project = None
283 todo = []
284
285 for line in script:
286 m = project_re.match(line)
287 if m:
288 name = m.group(1)
289 project = projects.get(name)
290 if not project:
291 _die('project %s not available for upload', name)
292 continue
293
294 m = branch_re.match(line)
295 if m:
296 name = m.group(1)
297 if not project:
298 _die('project for branch %s not in script', name)
299 branch = branches[project.name].get(name)
300 if not branch:
301 _die('branch %s not in %s', name, project.relpath)
302 todo.append(branch)
303 if not todo:
304 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700305
306 many_commits = False
307 for branch in todo:
308 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
309 many_commits = True
310 break
311 if many_commits:
312 if not _ConfirmManyUploads(multiple_branches=True):
313 _die("upload aborted by user")
314
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700315 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700316
bijia093fdb62013-11-28 09:19:22 +0800317 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700318 """
bijia093fdb62013-11-28 09:19:22 +0800319 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700320 Appends the list of users in the CC list in the git project's config if a
321 non-empty reviewer list was found.
322 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700323 name = branch.name
324 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800325
326 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
327 raw_list = project.config.GetString(key)
328 if not raw_list is None:
329 people[0].extend([entry.strip() for entry in raw_list.split(',')])
330
Ben Komalo08a3f682010-07-15 16:03:02 -0700331 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
332 raw_list = project.config.GetString(key)
333 if not raw_list is None and len(people[0]) > 0:
334 people[1].extend([entry.strip() for entry in raw_list.split(',')])
335
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700336 def _FindGerritChange(self, branch):
337 last_pub = branch.project.WasPublished(branch.name)
338 if last_pub is None:
339 return ""
340
341 refs = branch.GetPublishedRefs()
342 try:
343 # refs/changes/XYZ/N --> XYZ
344 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900345 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700346 return ""
347
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700348 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700349 have_errors = False
350 for branch in todo:
351 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700352 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800353 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700354
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500355 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700356 changes = branch.project.UncommitedFiles()
357 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900358 key = 'review.%s.autoupload' % branch.project.remote.review
359 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500360
David Pursehousec1b86a22012-11-14 11:36:51 +0900361 # if they want to auto upload, let's not ask because it could be automated
362 if answer is None:
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700363 sys.stdout.write('Uncommitted changes in ' + branch.project.name)
364 sys.stdout.write(' (did you forget to amend?):\n')
365 sys.stdout.write('\n'.join(changes) + '\n')
366 sys.stdout.write('Continue uploading? (y/N) ')
David Pursehousec1b86a22012-11-14 11:36:51 +0900367 a = sys.stdin.readline().strip().lower()
368 if a not in ('y', 'yes', 't', 'true', 'on'):
369 print("skipping upload", file=sys.stderr)
370 branch.uploaded = False
371 branch.error = 'User aborted'
372 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500373
Anthony Russellod666e932012-06-01 00:48:22 -0400374 # Check if topic branches should be sent to the server during upload
375 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900376 key = 'review.%s.uploadtopic' % branch.project.remote.review
377 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400378
Colin Cross59b31cb2013-10-08 23:10:52 -0700379 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700380
381 # Make sure our local branch is not setup to track a different remote branch
382 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700383 if destination:
384 full_dest = 'refs/heads/%s' % destination
385 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
386 print('merge branch %s does not match destination branch %s'
387 % (merge_branch, full_dest))
388 print('skipping upload.')
389 print('Please use `--destination %s` if this is intentional'
390 % destination)
391 branch.uploaded = False
392 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700393
Changcheng Xiao87984c62017-08-02 16:55:03 +0200394 branch.UploadForReview(people,
395 auto_topic=opt.auto_topic,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000396 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200397 private=opt.private,
398 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200399 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800400 validate_certs=opt.validate_certs,
401 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200402
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700403 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700404 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700405 branch.error = e
406 branch.uploaded = False
407 have_errors = True
408
Sarah Owenscecd1d82012-11-01 22:59:27 -0700409 print(file=sys.stderr)
410 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700411
412 if have_errors:
413 for branch in todo:
414 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700415 if len(str(branch.error)) <= 30:
416 fmt = ' (%s)'
417 else:
418 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700419 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700420 branch.project.relpath + '/', \
421 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700422 str(branch.error)),
423 file=sys.stderr)
424 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700425
426 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900427 if branch.uploaded:
428 print('[OK ] %-15s %s' % (
429 branch.project.relpath + '/',
430 branch.name),
431 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700432
433 if have_errors:
434 sys.exit(1)
435
Conley Owens3bfd7212013-09-30 15:54:38 -0700436 def _GetMergeBranch(self, project):
437 p = GitCommand(project,
438 ['rev-parse', '--abbrev-ref', 'HEAD'],
439 capture_stdout = True,
440 capture_stderr = True)
441 p.Wait()
442 local_branch = p.stdout.strip()
443 p = GitCommand(project,
444 ['config', '--get', 'branch.%s.merge' % local_branch],
445 capture_stdout = True,
446 capture_stderr = True)
447 p.Wait()
448 merge_branch = p.stdout.strip()
449 return merge_branch
450
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700451 def Execute(self, opt, args):
452 project_list = self.GetProjects(args)
453 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500454 reviewers = []
455 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700456 branch = None
457
458 if opt.branch:
459 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500460
Doug Anderson37282b42011-03-04 11:54:18 -0800461 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400462 if opt.current_branch:
463 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800464 up_branch = project.GetUploadableBranch(cbr)
465 if up_branch:
466 avail = [up_branch]
467 else:
468 avail = None
469 print('ERROR: Current branch (%s) not uploadable. '
470 'You may be able to type '
471 '"git branch --set-upstream-to m/master" to fix '
472 'your branch.' % str(cbr),
473 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400474 else:
475 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800476 if avail:
477 pending.append((project, avail))
478
Mike Frysinger163a3be2016-04-04 17:31:32 -0400479 if not pending:
480 print("no branches ready for upload", file=sys.stderr)
481 return
482
483 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800484 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400485 self.manifest.topdir,
486 self.manifest.manifestProject.GetRemote('origin').url,
487 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900488 pending_proj_names = [project.name for (project, available) in pending]
489 pending_worktrees = [project.worktree for (project, available) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800490 try:
David James8d201162013-10-11 17:03:19 -0700491 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
492 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700493 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700494 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800495 return
496
Joe Onorato2896a792008-11-17 16:56:36 -0500497 if opt.reviewers:
498 reviewers = _SplitEmails(opt.reviewers)
499 if opt.cc:
500 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900501 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700502
Mike Frysinger163a3be2016-04-04 17:31:32 -0400503 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700504 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700505 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700506 self._MultipleBranches(opt, pending, people)