blob: cf3c8a9fe189b96ac2158515e832d078627c480a [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 Frysinger84685ba2020-02-19 02:22:22 -0500133review.URL.uploadhashtags:
134
135To add hashtags whenever uploading a commit, you can set a per-project
136or global Git option to do so. The value of review.URL.uploadhashtags
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500137will be used as comma delimited hashtags like the --hashtag option.
138
139review.URL.uploadlabels:
140
141To add labels whenever uploading a commit, you can set a per-project
142or global Git option to do so. The value of review.URL.uploadlabels
143will be used as comma delimited labels like the --label option.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500144
Mike Frysingerf725e542020-03-14 17:39:03 -0400145review.URL.uploadnotify:
146
147Control e-mail notifications when uploading.
148https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify
149
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400150# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700151
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400152Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700153
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700154"""
155
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800156 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700157 p.add_option('-t',
158 dest='auto_topic', action='store_true',
159 help='Send local branch name to Gerrit Code Review')
Mike Frysinger84685ba2020-02-19 02:22:22 -0500160 p.add_option('--hashtag', '--ht',
161 dest='hashtags', action='append', default=[],
162 help='Add hashtags (comma delimited) to the review.')
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500163 p.add_option('--hashtag-branch', '--htb',
164 action='store_true',
165 help='Add local branch name as a hashtag.')
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500166 p.add_option('-l', '--label',
167 dest='labels', action='append', default=[],
168 help='Add a label when uploading.')
Joe Onorato2896a792008-11-17 16:56:36 -0500169 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900170 type='string', action='append', dest='reviewers',
Joe Onorato2896a792008-11-17 16:56:36 -0500171 help='Request reviews from these people.')
172 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900173 type='string', action='append', dest='cc',
Joe Onorato2896a792008-11-17 16:56:36 -0500174 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700175 p.add_option('--br',
David Pursehouse08671042020-02-12 13:52:31 +0900176 type='string', action='store', dest='branch',
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700177 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400178 p.add_option('--cbr', '--current-branch',
179 dest='current_branch', action='store_true',
180 help='Upload current git branch.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700181 p.add_option('--ne', '--no-emails',
182 action='store_false', dest='notify', default=True,
183 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200184 p.add_option('-p', '--private',
185 action='store_true', dest='private', default=False,
186 help='If specified, upload as a private change.')
187 p.add_option('-w', '--wip',
188 action='store_true', dest='wip', default=False,
189 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800190 p.add_option('-o', '--push-option',
191 type='string', action='append', dest='push_options',
192 default=[],
193 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400194 p.add_option('-D', '--destination', '--dest',
195 type='string', action='store', dest='dest_branch',
196 metavar='BRANCH',
197 help='Submit for review on this target branch.')
Mike Frysinger819cc812020-02-19 02:27:22 -0500198 p.add_option('-n', '--dry-run',
199 dest='dryrun', default=False, action='store_true',
200 help='Do everything except actually upload the CL.')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500201 p.add_option('-y', '--yes',
202 default=False, action='store_true',
203 help='Answer yes to all safe prompts.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500204 p.add_option('--no-cert-checks',
205 dest='validate_certs', action='store_false', default=True,
206 help='Disable verifying ssl certs (unsafe).')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800207
Doug Anderson37282b42011-03-04 11:54:18 -0800208 # Options relating to upload hook. Note that verify and no-verify are NOT
209 # opposites of each other, which is why they store to different locations.
210 # We are using them to match 'git commit' syntax.
211 #
212 # Combinations:
213 # - no-verify=False, verify=False (DEFAULT):
214 # If stdout is a tty, can prompt about running upload hooks if needed.
215 # If user denies running hooks, the upload is cancelled. If stdout is
216 # not a tty and we would need to prompt about upload hooks, upload is
217 # cancelled.
218 # - no-verify=False, verify=True:
219 # Always run upload hooks with no prompt.
220 # - no-verify=True, verify=False:
221 # Never run upload hooks, but upload anyway (AKA bypass hooks).
222 # - no-verify=True, verify=True:
223 # Invalid
Mike Frysinger21c15752020-02-11 05:17:16 -0500224 g = p.add_option_group('Upload hooks')
225 g.add_option('--no-verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800226 dest='bypass_hooks', action='store_true',
227 help='Do not run the upload hook.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500228 g.add_option('--verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800229 dest='allow_all_hooks', action='store_true',
230 help='Run the upload hook without prompting.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500231 g.add_option('--ignore-hooks',
232 dest='ignore_hooks', action='store_true',
233 help='Do not abort uploading if upload hooks fail.')
Doug Anderson37282b42011-03-04 11:54:18 -0800234
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700235 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700236 project = branch.project
237 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700238 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700239
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700240 key = 'review.%s.autoupload' % remote.review
241 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700242
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700243 if answer is False:
244 _die("upload blocked by %s = false" % key)
245
246 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700247 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900248 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700249
Chirayu Desai610d3c42013-06-24 14:02:12 +0530250 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200251 print('Upload project %s/ to remote branch %s%s:' %
Mike Frysingerb0fbc7f2020-02-25 02:58:04 -0500252 (project.relpath, destination, ' (private)' if opt.private else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700253 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900254 name,
255 len(commit_list),
256 len(commit_list) != 1 and 's' or '',
257 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900258 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700259 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700260
Mike Frysingerab85fe72019-07-04 17:35:11 -0400261 print('to %s (y/N)? ' % remote.review, end='')
262 # TODO: When we require Python 3, use flush=True w/print above.
263 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500264 if opt.yes:
265 print('<--yes>')
266 answer = True
267 else:
268 answer = sys.stdin.readline().strip().lower()
269 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700270
271 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700272 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
273 answer = _ConfirmManyUploads()
274
275 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700276 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700277 else:
278 _die("upload aborted by user")
279
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700280 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700281 projects = {}
282 branches = {}
283
284 script = []
285 script.append('# Uncomment the branches to upload:')
286 for project, avail in pending:
287 script.append('#')
288 script.append('# project %s/:' % project.relpath)
289
290 b = {}
291 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400292 if branch is None:
293 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700294 name = branch.name
295 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900296 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700297
298 if b:
299 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400300 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200301 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700302 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900303 len(commit_list),
304 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200305 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400306 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900307 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700308 script.append('# %s' % commit)
309 b[name] = branch
310
311 projects[project.relpath] = project
312 branches[project.name] = b
313 script.append('')
314
315 script = Editor.EditString("\n".join(script)).split("\n")
316
317 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
318 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
319
320 project = None
321 todo = []
322
323 for line in script:
324 m = project_re.match(line)
325 if m:
326 name = m.group(1)
327 project = projects.get(name)
328 if not project:
329 _die('project %s not available for upload', name)
330 continue
331
332 m = branch_re.match(line)
333 if m:
334 name = m.group(1)
335 if not project:
336 _die('project for branch %s not in script', name)
337 branch = branches[project.name].get(name)
338 if not branch:
339 _die('branch %s not in %s', name, project.relpath)
340 todo.append(branch)
341 if not todo:
342 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700343
344 many_commits = False
345 for branch in todo:
346 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
347 many_commits = True
348 break
349 if many_commits:
350 if not _ConfirmManyUploads(multiple_branches=True):
351 _die("upload aborted by user")
352
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700353 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700354
bijia093fdb62013-11-28 09:19:22 +0800355 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700356 """
bijia093fdb62013-11-28 09:19:22 +0800357 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700358 Appends the list of users in the CC list in the git project's config if a
359 non-empty reviewer list was found.
360 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700361 name = branch.name
362 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800363
364 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
365 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900366 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800367 people[0].extend([entry.strip() for entry in raw_list.split(',')])
368
Ben Komalo08a3f682010-07-15 16:03:02 -0700369 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
370 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900371 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700372 people[1].extend([entry.strip() for entry in raw_list.split(',')])
373
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700374 def _FindGerritChange(self, branch):
375 last_pub = branch.project.WasPublished(branch.name)
376 if last_pub is None:
377 return ""
378
379 refs = branch.GetPublishedRefs()
380 try:
381 # refs/changes/XYZ/N --> XYZ
382 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900383 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700384 return ""
385
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700386 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700387 have_errors = False
388 for branch in todo:
389 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700390 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800391 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700392
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500393 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700394 changes = branch.project.UncommitedFiles()
395 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900396 key = 'review.%s.autoupload' % branch.project.remote.review
397 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500398
David Pursehousec1b86a22012-11-14 11:36:51 +0900399 # if they want to auto upload, let's not ask because it could be automated
400 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400401 print()
402 print('Uncommitted changes in %s (did you forget to amend?):'
403 % branch.project.name)
404 print('\n'.join(changes))
405 print('Continue uploading? (y/N) ', end='')
406 # TODO: When we require Python 3, use flush=True w/print above.
407 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500408 if opt.yes:
409 print('<--yes>')
410 a = 'yes'
411 else:
412 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900413 if a not in ('y', 'yes', 't', 'true', 'on'):
414 print("skipping upload", file=sys.stderr)
415 branch.uploaded = False
416 branch.error = 'User aborted'
417 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500418
Anthony Russellod666e932012-06-01 00:48:22 -0400419 # Check if topic branches should be sent to the server during upload
420 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900421 key = 'review.%s.uploadtopic' % branch.project.remote.review
422 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400423
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500424 def _ExpandCommaList(value):
425 """Split |value| up into comma delimited entries."""
Mike Frysinger84685ba2020-02-19 02:22:22 -0500426 if not value:
427 return
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500428 for ret in value.split(','):
429 ret = ret.strip()
430 if ret:
431 yield ret
432
433 # Check if hashtags should be included.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500434 key = 'review.%s.uploadhashtags' % branch.project.remote.review
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500435 hashtags = set(_ExpandCommaList(branch.project.config.GetString(key)))
Mike Frysinger84685ba2020-02-19 02:22:22 -0500436 for tag in opt.hashtags:
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500437 hashtags.update(_ExpandCommaList(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500438 if opt.hashtag_branch:
439 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500440
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500441 # Check if labels should be included.
442 key = 'review.%s.uploadlabels' % branch.project.remote.review
443 labels = set(_ExpandCommaList(branch.project.config.GetString(key)))
444 for label in opt.labels:
445 labels.update(_ExpandCommaList(label))
446 # Basic sanity check on label syntax.
447 for label in labels:
448 if not re.match(r'^.+[+-][0-9]+$', label):
449 print('repo: error: invalid label syntax "%s": labels use forms '
450 'like CodeReview+1 or Verified-1' % (label,), file=sys.stderr)
451 sys.exit(1)
452
Mike Frysingerf725e542020-03-14 17:39:03 -0400453 # Handle e-mail notifications.
454 if opt.notify is False:
455 notify = 'NONE'
456 else:
457 key = 'review.%s.uploadnotify' % branch.project.remote.review
458 notify = branch.project.config.GetString(key)
459
Colin Cross59b31cb2013-10-08 23:10:52 -0700460 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700461
462 # Make sure our local branch is not setup to track a different remote branch
463 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700464 if destination:
465 full_dest = 'refs/heads/%s' % destination
466 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
467 print('merge branch %s does not match destination branch %s'
468 % (merge_branch, full_dest))
469 print('skipping upload.')
470 print('Please use `--destination %s` if this is intentional'
471 % destination)
472 branch.uploaded = False
473 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700474
Changcheng Xiao87984c62017-08-02 16:55:03 +0200475 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500476 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200477 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500478 hashtags=hashtags,
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500479 labels=labels,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200480 private=opt.private,
Mike Frysingerf725e542020-03-14 17:39:03 -0400481 notify=notify,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200482 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200483 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800484 validate_certs=opt.validate_certs,
485 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200486
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700487 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700488 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700489 branch.error = e
490 branch.uploaded = False
491 have_errors = True
492
Sarah Owenscecd1d82012-11-01 22:59:27 -0700493 print(file=sys.stderr)
494 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700495
496 if have_errors:
497 for branch in todo:
498 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700499 if len(str(branch.error)) <= 30:
500 fmt = ' (%s)'
501 else:
502 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700503 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900504 branch.project.relpath + '/',
505 branch.name,
506 str(branch.error)),
507 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700508 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700509
510 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900511 if branch.uploaded:
512 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900513 branch.project.relpath + '/',
514 branch.name),
515 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700516
517 if have_errors:
518 sys.exit(1)
519
Conley Owens3bfd7212013-09-30 15:54:38 -0700520 def _GetMergeBranch(self, project):
521 p = GitCommand(project,
522 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900523 capture_stdout=True,
524 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700525 p.Wait()
526 local_branch = p.stdout.strip()
527 p = GitCommand(project,
528 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900529 capture_stdout=True,
530 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700531 p.Wait()
532 merge_branch = p.stdout.strip()
533 return merge_branch
534
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700535 def Execute(self, opt, args):
536 project_list = self.GetProjects(args)
537 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500538 reviewers = []
539 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700540 branch = None
541
542 if opt.branch:
543 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500544
Doug Anderson37282b42011-03-04 11:54:18 -0800545 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400546 if opt.current_branch:
547 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800548 up_branch = project.GetUploadableBranch(cbr)
549 if up_branch:
550 avail = [up_branch]
551 else:
552 avail = None
553 print('ERROR: Current branch (%s) not uploadable. '
554 'You may be able to type '
555 '"git branch --set-upstream-to m/master" to fix '
556 'your branch.' % str(cbr),
557 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400558 else:
559 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800560 if avail:
561 pending.append((project, avail))
562
Mike Frysinger163a3be2016-04-04 17:31:32 -0400563 if not pending:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500564 if branch is None:
565 print('repo: error: no branches ready for upload', file=sys.stderr)
566 else:
567 print('repo: error: no branches named "%s" ready for upload' %
568 (branch,), file=sys.stderr)
569 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400570
571 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800572 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400573 self.manifest.topdir,
574 self.manifest.manifestProject.GetRemote('origin').url,
575 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900576 pending_proj_names = [project.name for (project, available) in pending]
577 pending_worktrees = [project.worktree for (project, available) in pending]
Mike Frysinger21c15752020-02-11 05:17:16 -0500578 passed = True
Doug Anderson37282b42011-03-04 11:54:18 -0800579 try:
David James8d201162013-10-11 17:03:19 -0700580 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
581 worktree_list=pending_worktrees)
Mike Frysinger21c15752020-02-11 05:17:16 -0500582 except SystemExit:
583 passed = False
584 if not opt.ignore_hooks:
585 raise
Sarah Owensa5be53f2012-09-09 15:37:57 -0700586 except HookError as e:
Mike Frysinger21c15752020-02-11 05:17:16 -0500587 passed = False
Sarah Owenscecd1d82012-11-01 22:59:27 -0700588 print("ERROR: %s" % str(e), file=sys.stderr)
Mike Frysinger21c15752020-02-11 05:17:16 -0500589
590 if not passed:
591 if opt.ignore_hooks:
592 print('\nWARNING: pre-upload hooks failed, but uploading anyways.',
593 file=sys.stderr)
594 else:
595 return
Doug Anderson37282b42011-03-04 11:54:18 -0800596
Joe Onorato2896a792008-11-17 16:56:36 -0500597 if opt.reviewers:
598 reviewers = _SplitEmails(opt.reviewers)
599 if opt.cc:
600 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900601 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700602
Mike Frysinger163a3be2016-04-04 17:31:32 -0400603 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700604 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700605 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700606 self._MultipleBranches(opt, pending, people)