blob: 91bec6f87c2461b559e02320dc93865523bea6e0 [file] [log] [blame]
Mike Frysingerf6013762019-06-13 02:30:51 -04001# -*- coding:utf-8 -*-
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07002#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Sarah Owenscecd1d82012-11-01 22:59:27 -070017from __future__ import print_function
Ben Komalo08a3f682010-07-15 16:03:02 -070018import copy
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070019import re
20import sys
21
22from command import InteractiveCommand
23from editor import Editor
Doug Anderson37282b42011-03-04 11:54:18 -080024from error import HookError, UploadError
Conley Owens3bfd7212013-09-30 15:54:38 -070025from git_command import GitCommand
Doug Anderson37282b42011-03-04 11:54:18 -080026from project import RepoHook
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070027
David Pursehouse59bbb582013-05-17 10:49:33 +090028from pyversion import is_python3
29if not is_python3():
David Pursehousea46bf7d2020-02-15 12:45:53 +090030 input = raw_input # noqa: F821
Anthony Kingd792f792014-05-05 22:01:07 +010031else:
32 unicode = str
Chirayu Desai217ea7d2013-03-01 19:14:38 +053033
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070034UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070035
David Pursehouse819827a2020-02-12 15:20:19 +090036
Dan Morrill879a9a52010-05-04 16:56:07 -070037def _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
David Pursehouse819827a2020-02-12 15:20:19 +090048
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070049def _die(fmt, *args):
50 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070051 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070052 sys.exit(1)
53
David Pursehouse819827a2020-02-12 15:20:19 +090054
Joe Onorato2896a792008-11-17 16:56:36 -050055def _SplitEmails(values):
56 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090057 for value in values:
58 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050059 return result
60
David Pursehouse819827a2020-02-12 15:20:19 +090061
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070062class Upload(InteractiveCommand):
63 common = True
64 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090065 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070066%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070067"""
68 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070069The '%prog' command is used to send changes to the Gerrit Code
70Review system. It searches for topic branches in local projects
71that have not yet been published for review. If multiple topic
72branches are found, '%prog' opens an editor to allow the user to
73select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070074
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070075'%prog' searches for uploadable changes in all projects listed at
76the command line. Projects can be specified either by name, or by
77a relative or absolute path to the project's local directory. If no
78projects are specified, '%prog' will search for uploadable changes
79in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050080
81If the --reviewers or --cc options are passed, those emails are
82added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070083new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050084with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080085
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040086# Configuration
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070087
88review.URL.autoupload:
89
Mike Frysingere9311272011-08-11 15:46:43 -040090To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070091or global Git configuration option. If review.URL.autoupload is set
92to "true" then repo will assume you always answer "y" at the prompt,
93and will not prompt you further. If it is set to "false" then repo
94will assume you always answer "n", and will abort.
95
bijia093fdb62013-11-28 09:19:22 +080096review.URL.autoreviewer:
97
98To automatically append a user or mailing list to reviews, you can set
99a per-project or global Git option to do so.
100
Ben Komalo08a3f682010-07-15 16:03:02 -0700101review.URL.autocopy:
102
103To automatically copy a user or mailing list to all uploaded reviews,
104you can set a per-project or global Git option to do so. Specifically,
105review.URL.autocopy can be set to a comma separated list of reviewers
106who you always want copied on all uploads with a non-empty --re
107argument.
108
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700109review.URL.username:
110
111Override the username used to connect to Gerrit Code Review.
112By default the local part of the email address is used.
113
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700114The URL must match the review URL listed in the manifest XML file,
115or in the .git/config within the project. For example:
116
117 [remote "origin"]
118 url = git://git.example.com/project.git
119 review = http://review.example.com/
120
121 [review "http://review.example.com/"]
122 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700123 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700124
Anthony Russellod666e932012-06-01 00:48:22 -0400125review.URL.uploadtopic:
126
127To add a topic branch whenever uploading a commit, you can set a
128per-project or global Git option to do so. If review.URL.uploadtopic
129is set to "true" then repo will assume you always want the equivalent
130of the -t option to the repo command. If unset or set to "false" then
131repo will make use of only the command line option.
132
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400133# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700134
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400135Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700136
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700137"""
138
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800139 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700140 p.add_option('-t',
141 dest='auto_topic', action='store_true',
142 help='Send local branch name to Gerrit Code Review')
Joe Onorato2896a792008-11-17 16:56:36 -0500143 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900144 type='string', action='append', dest='reviewers',
Joe Onorato2896a792008-11-17 16:56:36 -0500145 help='Request reviews from these people.')
146 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900147 type='string', action='append', dest='cc',
Joe Onorato2896a792008-11-17 16:56:36 -0500148 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700149 p.add_option('--br',
David Pursehouse08671042020-02-12 13:52:31 +0900150 type='string', action='store', dest='branch',
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700151 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400152 p.add_option('--cbr', '--current-branch',
153 dest='current_branch', action='store_true',
154 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700155 p.add_option('-d', '--draft',
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000156 action='store_true', dest='draft', default=False,
157 help='If specified, upload as a draft.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700158 p.add_option('--ne', '--no-emails',
159 action='store_false', dest='notify', default=True,
160 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200161 p.add_option('-p', '--private',
162 action='store_true', dest='private', default=False,
163 help='If specified, upload as a private change.')
164 p.add_option('-w', '--wip',
165 action='store_true', dest='wip', default=False,
166 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800167 p.add_option('-o', '--push-option',
168 type='string', action='append', dest='push_options',
169 default=[],
170 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400171 p.add_option('-D', '--destination', '--dest',
172 type='string', action='store', dest='dest_branch',
173 metavar='BRANCH',
174 help='Submit for review on this target branch.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500175 p.add_option('--no-cert-checks',
176 dest='validate_certs', action='store_false', default=True,
177 help='Disable verifying ssl certs (unsafe).')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800178
Doug Anderson37282b42011-03-04 11:54:18 -0800179 # Options relating to upload hook. Note that verify and no-verify are NOT
180 # opposites of each other, which is why they store to different locations.
181 # We are using them to match 'git commit' syntax.
182 #
183 # Combinations:
184 # - no-verify=False, verify=False (DEFAULT):
185 # If stdout is a tty, can prompt about running upload hooks if needed.
186 # If user denies running hooks, the upload is cancelled. If stdout is
187 # not a tty and we would need to prompt about upload hooks, upload is
188 # cancelled.
189 # - no-verify=False, verify=True:
190 # Always run upload hooks with no prompt.
191 # - no-verify=True, verify=False:
192 # Never run upload hooks, but upload anyway (AKA bypass hooks).
193 # - no-verify=True, verify=True:
194 # Invalid
Mike Frysinger21c15752020-02-11 05:17:16 -0500195 g = p.add_option_group('Upload hooks')
196 g.add_option('--no-verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800197 dest='bypass_hooks', action='store_true',
198 help='Do not run the upload hook.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500199 g.add_option('--verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800200 dest='allow_all_hooks', action='store_true',
201 help='Run the upload hook without prompting.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500202 g.add_option('--ignore-hooks',
203 dest='ignore_hooks', action='store_true',
204 help='Do not abort uploading if upload hooks fail.')
Doug Anderson37282b42011-03-04 11:54:18 -0800205
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700206 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700207 project = branch.project
208 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700209 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700210
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700211 key = 'review.%s.autoupload' % remote.review
212 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700213
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700214 if answer is False:
215 _die("upload blocked by %s = false" % key)
216
217 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700218 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900219 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700220
Chirayu Desai610d3c42013-06-24 14:02:12 +0530221 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200222 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000223 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700224 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900225 name,
226 len(commit_list),
227 len(commit_list) != 1 and 's' or '',
228 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900229 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700230 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700231
Mike Frysingerab85fe72019-07-04 17:35:11 -0400232 print('to %s (y/N)? ' % remote.review, end='')
233 # TODO: When we require Python 3, use flush=True w/print above.
234 sys.stdout.flush()
David Pursehousefc241242012-11-14 09:19:39 +0900235 answer = sys.stdin.readline().strip().lower()
236 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700237
238 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700239 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
240 answer = _ConfirmManyUploads()
241
242 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700243 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700244 else:
245 _die("upload aborted by user")
246
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700247 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700248 projects = {}
249 branches = {}
250
251 script = []
252 script.append('# Uncomment the branches to upload:')
253 for project, avail in pending:
254 script.append('#')
255 script.append('# project %s/:' % project.relpath)
256
257 b = {}
258 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400259 if branch is None:
260 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700261 name = branch.name
262 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900263 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700264
265 if b:
266 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400267 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200268 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700269 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900270 len(commit_list),
271 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200272 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400273 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900274 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700275 script.append('# %s' % commit)
276 b[name] = branch
277
278 projects[project.relpath] = project
279 branches[project.name] = b
280 script.append('')
281
282 script = Editor.EditString("\n".join(script)).split("\n")
283
284 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
285 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
286
287 project = None
288 todo = []
289
290 for line in script:
291 m = project_re.match(line)
292 if m:
293 name = m.group(1)
294 project = projects.get(name)
295 if not project:
296 _die('project %s not available for upload', name)
297 continue
298
299 m = branch_re.match(line)
300 if m:
301 name = m.group(1)
302 if not project:
303 _die('project for branch %s not in script', name)
304 branch = branches[project.name].get(name)
305 if not branch:
306 _die('branch %s not in %s', name, project.relpath)
307 todo.append(branch)
308 if not todo:
309 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700310
311 many_commits = False
312 for branch in todo:
313 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
314 many_commits = True
315 break
316 if many_commits:
317 if not _ConfirmManyUploads(multiple_branches=True):
318 _die("upload aborted by user")
319
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700320 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700321
bijia093fdb62013-11-28 09:19:22 +0800322 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700323 """
bijia093fdb62013-11-28 09:19:22 +0800324 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700325 Appends the list of users in the CC list in the git project's config if a
326 non-empty reviewer list was found.
327 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700328 name = branch.name
329 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800330
331 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
332 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900333 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800334 people[0].extend([entry.strip() for entry in raw_list.split(',')])
335
Ben Komalo08a3f682010-07-15 16:03:02 -0700336 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
337 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900338 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700339 people[1].extend([entry.strip() for entry in raw_list.split(',')])
340
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700341 def _FindGerritChange(self, branch):
342 last_pub = branch.project.WasPublished(branch.name)
343 if last_pub is None:
344 return ""
345
346 refs = branch.GetPublishedRefs()
347 try:
348 # refs/changes/XYZ/N --> XYZ
349 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900350 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700351 return ""
352
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700353 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700354 have_errors = False
355 for branch in todo:
356 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700357 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800358 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700359
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500360 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700361 changes = branch.project.UncommitedFiles()
362 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900363 key = 'review.%s.autoupload' % branch.project.remote.review
364 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500365
David Pursehousec1b86a22012-11-14 11:36:51 +0900366 # if they want to auto upload, let's not ask because it could be automated
367 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400368 print()
369 print('Uncommitted changes in %s (did you forget to amend?):'
370 % branch.project.name)
371 print('\n'.join(changes))
372 print('Continue uploading? (y/N) ', end='')
373 # TODO: When we require Python 3, use flush=True w/print above.
374 sys.stdout.flush()
David Pursehousec1b86a22012-11-14 11:36:51 +0900375 a = sys.stdin.readline().strip().lower()
376 if a not in ('y', 'yes', 't', 'true', 'on'):
377 print("skipping upload", file=sys.stderr)
378 branch.uploaded = False
379 branch.error = 'User aborted'
380 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500381
Anthony Russellod666e932012-06-01 00:48:22 -0400382 # Check if topic branches should be sent to the server during upload
383 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900384 key = 'review.%s.uploadtopic' % branch.project.remote.review
385 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400386
Colin Cross59b31cb2013-10-08 23:10:52 -0700387 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700388
389 # Make sure our local branch is not setup to track a different remote branch
390 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700391 if destination:
392 full_dest = 'refs/heads/%s' % destination
393 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
394 print('merge branch %s does not match destination branch %s'
395 % (merge_branch, full_dest))
396 print('skipping upload.')
397 print('Please use `--destination %s` if this is intentional'
398 % destination)
399 branch.uploaded = False
400 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700401
Changcheng Xiao87984c62017-08-02 16:55:03 +0200402 branch.UploadForReview(people,
403 auto_topic=opt.auto_topic,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000404 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200405 private=opt.private,
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700406 notify=None if opt.notify else 'NONE',
Changcheng Xiao87984c62017-08-02 16:55:03 +0200407 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200408 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800409 validate_certs=opt.validate_certs,
410 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200411
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700412 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700413 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700414 branch.error = e
415 branch.uploaded = False
416 have_errors = True
417
Sarah Owenscecd1d82012-11-01 22:59:27 -0700418 print(file=sys.stderr)
419 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700420
421 if have_errors:
422 for branch in todo:
423 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700424 if len(str(branch.error)) <= 30:
425 fmt = ' (%s)'
426 else:
427 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700428 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900429 branch.project.relpath + '/',
430 branch.name,
431 str(branch.error)),
432 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700433 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700434
435 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900436 if branch.uploaded:
437 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900438 branch.project.relpath + '/',
439 branch.name),
440 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700441
442 if have_errors:
443 sys.exit(1)
444
Conley Owens3bfd7212013-09-30 15:54:38 -0700445 def _GetMergeBranch(self, project):
446 p = GitCommand(project,
447 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900448 capture_stdout=True,
449 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700450 p.Wait()
451 local_branch = p.stdout.strip()
452 p = GitCommand(project,
453 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900454 capture_stdout=True,
455 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700456 p.Wait()
457 merge_branch = p.stdout.strip()
458 return merge_branch
459
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700460 def Execute(self, opt, args):
461 project_list = self.GetProjects(args)
462 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500463 reviewers = []
464 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700465 branch = None
466
467 if opt.branch:
468 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500469
Doug Anderson37282b42011-03-04 11:54:18 -0800470 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400471 if opt.current_branch:
472 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800473 up_branch = project.GetUploadableBranch(cbr)
474 if up_branch:
475 avail = [up_branch]
476 else:
477 avail = None
478 print('ERROR: Current branch (%s) not uploadable. '
479 'You may be able to type '
480 '"git branch --set-upstream-to m/master" to fix '
481 'your branch.' % str(cbr),
482 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400483 else:
484 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800485 if avail:
486 pending.append((project, avail))
487
Mike Frysinger163a3be2016-04-04 17:31:32 -0400488 if not pending:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500489 if branch is None:
490 print('repo: error: no branches ready for upload', file=sys.stderr)
491 else:
492 print('repo: error: no branches named "%s" ready for upload' %
493 (branch,), file=sys.stderr)
494 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400495
496 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800497 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400498 self.manifest.topdir,
499 self.manifest.manifestProject.GetRemote('origin').url,
500 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900501 pending_proj_names = [project.name for (project, available) in pending]
502 pending_worktrees = [project.worktree for (project, available) in pending]
Mike Frysinger21c15752020-02-11 05:17:16 -0500503 passed = True
Doug Anderson37282b42011-03-04 11:54:18 -0800504 try:
David James8d201162013-10-11 17:03:19 -0700505 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
506 worktree_list=pending_worktrees)
Mike Frysinger21c15752020-02-11 05:17:16 -0500507 except SystemExit:
508 passed = False
509 if not opt.ignore_hooks:
510 raise
Sarah Owensa5be53f2012-09-09 15:37:57 -0700511 except HookError as e:
Mike Frysinger21c15752020-02-11 05:17:16 -0500512 passed = False
Sarah Owenscecd1d82012-11-01 22:59:27 -0700513 print("ERROR: %s" % str(e), file=sys.stderr)
Mike Frysinger21c15752020-02-11 05:17:16 -0500514
515 if not passed:
516 if opt.ignore_hooks:
517 print('\nWARNING: pre-upload hooks failed, but uploading anyways.',
518 file=sys.stderr)
519 else:
520 return
Doug Anderson37282b42011-03-04 11:54:18 -0800521
Joe Onorato2896a792008-11-17 16:56:36 -0500522 if opt.reviewers:
523 reviewers = _SplitEmails(opt.reviewers)
524 if opt.cc:
525 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900526 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700527
Mike Frysinger163a3be2016-04-04 17:31:32 -0400528 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700529 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700530 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700531 self._MultipleBranches(opt, pending, people)