blob: d12efd1a8d0ebea2de06020023219f5d4eac8e2c [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
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070081Configuration
82-------------
83
84review.URL.autoupload:
85
Mike Frysingere9311272011-08-11 15:46:43 -040086To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070087or global Git configuration option. If review.URL.autoupload is set
88to "true" then repo will assume you always answer "y" at the prompt,
89and will not prompt you further. If it is set to "false" then repo
90will assume you always answer "n", and will abort.
91
bijia093fdb62013-11-28 09:19:22 +080092review.URL.autoreviewer:
93
94To automatically append a user or mailing list to reviews, you can set
95a per-project or global Git option to do so.
96
Ben Komalo08a3f682010-07-15 16:03:02 -070097review.URL.autocopy:
98
99To automatically copy a user or mailing list to all uploaded reviews,
100you can set a per-project or global Git option to do so. Specifically,
101review.URL.autocopy can be set to a comma separated list of reviewers
102who you always want copied on all uploads with a non-empty --re
103argument.
104
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700105review.URL.username:
106
107Override the username used to connect to Gerrit Code Review.
108By default the local part of the email address is used.
109
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700110The URL must match the review URL listed in the manifest XML file,
111or in the .git/config within the project. For example:
112
113 [remote "origin"]
114 url = git://git.example.com/project.git
115 review = http://review.example.com/
116
117 [review "http://review.example.com/"]
118 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700119 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700120
Anthony Russellod666e932012-06-01 00:48:22 -0400121review.URL.uploadtopic:
122
123To add a topic branch whenever uploading a commit, you can set a
124per-project or global Git option to do so. If review.URL.uploadtopic
125is set to "true" then repo will assume you always want the equivalent
126of the -t option to the repo command. If unset or set to "false" then
127repo will make use of only the command line option.
128
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700129References
130----------
131
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400132Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700133
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700134"""
135
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800136 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700137 p.add_option('-t',
138 dest='auto_topic', action='store_true',
139 help='Send local branch name to Gerrit Code Review')
Joe Onorato2896a792008-11-17 16:56:36 -0500140 p.add_option('--re', '--reviewers',
141 type='string', action='append', dest='reviewers',
142 help='Request reviews from these people.')
143 p.add_option('--cc',
144 type='string', action='append', dest='cc',
145 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700146 p.add_option('--br',
147 type='string', action='store', dest='branch',
148 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400149 p.add_option('--cbr', '--current-branch',
150 dest='current_branch', action='store_true',
151 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700152 p.add_option('-d', '--draft',
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000153 action='store_true', dest='draft', default=False,
154 help='If specified, upload as a draft.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200155 p.add_option('-p', '--private',
156 action='store_true', dest='private', default=False,
157 help='If specified, upload as a private change.')
158 p.add_option('-w', '--wip',
159 action='store_true', dest='wip', default=False,
160 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800161 p.add_option('-o', '--push-option',
162 type='string', action='append', dest='push_options',
163 default=[],
164 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400165 p.add_option('-D', '--destination', '--dest',
166 type='string', action='store', dest='dest_branch',
167 metavar='BRANCH',
168 help='Submit for review on this target branch.')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800169
Doug Anderson37282b42011-03-04 11:54:18 -0800170 # Options relating to upload hook. Note that verify and no-verify are NOT
171 # opposites of each other, which is why they store to different locations.
172 # We are using them to match 'git commit' syntax.
173 #
174 # Combinations:
175 # - no-verify=False, verify=False (DEFAULT):
176 # If stdout is a tty, can prompt about running upload hooks if needed.
177 # If user denies running hooks, the upload is cancelled. If stdout is
178 # not a tty and we would need to prompt about upload hooks, upload is
179 # cancelled.
180 # - no-verify=False, verify=True:
181 # Always run upload hooks with no prompt.
182 # - no-verify=True, verify=False:
183 # Never run upload hooks, but upload anyway (AKA bypass hooks).
184 # - no-verify=True, verify=True:
185 # Invalid
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200186 p.add_option('--no-cert-checks',
187 dest='validate_certs', action='store_false', default=True,
188 help='Disable verifying ssl certs (unsafe).')
Doug Anderson37282b42011-03-04 11:54:18 -0800189 p.add_option('--no-verify',
190 dest='bypass_hooks', action='store_true',
191 help='Do not run the upload hook.')
192 p.add_option('--verify',
193 dest='allow_all_hooks', action='store_true',
194 help='Run the upload hook without prompting.')
195
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700196 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700197 project = branch.project
198 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700199 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700200
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700201 key = 'review.%s.autoupload' % remote.review
202 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700203
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700204 if answer is False:
205 _die("upload blocked by %s = false" % key)
206
207 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700208 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900209 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700210
Chirayu Desai610d3c42013-06-24 14:02:12 +0530211 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200212 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000213 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700214 print(' branch %s (%2d commit%s, %s):' % (
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700215 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900216 len(commit_list),
217 len(commit_list) != 1 and 's' or '',
Sarah Owenscecd1d82012-11-01 22:59:27 -0700218 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900219 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700220 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700221
Mike Frysingere9311272011-08-11 15:46:43 -0400222 sys.stdout.write('to %s (y/N)? ' % remote.review)
David Pursehousefc241242012-11-14 09:19:39 +0900223 answer = sys.stdin.readline().strip().lower()
224 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700225
226 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700227 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
228 answer = _ConfirmManyUploads()
229
230 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700231 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700232 else:
233 _die("upload aborted by user")
234
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700235 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700236 projects = {}
237 branches = {}
238
239 script = []
240 script.append('# Uncomment the branches to upload:')
241 for project, avail in pending:
242 script.append('#')
243 script.append('# project %s/:' % project.relpath)
244
245 b = {}
246 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400247 if branch is None:
248 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700249 name = branch.name
250 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900251 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700252
253 if b:
254 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400255 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200256 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700257 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900258 len(commit_list),
259 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200260 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400261 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900262 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700263 script.append('# %s' % commit)
264 b[name] = branch
265
266 projects[project.relpath] = project
267 branches[project.name] = b
268 script.append('')
269
chenguodong605a9a42011-08-22 18:42:47 +0800270 script = [ x.encode('utf-8')
271 if issubclass(type(x), unicode)
272 else x
273 for x in script ]
274
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700275 script = Editor.EditString("\n".join(script)).split("\n")
276
277 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
278 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
279
280 project = None
281 todo = []
282
283 for line in script:
284 m = project_re.match(line)
285 if m:
286 name = m.group(1)
287 project = projects.get(name)
288 if not project:
289 _die('project %s not available for upload', name)
290 continue
291
292 m = branch_re.match(line)
293 if m:
294 name = m.group(1)
295 if not project:
296 _die('project for branch %s not in script', name)
297 branch = branches[project.name].get(name)
298 if not branch:
299 _die('branch %s not in %s', name, project.relpath)
300 todo.append(branch)
301 if not todo:
302 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700303
304 many_commits = False
305 for branch in todo:
306 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
307 many_commits = True
308 break
309 if many_commits:
310 if not _ConfirmManyUploads(multiple_branches=True):
311 _die("upload aborted by user")
312
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700313 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700314
bijia093fdb62013-11-28 09:19:22 +0800315 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700316 """
bijia093fdb62013-11-28 09:19:22 +0800317 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700318 Appends the list of users in the CC list in the git project's config if a
319 non-empty reviewer list was found.
320 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700321 name = branch.name
322 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800323
324 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
325 raw_list = project.config.GetString(key)
326 if not raw_list is None:
327 people[0].extend([entry.strip() for entry in raw_list.split(',')])
328
Ben Komalo08a3f682010-07-15 16:03:02 -0700329 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
330 raw_list = project.config.GetString(key)
331 if not raw_list is None and len(people[0]) > 0:
332 people[1].extend([entry.strip() for entry in raw_list.split(',')])
333
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700334 def _FindGerritChange(self, branch):
335 last_pub = branch.project.WasPublished(branch.name)
336 if last_pub is None:
337 return ""
338
339 refs = branch.GetPublishedRefs()
340 try:
341 # refs/changes/XYZ/N --> XYZ
342 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900343 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700344 return ""
345
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700346 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700347 have_errors = False
348 for branch in todo:
349 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700350 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800351 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700352
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500353 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700354 changes = branch.project.UncommitedFiles()
355 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900356 key = 'review.%s.autoupload' % branch.project.remote.review
357 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500358
David Pursehousec1b86a22012-11-14 11:36:51 +0900359 # if they want to auto upload, let's not ask because it could be automated
360 if answer is None:
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700361 sys.stdout.write('Uncommitted changes in ' + branch.project.name)
362 sys.stdout.write(' (did you forget to amend?):\n')
363 sys.stdout.write('\n'.join(changes) + '\n')
364 sys.stdout.write('Continue uploading? (y/N) ')
David Pursehousec1b86a22012-11-14 11:36:51 +0900365 a = sys.stdin.readline().strip().lower()
366 if a not in ('y', 'yes', 't', 'true', 'on'):
367 print("skipping upload", file=sys.stderr)
368 branch.uploaded = False
369 branch.error = 'User aborted'
370 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500371
Anthony Russellod666e932012-06-01 00:48:22 -0400372 # Check if topic branches should be sent to the server during upload
373 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900374 key = 'review.%s.uploadtopic' % branch.project.remote.review
375 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400376
Colin Cross59b31cb2013-10-08 23:10:52 -0700377 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700378
379 # Make sure our local branch is not setup to track a different remote branch
380 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700381 if destination:
382 full_dest = 'refs/heads/%s' % destination
383 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
384 print('merge branch %s does not match destination branch %s'
385 % (merge_branch, full_dest))
386 print('skipping upload.')
387 print('Please use `--destination %s` if this is intentional'
388 % destination)
389 branch.uploaded = False
390 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700391
Changcheng Xiao87984c62017-08-02 16:55:03 +0200392 branch.UploadForReview(people,
393 auto_topic=opt.auto_topic,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000394 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200395 private=opt.private,
396 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200397 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800398 validate_certs=opt.validate_certs,
399 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200400
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700401 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700402 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700403 branch.error = e
404 branch.uploaded = False
405 have_errors = True
406
Sarah Owenscecd1d82012-11-01 22:59:27 -0700407 print(file=sys.stderr)
408 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700409
410 if have_errors:
411 for branch in todo:
412 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700413 if len(str(branch.error)) <= 30:
414 fmt = ' (%s)'
415 else:
416 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700417 print(('[FAILED] %-15s %-15s' + fmt) % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700418 branch.project.relpath + '/', \
419 branch.name, \
Sarah Owenscecd1d82012-11-01 22:59:27 -0700420 str(branch.error)),
421 file=sys.stderr)
422 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700423
424 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900425 if branch.uploaded:
426 print('[OK ] %-15s %s' % (
427 branch.project.relpath + '/',
428 branch.name),
429 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700430
431 if have_errors:
432 sys.exit(1)
433
Conley Owens3bfd7212013-09-30 15:54:38 -0700434 def _GetMergeBranch(self, project):
435 p = GitCommand(project,
436 ['rev-parse', '--abbrev-ref', 'HEAD'],
437 capture_stdout = True,
438 capture_stderr = True)
439 p.Wait()
440 local_branch = p.stdout.strip()
441 p = GitCommand(project,
442 ['config', '--get', 'branch.%s.merge' % local_branch],
443 capture_stdout = True,
444 capture_stderr = True)
445 p.Wait()
446 merge_branch = p.stdout.strip()
447 return merge_branch
448
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700449 def Execute(self, opt, args):
450 project_list = self.GetProjects(args)
451 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500452 reviewers = []
453 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700454 branch = None
455
456 if opt.branch:
457 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500458
Doug Anderson37282b42011-03-04 11:54:18 -0800459 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400460 if opt.current_branch:
461 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800462 up_branch = project.GetUploadableBranch(cbr)
463 if up_branch:
464 avail = [up_branch]
465 else:
466 avail = None
467 print('ERROR: Current branch (%s) not uploadable. '
468 'You may be able to type '
469 '"git branch --set-upstream-to m/master" to fix '
470 'your branch.' % str(cbr),
471 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400472 else:
473 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800474 if avail:
475 pending.append((project, avail))
476
Mike Frysinger163a3be2016-04-04 17:31:32 -0400477 if not pending:
478 print("no branches ready for upload", file=sys.stderr)
479 return
480
481 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800482 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400483 self.manifest.topdir,
484 self.manifest.manifestProject.GetRemote('origin').url,
485 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900486 pending_proj_names = [project.name for (project, available) in pending]
487 pending_worktrees = [project.worktree for (project, available) in pending]
Doug Anderson37282b42011-03-04 11:54:18 -0800488 try:
David James8d201162013-10-11 17:03:19 -0700489 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
490 worktree_list=pending_worktrees)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700491 except HookError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700492 print("ERROR: %s" % str(e), file=sys.stderr)
Doug Anderson37282b42011-03-04 11:54:18 -0800493 return
494
Joe Onorato2896a792008-11-17 16:56:36 -0500495 if opt.reviewers:
496 reviewers = _SplitEmails(opt.reviewers)
497 if opt.cc:
498 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900499 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700500
Mike Frysinger163a3be2016-04-04 17:31:32 -0400501 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700502 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700503 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700504 self._MultipleBranches(opt, pending, people)