blob: 50dccc526cc8d4a49624295e8c8191f3cd341e53 [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
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070016import re
17import sys
18
19from command import InteractiveCommand
20from editor import Editor
Remy Bohmer7f7acfe2020-08-01 18:36:44 +020021from error import UploadError
Conley Owens3bfd7212013-09-30 15:54:38 -070022from git_command import GitCommand
Sean McAllister682f0b62020-05-18 09:15:51 -060023from git_refs import R_HEADS
Remy Bohmer16c13282020-09-10 10:38:04 +020024from hooks import RepoHook
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070025
Chirayu Desai217ea7d2013-03-01 19:14:38 +053026
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070027UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070028
David Pursehouse819827a2020-02-12 15:20:19 +090029
Dan Morrill879a9a52010-05-04 16:56:07 -070030def _ConfirmManyUploads(multiple_branches=False):
31 if multiple_branches:
David Pursehouse2f9e7e42013-03-05 17:26:46 +090032 print('ATTENTION: One or more branches has an unusually high number '
Sarah Owenscecd1d82012-11-01 22:59:27 -070033 'of commits.')
Dan Morrill879a9a52010-05-04 16:56:07 -070034 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -070035 print('ATTENTION: You are uploading an unusually high number of commits.')
David Pursehouse2f9e7e42013-03-05 17:26:46 +090036 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
Sarah Owenscecd1d82012-11-01 22:59:27 -070037 'branches?)')
Chirayu Desai217ea7d2013-03-01 19:14:38 +053038 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
Dan Morrill879a9a52010-05-04 16:56:07 -070039 return answer == "yes"
40
David Pursehouse819827a2020-02-12 15:20:19 +090041
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070042def _die(fmt, *args):
43 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070044 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070045 sys.exit(1)
46
David Pursehouse819827a2020-02-12 15:20:19 +090047
Joe Onorato2896a792008-11-17 16:56:36 -050048def _SplitEmails(values):
49 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090050 for value in values:
51 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050052 return result
53
David Pursehouse819827a2020-02-12 15:20:19 +090054
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070055class Upload(InteractiveCommand):
56 common = True
57 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090058 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070059%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070060"""
61 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070062The '%prog' command is used to send changes to the Gerrit Code
63Review system. It searches for topic branches in local projects
64that have not yet been published for review. If multiple topic
65branches are found, '%prog' opens an editor to allow the user to
66select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070067
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070068'%prog' searches for uploadable changes in all projects listed at
69the command line. Projects can be specified either by name, or by
70a relative or absolute path to the project's local directory. If no
71projects are specified, '%prog' will search for uploadable changes
72in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050073
74If the --reviewers or --cc options are passed, those emails are
75added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070076new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050077with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080078
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040079# Configuration
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070080
81review.URL.autoupload:
82
Mike Frysingere9311272011-08-11 15:46:43 -040083To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070084or global Git configuration option. If review.URL.autoupload is set
85to "true" then repo will assume you always answer "y" at the prompt,
86and will not prompt you further. If it is set to "false" then repo
87will assume you always answer "n", and will abort.
88
bijia093fdb62013-11-28 09:19:22 +080089review.URL.autoreviewer:
90
91To automatically append a user or mailing list to reviews, you can set
92a per-project or global Git option to do so.
93
Ben Komalo08a3f682010-07-15 16:03:02 -070094review.URL.autocopy:
95
96To automatically copy a user or mailing list to all uploaded reviews,
97you can set a per-project or global Git option to do so. Specifically,
98review.URL.autocopy can be set to a comma separated list of reviewers
99who you always want copied on all uploads with a non-empty --re
100argument.
101
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700102review.URL.username:
103
104Override the username used to connect to Gerrit Code Review.
105By default the local part of the email address is used.
106
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700107The URL must match the review URL listed in the manifest XML file,
108or in the .git/config within the project. For example:
109
110 [remote "origin"]
111 url = git://git.example.com/project.git
112 review = http://review.example.com/
113
114 [review "http://review.example.com/"]
115 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700116 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700117
Anthony Russellod666e932012-06-01 00:48:22 -0400118review.URL.uploadtopic:
119
120To add a topic branch whenever uploading a commit, you can set a
121per-project or global Git option to do so. If review.URL.uploadtopic
122is set to "true" then repo will assume you always want the equivalent
123of the -t option to the repo command. If unset or set to "false" then
124repo will make use of only the command line option.
125
Mike Frysinger84685ba2020-02-19 02:22:22 -0500126review.URL.uploadhashtags:
127
128To add hashtags whenever uploading a commit, you can set a per-project
129or global Git option to do so. The value of review.URL.uploadhashtags
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500130will be used as comma delimited hashtags like the --hashtag option.
131
132review.URL.uploadlabels:
133
134To add labels whenever uploading a commit, you can set a per-project
135or global Git option to do so. The value of review.URL.uploadlabels
136will be used as comma delimited labels like the --label option.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500137
Mike Frysingerf725e542020-03-14 17:39:03 -0400138review.URL.uploadnotify:
139
140Control e-mail notifications when uploading.
141https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify
142
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400143# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700144
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400145Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700146
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700147"""
148
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800149 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700150 p.add_option('-t',
151 dest='auto_topic', action='store_true',
152 help='Send local branch name to Gerrit Code Review')
Mike Frysinger84685ba2020-02-19 02:22:22 -0500153 p.add_option('--hashtag', '--ht',
154 dest='hashtags', action='append', default=[],
155 help='Add hashtags (comma delimited) to the review.')
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500156 p.add_option('--hashtag-branch', '--htb',
157 action='store_true',
158 help='Add local branch name as a hashtag.')
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500159 p.add_option('-l', '--label',
160 dest='labels', action='append', default=[],
161 help='Add a label when uploading.')
Joe Onorato2896a792008-11-17 16:56:36 -0500162 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900163 type='string', action='append', dest='reviewers',
Joe Onorato2896a792008-11-17 16:56:36 -0500164 help='Request reviews from these people.')
165 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900166 type='string', action='append', dest='cc',
Joe Onorato2896a792008-11-17 16:56:36 -0500167 help='Also send email to these email addresses.')
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700168 p.add_option('--br',
David Pursehouse08671042020-02-12 13:52:31 +0900169 type='string', action='store', dest='branch',
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700170 help='Branch to upload.')
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400171 p.add_option('--cbr', '--current-branch',
172 dest='current_branch', action='store_true',
173 help='Upload current git branch.')
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700174 p.add_option('--ne', '--no-emails',
175 action='store_false', dest='notify', default=True,
176 help='If specified, do not send emails on upload.')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200177 p.add_option('-p', '--private',
178 action='store_true', dest='private', default=False,
179 help='If specified, upload as a private change.')
180 p.add_option('-w', '--wip',
181 action='store_true', dest='wip', default=False,
182 help='If specified, upload as a work-in-progress change.')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800183 p.add_option('-o', '--push-option',
184 type='string', action='append', dest='push_options',
185 default=[],
186 help='Additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400187 p.add_option('-D', '--destination', '--dest',
188 type='string', action='store', dest='dest_branch',
189 metavar='BRANCH',
190 help='Submit for review on this target branch.')
Mike Frysinger819cc812020-02-19 02:27:22 -0500191 p.add_option('-n', '--dry-run',
192 dest='dryrun', default=False, action='store_true',
193 help='Do everything except actually upload the CL.')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500194 p.add_option('-y', '--yes',
195 default=False, action='store_true',
196 help='Answer yes to all safe prompts.')
Mike Frysinger21c15752020-02-11 05:17:16 -0500197 p.add_option('--no-cert-checks',
198 dest='validate_certs', action='store_false', default=True,
199 help='Disable verifying ssl certs (unsafe).')
Remy Bohmer7f7acfe2020-08-01 18:36:44 +0200200 RepoHook.AddOptionGroup(p, 'pre-upload')
Doug Anderson37282b42011-03-04 11:54:18 -0800201
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700202 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700203 project = branch.project
204 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700205 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700206
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700207 key = 'review.%s.autoupload' % remote.review
208 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700209
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700210 if answer is False:
211 _die("upload blocked by %s = false" % key)
212
213 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700214 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900215 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700216
Chirayu Desai610d3c42013-06-24 14:02:12 +0530217 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200218 print('Upload project %s/ to remote branch %s%s:' %
Mike Frysingerb0fbc7f2020-02-25 02:58:04 -0500219 (project.relpath, destination, ' (private)' if opt.private else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700220 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900221 name,
222 len(commit_list),
223 len(commit_list) != 1 and 's' or '',
224 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900225 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700226 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700227
Mike Frysingerab85fe72019-07-04 17:35:11 -0400228 print('to %s (y/N)? ' % remote.review, end='')
229 # TODO: When we require Python 3, use flush=True w/print above.
230 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500231 if opt.yes:
232 print('<--yes>')
233 answer = True
234 else:
235 answer = sys.stdin.readline().strip().lower()
236 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700237
238 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700239 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
240 answer = _ConfirmManyUploads()
241
242 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700243 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700244 else:
245 _die("upload aborted by user")
246
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700247 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700248 projects = {}
249 branches = {}
250
251 script = []
252 script.append('# Uncomment the branches to upload:')
253 for project, avail in pending:
254 script.append('#')
255 script.append('# project %s/:' % project.relpath)
256
257 b = {}
258 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400259 if branch is None:
260 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700261 name = branch.name
262 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900263 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700264
265 if b:
266 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400267 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200268 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700269 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900270 len(commit_list),
271 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200272 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400273 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900274 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700275 script.append('# %s' % commit)
276 b[name] = branch
277
278 projects[project.relpath] = project
279 branches[project.name] = b
280 script.append('')
281
282 script = Editor.EditString("\n".join(script)).split("\n")
283
284 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
285 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
286
287 project = None
288 todo = []
289
290 for line in script:
291 m = project_re.match(line)
292 if m:
293 name = m.group(1)
294 project = projects.get(name)
295 if not project:
296 _die('project %s not available for upload', name)
297 continue
298
299 m = branch_re.match(line)
300 if m:
301 name = m.group(1)
302 if not project:
303 _die('project for branch %s not in script', name)
304 branch = branches[project.name].get(name)
305 if not branch:
306 _die('branch %s not in %s', name, project.relpath)
307 todo.append(branch)
308 if not todo:
309 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700310
311 many_commits = False
312 for branch in todo:
313 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
314 many_commits = True
315 break
316 if many_commits:
317 if not _ConfirmManyUploads(multiple_branches=True):
318 _die("upload aborted by user")
319
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700320 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700321
bijia093fdb62013-11-28 09:19:22 +0800322 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700323 """
bijia093fdb62013-11-28 09:19:22 +0800324 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700325 Appends the list of users in the CC list in the git project's config if a
326 non-empty reviewer list was found.
327 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700328 name = branch.name
329 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800330
331 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
332 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900333 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800334 people[0].extend([entry.strip() for entry in raw_list.split(',')])
335
Ben Komalo08a3f682010-07-15 16:03:02 -0700336 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
337 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900338 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700339 people[1].extend([entry.strip() for entry in raw_list.split(',')])
340
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700341 def _FindGerritChange(self, branch):
342 last_pub = branch.project.WasPublished(branch.name)
343 if last_pub is None:
344 return ""
345
346 refs = branch.GetPublishedRefs()
347 try:
348 # refs/changes/XYZ/N --> XYZ
349 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900350 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700351 return ""
352
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700353 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700354 have_errors = False
355 for branch in todo:
356 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700357 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800358 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700359
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500360 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700361 changes = branch.project.UncommitedFiles()
362 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900363 key = 'review.%s.autoupload' % branch.project.remote.review
364 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500365
David Pursehousec1b86a22012-11-14 11:36:51 +0900366 # if they want to auto upload, let's not ask because it could be automated
367 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400368 print()
369 print('Uncommitted changes in %s (did you forget to amend?):'
370 % branch.project.name)
371 print('\n'.join(changes))
372 print('Continue uploading? (y/N) ', end='')
373 # TODO: When we require Python 3, use flush=True w/print above.
374 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500375 if opt.yes:
376 print('<--yes>')
377 a = 'yes'
378 else:
379 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900380 if a not in ('y', 'yes', 't', 'true', 'on'):
381 print("skipping upload", file=sys.stderr)
382 branch.uploaded = False
383 branch.error = 'User aborted'
384 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500385
Anthony Russellod666e932012-06-01 00:48:22 -0400386 # Check if topic branches should be sent to the server during upload
387 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900388 key = 'review.%s.uploadtopic' % branch.project.remote.review
389 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400390
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500391 def _ExpandCommaList(value):
392 """Split |value| up into comma delimited entries."""
Mike Frysinger84685ba2020-02-19 02:22:22 -0500393 if not value:
394 return
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500395 for ret in value.split(','):
396 ret = ret.strip()
397 if ret:
398 yield ret
399
400 # Check if hashtags should be included.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500401 key = 'review.%s.uploadhashtags' % branch.project.remote.review
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500402 hashtags = set(_ExpandCommaList(branch.project.config.GetString(key)))
Mike Frysinger84685ba2020-02-19 02:22:22 -0500403 for tag in opt.hashtags:
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500404 hashtags.update(_ExpandCommaList(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500405 if opt.hashtag_branch:
406 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500407
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500408 # Check if labels should be included.
409 key = 'review.%s.uploadlabels' % branch.project.remote.review
410 labels = set(_ExpandCommaList(branch.project.config.GetString(key)))
411 for label in opt.labels:
412 labels.update(_ExpandCommaList(label))
413 # Basic sanity check on label syntax.
414 for label in labels:
415 if not re.match(r'^.+[+-][0-9]+$', label):
416 print('repo: error: invalid label syntax "%s": labels use forms '
417 'like CodeReview+1 or Verified-1' % (label,), file=sys.stderr)
418 sys.exit(1)
419
Mike Frysingerf725e542020-03-14 17:39:03 -0400420 # Handle e-mail notifications.
421 if opt.notify is False:
422 notify = 'NONE'
423 else:
424 key = 'review.%s.uploadnotify' % branch.project.remote.review
425 notify = branch.project.config.GetString(key)
426
Colin Cross59b31cb2013-10-08 23:10:52 -0700427 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700428
429 # Make sure our local branch is not setup to track a different remote branch
430 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700431 if destination:
Sean McAllister682f0b62020-05-18 09:15:51 -0600432 full_dest = destination
433 if not full_dest.startswith(R_HEADS):
434 full_dest = R_HEADS + full_dest
435
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700436 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
437 print('merge branch %s does not match destination branch %s'
438 % (merge_branch, full_dest))
439 print('skipping upload.')
440 print('Please use `--destination %s` if this is intentional'
441 % destination)
442 branch.uploaded = False
443 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700444
Changcheng Xiao87984c62017-08-02 16:55:03 +0200445 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500446 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200447 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500448 hashtags=hashtags,
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500449 labels=labels,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200450 private=opt.private,
Mike Frysingerf725e542020-03-14 17:39:03 -0400451 notify=notify,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200452 wip=opt.wip,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200453 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800454 validate_certs=opt.validate_certs,
455 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200456
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700457 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700458 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700459 branch.error = e
460 branch.uploaded = False
461 have_errors = True
462
Sarah Owenscecd1d82012-11-01 22:59:27 -0700463 print(file=sys.stderr)
464 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700465
466 if have_errors:
467 for branch in todo:
468 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700469 if len(str(branch.error)) <= 30:
470 fmt = ' (%s)'
471 else:
472 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700473 print(('[FAILED] %-15s %-15s' + fmt) % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900474 branch.project.relpath + '/',
475 branch.name,
476 str(branch.error)),
477 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700478 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700479
480 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900481 if branch.uploaded:
482 print('[OK ] %-15s %s' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900483 branch.project.relpath + '/',
484 branch.name),
485 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700486
487 if have_errors:
488 sys.exit(1)
489
Conley Owens3bfd7212013-09-30 15:54:38 -0700490 def _GetMergeBranch(self, project):
491 p = GitCommand(project,
492 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900493 capture_stdout=True,
494 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700495 p.Wait()
496 local_branch = p.stdout.strip()
497 p = GitCommand(project,
498 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900499 capture_stdout=True,
500 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700501 p.Wait()
502 merge_branch = p.stdout.strip()
503 return merge_branch
504
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700505 def Execute(self, opt, args):
506 project_list = self.GetProjects(args)
507 pending = []
Joe Onorato2896a792008-11-17 16:56:36 -0500508 reviewers = []
509 cc = []
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700510 branch = None
511
512 if opt.branch:
513 branch = opt.branch
Joe Onorato2896a792008-11-17 16:56:36 -0500514
Doug Anderson37282b42011-03-04 11:54:18 -0800515 for project in project_list:
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400516 if opt.current_branch:
517 cbr = project.CurrentBranch
Warren Turkal011d4f42013-11-27 16:20:57 -0800518 up_branch = project.GetUploadableBranch(cbr)
519 if up_branch:
520 avail = [up_branch]
521 else:
522 avail = None
Mike Frysinger160748f2020-11-10 01:09:51 -0500523 print('repo: error: Unable to upload branch "%s". '
524 'You might be able to fix the branch by running:\n'
525 ' git branch --set-upstream-to m/%s' %
526 (str(cbr), self.manifest.branch),
Warren Turkal011d4f42013-11-27 16:20:57 -0800527 file=sys.stderr)
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400528 else:
529 avail = project.GetUploadableBranches(branch)
Doug Anderson37282b42011-03-04 11:54:18 -0800530 if avail:
531 pending.append((project, avail))
532
Mike Frysinger163a3be2016-04-04 17:31:32 -0400533 if not pending:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500534 if branch is None:
535 print('repo: error: no branches ready for upload', file=sys.stderr)
536 else:
537 print('repo: error: no branches named "%s" ready for upload' %
538 (branch,), file=sys.stderr)
539 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400540
Remy Bohmer7f7acfe2020-08-01 18:36:44 +0200541 pending_proj_names = [project.name for (project, available) in pending]
542 pending_worktrees = [project.worktree for (project, available) in pending]
543 hook = RepoHook.FromSubcmd(
544 hook_type='pre-upload', manifest=self.manifest,
545 opt=opt, abort_if_user_denies=True)
546 if not hook.Run(
547 project_list=pending_proj_names,
548 worktree_list=pending_worktrees):
549 return 1
Doug Anderson37282b42011-03-04 11:54:18 -0800550
Joe Onorato2896a792008-11-17 16:56:36 -0500551 if opt.reviewers:
552 reviewers = _SplitEmails(opt.reviewers)
553 if opt.cc:
554 cc = _SplitEmails(opt.cc)
David Pursehouse8f62fb72012-11-14 12:09:38 +0900555 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700556
Mike Frysinger163a3be2016-04-04 17:31:32 -0400557 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700558 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700559 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700560 self._MultipleBranches(opt, pending, people)