blob: 93f9c1e7f1b74d3acac52af4425d0074da691e08 [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 Frysingerb8f7bb02018-10-10 01:05:11 -0400145# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700146
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400147Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700148
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700149"""
150
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800151 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700152 p.add_option('-t',
153 dest='auto_topic', action='store_true',
154 help='Send local branch name to Gerrit Code Review')
Mike Frysinger84685ba2020-02-19 02:22:22 -0500155 p.add_option('--hashtag', '--ht',
156 dest='hashtags', action='append', default=[],
157 help='Add hashtags (comma delimited) to the review.')
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500158 p.add_option('--hashtag-branch', '--htb',
159 action='store_true',
160 help='Add local branch name as a hashtag.')
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500161 p.add_option('-l', '--label',
162 dest='labels', action='append', default=[],
163 help='Add a label when uploading.')
Joe Onorato2896a792008-11-17 16:56:36 -0500164 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900165 type='string', action='append', dest='reviewers',
Joe Onorato2896a792008-11-17 16:56:36 -0500166 help='Request reviews from these people.')
167 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900168 type='string', action='append', dest='cc',
Joe Onorato2896a792008-11-17 16:56:36 -0500169 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700170 p.add_option('--br',
David Pursehouse08671042020-02-12 13:52:31 +0900171 type='string', action='store', dest='branch',
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700172 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400173 p.add_option('--cbr', '--current-branch',
174 dest='current_branch', action='store_true',
175 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700176 p.add_option('-d', '--draft',
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000177 action='store_true', dest='draft', default=False,
178 help='If specified, upload as a draft.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700179 p.add_option('--ne', '--no-emails',
180 action='store_false', dest='notify', default=True,
181 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200182 p.add_option('-p', '--private',
183 action='store_true', dest='private', default=False,
184 help='If specified, upload as a private change.')
185 p.add_option('-w', '--wip',
186 action='store_true', dest='wip', default=False,
187 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800188 p.add_option('-o', '--push-option',
189 type='string', action='append', dest='push_options',
190 default=[],
191 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400192 p.add_option('-D', '--destination', '--dest',
193 type='string', action='store', dest='dest_branch',
194 metavar='BRANCH',
195 help='Submit for review on this target branch.')
Mike Frysinger819cc812020-02-19 02:27:22 -0500196 p.add_option('-n', '--dry-run',
197 dest='dryrun', default=False, action='store_true',
198 help='Do everything except actually upload the CL.')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500199 p.add_option('-y', '--yes',
200 default=False, action='store_true',
201 help='Answer yes to all safe prompts.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500202 p.add_option('--no-cert-checks',
203 dest='validate_certs', action='store_false', default=True,
204 help='Disable verifying ssl certs (unsafe).')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800205
Doug Anderson37282b42011-03-04 11:54:18 -0800206 # Options relating to upload hook. Note that verify and no-verify are NOT
207 # opposites of each other, which is why they store to different locations.
208 # We are using them to match 'git commit' syntax.
209 #
210 # Combinations:
211 # - no-verify=False, verify=False (DEFAULT):
212 # If stdout is a tty, can prompt about running upload hooks if needed.
213 # If user denies running hooks, the upload is cancelled. If stdout is
214 # not a tty and we would need to prompt about upload hooks, upload is
215 # cancelled.
216 # - no-verify=False, verify=True:
217 # Always run upload hooks with no prompt.
218 # - no-verify=True, verify=False:
219 # Never run upload hooks, but upload anyway (AKA bypass hooks).
220 # - no-verify=True, verify=True:
221 # Invalid
Mike Frysinger21c15752020-02-11 05:17:16 -0500222 g = p.add_option_group('Upload hooks')
223 g.add_option('--no-verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800224 dest='bypass_hooks', action='store_true',
225 help='Do not run the upload hook.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500226 g.add_option('--verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800227 dest='allow_all_hooks', action='store_true',
228 help='Run the upload hook without prompting.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500229 g.add_option('--ignore-hooks',
230 dest='ignore_hooks', action='store_true',
231 help='Do not abort uploading if upload hooks fail.')
Doug Anderson37282b42011-03-04 11:54:18 -0800232
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700233 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700234 project = branch.project
235 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700236 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700237
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700238 key = 'review.%s.autoupload' % remote.review
239 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700240
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700241 if answer is False:
242 _die("upload blocked by %s = false" % key)
243
244 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700245 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900246 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700247
Chirayu Desai610d3c42013-06-24 14:02:12 +0530248 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200249 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000250 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700251 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900252 name,
253 len(commit_list),
254 len(commit_list) != 1 and 's' or '',
255 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900256 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700257 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700258
Mike Frysingerab85fe72019-07-04 17:35:11 -0400259 print('to %s (y/N)? ' % remote.review, end='')
260 # TODO: When we require Python 3, use flush=True w/print above.
261 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500262 if opt.yes:
263 print('<--yes>')
264 answer = True
265 else:
266 answer = sys.stdin.readline().strip().lower()
267 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700268
269 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700270 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
271 answer = _ConfirmManyUploads()
272
273 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700274 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700275 else:
276 _die("upload aborted by user")
277
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700278 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700279 projects = {}
280 branches = {}
281
282 script = []
283 script.append('# Uncomment the branches to upload:')
284 for project, avail in pending:
285 script.append('#')
286 script.append('# project %s/:' % project.relpath)
287
288 b = {}
289 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400290 if branch is None:
291 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700292 name = branch.name
293 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900294 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700295
296 if b:
297 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400298 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200299 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700300 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900301 len(commit_list),
302 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200303 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400304 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900305 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700306 script.append('# %s' % commit)
307 b[name] = branch
308
309 projects[project.relpath] = project
310 branches[project.name] = b
311 script.append('')
312
313 script = Editor.EditString("\n".join(script)).split("\n")
314
315 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
316 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
317
318 project = None
319 todo = []
320
321 for line in script:
322 m = project_re.match(line)
323 if m:
324 name = m.group(1)
325 project = projects.get(name)
326 if not project:
327 _die('project %s not available for upload', name)
328 continue
329
330 m = branch_re.match(line)
331 if m:
332 name = m.group(1)
333 if not project:
334 _die('project for branch %s not in script', name)
335 branch = branches[project.name].get(name)
336 if not branch:
337 _die('branch %s not in %s', name, project.relpath)
338 todo.append(branch)
339 if not todo:
340 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700341
342 many_commits = False
343 for branch in todo:
344 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
345 many_commits = True
346 break
347 if many_commits:
348 if not _ConfirmManyUploads(multiple_branches=True):
349 _die("upload aborted by user")
350
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700351 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700352
bijia093fdb62013-11-28 09:19:22 +0800353 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700354 """
bijia093fdb62013-11-28 09:19:22 +0800355 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700356 Appends the list of users in the CC list in the git project's config if a
357 non-empty reviewer list was found.
358 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700359 name = branch.name
360 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800361
362 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
363 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900364 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800365 people[0].extend([entry.strip() for entry in raw_list.split(',')])
366
Ben Komalo08a3f682010-07-15 16:03:02 -0700367 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
368 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900369 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700370 people[1].extend([entry.strip() for entry in raw_list.split(',')])
371
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700372 def _FindGerritChange(self, branch):
373 last_pub = branch.project.WasPublished(branch.name)
374 if last_pub is None:
375 return ""
376
377 refs = branch.GetPublishedRefs()
378 try:
379 # refs/changes/XYZ/N --> XYZ
380 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900381 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700382 return ""
383
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700384 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700385 have_errors = False
386 for branch in todo:
387 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700388 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800389 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700390
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500391 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700392 changes = branch.project.UncommitedFiles()
393 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900394 key = 'review.%s.autoupload' % branch.project.remote.review
395 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500396
David Pursehousec1b86a22012-11-14 11:36:51 +0900397 # if they want to auto upload, let's not ask because it could be automated
398 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400399 print()
400 print('Uncommitted changes in %s (did you forget to amend?):'
401 % branch.project.name)
402 print('\n'.join(changes))
403 print('Continue uploading? (y/N) ', end='')
404 # TODO: When we require Python 3, use flush=True w/print above.
405 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500406 if opt.yes:
407 print('<--yes>')
408 a = 'yes'
409 else:
410 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900411 if a not in ('y', 'yes', 't', 'true', 'on'):
412 print("skipping upload", file=sys.stderr)
413 branch.uploaded = False
414 branch.error = 'User aborted'
415 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500416
Anthony Russellod666e932012-06-01 00:48:22 -0400417 # Check if topic branches should be sent to the server during upload
418 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900419 key = 'review.%s.uploadtopic' % branch.project.remote.review
420 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400421
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500422 def _ExpandCommaList(value):
423 """Split |value| up into comma delimited entries."""
Mike Frysinger84685ba2020-02-19 02:22:22 -0500424 if not value:
425 return
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500426 for ret in value.split(','):
427 ret = ret.strip()
428 if ret:
429 yield ret
430
431 # Check if hashtags should be included.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500432 key = 'review.%s.uploadhashtags' % branch.project.remote.review
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500433 hashtags = set(_ExpandCommaList(branch.project.config.GetString(key)))
Mike Frysinger84685ba2020-02-19 02:22:22 -0500434 for tag in opt.hashtags:
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500435 hashtags.update(_ExpandCommaList(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500436 if opt.hashtag_branch:
437 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500438
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500439 # Check if labels should be included.
440 key = 'review.%s.uploadlabels' % branch.project.remote.review
441 labels = set(_ExpandCommaList(branch.project.config.GetString(key)))
442 for label in opt.labels:
443 labels.update(_ExpandCommaList(label))
444 # Basic sanity check on label syntax.
445 for label in labels:
446 if not re.match(r'^.+[+-][0-9]+$', label):
447 print('repo: error: invalid label syntax "%s": labels use forms '
448 'like CodeReview+1 or Verified-1' % (label,), file=sys.stderr)
449 sys.exit(1)
450
Colin Cross59b31cb2013-10-08 23:10:52 -0700451 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700452
453 # Make sure our local branch is not setup to track a different remote branch
454 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700455 if destination:
456 full_dest = 'refs/heads/%s' % destination
457 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
458 print('merge branch %s does not match destination branch %s'
459 % (merge_branch, full_dest))
460 print('skipping upload.')
461 print('Please use `--destination %s` if this is intentional'
462 % destination)
463 branch.uploaded = False
464 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700465
Changcheng Xiao87984c62017-08-02 16:55:03 +0200466 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500467 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200468 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500469 hashtags=hashtags,
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500470 labels=labels,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000471 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200472 private=opt.private,
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700473 notify=None if opt.notify else 'NONE',
Changcheng Xiao87984c62017-08-02 16:55:03 +0200474 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200475 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800476 validate_certs=opt.validate_certs,
477 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200478
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700479 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700480 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700481 branch.error = e
482 branch.uploaded = False
483 have_errors = True
484
Sarah Owenscecd1d82012-11-01 22:59:27 -0700485 print(file=sys.stderr)
486 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700487
488 if have_errors:
489 for branch in todo:
490 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700491 if len(str(branch.error)) <= 30:
492 fmt = ' (%s)'
493 else:
494 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700495 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900496 branch.project.relpath + '/',
497 branch.name,
498 str(branch.error)),
499 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700500 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700501
502 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900503 if branch.uploaded:
504 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900505 branch.project.relpath + '/',
506 branch.name),
507 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700508
509 if have_errors:
510 sys.exit(1)
511
Conley Owens3bfd7212013-09-30 15:54:38 -0700512 def _GetMergeBranch(self, project):
513 p = GitCommand(project,
514 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900515 capture_stdout=True,
516 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700517 p.Wait()
518 local_branch = p.stdout.strip()
519 p = GitCommand(project,
520 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900521 capture_stdout=True,
522 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700523 p.Wait()
524 merge_branch = p.stdout.strip()
525 return merge_branch
526
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700527 def Execute(self, opt, args):
528 project_list = self.GetProjects(args)
529 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500530 reviewers = []
531 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700532 branch = None
533
534 if opt.branch:
535 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500536
Doug Anderson37282b42011-03-04 11:54:18 -0800537 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400538 if opt.current_branch:
539 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800540 up_branch = project.GetUploadableBranch(cbr)
541 if up_branch:
542 avail = [up_branch]
543 else:
544 avail = None
545 print('ERROR: Current branch (%s) not uploadable. '
546 'You may be able to type '
547 '"git branch --set-upstream-to m/master" to fix '
548 'your branch.' % str(cbr),
549 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400550 else:
551 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800552 if avail:
553 pending.append((project, avail))
554
Mike Frysinger163a3be2016-04-04 17:31:32 -0400555 if not pending:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500556 if branch is None:
557 print('repo: error: no branches ready for upload', file=sys.stderr)
558 else:
559 print('repo: error: no branches named "%s" ready for upload' %
560 (branch,), file=sys.stderr)
561 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400562
563 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800564 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400565 self.manifest.topdir,
566 self.manifest.manifestProject.GetRemote('origin').url,
567 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900568 pending_proj_names = [project.name for (project, available) in pending]
569 pending_worktrees = [project.worktree for (project, available) in pending]
Mike Frysinger21c15752020-02-11 05:17:16 -0500570 passed = True
Doug Anderson37282b42011-03-04 11:54:18 -0800571 try:
David James8d201162013-10-11 17:03:19 -0700572 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
573 worktree_list=pending_worktrees)
Mike Frysinger21c15752020-02-11 05:17:16 -0500574 except SystemExit:
575 passed = False
576 if not opt.ignore_hooks:
577 raise
Sarah Owensa5be53f2012-09-09 15:37:57 -0700578 except HookError as e:
Mike Frysinger21c15752020-02-11 05:17:16 -0500579 passed = False
Sarah Owenscecd1d82012-11-01 22:59:27 -0700580 print("ERROR: %s" % str(e), file=sys.stderr)
Mike Frysinger21c15752020-02-11 05:17:16 -0500581
582 if not passed:
583 if opt.ignore_hooks:
584 print('\nWARNING: pre-upload hooks failed, but uploading anyways.',
585 file=sys.stderr)
586 else:
587 return
Doug Anderson37282b42011-03-04 11:54:18 -0800588
Joe Onorato2896a792008-11-17 16:56:36 -0500589 if opt.reviewers:
590 reviewers = _SplitEmails(opt.reviewers)
591 if opt.cc:
592 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900593 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700594
Mike Frysinger163a3be2016-04-04 17:31:32 -0400595 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700596 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700597 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700598 self._MultipleBranches(opt, pending, people)