blob: 6196fe4c0c9f6b8171d42c19da29b8bdfba222e2 [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
Remy Bohmer7f7acfe2020-08-01 18:36:44 +020024from error import UploadError
Conley Owens3bfd7212013-09-30 15:54:38 -070025from git_command import GitCommand
Sean McAllister682f0b62020-05-18 09:15:51 -060026from git_refs import R_HEADS
Remy Bohmer16c13282020-09-10 10:38:04 +020027from hooks import RepoHook
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070028
David Pursehouse59bbb582013-05-17 10:49:33 +090029from pyversion import is_python3
30if not is_python3():
David Pursehousea46bf7d2020-02-15 12:45:53 +090031 input = raw_input # noqa: F821
Anthony Kingd792f792014-05-05 22:01:07 +010032else:
33 unicode = str
Chirayu Desai217ea7d2013-03-01 19:14:38 +053034
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070035UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070036
David Pursehouse819827a2020-02-12 15:20:19 +090037
Dan Morrill879a9a52010-05-04 16:56:07 -070038def _ConfirmManyUploads(multiple_branches=False):
39 if multiple_branches:
David Pursehouse2f9e7e42013-03-05 17:26:46 +090040 print('ATTENTION: One or more branches has an unusually high number '
Sarah Owenscecd1d82012-11-01 22:59:27 -070041 'of commits.')
Dan Morrill879a9a52010-05-04 16:56:07 -070042 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -070043 print('ATTENTION: You are uploading an unusually high number of commits.')
David Pursehouse2f9e7e42013-03-05 17:26:46 +090044 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
Sarah Owenscecd1d82012-11-01 22:59:27 -070045 'branches?)')
Chirayu Desai217ea7d2013-03-01 19:14:38 +053046 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
Dan Morrill879a9a52010-05-04 16:56:07 -070047 return answer == "yes"
48
David Pursehouse819827a2020-02-12 15:20:19 +090049
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070050def _die(fmt, *args):
51 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070052 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070053 sys.exit(1)
54
David Pursehouse819827a2020-02-12 15:20:19 +090055
Joe Onorato2896a792008-11-17 16:56:36 -050056def _SplitEmails(values):
57 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090058 for value in values:
59 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050060 return result
61
David Pursehouse819827a2020-02-12 15:20:19 +090062
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070063class Upload(InteractiveCommand):
64 common = True
65 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090066 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070067%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070068"""
69 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070070The '%prog' command is used to send changes to the Gerrit Code
71Review system. It searches for topic branches in local projects
72that have not yet been published for review. If multiple topic
73branches are found, '%prog' opens an editor to allow the user to
74select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070075
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070076'%prog' searches for uploadable changes in all projects listed at
77the command line. Projects can be specified either by name, or by
78a relative or absolute path to the project's local directory. If no
79projects are specified, '%prog' will search for uploadable changes
80in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050081
82If the --reviewers or --cc options are passed, those emails are
83added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070084new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050085with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080086
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040087# Configuration
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070088
89review.URL.autoupload:
90
Mike Frysingere9311272011-08-11 15:46:43 -040091To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070092or global Git configuration option. If review.URL.autoupload is set
93to "true" then repo will assume you always answer "y" at the prompt,
94and will not prompt you further. If it is set to "false" then repo
95will assume you always answer "n", and will abort.
96
bijia093fdb62013-11-28 09:19:22 +080097review.URL.autoreviewer:
98
99To automatically append a user or mailing list to reviews, you can set
100a per-project or global Git option to do so.
101
Ben Komalo08a3f682010-07-15 16:03:02 -0700102review.URL.autocopy:
103
104To automatically copy a user or mailing list to all uploaded reviews,
105you can set a per-project or global Git option to do so. Specifically,
106review.URL.autocopy can be set to a comma separated list of reviewers
107who you always want copied on all uploads with a non-empty --re
108argument.
109
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700110review.URL.username:
111
112Override the username used to connect to Gerrit Code Review.
113By default the local part of the email address is used.
114
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700115The URL must match the review URL listed in the manifest XML file,
116or in the .git/config within the project. For example:
117
118 [remote "origin"]
119 url = git://git.example.com/project.git
120 review = http://review.example.com/
121
122 [review "http://review.example.com/"]
123 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700124 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700125
Anthony Russellod666e932012-06-01 00:48:22 -0400126review.URL.uploadtopic:
127
128To add a topic branch whenever uploading a commit, you can set a
129per-project or global Git option to do so. If review.URL.uploadtopic
130is set to "true" then repo will assume you always want the equivalent
131of the -t option to the repo command. If unset or set to "false" then
132repo will make use of only the command line option.
133
Mike Frysinger84685ba2020-02-19 02:22:22 -0500134review.URL.uploadhashtags:
135
136To add hashtags whenever uploading a commit, you can set a per-project
137or global Git option to do so. The value of review.URL.uploadhashtags
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500138will be used as comma delimited hashtags like the --hashtag option.
139
140review.URL.uploadlabels:
141
142To add labels whenever uploading a commit, you can set a per-project
143or global Git option to do so. The value of review.URL.uploadlabels
144will be used as comma delimited labels like the --label option.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500145
Mike Frysingerf725e542020-03-14 17:39:03 -0400146review.URL.uploadnotify:
147
148Control e-mail notifications when uploading.
149https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify
150
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400151# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700152
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400153Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700154
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700155"""
156
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800157 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700158 p.add_option('-t',
159 dest='auto_topic', action='store_true',
160 help='Send local branch name to Gerrit Code Review')
Mike Frysinger84685ba2020-02-19 02:22:22 -0500161 p.add_option('--hashtag', '--ht',
162 dest='hashtags', action='append', default=[],
163 help='Add hashtags (comma delimited) to the review.')
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500164 p.add_option('--hashtag-branch', '--htb',
165 action='store_true',
166 help='Add local branch name as a hashtag.')
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500167 p.add_option('-l', '--label',
168 dest='labels', action='append', default=[],
169 help='Add a label when uploading.')
Joe Onorato2896a792008-11-17 16:56:36 -0500170 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900171 type='string', action='append', dest='reviewers',
Joe Onorato2896a792008-11-17 16:56:36 -0500172 help='Request reviews from these people.')
173 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900174 type='string', action='append', dest='cc',
Joe Onorato2896a792008-11-17 16:56:36 -0500175 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700176 p.add_option('--br',
David Pursehouse08671042020-02-12 13:52:31 +0900177 type='string', action='store', dest='branch',
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700178 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400179 p.add_option('--cbr', '--current-branch',
180 dest='current_branch', action='store_true',
181 help='Upload current git branch.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700182 p.add_option('--ne', '--no-emails',
183 action='store_false', dest='notify', default=True,
184 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200185 p.add_option('-p', '--private',
186 action='store_true', dest='private', default=False,
187 help='If specified, upload as a private change.')
188 p.add_option('-w', '--wip',
189 action='store_true', dest='wip', default=False,
190 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800191 p.add_option('-o', '--push-option',
192 type='string', action='append', dest='push_options',
193 default=[],
194 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400195 p.add_option('-D', '--destination', '--dest',
196 type='string', action='store', dest='dest_branch',
197 metavar='BRANCH',
198 help='Submit for review on this target branch.')
Mike Frysinger819cc812020-02-19 02:27:22 -0500199 p.add_option('-n', '--dry-run',
200 dest='dryrun', default=False, action='store_true',
201 help='Do everything except actually upload the CL.')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500202 p.add_option('-y', '--yes',
203 default=False, action='store_true',
204 help='Answer yes to all safe prompts.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500205 p.add_option('--no-cert-checks',
206 dest='validate_certs', action='store_false', default=True,
207 help='Disable verifying ssl certs (unsafe).')
Remy Bohmer7f7acfe2020-08-01 18:36:44 +0200208 RepoHook.AddOptionGroup(p, 'pre-upload')
Doug Anderson37282b42011-03-04 11:54:18 -0800209
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700210 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700211 project = branch.project
212 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700213 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700214
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700215 key = 'review.%s.autoupload' % remote.review
216 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700217
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700218 if answer is False:
219 _die("upload blocked by %s = false" % key)
220
221 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700222 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900223 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700224
Chirayu Desai610d3c42013-06-24 14:02:12 +0530225 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200226 print('Upload project %s/ to remote branch %s%s:' %
Mike Frysingerb0fbc7f2020-02-25 02:58:04 -0500227 (project.relpath, destination, ' (private)' if opt.private else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700228 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900229 name,
230 len(commit_list),
231 len(commit_list) != 1 and 's' or '',
232 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900233 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700234 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700235
Mike Frysingerab85fe72019-07-04 17:35:11 -0400236 print('to %s (y/N)? ' % remote.review, end='')
237 # TODO: When we require Python 3, use flush=True w/print above.
238 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500239 if opt.yes:
240 print('<--yes>')
241 answer = True
242 else:
243 answer = sys.stdin.readline().strip().lower()
244 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700245
246 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700247 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
248 answer = _ConfirmManyUploads()
249
250 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700251 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700252 else:
253 _die("upload aborted by user")
254
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700255 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700256 projects = {}
257 branches = {}
258
259 script = []
260 script.append('# Uncomment the branches to upload:')
261 for project, avail in pending:
262 script.append('#')
263 script.append('# project %s/:' % project.relpath)
264
265 b = {}
266 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400267 if branch is None:
268 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700269 name = branch.name
270 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900271 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700272
273 if b:
274 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400275 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200276 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700277 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900278 len(commit_list),
279 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200280 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400281 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900282 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700283 script.append('# %s' % commit)
284 b[name] = branch
285
286 projects[project.relpath] = project
287 branches[project.name] = b
288 script.append('')
289
290 script = Editor.EditString("\n".join(script)).split("\n")
291
292 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
293 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
294
295 project = None
296 todo = []
297
298 for line in script:
299 m = project_re.match(line)
300 if m:
301 name = m.group(1)
302 project = projects.get(name)
303 if not project:
304 _die('project %s not available for upload', name)
305 continue
306
307 m = branch_re.match(line)
308 if m:
309 name = m.group(1)
310 if not project:
311 _die('project for branch %s not in script', name)
312 branch = branches[project.name].get(name)
313 if not branch:
314 _die('branch %s not in %s', name, project.relpath)
315 todo.append(branch)
316 if not todo:
317 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700318
319 many_commits = False
320 for branch in todo:
321 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
322 many_commits = True
323 break
324 if many_commits:
325 if not _ConfirmManyUploads(multiple_branches=True):
326 _die("upload aborted by user")
327
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700328 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700329
bijia093fdb62013-11-28 09:19:22 +0800330 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700331 """
bijia093fdb62013-11-28 09:19:22 +0800332 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700333 Appends the list of users in the CC list in the git project's config if a
334 non-empty reviewer list was found.
335 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700336 name = branch.name
337 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800338
339 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
340 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900341 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800342 people[0].extend([entry.strip() for entry in raw_list.split(',')])
343
Ben Komalo08a3f682010-07-15 16:03:02 -0700344 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
345 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900346 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700347 people[1].extend([entry.strip() for entry in raw_list.split(',')])
348
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700349 def _FindGerritChange(self, branch):
350 last_pub = branch.project.WasPublished(branch.name)
351 if last_pub is None:
352 return ""
353
354 refs = branch.GetPublishedRefs()
355 try:
356 # refs/changes/XYZ/N --> XYZ
357 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900358 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700359 return ""
360
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700361 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700362 have_errors = False
363 for branch in todo:
364 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700365 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800366 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700367
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500368 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700369 changes = branch.project.UncommitedFiles()
370 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900371 key = 'review.%s.autoupload' % branch.project.remote.review
372 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500373
David Pursehousec1b86a22012-11-14 11:36:51 +0900374 # if they want to auto upload, let's not ask because it could be automated
375 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400376 print()
377 print('Uncommitted changes in %s (did you forget to amend?):'
378 % branch.project.name)
379 print('\n'.join(changes))
380 print('Continue uploading? (y/N) ', end='')
381 # TODO: When we require Python 3, use flush=True w/print above.
382 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500383 if opt.yes:
384 print('<--yes>')
385 a = 'yes'
386 else:
387 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900388 if a not in ('y', 'yes', 't', 'true', 'on'):
389 print("skipping upload", file=sys.stderr)
390 branch.uploaded = False
391 branch.error = 'User aborted'
392 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500393
Anthony Russellod666e932012-06-01 00:48:22 -0400394 # Check if topic branches should be sent to the server during upload
395 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900396 key = 'review.%s.uploadtopic' % branch.project.remote.review
397 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400398
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500399 def _ExpandCommaList(value):
400 """Split |value| up into comma delimited entries."""
Mike Frysinger84685ba2020-02-19 02:22:22 -0500401 if not value:
402 return
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500403 for ret in value.split(','):
404 ret = ret.strip()
405 if ret:
406 yield ret
407
408 # Check if hashtags should be included.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500409 key = 'review.%s.uploadhashtags' % branch.project.remote.review
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500410 hashtags = set(_ExpandCommaList(branch.project.config.GetString(key)))
Mike Frysinger84685ba2020-02-19 02:22:22 -0500411 for tag in opt.hashtags:
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500412 hashtags.update(_ExpandCommaList(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500413 if opt.hashtag_branch:
414 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500415
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500416 # Check if labels should be included.
417 key = 'review.%s.uploadlabels' % branch.project.remote.review
418 labels = set(_ExpandCommaList(branch.project.config.GetString(key)))
419 for label in opt.labels:
420 labels.update(_ExpandCommaList(label))
421 # Basic sanity check on label syntax.
422 for label in labels:
423 if not re.match(r'^.+[+-][0-9]+$', label):
424 print('repo: error: invalid label syntax "%s": labels use forms '
425 'like CodeReview+1 or Verified-1' % (label,), file=sys.stderr)
426 sys.exit(1)
427
Mike Frysingerf725e542020-03-14 17:39:03 -0400428 # Handle e-mail notifications.
429 if opt.notify is False:
430 notify = 'NONE'
431 else:
432 key = 'review.%s.uploadnotify' % branch.project.remote.review
433 notify = branch.project.config.GetString(key)
434
Colin Cross59b31cb2013-10-08 23:10:52 -0700435 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700436
437 # Make sure our local branch is not setup to track a different remote branch
438 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700439 if destination:
Sean McAllister682f0b62020-05-18 09:15:51 -0600440 full_dest = destination
441 if not full_dest.startswith(R_HEADS):
442 full_dest = R_HEADS + full_dest
443
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700444 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
445 print('merge branch %s does not match destination branch %s'
446 % (merge_branch, full_dest))
447 print('skipping upload.')
448 print('Please use `--destination %s` if this is intentional'
449 % destination)
450 branch.uploaded = False
451 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700452
Changcheng Xiao87984c62017-08-02 16:55:03 +0200453 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500454 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200455 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500456 hashtags=hashtags,
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500457 labels=labels,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200458 private=opt.private,
Mike Frysingerf725e542020-03-14 17:39:03 -0400459 notify=notify,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200460 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200461 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800462 validate_certs=opt.validate_certs,
463 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200464
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700465 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700466 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700467 branch.error = e
468 branch.uploaded = False
469 have_errors = True
470
Sarah Owenscecd1d82012-11-01 22:59:27 -0700471 print(file=sys.stderr)
472 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700473
474 if have_errors:
475 for branch in todo:
476 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700477 if len(str(branch.error)) <= 30:
478 fmt = ' (%s)'
479 else:
480 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700481 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900482 branch.project.relpath + '/',
483 branch.name,
484 str(branch.error)),
485 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700486 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700487
488 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900489 if branch.uploaded:
490 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900491 branch.project.relpath + '/',
492 branch.name),
493 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700494
495 if have_errors:
496 sys.exit(1)
497
Conley Owens3bfd7212013-09-30 15:54:38 -0700498 def _GetMergeBranch(self, project):
499 p = GitCommand(project,
500 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900501 capture_stdout=True,
502 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700503 p.Wait()
504 local_branch = p.stdout.strip()
505 p = GitCommand(project,
506 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900507 capture_stdout=True,
508 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700509 p.Wait()
510 merge_branch = p.stdout.strip()
511 return merge_branch
512
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700513 def Execute(self, opt, args):
514 project_list = self.GetProjects(args)
515 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500516 reviewers = []
517 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700518 branch = None
519
520 if opt.branch:
521 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500522
Doug Anderson37282b42011-03-04 11:54:18 -0800523 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400524 if opt.current_branch:
525 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800526 up_branch = project.GetUploadableBranch(cbr)
527 if up_branch:
528 avail = [up_branch]
529 else:
530 avail = None
Mike Frysinger160748f2020-11-10 01:09:51 -0500531 print('repo: error: Unable to upload branch "%s". '
532 'You might be able to fix the branch by running:\n'
533 ' git branch --set-upstream-to m/%s' %
534 (str(cbr), self.manifest.branch),
Warren Turkal011d4f42013-11-27 16:20:57 -0800535 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400536 else:
537 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800538 if avail:
539 pending.append((project, avail))
540
Mike Frysinger163a3be2016-04-04 17:31:32 -0400541 if not pending:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500542 if branch is None:
543 print('repo: error: no branches ready for upload', file=sys.stderr)
544 else:
545 print('repo: error: no branches named "%s" ready for upload' %
546 (branch,), file=sys.stderr)
547 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400548
Remy Bohmer7f7acfe2020-08-01 18:36:44 +0200549 pending_proj_names = [project.name for (project, available) in pending]
550 pending_worktrees = [project.worktree for (project, available) in pending]
551 hook = RepoHook.FromSubcmd(
552 hook_type='pre-upload', manifest=self.manifest,
553 opt=opt, abort_if_user_denies=True)
554 if not hook.Run(
555 project_list=pending_proj_names,
556 worktree_list=pending_worktrees):
557 return 1
Doug Anderson37282b42011-03-04 11:54:18 -0800558
Joe Onorato2896a792008-11-17 16:56:36 -0500559 if opt.reviewers:
560 reviewers = _SplitEmails(opt.reviewers)
561 if opt.cc:
562 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900563 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700564
Mike Frysinger163a3be2016-04-04 17:31:32 -0400565 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700566 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700567 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700568 self._MultipleBranches(opt, pending, people)