blob: 0dd0b7da7f724383099c68c615344c2204bd1a90 [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001# Copyright (C) 2008 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Ben Komalo08a3f682010-07-15 16:03:02 -070015import copy
Mike Frysingerd1f3e142021-05-01 12:02:01 -040016import functools
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070017import re
18import sys
19
Mike Frysingerd1f3e142021-05-01 12:02:01 -040020from command import DEFAULT_LOCAL_JOBS, InteractiveCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070021from editor import Editor
Remy Bohmer7f7acfe2020-08-01 18:36:44 +020022from error import UploadError
Conley Owens3bfd7212013-09-30 15:54:38 -070023from git_command import GitCommand
Sean McAllister682f0b62020-05-18 09:15:51 -060024from git_refs import R_HEADS
Remy Bohmer16c13282020-09-10 10:38:04 +020025from hooks import RepoHook
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070026
Chirayu Desai217ea7d2013-03-01 19:14:38 +053027
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070028UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070029
David Pursehouse819827a2020-02-12 15:20:19 +090030
Dan Morrill879a9a52010-05-04 16:56:07 -070031def _ConfirmManyUploads(multiple_branches=False):
32 if multiple_branches:
David Pursehouse2f9e7e42013-03-05 17:26:46 +090033 print('ATTENTION: One or more branches has an unusually high number '
Sarah Owenscecd1d82012-11-01 22:59:27 -070034 'of commits.')
Dan Morrill879a9a52010-05-04 16:56:07 -070035 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -070036 print('ATTENTION: You are uploading an unusually high number of commits.')
David Pursehouse2f9e7e42013-03-05 17:26:46 +090037 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
Sarah Owenscecd1d82012-11-01 22:59:27 -070038 'branches?)')
Chirayu Desai217ea7d2013-03-01 19:14:38 +053039 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
Dan Morrill879a9a52010-05-04 16:56:07 -070040 return answer == "yes"
41
David Pursehouse819827a2020-02-12 15:20:19 +090042
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070043def _die(fmt, *args):
44 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070045 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070046 sys.exit(1)
47
David Pursehouse819827a2020-02-12 15:20:19 +090048
Joe Onorato2896a792008-11-17 16:56:36 -050049def _SplitEmails(values):
50 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090051 for value in values:
52 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050053 return result
54
David Pursehouse819827a2020-02-12 15:20:19 +090055
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070056class Upload(InteractiveCommand):
57 common = True
58 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090059 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070060%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070061"""
62 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070063The '%prog' command is used to send changes to the Gerrit Code
64Review system. It searches for topic branches in local projects
65that have not yet been published for review. If multiple topic
66branches are found, '%prog' opens an editor to allow the user to
67select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070068
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070069'%prog' searches for uploadable changes in all projects listed at
70the command line. Projects can be specified either by name, or by
71a relative or absolute path to the project's local directory. If no
72projects are specified, '%prog' will search for uploadable changes
73in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050074
75If the --reviewers or --cc options are passed, those emails are
76added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070077new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050078with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080079
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040080# Configuration
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070081
82review.URL.autoupload:
83
Mike Frysingere9311272011-08-11 15:46:43 -040084To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070085or global Git configuration option. If review.URL.autoupload is set
86to "true" then repo will assume you always answer "y" at the prompt,
87and will not prompt you further. If it is set to "false" then repo
88will assume you always answer "n", and will abort.
89
bijia093fdb62013-11-28 09:19:22 +080090review.URL.autoreviewer:
91
92To automatically append a user or mailing list to reviews, you can set
93a per-project or global Git option to do so.
94
Ben Komalo08a3f682010-07-15 16:03:02 -070095review.URL.autocopy:
96
97To automatically copy a user or mailing list to all uploaded reviews,
98you can set a per-project or global Git option to do so. Specifically,
99review.URL.autocopy can be set to a comma separated list of reviewers
100who you always want copied on all uploads with a non-empty --re
101argument.
102
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700103review.URL.username:
104
105Override the username used to connect to Gerrit Code Review.
106By default the local part of the email address is used.
107
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700108The URL must match the review URL listed in the manifest XML file,
109or in the .git/config within the project. For example:
110
111 [remote "origin"]
112 url = git://git.example.com/project.git
113 review = http://review.example.com/
114
115 [review "http://review.example.com/"]
116 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700117 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700118
Anthony Russellod666e932012-06-01 00:48:22 -0400119review.URL.uploadtopic:
120
121To add a topic branch whenever uploading a commit, you can set a
122per-project or global Git option to do so. If review.URL.uploadtopic
123is set to "true" then repo will assume you always want the equivalent
124of the -t option to the repo command. If unset or set to "false" then
125repo will make use of only the command line option.
126
Mike Frysinger84685ba2020-02-19 02:22:22 -0500127review.URL.uploadhashtags:
128
129To add hashtags whenever uploading a commit, you can set a per-project
130or global Git option to do so. The value of review.URL.uploadhashtags
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500131will be used as comma delimited hashtags like the --hashtag option.
132
133review.URL.uploadlabels:
134
135To add labels whenever uploading a commit, you can set a per-project
136or global Git option to do so. The value of review.URL.uploadlabels
137will be used as comma delimited labels like the --label option.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500138
Mike Frysingerf725e542020-03-14 17:39:03 -0400139review.URL.uploadnotify:
140
141Control e-mail notifications when uploading.
142https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify
143
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400144# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700145
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400146Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700147
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700148"""
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400149 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700150
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.')
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400170 p.add_option('--br', '--branch',
David Pursehouse08671042020-02-12 13:52:31 +0900171 type='string', action='store', dest='branch',
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400172 help='(Local) 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.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700176 p.add_option('--ne', '--no-emails',
177 action='store_false', dest='notify', default=True,
178 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200179 p.add_option('-p', '--private',
180 action='store_true', dest='private', default=False,
181 help='If specified, upload as a private change.')
182 p.add_option('-w', '--wip',
183 action='store_true', dest='wip', default=False,
184 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800185 p.add_option('-o', '--push-option',
186 type='string', action='append', dest='push_options',
187 default=[],
188 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400189 p.add_option('-D', '--destination', '--dest',
190 type='string', action='store', dest='dest_branch',
191 metavar='BRANCH',
192 help='Submit for review on this target branch.')
Mike Frysinger819cc812020-02-19 02:27:22 -0500193 p.add_option('-n', '--dry-run',
194 dest='dryrun', default=False, action='store_true',
195 help='Do everything except actually upload the CL.')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500196 p.add_option('-y', '--yes',
197 default=False, action='store_true',
198 help='Answer yes to all safe prompts.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500199 p.add_option('--no-cert-checks',
200 dest='validate_certs', action='store_false', default=True,
201 help='Disable verifying ssl certs (unsafe).')
Remy Bohmer7f7acfe2020-08-01 18:36:44 +0200202 RepoHook.AddOptionGroup(p, 'pre-upload')
Doug Anderson37282b42011-03-04 11:54:18 -0800203
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700204 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700205 project = branch.project
206 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700207 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700208
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700209 key = 'review.%s.autoupload' % remote.review
210 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700211
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700212 if answer is False:
213 _die("upload blocked by %s = false" % key)
214
215 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700216 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900217 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700218
Chirayu Desai610d3c42013-06-24 14:02:12 +0530219 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200220 print('Upload project %s/ to remote branch %s%s:' %
Mike Frysingerb0fbc7f2020-02-25 02:58:04 -0500221 (project.relpath, destination, ' (private)' if opt.private else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700222 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900223 name,
224 len(commit_list),
225 len(commit_list) != 1 and 's' or '',
226 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900227 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700228 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700229
Mike Frysingerab85fe72019-07-04 17:35:11 -0400230 print('to %s (y/N)? ' % remote.review, end='')
231 # TODO: When we require Python 3, use flush=True w/print above.
232 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500233 if opt.yes:
234 print('<--yes>')
235 answer = True
236 else:
237 answer = sys.stdin.readline().strip().lower()
238 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700239
240 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700241 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
242 answer = _ConfirmManyUploads()
243
244 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700245 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700246 else:
247 _die("upload aborted by user")
248
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700249 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700250 projects = {}
251 branches = {}
252
253 script = []
254 script.append('# Uncomment the branches to upload:')
255 for project, avail in pending:
256 script.append('#')
257 script.append('# project %s/:' % project.relpath)
258
259 b = {}
260 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400261 if branch is None:
262 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700263 name = branch.name
264 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900265 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700266
267 if b:
268 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400269 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200270 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700271 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900272 len(commit_list),
273 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200274 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400275 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900276 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700277 script.append('# %s' % commit)
278 b[name] = branch
279
280 projects[project.relpath] = project
281 branches[project.name] = b
282 script.append('')
283
284 script = Editor.EditString("\n".join(script)).split("\n")
285
286 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
287 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
288
289 project = None
290 todo = []
291
292 for line in script:
293 m = project_re.match(line)
294 if m:
295 name = m.group(1)
296 project = projects.get(name)
297 if not project:
298 _die('project %s not available for upload', name)
299 continue
300
301 m = branch_re.match(line)
302 if m:
303 name = m.group(1)
304 if not project:
305 _die('project for branch %s not in script', name)
306 branch = branches[project.name].get(name)
307 if not branch:
308 _die('branch %s not in %s', name, project.relpath)
309 todo.append(branch)
310 if not todo:
311 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700312
313 many_commits = False
314 for branch in todo:
315 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
316 many_commits = True
317 break
318 if many_commits:
319 if not _ConfirmManyUploads(multiple_branches=True):
320 _die("upload aborted by user")
321
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700322 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700323
bijia093fdb62013-11-28 09:19:22 +0800324 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700325 """
bijia093fdb62013-11-28 09:19:22 +0800326 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700327 Appends the list of users in the CC list in the git project's config if a
328 non-empty reviewer list was found.
329 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700330 name = branch.name
331 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800332
333 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
334 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900335 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800336 people[0].extend([entry.strip() for entry in raw_list.split(',')])
337
Ben Komalo08a3f682010-07-15 16:03:02 -0700338 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
339 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900340 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700341 people[1].extend([entry.strip() for entry in raw_list.split(',')])
342
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700343 def _FindGerritChange(self, branch):
344 last_pub = branch.project.WasPublished(branch.name)
345 if last_pub is None:
346 return ""
347
348 refs = branch.GetPublishedRefs()
349 try:
350 # refs/changes/XYZ/N --> XYZ
351 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900352 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700353 return ""
354
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700355 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700356 have_errors = False
357 for branch in todo:
358 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700359 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800360 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700361
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500362 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700363 changes = branch.project.UncommitedFiles()
364 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900365 key = 'review.%s.autoupload' % branch.project.remote.review
366 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500367
David Pursehousec1b86a22012-11-14 11:36:51 +0900368 # if they want to auto upload, let's not ask because it could be automated
369 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400370 print()
371 print('Uncommitted changes in %s (did you forget to amend?):'
372 % branch.project.name)
373 print('\n'.join(changes))
374 print('Continue uploading? (y/N) ', end='')
375 # TODO: When we require Python 3, use flush=True w/print above.
376 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500377 if opt.yes:
378 print('<--yes>')
379 a = 'yes'
380 else:
381 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900382 if a not in ('y', 'yes', 't', 'true', 'on'):
383 print("skipping upload", file=sys.stderr)
384 branch.uploaded = False
385 branch.error = 'User aborted'
386 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500387
Anthony Russellod666e932012-06-01 00:48:22 -0400388 # Check if topic branches should be sent to the server during upload
389 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900390 key = 'review.%s.uploadtopic' % branch.project.remote.review
391 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400392
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500393 def _ExpandCommaList(value):
394 """Split |value| up into comma delimited entries."""
Mike Frysinger84685ba2020-02-19 02:22:22 -0500395 if not value:
396 return
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500397 for ret in value.split(','):
398 ret = ret.strip()
399 if ret:
400 yield ret
401
402 # Check if hashtags should be included.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500403 key = 'review.%s.uploadhashtags' % branch.project.remote.review
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500404 hashtags = set(_ExpandCommaList(branch.project.config.GetString(key)))
Mike Frysinger84685ba2020-02-19 02:22:22 -0500405 for tag in opt.hashtags:
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500406 hashtags.update(_ExpandCommaList(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500407 if opt.hashtag_branch:
408 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500409
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500410 # Check if labels should be included.
411 key = 'review.%s.uploadlabels' % branch.project.remote.review
412 labels = set(_ExpandCommaList(branch.project.config.GetString(key)))
413 for label in opt.labels:
414 labels.update(_ExpandCommaList(label))
415 # Basic sanity check on label syntax.
416 for label in labels:
417 if not re.match(r'^.+[+-][0-9]+$', label):
418 print('repo: error: invalid label syntax "%s": labels use forms '
419 'like CodeReview+1 or Verified-1' % (label,), file=sys.stderr)
420 sys.exit(1)
421
Mike Frysingerf725e542020-03-14 17:39:03 -0400422 # Handle e-mail notifications.
423 if opt.notify is False:
424 notify = 'NONE'
425 else:
426 key = 'review.%s.uploadnotify' % branch.project.remote.review
427 notify = branch.project.config.GetString(key)
428
Colin Cross59b31cb2013-10-08 23:10:52 -0700429 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700430
431 # Make sure our local branch is not setup to track a different remote branch
432 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700433 if destination:
Sean McAllister682f0b62020-05-18 09:15:51 -0600434 full_dest = destination
435 if not full_dest.startswith(R_HEADS):
436 full_dest = R_HEADS + full_dest
437
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700438 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
439 print('merge branch %s does not match destination branch %s'
440 % (merge_branch, full_dest))
441 print('skipping upload.')
442 print('Please use `--destination %s` if this is intentional'
443 % destination)
444 branch.uploaded = False
445 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700446
Changcheng Xiao87984c62017-08-02 16:55:03 +0200447 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500448 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200449 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500450 hashtags=hashtags,
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500451 labels=labels,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200452 private=opt.private,
Mike Frysingerf725e542020-03-14 17:39:03 -0400453 notify=notify,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200454 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200455 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800456 validate_certs=opt.validate_certs,
457 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200458
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700459 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700460 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700461 branch.error = e
462 branch.uploaded = False
463 have_errors = True
464
Sarah Owenscecd1d82012-11-01 22:59:27 -0700465 print(file=sys.stderr)
466 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700467
468 if have_errors:
469 for branch in todo:
470 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700471 if len(str(branch.error)) <= 30:
472 fmt = ' (%s)'
473 else:
474 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700475 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900476 branch.project.relpath + '/',
477 branch.name,
478 str(branch.error)),
479 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700480 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700481
482 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900483 if branch.uploaded:
484 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900485 branch.project.relpath + '/',
486 branch.name),
487 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700488
489 if have_errors:
490 sys.exit(1)
491
Conley Owens3bfd7212013-09-30 15:54:38 -0700492 def _GetMergeBranch(self, project):
493 p = GitCommand(project,
494 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900495 capture_stdout=True,
496 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700497 p.Wait()
498 local_branch = p.stdout.strip()
499 p = GitCommand(project,
500 ['config', '--get', 'branch.%s.merge' % local_branch],
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 merge_branch = p.stdout.strip()
505 return merge_branch
506
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400507 @staticmethod
508 def _GatherOne(opt, project):
509 """Figure out the upload status for |project|."""
510 if opt.current_branch:
511 cbr = project.CurrentBranch
512 up_branch = project.GetUploadableBranch(cbr)
513 avail = [up_branch] if up_branch else None
514 else:
515 avail = project.GetUploadableBranches(opt.branch)
516 return (project, avail)
517
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700518 def Execute(self, opt, args):
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400519 projects = self.GetProjects(args)
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700520
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400521 def _ProcessResults(_pool, _out, results):
522 pending = []
523 for result in results:
524 project, avail = result
525 if avail is None:
Mike Frysinger3b038ce2021-05-01 00:45:19 -0400526 print('repo: error: %s: Unable to upload branch "%s". '
Mike Frysinger160748f2020-11-10 01:09:51 -0500527 'You might be able to fix the branch by running:\n'
528 ' git branch --set-upstream-to m/%s' %
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400529 (project.relpath, project.CurrentBranch, self.manifest.branch),
Warren Turkal011d4f42013-11-27 16:20:57 -0800530 file=sys.stderr)
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400531 elif avail:
532 pending.append(result)
533 return pending
534
535 pending = self.ExecuteInParallel(
536 opt.jobs,
537 functools.partial(self._GatherOne, opt),
538 projects,
539 callback=_ProcessResults)
Doug Anderson37282b42011-03-04 11:54:18 -0800540
Mike Frysinger163a3be2016-04-04 17:31:32 -0400541 if not pending:
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400542 if opt.branch is None:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500543 print('repo: error: no branches ready for upload', file=sys.stderr)
544 else:
545 print('repo: error: no branches named "%s" ready for upload' %
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400546 (opt.branch,), file=sys.stderr)
Mike Frysinger7a753b82020-02-19 00:14:32 -0500547 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
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400559 reviewers = _SplitEmails(opt.reviewers) if opt.reviewers else []
560 cc = _SplitEmails(opt.cc) if opt.cc else []
David Pursehouse8f62fb72012-11-14 12:09:38 +0900561 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700562
Mike Frysinger163a3be2016-04-04 17:31:32 -0400563 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700564 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700565 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700566 self._MultipleBranches(opt, pending, people)