blob: 60feff7a850af06c0d39d97c628d0c1a13c07997 [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.')
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,
396 validate_certs=opt.validate_certs)
397
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700398 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700399 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700400 branch.error = e
401 branch.uploaded = False
402 have_errors = True
403
Sarah Owenscecd1d82012-11-01 22:59:27 -0700404 print(file=sys.stderr)
405 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700406
407 if have_errors:
408 for branch in todo:
409 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700410 if len(str(branch.error)) <= 30:
411 fmt = ' (%s)'
412 else:
413 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700414 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700415 branch.project.relpath + '/', \
416 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700417 str(branch.error)),
418 file=sys.stderr)
419 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700420
421 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900422 if branch.uploaded:
423 print('[OK ] %-15s %s' % (
424 branch.project.relpath + '/',
425 branch.name),
426 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700427
428 if have_errors:
429 sys.exit(1)
430
Conley Owens3bfd7212013-09-30 15:54:38 -0700431 def _GetMergeBranch(self, project):
432 p = GitCommand(project,
433 ['rev-parse', '--abbrev-ref', 'HEAD'],
434 capture_stdout = True,
435 capture_stderr = True)
436 p.Wait()
437 local_branch = p.stdout.strip()
438 p = GitCommand(project,
439 ['config', '--get', 'branch.%s.merge' % local_branch],
440 capture_stdout = True,
441 capture_stderr = True)
442 p.Wait()
443 merge_branch = p.stdout.strip()
444 return merge_branch
445
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700446 def Execute(self, opt, args):
447 project_list = self.GetProjects(args)
448 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500449 reviewers = []
450 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700451 branch = None
452
453 if opt.branch:
454 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500455
Doug Anderson37282b42011-03-04 11:54:18 -0800456 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400457 if opt.current_branch:
458 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800459 up_branch = project.GetUploadableBranch(cbr)
460 if up_branch:
461 avail = [up_branch]
462 else:
463 avail = None
464 print('ERROR: Current branch (%s) not uploadable. '
465 'You may be able to type '
466 '"git branch --set-upstream-to m/master" to fix '
467 'your branch.' % str(cbr),
468 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400469 else:
470 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800471 if avail:
472 pending.append((project, avail))
473
Mike Frysinger163a3be2016-04-04 17:31:32 -0400474 if not pending:
475 print("no branches ready for upload", file=sys.stderr)
476 return
477
478 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800479 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400480 self.manifest.topdir,
481 self.manifest.manifestProject.GetRemote('origin').url,
482 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900483 pending_proj_names = [project.name for (project, available) in pending]
484 pending_worktrees = [project.worktree for (project, available) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800485 try:
David James8d201162013-10-11 17:03:19 -0700486 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
487 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700488 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700489 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800490 return
491
Joe Onorato2896a792008-11-17 16:56:36 -0500492 if opt.reviewers:
493 reviewers = _SplitEmails(opt.reviewers)
494 if opt.cc:
495 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900496 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700497
Mike Frysinger163a3be2016-04-04 17:31:32 -0400498 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700499 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700500 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700501 self._MultipleBranches(opt, pending, people)