blob: acb9d7f031f3981ea135cdfdc72b91c74899bf9a [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.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700153 p.add_option('--ne', '--no-emails',
154 action='store_false', dest='notify', default=True,
155 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200156 p.add_option('-p', '--private',
157 action='store_true', dest='private', default=False,
158 help='If specified, upload as a private change.')
159 p.add_option('-w', '--wip',
160 action='store_true', dest='wip', default=False,
161 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800162 p.add_option('-o', '--push-option',
163 type='string', action='append', dest='push_options',
164 default=[],
165 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400166 p.add_option('-D', '--destination', '--dest',
167 type='string', action='store', dest='dest_branch',
168 metavar='BRANCH',
169 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800170
Doug Anderson37282b42011-03-04 11:54:18 -0800171 # Options relating to upload hook. Note that verify and no-verify are NOT
172 # opposites of each other, which is why they store to different locations.
173 # We are using them to match 'git commit' syntax.
174 #
175 # Combinations:
176 # - no-verify=False, verify=False (DEFAULT):
177 # If stdout is a tty, can prompt about running upload hooks if needed.
178 # If user denies running hooks, the upload is cancelled. If stdout is
179 # not a tty and we would need to prompt about upload hooks, upload is
180 # cancelled.
181 # - no-verify=False, verify=True:
182 # Always run upload hooks with no prompt.
183 # - no-verify=True, verify=False:
184 # Never run upload hooks, but upload anyway (AKA bypass hooks).
185 # - no-verify=True, verify=True:
186 # Invalid
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200187 p.add_option('--no-cert-checks',
188 dest='validate_certs', action='store_false', default=True,
189 help='Disable verifying ssl certs (unsafe).')
Doug Anderson37282b42011-03-04 11:54:18 -0800190 p.add_option('--no-verify',
191 dest='bypass_hooks', action='store_true',
192 help='Do not run the upload hook.')
193 p.add_option('--verify',
194 dest='allow_all_hooks', action='store_true',
195 help='Run the upload hook without prompting.')
196
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700197 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700198 project = branch.project
199 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700200 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700201
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700202 key = 'review.%s.autoupload' % remote.review
203 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700204
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700205 if answer is False:
206 _die("upload blocked by %s = false" % key)
207
208 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700209 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900210 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700211
Chirayu Desai610d3c42013-06-24 14:02:12 +0530212 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200213 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000214 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700215 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700216 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900217 len(commit_list),
218 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700219 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900220 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700221 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700222
Mike Frysingere9311272011-08-11 15:46:43 -0400223 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900224 answer = sys.stdin.readline().strip().lower()
225 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700226
227 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700228 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
229 answer = _ConfirmManyUploads()
230
231 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700232 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700233 else:
234 _die("upload aborted by user")
235
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700236 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700237 projects = {}
238 branches = {}
239
240 script = []
241 script.append('# Uncomment the branches to upload:')
242 for project, avail in pending:
243 script.append('#')
244 script.append('# project %s/:' % project.relpath)
245
246 b = {}
247 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400248 if branch is None:
249 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700250 name = branch.name
251 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900252 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700253
254 if b:
255 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400256 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200257 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700258 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900259 len(commit_list),
260 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200261 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400262 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900263 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700264 script.append('# %s' % commit)
265 b[name] = branch
266
267 projects[project.relpath] = project
268 branches[project.name] = b
269 script.append('')
270
chenguodong605a9a42011-08-22 18:42:47 +0800271 script = [ x.encode('utf-8')
272 if issubclass(type(x), unicode)
273 else x
274 for x in script ]
275
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700276 script = Editor.EditString("\n".join(script)).split("\n")
277
278 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
279 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
280
281 project = None
282 todo = []
283
284 for line in script:
285 m = project_re.match(line)
286 if m:
287 name = m.group(1)
288 project = projects.get(name)
289 if not project:
290 _die('project %s not available for upload', name)
291 continue
292
293 m = branch_re.match(line)
294 if m:
295 name = m.group(1)
296 if not project:
297 _die('project for branch %s not in script', name)
298 branch = branches[project.name].get(name)
299 if not branch:
300 _die('branch %s not in %s', name, project.relpath)
301 todo.append(branch)
302 if not todo:
303 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700304
305 many_commits = False
306 for branch in todo:
307 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
308 many_commits = True
309 break
310 if many_commits:
311 if not _ConfirmManyUploads(multiple_branches=True):
312 _die("upload aborted by user")
313
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700314 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700315
bijia093fdb62013-11-28 09:19:22 +0800316 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700317 """
bijia093fdb62013-11-28 09:19:22 +0800318 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700319 Appends the list of users in the CC list in the git project's config if a
320 non-empty reviewer list was found.
321 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700322 name = branch.name
323 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800324
325 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
326 raw_list = project.config.GetString(key)
327 if not raw_list is None:
328 people[0].extend([entry.strip() for entry in raw_list.split(',')])
329
Ben Komalo08a3f682010-07-15 16:03:02 -0700330 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
331 raw_list = project.config.GetString(key)
332 if not raw_list is None and len(people[0]) > 0:
333 people[1].extend([entry.strip() for entry in raw_list.split(',')])
334
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700335 def _FindGerritChange(self, branch):
336 last_pub = branch.project.WasPublished(branch.name)
337 if last_pub is None:
338 return ""
339
340 refs = branch.GetPublishedRefs()
341 try:
342 # refs/changes/XYZ/N --> XYZ
343 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900344 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700345 return ""
346
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700347 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700348 have_errors = False
349 for branch in todo:
350 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700351 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800352 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700353
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500354 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700355 changes = branch.project.UncommitedFiles()
356 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900357 key = 'review.%s.autoupload' % branch.project.remote.review
358 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500359
David Pursehousec1b86a22012-11-14 11:36:51 +0900360 # if they want to auto upload, let's not ask because it could be automated
361 if answer is None:
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700362 sys.stdout.write('Uncommitted changes in ' + branch.project.name)
363 sys.stdout.write(' (did you forget to amend?):\n')
364 sys.stdout.write('\n'.join(changes) + '\n')
365 sys.stdout.write('Continue uploading? (y/N) ')
David Pursehousec1b86a22012-11-14 11:36:51 +0900366 a = sys.stdin.readline().strip().lower()
367 if a not in ('y', 'yes', 't', 'true', 'on'):
368 print("skipping upload", file=sys.stderr)
369 branch.uploaded = False
370 branch.error = 'User aborted'
371 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500372
Anthony Russellod666e932012-06-01 00:48:22 -0400373 # Check if topic branches should be sent to the server during upload
374 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900375 key = 'review.%s.uploadtopic' % branch.project.remote.review
376 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400377
Colin Cross59b31cb2013-10-08 23:10:52 -0700378 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700379
380 # Make sure our local branch is not setup to track a different remote branch
381 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700382 if destination:
383 full_dest = 'refs/heads/%s' % destination
384 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
385 print('merge branch %s does not match destination branch %s'
386 % (merge_branch, full_dest))
387 print('skipping upload.')
388 print('Please use `--destination %s` if this is intentional'
389 % destination)
390 branch.uploaded = False
391 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700392
Changcheng Xiao87984c62017-08-02 16:55:03 +0200393 branch.UploadForReview(people,
394 auto_topic=opt.auto_topic,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000395 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200396 private=opt.private,
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700397 notify=None if opt.notify else 'NONE',
Changcheng Xiao87984c62017-08-02 16:55:03 +0200398 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)