blob: 01d1dea46478033db3e27974e4348b1f2077482a [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
Mike Frysingerb8e09ea2021-05-03 00:51:52 -040017import optparse
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070018import re
19import sys
20
Mike Frysingerd1f3e142021-05-01 12:02:01 -040021from command import DEFAULT_LOCAL_JOBS, InteractiveCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070022from editor import Editor
Remy Bohmer7f7acfe2020-08-01 18:36:44 +020023from error import UploadError
Conley Owens3bfd7212013-09-30 15:54:38 -070024from git_command import GitCommand
Sean McAllister682f0b62020-05-18 09:15:51 -060025from git_refs import R_HEADS
Remy Bohmer16c13282020-09-10 10:38:04 +020026from hooks import RepoHook
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070027
Chirayu Desai217ea7d2013-03-01 19:14:38 +053028
Dan Morrillf0a9a1a2010-05-05 08:18:35 -070029UNUSUAL_COMMIT_THRESHOLD = 5
Dan Morrill879a9a52010-05-04 16:56:07 -070030
David Pursehouse819827a2020-02-12 15:20:19 +090031
Dan Morrill879a9a52010-05-04 16:56:07 -070032def _ConfirmManyUploads(multiple_branches=False):
33 if multiple_branches:
David Pursehouse2f9e7e42013-03-05 17:26:46 +090034 print('ATTENTION: One or more branches has an unusually high number '
Sarah Owenscecd1d82012-11-01 22:59:27 -070035 'of commits.')
Dan Morrill879a9a52010-05-04 16:56:07 -070036 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -070037 print('ATTENTION: You are uploading an unusually high number of commits.')
David Pursehouse2f9e7e42013-03-05 17:26:46 +090038 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
Sarah Owenscecd1d82012-11-01 22:59:27 -070039 'branches?)')
Chirayu Desai217ea7d2013-03-01 19:14:38 +053040 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
Dan Morrill879a9a52010-05-04 16:56:07 -070041 return answer == "yes"
42
David Pursehouse819827a2020-02-12 15:20:19 +090043
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070044def _die(fmt, *args):
45 msg = fmt % args
Sarah Owenscecd1d82012-11-01 22:59:27 -070046 print('error: %s' % msg, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070047 sys.exit(1)
48
David Pursehouse819827a2020-02-12 15:20:19 +090049
Joe Onorato2896a792008-11-17 16:56:36 -050050def _SplitEmails(values):
51 result = []
David Pursehouse8a68ff92012-09-24 12:15:13 +090052 for value in values:
53 result.extend([s.strip() for s in value.split(',')])
Joe Onorato2896a792008-11-17 16:56:36 -050054 return result
55
David Pursehouse819827a2020-02-12 15:20:19 +090056
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070057class Upload(InteractiveCommand):
Mike Frysinger4f210542021-06-14 16:05:19 -040058 COMMON = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070059 helpSummary = "Upload changes for code review"
David Pursehouse8f62fb72012-11-14 12:09:38 +090060 helpUsage = """
Ficus Kirkpatricka0de6e82010-10-22 13:06:47 -070061%prog [--re --cc] [<project>]...
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070062"""
63 helpDescription = """
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070064The '%prog' command is used to send changes to the Gerrit Code
65Review system. It searches for topic branches in local projects
66that have not yet been published for review. If multiple topic
67branches are found, '%prog' opens an editor to allow the user to
68select which branches to upload.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070069
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070070'%prog' searches for uploadable changes in all projects listed at
71the command line. Projects can be specified either by name, or by
72a relative or absolute path to the project's local directory. If no
73projects are specified, '%prog' will search for uploadable changes
74in all projects listed in the manifest.
Joe Onorato2896a792008-11-17 16:56:36 -050075
76If the --reviewers or --cc options are passed, those emails are
77added to the respective list of users, and emails are sent to any
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -070078new users. Users passed as --reviewers must already be registered
Joe Onorato2896a792008-11-17 16:56:36 -050079with the code review system, or the upload will fail.
Shawn O. Pearcea6df7d22008-12-12 08:04:07 -080080
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040081# Configuration
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070082
83review.URL.autoupload:
84
Mike Frysingere9311272011-08-11 15:46:43 -040085To disable the "Upload ... (y/N)?" prompt, you can set a per-project
Shawn O. Pearcea608fb02009-04-17 12:11:24 -070086or global Git configuration option. If review.URL.autoupload is set
87to "true" then repo will assume you always answer "y" at the prompt,
88and will not prompt you further. If it is set to "false" then repo
89will assume you always answer "n", and will abort.
90
bijia093fdb62013-11-28 09:19:22 +080091review.URL.autoreviewer:
92
93To automatically append a user or mailing list to reviews, you can set
94a per-project or global Git option to do so.
95
Ben Komalo08a3f682010-07-15 16:03:02 -070096review.URL.autocopy:
97
98To automatically copy a user or mailing list to all uploaded reviews,
99you can set a per-project or global Git option to do so. Specifically,
100review.URL.autocopy can be set to a comma separated list of reviewers
101who you always want copied on all uploads with a non-empty --re
102argument.
103
Shawn O. Pearce3575b8f2010-07-15 17:00:14 -0700104review.URL.username:
105
106Override the username used to connect to Gerrit Code Review.
107By default the local part of the email address is used.
108
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700109The URL must match the review URL listed in the manifest XML file,
110or in the .git/config within the project. For example:
111
112 [remote "origin"]
113 url = git://git.example.com/project.git
114 review = http://review.example.com/
115
116 [review "http://review.example.com/"]
117 autoupload = true
Ben Komalo08a3f682010-07-15 16:03:02 -0700118 autocopy = johndoe@company.com,my-team-alias@company.com
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700119
Anthony Russellod666e932012-06-01 00:48:22 -0400120review.URL.uploadtopic:
121
122To add a topic branch whenever uploading a commit, you can set a
123per-project or global Git option to do so. If review.URL.uploadtopic
124is set to "true" then repo will assume you always want the equivalent
125of the -t option to the repo command. If unset or set to "false" then
126repo will make use of only the command line option.
127
Mike Frysinger84685ba2020-02-19 02:22:22 -0500128review.URL.uploadhashtags:
129
130To add hashtags whenever uploading a commit, you can set a per-project
131or global Git option to do so. The value of review.URL.uploadhashtags
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500132will be used as comma delimited hashtags like the --hashtag option.
133
134review.URL.uploadlabels:
135
136To add labels whenever uploading a commit, you can set a per-project
137or global Git option to do so. The value of review.URL.uploadlabels
138will be used as comma delimited labels like the --label option.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500139
Mike Frysingerf725e542020-03-14 17:39:03 -0400140review.URL.uploadnotify:
141
142Control e-mail notifications when uploading.
143https://gerrit-review.googlesource.com/Documentation/user-upload.html#notify
144
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400145# References
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700146
Mike Frysinger3b24e7b2018-10-10 00:57:44 -0400147Gerrit Code Review: https://www.gerritcodereview.com/
Shawn O. Pearce337fb9c2009-04-18 10:59:33 -0700148
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700149"""
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400150 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700151
Shawn O. Pearcec99883f2008-11-11 17:12:43 -0800152 def _Options(self, p):
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700153 p.add_option('-t',
154 dest='auto_topic', action='store_true',
Mike Frysingerc177f942021-05-04 08:06:36 -0400155 help='send local branch name to Gerrit Code Review')
Mike Frysinger84685ba2020-02-19 02:22:22 -0500156 p.add_option('--hashtag', '--ht',
157 dest='hashtags', action='append', default=[],
Mike Frysingerc177f942021-05-04 08:06:36 -0400158 help='add hashtags (comma delimited) to the review')
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500159 p.add_option('--hashtag-branch', '--htb',
160 action='store_true',
Mike Frysingerc177f942021-05-04 08:06:36 -0400161 help='add local branch name as a hashtag')
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500162 p.add_option('-l', '--label',
163 dest='labels', action='append', default=[],
Mike Frysingerc177f942021-05-04 08:06:36 -0400164 help='add a label when uploading')
Joe Onorato2896a792008-11-17 16:56:36 -0500165 p.add_option('--re', '--reviewers',
David Pursehouse08671042020-02-12 13:52:31 +0900166 type='string', action='append', dest='reviewers',
Mike Frysingerc177f942021-05-04 08:06:36 -0400167 help='request reviews from these people')
Joe Onorato2896a792008-11-17 16:56:36 -0500168 p.add_option('--cc',
David Pursehouse08671042020-02-12 13:52:31 +0900169 type='string', action='append', dest='cc',
Mike Frysingerc177f942021-05-04 08:06:36 -0400170 help='also send email to these email addresses')
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400171 p.add_option('--br', '--branch',
David Pursehouse08671042020-02-12 13:52:31 +0900172 type='string', action='store', dest='branch',
Mike Frysingerc177f942021-05-04 08:06:36 -0400173 help='(local) branch to upload')
Mike Frysingerb8e09ea2021-05-03 00:51:52 -0400174 p.add_option('-c', '--current-branch',
Daniel Sandlere9d6b612012-04-06 10:39:32 -0400175 dest='current_branch', action='store_true',
Mike Frysingerc177f942021-05-04 08:06:36 -0400176 help='upload current git branch')
Mike Frysinger73561142021-05-03 01:10:09 -0400177 p.add_option('--no-current-branch',
178 dest='current_branch', action='store_false',
Mike Frysingerc177f942021-05-04 08:06:36 -0400179 help='upload all git branches')
Mike Frysingerb8e09ea2021-05-03 00:51:52 -0400180 # Turn this into a warning & remove this someday.
181 p.add_option('--cbr',
182 dest='current_branch', action='store_true',
183 help=optparse.SUPPRESS_HELP)
Vadim Bendeburybd8f6582018-10-31 13:48:01 -0700184 p.add_option('--ne', '--no-emails',
185 action='store_false', dest='notify', default=True,
Mike Frysingerc177f942021-05-04 08:06:36 -0400186 help='do not send e-mails on upload')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200187 p.add_option('-p', '--private',
188 action='store_true', dest='private', default=False,
Mike Frysingerc177f942021-05-04 08:06:36 -0400189 help='upload as a private change (deprecated; use --wip)')
Changcheng Xiao87984c62017-08-02 16:55:03 +0200190 p.add_option('-w', '--wip',
191 action='store_true', dest='wip', default=False,
Mike Frysingerc177f942021-05-04 08:06:36 -0400192 help='upload as a work-in-progress change')
William Escandeac76fd32022-08-02 16:05:37 -0700193 p.add_option('-r', '--ready',
194 action='store_true', default=False,
195 help='mark change as ready (clears work-in-progress setting)')
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800196 p.add_option('-o', '--push-option',
197 type='string', action='append', dest='push_options',
198 default=[],
Mike Frysingerc177f942021-05-04 08:06:36 -0400199 help='additional push options to transmit')
Bryan Jacobsf609f912013-05-06 13:36:24 -0400200 p.add_option('-D', '--destination', '--dest',
201 type='string', action='store', dest='dest_branch',
202 metavar='BRANCH',
Mike Frysingerc177f942021-05-04 08:06:36 -0400203 help='submit for review on this target branch')
Mike Frysinger819cc812020-02-19 02:27:22 -0500204 p.add_option('-n', '--dry-run',
205 dest='dryrun', default=False, action='store_true',
Mike Frysingerc177f942021-05-04 08:06:36 -0400206 help='do everything except actually upload the CL')
Mike Frysinger02aa8892020-02-19 02:32:52 -0500207 p.add_option('-y', '--yes',
208 default=False, action='store_true',
Mike Frysingerc177f942021-05-04 08:06:36 -0400209 help='answer yes to all safe prompts')
Martin Geisler9fb64ae2022-07-08 10:50:10 +0200210 p.add_option('--ignore-untracked-files',
211 action='store_true', default=False,
212 help='ignore untracked files in the working copy')
213 p.add_option('--no-ignore-untracked-files',
214 dest='ignore_untracked_files', action='store_false',
215 help='always ask about untracked files in the working copy')
Mike Frysinger21c15752020-02-11 05:17:16 -0500216 p.add_option('--no-cert-checks',
217 dest='validate_certs', action='store_false', default=True,
Mike Frysingerc177f942021-05-04 08:06:36 -0400218 help='disable verifying ssl certs (unsafe)')
Remy Bohmer7f7acfe2020-08-01 18:36:44 +0200219 RepoHook.AddOptionGroup(p, 'pre-upload')
Doug Anderson37282b42011-03-04 11:54:18 -0800220
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700221 def _SingleBranch(self, opt, branch, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700222 project = branch.project
223 name = branch.name
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700224 remote = project.GetBranch(name).remote
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700225
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700226 key = 'review.%s.autoupload' % remote.review
227 answer = project.config.GetBoolean(key)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700228
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700229 if answer is False:
230 _die("upload blocked by %s = false" % key)
231
232 if answer is None:
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700233 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900234 commit_list = branch.commits
Shawn O. Pearce66bdd462009-04-17 18:47:22 -0700235
Chirayu Desai610d3c42013-06-24 14:02:12 +0530236 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Nicolas Cornub54343d2017-07-10 10:31:24 +0200237 print('Upload project %s/ to remote branch %s%s:' %
LaMont Jonescc879a92021-11-18 22:40:18 +0000238 (project.RelPath(local=opt.this_manifest_only), destination,
239 ' (private)' if opt.private else ''))
Sarah Owenscecd1d82012-11-01 22:59:27 -0700240 print(' branch %s (%2d commit%s, %s):' % (
David Pursehouseabdf7502020-02-12 14:58:39 +0900241 name,
242 len(commit_list),
243 len(commit_list) != 1 and 's' or '',
244 date))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900245 for commit in commit_list:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700246 print(' %s' % commit)
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700247
Mike Frysingerab85fe72019-07-04 17:35:11 -0400248 print('to %s (y/N)? ' % remote.review, end='')
249 # TODO: When we require Python 3, use flush=True w/print above.
250 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500251 if opt.yes:
252 print('<--yes>')
253 answer = True
254 else:
255 answer = sys.stdin.readline().strip().lower()
256 answer = answer in ('y', 'yes', '1', 'true', 't')
Shawn O. Pearcea608fb02009-04-17 12:11:24 -0700257
258 if answer:
Dan Morrill879a9a52010-05-04 16:56:07 -0700259 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
260 answer = _ConfirmManyUploads()
261
262 if answer:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700263 self._UploadAndReport(opt, [branch], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700264 else:
265 _die("upload aborted by user")
266
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700267 def _MultipleBranches(self, opt, pending, people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700268 projects = {}
269 branches = {}
270
271 script = []
272 script.append('# Uncomment the branches to upload:')
273 for project, avail in pending:
274 script.append('#')
LaMont Jonescc879a92021-11-18 22:40:18 +0000275 script.append('# project %s/:' % project.RelPath(local=opt.this_manifest_only))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700276
277 b = {}
278 for branch in avail:
Bryan Jacobs710d4b02013-05-31 15:28:05 -0400279 if branch is None:
280 continue
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700281 name = branch.name
282 date = branch.date
David Pursehouse8a68ff92012-09-24 12:15:13 +0900283 commit_list = branch.commits
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700284
285 if b:
286 script.append('#')
Bryan Jacobs691a7592013-05-31 15:45:28 -0400287 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200288 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700289 name,
David Pursehouse8a68ff92012-09-24 12:15:13 +0900290 len(commit_list),
291 len(commit_list) != 1 and 's' or '',
Christer Fletcher6a1f7372011-04-28 14:13:14 +0200292 date,
Bryan Jacobs691a7592013-05-31 15:45:28 -0400293 destination))
David Pursehouse8a68ff92012-09-24 12:15:13 +0900294 for commit in commit_list:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700295 script.append('# %s' % commit)
296 b[name] = branch
297
LaMont Jonescc879a92021-11-18 22:40:18 +0000298 projects[project.RelPath(local=opt.this_manifest_only)] = project
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700299 branches[project.name] = b
300 script.append('')
301
302 script = Editor.EditString("\n".join(script)).split("\n")
303
304 project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$')
305 branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*')
306
307 project = None
308 todo = []
309
310 for line in script:
311 m = project_re.match(line)
312 if m:
313 name = m.group(1)
314 project = projects.get(name)
315 if not project:
316 _die('project %s not available for upload', name)
317 continue
318
319 m = branch_re.match(line)
320 if m:
321 name = m.group(1)
322 if not project:
323 _die('project for branch %s not in script', name)
324 branch = branches[project.name].get(name)
325 if not branch:
LaMont Jonescc879a92021-11-18 22:40:18 +0000326 _die('branch %s not in %s', name, project.RelPath(local=opt.this_manifest_only))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700327 todo.append(branch)
328 if not todo:
329 _die("nothing uncommented for upload")
Dan Morrill879a9a52010-05-04 16:56:07 -0700330
331 many_commits = False
332 for branch in todo:
333 if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD:
334 many_commits = True
335 break
336 if many_commits:
337 if not _ConfirmManyUploads(multiple_branches=True):
338 _die("upload aborted by user")
339
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700340 self._UploadAndReport(opt, todo, people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700341
bijia093fdb62013-11-28 09:19:22 +0800342 def _AppendAutoList(self, branch, people):
Ben Komalo08a3f682010-07-15 16:03:02 -0700343 """
bijia093fdb62013-11-28 09:19:22 +0800344 Appends the list of reviewers in the git project's config.
Ben Komalo08a3f682010-07-15 16:03:02 -0700345 Appends the list of users in the CC list in the git project's config if a
346 non-empty reviewer list was found.
347 """
Ben Komalo08a3f682010-07-15 16:03:02 -0700348 name = branch.name
349 project = branch.project
bijia093fdb62013-11-28 09:19:22 +0800350
351 key = 'review.%s.autoreviewer' % project.GetBranch(name).remote.review
352 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900353 if raw_list is not None:
bijia093fdb62013-11-28 09:19:22 +0800354 people[0].extend([entry.strip() for entry in raw_list.split(',')])
355
Ben Komalo08a3f682010-07-15 16:03:02 -0700356 key = 'review.%s.autocopy' % project.GetBranch(name).remote.review
357 raw_list = project.config.GetString(key)
David Pursehouse8f78a832020-02-12 11:20:36 +0900358 if raw_list is not None and len(people[0]) > 0:
Ben Komalo08a3f682010-07-15 16:03:02 -0700359 people[1].extend([entry.strip() for entry in raw_list.split(',')])
360
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700361 def _FindGerritChange(self, branch):
362 last_pub = branch.project.WasPublished(branch.name)
363 if last_pub is None:
364 return ""
365
366 refs = branch.GetPublishedRefs()
367 try:
368 # refs/changes/XYZ/N --> XYZ
369 return refs.get(last_pub).split('/')[-2]
David Pursehouse1d947b32012-10-25 12:23:11 +0900370 except (AttributeError, IndexError):
Ficus Kirkpatrickbc7ef672009-05-04 12:45:11 -0700371 return ""
372
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700373 def _UploadAndReport(self, opt, todo, original_people):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700374 have_errors = False
375 for branch in todo:
376 try:
Ben Komalo08a3f682010-07-15 16:03:02 -0700377 people = copy.deepcopy(original_people)
bijia093fdb62013-11-28 09:19:22 +0800378 self._AppendAutoList(branch, people)
Ben Komalo08a3f682010-07-15 16:03:02 -0700379
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500380 # Check if there are local changes that may have been forgotten
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700381 changes = branch.project.UncommitedFiles()
Martin Geisler9fb64ae2022-07-08 10:50:10 +0200382 if opt.ignore_untracked_files:
383 untracked = set(branch.project.UntrackedFiles())
384 changes = [x for x in changes if x not in untracked]
385
Vadim Bendebury14e134d2014-10-05 15:40:30 -0700386 if changes:
David Pursehousec1b86a22012-11-14 11:36:51 +0900387 key = 'review.%s.autoupload' % branch.project.remote.review
388 answer = branch.project.config.GetBoolean(key)
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500389
David Pursehousec1b86a22012-11-14 11:36:51 +0900390 # if they want to auto upload, let's not ask because it could be automated
391 if answer is None:
Mike Frysingerab85fe72019-07-04 17:35:11 -0400392 print()
393 print('Uncommitted changes in %s (did you forget to amend?):'
394 % branch.project.name)
395 print('\n'.join(changes))
396 print('Continue uploading? (y/N) ', end='')
397 # TODO: When we require Python 3, use flush=True w/print above.
398 sys.stdout.flush()
Mike Frysinger02aa8892020-02-19 02:32:52 -0500399 if opt.yes:
400 print('<--yes>')
401 a = 'yes'
402 else:
403 a = sys.stdin.readline().strip().lower()
David Pursehousec1b86a22012-11-14 11:36:51 +0900404 if a not in ('y', 'yes', 't', 'true', 'on'):
405 print("skipping upload", file=sys.stderr)
406 branch.uploaded = False
407 branch.error = 'User aborted'
408 continue
Anthony Newnamcc50bac2010-04-08 10:28:59 -0500409
Anthony Russellod666e932012-06-01 00:48:22 -0400410 # Check if topic branches should be sent to the server during upload
411 if opt.auto_topic is not True:
David Pursehousec1b86a22012-11-14 11:36:51 +0900412 key = 'review.%s.uploadtopic' % branch.project.remote.review
413 opt.auto_topic = branch.project.config.GetBoolean(key)
Anthony Russellod666e932012-06-01 00:48:22 -0400414
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500415 def _ExpandCommaList(value):
416 """Split |value| up into comma delimited entries."""
Mike Frysinger84685ba2020-02-19 02:22:22 -0500417 if not value:
418 return
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500419 for ret in value.split(','):
420 ret = ret.strip()
421 if ret:
422 yield ret
423
424 # Check if hashtags should be included.
Mike Frysinger84685ba2020-02-19 02:22:22 -0500425 key = 'review.%s.uploadhashtags' % branch.project.remote.review
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500426 hashtags = set(_ExpandCommaList(branch.project.config.GetString(key)))
Mike Frysinger84685ba2020-02-19 02:22:22 -0500427 for tag in opt.hashtags:
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500428 hashtags.update(_ExpandCommaList(tag))
Mike Frysinger7ff80af2020-02-19 03:00:26 -0500429 if opt.hashtag_branch:
430 hashtags.add(branch.name)
Mike Frysinger84685ba2020-02-19 02:22:22 -0500431
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500432 # Check if labels should be included.
433 key = 'review.%s.uploadlabels' % branch.project.remote.review
434 labels = set(_ExpandCommaList(branch.project.config.GetString(key)))
435 for label in opt.labels:
436 labels.update(_ExpandCommaList(label))
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500437
Mike Frysingerf725e542020-03-14 17:39:03 -0400438 # Handle e-mail notifications.
439 if opt.notify is False:
440 notify = 'NONE'
441 else:
442 key = 'review.%s.uploadnotify' % branch.project.remote.review
443 notify = branch.project.config.GetString(key)
444
Colin Cross59b31cb2013-10-08 23:10:52 -0700445 destination = opt.dest_branch or branch.project.dest_branch
Conley Owens3bfd7212013-09-30 15:54:38 -0700446
447 # Make sure our local branch is not setup to track a different remote branch
448 merge_branch = self._GetMergeBranch(branch.project)
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700449 if destination:
Sean McAllister682f0b62020-05-18 09:15:51 -0600450 full_dest = destination
451 if not full_dest.startswith(R_HEADS):
452 full_dest = R_HEADS + full_dest
453
Conley Owensfbd3f2a2013-10-15 12:59:00 -0700454 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
455 print('merge branch %s does not match destination branch %s'
456 % (merge_branch, full_dest))
457 print('skipping upload.')
458 print('Please use `--destination %s` if this is intentional'
459 % destination)
460 branch.uploaded = False
461 continue
Conley Owens3bfd7212013-09-30 15:54:38 -0700462
Changcheng Xiao87984c62017-08-02 16:55:03 +0200463 branch.UploadForReview(people,
Mike Frysinger819cc812020-02-19 02:27:22 -0500464 dryrun=opt.dryrun,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200465 auto_topic=opt.auto_topic,
Mike Frysinger84685ba2020-02-19 02:22:22 -0500466 hashtags=hashtags,
Mike Frysingerfc1b18a2020-02-24 15:38:07 -0500467 labels=labels,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200468 private=opt.private,
Mike Frysingerf725e542020-03-14 17:39:03 -0400469 notify=notify,
Changcheng Xiao87984c62017-08-02 16:55:03 +0200470 wip=opt.wip,
William Escandeac76fd32022-08-02 16:05:37 -0700471 ready=opt.ready,
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200472 dest_branch=destination,
Masaya Suzuki305a2d02017-11-13 10:48:34 -0800473 validate_certs=opt.validate_certs,
474 push_options=opt.push_options)
Łukasz Gardońbed59ce2017-08-08 10:18:11 +0200475
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700476 branch.uploaded = True
Sarah Owensa5be53f2012-09-09 15:37:57 -0700477 except UploadError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700478 branch.error = e
479 branch.uploaded = False
480 have_errors = True
481
Sarah Owenscecd1d82012-11-01 22:59:27 -0700482 print(file=sys.stderr)
483 print('----------------------------------------------------------------------', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700484
485 if have_errors:
486 for branch in todo:
487 if not branch.uploaded:
Shawn O. Pearcef00e0ce2009-08-22 18:39:49 -0700488 if len(str(branch.error)) <= 30:
489 fmt = ' (%s)'
490 else:
491 fmt = '\n (%s)'
Sarah Owenscecd1d82012-11-01 22:59:27 -0700492 print(('[FAILED] %-15s %-15s' + fmt) % (
LaMont Jonescc879a92021-11-18 22:40:18 +0000493 branch.project.RelPath(local=opt.this_manifest_only) + '/',
David Pursehouseabdf7502020-02-12 14:58:39 +0900494 branch.name,
495 str(branch.error)),
496 file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700497 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700498
499 for branch in todo:
David Pursehousec1b86a22012-11-14 11:36:51 +0900500 if branch.uploaded:
501 print('[OK ] %-15s %s' % (
LaMont Jonescc879a92021-11-18 22:40:18 +0000502 branch.project.RelPath(local=opt.this_manifest_only) + '/',
David Pursehouseabdf7502020-02-12 14:58:39 +0900503 branch.name),
504 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700505
506 if have_errors:
507 sys.exit(1)
508
Conley Owens3bfd7212013-09-30 15:54:38 -0700509 def _GetMergeBranch(self, project):
510 p = GitCommand(project,
511 ['rev-parse', '--abbrev-ref', 'HEAD'],
David Pursehousee5913ae2020-02-12 13:56:59 +0900512 capture_stdout=True,
513 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700514 p.Wait()
515 local_branch = p.stdout.strip()
516 p = GitCommand(project,
517 ['config', '--get', 'branch.%s.merge' % local_branch],
David Pursehousee5913ae2020-02-12 13:56:59 +0900518 capture_stdout=True,
519 capture_stderr=True)
Conley Owens3bfd7212013-09-30 15:54:38 -0700520 p.Wait()
521 merge_branch = p.stdout.strip()
522 return merge_branch
523
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400524 @staticmethod
525 def _GatherOne(opt, project):
526 """Figure out the upload status for |project|."""
527 if opt.current_branch:
528 cbr = project.CurrentBranch
529 up_branch = project.GetUploadableBranch(cbr)
530 avail = [up_branch] if up_branch else None
531 else:
532 avail = project.GetUploadableBranches(opt.branch)
533 return (project, avail)
534
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700535 def Execute(self, opt, args):
LaMont Jonescc879a92021-11-18 22:40:18 +0000536 projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
Mandeep Singh Bainesd6c93a22011-05-26 10:34:11 -0700537
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400538 def _ProcessResults(_pool, _out, results):
539 pending = []
540 for result in results:
541 project, avail = result
542 if avail is None:
Mike Frysinger3b038ce2021-05-01 00:45:19 -0400543 print('repo: error: %s: Unable to upload branch "%s". '
Mike Frysinger160748f2020-11-10 01:09:51 -0500544 'You might be able to fix the branch by running:\n'
545 ' git branch --set-upstream-to m/%s' %
LaMont Jonescc879a92021-11-18 22:40:18 +0000546 (project.RelPath(local=opt.this_manifest_only), project.CurrentBranch,
547 project.manifest.branch),
Warren Turkal011d4f42013-11-27 16:20:57 -0800548 file=sys.stderr)
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400549 elif avail:
550 pending.append(result)
551 return pending
552
553 pending = self.ExecuteInParallel(
554 opt.jobs,
555 functools.partial(self._GatherOne, opt),
556 projects,
557 callback=_ProcessResults)
Doug Anderson37282b42011-03-04 11:54:18 -0800558
Mike Frysinger163a3be2016-04-04 17:31:32 -0400559 if not pending:
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400560 if opt.branch is None:
Mike Frysinger7a753b82020-02-19 00:14:32 -0500561 print('repo: error: no branches ready for upload', file=sys.stderr)
562 else:
563 print('repo: error: no branches named "%s" ready for upload' %
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400564 (opt.branch,), file=sys.stderr)
Mike Frysinger7a753b82020-02-19 00:14:32 -0500565 return 1
Mike Frysinger163a3be2016-04-04 17:31:32 -0400566
LaMont Jonescc879a92021-11-18 22:40:18 +0000567 manifests = {project.manifest.topdir: project.manifest
568 for (project, available) in pending}
569 ret = 0
570 for manifest in manifests.values():
571 pending_proj_names = [project.name for (project, available) in pending
572 if project.manifest.topdir == manifest.topdir]
573 pending_worktrees = [project.worktree for (project, available) in pending
574 if project.manifest.topdir == manifest.topdir]
575 hook = RepoHook.FromSubcmd(
576 hook_type='pre-upload', manifest=manifest,
577 opt=opt, abort_if_user_denies=True)
578 if not hook.Run(
579 project_list=pending_proj_names,
580 worktree_list=pending_worktrees):
581 ret = 1
582 if ret:
583 return ret
Doug Anderson37282b42011-03-04 11:54:18 -0800584
Mike Frysingerd1f3e142021-05-01 12:02:01 -0400585 reviewers = _SplitEmails(opt.reviewers) if opt.reviewers else []
586 cc = _SplitEmails(opt.cc) if opt.cc else []
David Pursehouse8f62fb72012-11-14 12:09:38 +0900587 people = (reviewers, cc)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700588
Mike Frysinger163a3be2016-04-04 17:31:32 -0400589 if len(pending) == 1 and len(pending[0][1]) == 1:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700590 self._SingleBranch(opt, pending[0][1][0], people)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700591 else:
Shawn O. Pearcea5ece0e2010-07-15 16:52:42 -0700592 self._MultipleBranches(opt, pending, people)