blob: ef6d02424c27e3406957e326952fa981af2c98d8 [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
137will be used as comma delimited hashtags like the --hashtags option.
138
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400139# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700140
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400141Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700142
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700143"""
144
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800145 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700146 p.add_option('-t',
147 dest='auto_topic', action='store_true',
148 help='Send local branch name to Gerrit Code Review')
Mike Frysinger84685ba2020-02-19 02:22:22 -0500149 p.add_option('--hashtag', '--ht',
150 dest='hashtags', action='append', default=[],
151 help='Add hashtags (comma delimited) to the review.')
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500152 p.add_option('--hashtag-branch', '--htb',
153 action='store_true',
154 help='Add local branch name as a hashtag.')
Joe Onorato2896a792008-11-17 16:56:36 -0500155 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900156 type='string', action='append', dest='reviewers',
Joe Onorato2896a792008-11-17 16:56:36 -0500157 help='Request reviews from these people.')
158 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900159 type='string', action='append', dest='cc',
Joe Onorato2896a792008-11-17 16:56:36 -0500160 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700161 p.add_option('--br',
David Pursehouse08671042020-02-12 13:52:31 +0900162 type='string', action='store', dest='branch',
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700163 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400164 p.add_option('--cbr', '--current-branch',
165 dest='current_branch', action='store_true',
166 help='Upload current git branch.')
Brian Harring435370c2012-07-28 15:37:04 -0700167 p.add_option('-d', '--draft',
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000168 action='store_true', dest='draft', default=False,
169 help='If specified, upload as a draft.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700170 p.add_option('--ne', '--no-emails',
171 action='store_false', dest='notify', default=True,
172 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200173 p.add_option('-p', '--private',
174 action='store_true', dest='private', default=False,
175 help='If specified, upload as a private change.')
176 p.add_option('-w', '--wip',
177 action='store_true', dest='wip', default=False,
178 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800179 p.add_option('-o', '--push-option',
180 type='string', action='append', dest='push_options',
181 default=[],
182 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400183 p.add_option('-D', '--destination', '--dest',
184 type='string', action='store', dest='dest_branch',
185 metavar='BRANCH',
186 help='Submit for review on this target branch.')
Mike Frysinger819cc812020-02-19 02:27:22 -0500187 p.add_option('-n', '--dry-run',
188 dest='dryrun', default=False, action='store_true',
189 help='Do everything except actually upload the CL.')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500190 p.add_option('-y', '--yes',
191 default=False, action='store_true',
192 help='Answer yes to all safe prompts.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500193 p.add_option('--no-cert-checks',
194 dest='validate_certs', action='store_false', default=True,
195 help='Disable verifying ssl certs (unsafe).')
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800196
Doug Anderson37282b42011-03-04 11:54:18 -0800197 # Options relating to upload hook. Note that verify and no-verify are NOT
198 # opposites of each other, which is why they store to different locations.
199 # We are using them to match 'git commit' syntax.
200 #
201 # Combinations:
202 # - no-verify=False, verify=False (DEFAULT):
203 # If stdout is a tty, can prompt about running upload hooks if needed.
204 # If user denies running hooks, the upload is cancelled. If stdout is
205 # not a tty and we would need to prompt about upload hooks, upload is
206 # cancelled.
207 # - no-verify=False, verify=True:
208 # Always run upload hooks with no prompt.
209 # - no-verify=True, verify=False:
210 # Never run upload hooks, but upload anyway (AKA bypass hooks).
211 # - no-verify=True, verify=True:
212 # Invalid
Mike Frysinger21c15752020-02-11 05:17:16 -0500213 g = p.add_option_group('Upload hooks')
214 g.add_option('--no-verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800215 dest='bypass_hooks', action='store_true',
216 help='Do not run the upload hook.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500217 g.add_option('--verify',
Doug Anderson37282b42011-03-04 11:54:18 -0800218 dest='allow_all_hooks', action='store_true',
219 help='Run the upload hook without prompting.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500220 g.add_option('--ignore-hooks',
221 dest='ignore_hooks', action='store_true',
222 help='Do not abort uploading if upload hooks fail.')
Doug Anderson37282b42011-03-04 11:54:18 -0800223
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700224 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700225 project = branch.project
226 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700227 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700228
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700229 key = 'review.%s.autoupload' % remote.review
230 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700231
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700232 if answer is False:
233 _die("upload blocked by %s = false" % key)
234
235 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700236 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900237 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700238
Chirayu Desai610d3c42013-06-24 14:02:12 +0530239 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200240 print('Upload project %s/ to remote branch %s%s:' %
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000241 (project.relpath, destination, ' (draft)' if opt.draft else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700242 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900243 name,
244 len(commit_list),
245 len(commit_list) != 1 and 's' or '',
246 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900247 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700248 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700249
Mike Frysingerab85fe72019-07-04 17:35:11 -0400250 print('to %s (y/N)? ' % remote.review, end='')
251 # TODO: When we require Python 3, use flush=True w/print above.
252 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500253 if opt.yes:
254 print('<--yes>')
255 answer = True
256 else:
257 answer = sys.stdin.readline().strip().lower()
258 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700259
260 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700261 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
262 answer = _ConfirmManyUploads()
263
264 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700265 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700266 else:
267 _die("upload aborted by user")
268
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700269 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700270 projects = {}
271 branches = {}
272
273 script = []
274 script.append('# Uncomment the branches to upload:')
275 for project, avail in pending:
276 script.append('#')
277 script.append('# project %s/:' % project.relpath)
278
279 b = {}
280 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400281 if branch is None:
282 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700283 name = branch.name
284 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900285 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700286
287 if b:
288 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400289 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200290 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700291 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900292 len(commit_list),
293 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200294 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400295 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900296 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700297 script.append('# %s' % commit)
298 b[name] = branch
299
300 projects[project.relpath] = project
301 branches[project.name] = b
302 script.append('')
303
304 script = Editor.EditString("\n".join(script)).split("\n")
305
306 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
307 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
308
309 project = None
310 todo = []
311
312 for line in script:
313 m = project_re.match(line)
314 if m:
315 name = m.group(1)
316 project = projects.get(name)
317 if not project:
318 _die('project %s not available for upload', name)
319 continue
320
321 m = branch_re.match(line)
322 if m:
323 name = m.group(1)
324 if not project:
325 _die('project for branch %s not in script', name)
326 branch = branches[project.name].get(name)
327 if not branch:
328 _die('branch %s not in %s', name, project.relpath)
329 todo.append(branch)
330 if not todo:
331 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700332
333 many_commits = False
334 for branch in todo:
335 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
336 many_commits = True
337 break
338 if many_commits:
339 if not _ConfirmManyUploads(multiple_branches=True):
340 _die("upload aborted by user")
341
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700342 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700343
bijia093fdb62013-11-28 09:19:22 +0800344 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700345 """
bijia093fdb62013-11-28 09:19:22 +0800346 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700347 Appends the list of users in the CC list in the git project's config if a
348 non-empty reviewer list was found.
349 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700350 name = branch.name
351 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800352
353 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
354 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900355 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800356 people[0].extend([entry.strip() for entry in raw_list.split(',')])
357
Ben Komalo08a3f682010-07-15 16:03:02 -0700358 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
359 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900360 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700361 people[1].extend([entry.strip() for entry in raw_list.split(',')])
362
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700363 def _FindGerritChange(self, branch):
364 last_pub = branch.project.WasPublished(branch.name)
365 if last_pub is None:
366 return ""
367
368 refs = branch.GetPublishedRefs()
369 try:
370 # refs/changes/XYZ/N --> XYZ
371 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900372 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700373 return ""
374
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700375 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700376 have_errors = False
377 for branch in todo:
378 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700379 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800380 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700381
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500382 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700383 changes = branch.project.UncommitedFiles()
384 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900385 key = 'review.%s.autoupload' % branch.project.remote.review
386 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500387
David Pursehousec1b86a22012-11-14 11:36:51 +0900388 # if they want to auto upload, let's not ask because it could be automated
389 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400390 print()
391 print('Uncommitted changes in %s (did you forget to amend?):'
392 % branch.project.name)
393 print('\n'.join(changes))
394 print('Continue uploading? (y/N) ', end='')
395 # TODO: When we require Python 3, use flush=True w/print above.
396 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500397 if opt.yes:
398 print('<--yes>')
399 a = 'yes'
400 else:
401 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900402 if a not in ('y', 'yes', 't', 'true', 'on'):
403 print("skipping upload", file=sys.stderr)
404 branch.uploaded = False
405 branch.error = 'User aborted'
406 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500407
Anthony Russellod666e932012-06-01 00:48:22 -0400408 # Check if topic branches should be sent to the server during upload
409 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900410 key = 'review.%s.uploadtopic' % branch.project.remote.review
411 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400412
Mike Frysinger84685ba2020-02-19 02:22:22 -0500413 # Check if hashtags should be included.
414 def _ExpandHashtag(value):
415 """Split |value| up into comma delimited tags."""
416 if not value:
417 return
418 for tag in value.split(','):
419 tag = tag.strip()
420 if tag:
421 yield tag
422 key = 'review.%s.uploadhashtags' % branch.project.remote.review
423 hashtags = set(_ExpandHashtag(branch.project.config.GetString(key)))
424 for tag in opt.hashtags:
425 hashtags.update(_ExpandHashtag(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500426 if opt.hashtag_branch:
427 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500428
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:
434 full_dest = 'refs/heads/%s' % destination
435 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
436 print('merge branch %s does not match destination branch %s'
437 % (merge_branch, full_dest))
438 print('skipping upload.')
439 print('Please use `--destination %s` if this is intentional'
440 % destination)
441 branch.uploaded = False
442 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700443
Changcheng Xiao87984c62017-08-02 16:55:03 +0200444 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500445 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200446 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500447 hashtags=hashtags,
Jonathan Niederc94d6eb2017-08-08 18:34:53 +0000448 draft=opt.draft,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200449 private=opt.private,
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700450 notify=None if opt.notify else 'NONE',
Changcheng Xiao87984c62017-08-02 16:55:03 +0200451 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200452 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800453 validate_certs=opt.validate_certs,
454 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200455
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700456 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700457 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700458 branch.error = e
459 branch.uploaded = False
460 have_errors = True
461
Sarah Owenscecd1d82012-11-01 22:59:27 -0700462 print(file=sys.stderr)
463 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700464
465 if have_errors:
466 for branch in todo:
467 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700468 if len(str(branch.error)) <= 30:
469 fmt = ' (%s)'
470 else:
471 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700472 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900473 branch.project.relpath + '/',
474 branch.name,
475 str(branch.error)),
476 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700477 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700478
479 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900480 if branch.uploaded:
481 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900482 branch.project.relpath + '/',
483 branch.name),
484 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700485
486 if have_errors:
487 sys.exit(1)
488
Conley Owens3bfd7212013-09-30 15:54:38 -0700489 def _GetMergeBranch(self, project):
490 p = GitCommand(project,
491 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900492 capture_stdout=True,
493 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700494 p.Wait()
495 local_branch = p.stdout.strip()
496 p = GitCommand(project,
497 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900498 capture_stdout=True,
499 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700500 p.Wait()
501 merge_branch = p.stdout.strip()
502 return merge_branch
503
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700504 def Execute(self, opt, args):
505 project_list = self.GetProjects(args)
506 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500507 reviewers = []
508 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700509 branch = None
510
511 if opt.branch:
512 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500513
Doug Anderson37282b42011-03-04 11:54:18 -0800514 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400515 if opt.current_branch:
516 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800517 up_branch = project.GetUploadableBranch(cbr)
518 if up_branch:
519 avail = [up_branch]
520 else:
521 avail = None
522 print('ERROR: Current branch (%s) not uploadable. '
523 'You may be able to type '
524 '"git branch --set-upstream-to m/master" to fix '
525 'your branch.' % str(cbr),
526 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400527 else:
528 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800529 if avail:
530 pending.append((project, avail))
531
Mike Frysinger163a3be2016-04-04 17:31:32 -0400532 if not pending:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500533 if branch is None:
534 print('repo: error: no branches ready for upload', file=sys.stderr)
535 else:
536 print('repo: error: no branches named "%s" ready for upload' %
537 (branch,), file=sys.stderr)
538 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400539
540 if not opt.bypass_hooks:
Doug Anderson37282b42011-03-04 11:54:18 -0800541 hook = RepoHook('pre-upload', self.manifest.repo_hooks_project,
Mike Frysinger40252c22016-08-15 21:23:44 -0400542 self.manifest.topdir,
543 self.manifest.manifestProject.GetRemote('origin').url,
544 abort_if_user_denies=True)
David Pursehouse3bcd3052017-07-10 22:42:22 +0900545 pending_proj_names = [project.name for (project, available) in pending]
546 pending_worktrees = [project.worktree for (project, available) in pending]
Mike Frysinger21c15752020-02-11 05:17:16 -0500547 passed = True
Doug Anderson37282b42011-03-04 11:54:18 -0800548 try:
David James8d201162013-10-11 17:03:19 -0700549 hook.Run(opt.allow_all_hooks, project_list=pending_proj_names,
550 worktree_list=pending_worktrees)
Mike Frysinger21c15752020-02-11 05:17:16 -0500551 except SystemExit:
552 passed = False
553 if not opt.ignore_hooks:
554 raise
Sarah Owensa5be53f2012-09-09 15:37:57 -0700555 except HookError as e:
Mike Frysinger21c15752020-02-11 05:17:16 -0500556 passed = False
Sarah Owenscecd1d82012-11-01 22:59:27 -0700557 print("ERROR: %s" % str(e), file=sys.stderr)
Mike Frysinger21c15752020-02-11 05:17:16 -0500558
559 if not passed:
560 if opt.ignore_hooks:
561 print('\nWARNING: pre-upload hooks failed, but uploading anyways.',
562 file=sys.stderr)
563 else:
564 return
Doug Anderson37282b42011-03-04 11:54:18 -0800565
Joe Onorato2896a792008-11-17 16:56:36 -0500566 if opt.reviewers:
567 reviewers = _SplitEmails(opt.reviewers)
568 if opt.cc:
569 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900570 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700571
Mike Frysinger163a3be2016-04-04 17:31:32 -0400572 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700573 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700574 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700575 self._MultipleBranches(opt, pending, people)