blob: c33f7fab8bb2a1a8d9e1036fa26994342be10f2a [file] [log] [blame]
Josip Sokcevic84434e82021-06-09 22:48:43 +00001#!/usr/bin/env vpython3
dimu833c94c2017-01-18 17:36:15 -08002# Copyright 2017 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
dimu833c94c2017-01-18 17:36:15 -08005"""Simple client for the Gerrit REST API.
6
7Example usage:
Michael Moss5eebf6f2021-07-16 13:18:34 +00008 ./gerrit_client.py [command] [args]
dimu833c94c2017-01-18 17:36:15 -08009"""
10
dimu833c94c2017-01-18 17:36:15 -080011import json
12import logging
13import optparse
14import subcommand
15import sys
Gavin Makcc976552023-08-28 17:01:52 +000016import urllib.parse
dimu833c94c2017-01-18 17:36:15 -080017
dimu833c94c2017-01-18 17:36:15 -080018import fix_encoding
19import gerrit_util
20import setup_color
21
22__version__ = '0.1'
dimu833c94c2017-01-18 17:36:15 -080023
24
25def write_result(result, opt):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000026 if opt.json_file:
27 with open(opt.json_file, 'w') as json_file:
28 json_file.write(json.dumps(result))
dimu833c94c2017-01-18 17:36:15 -080029
30
31@subcommand.usage('[args ...]')
Josip Sokcevicc39ab992020-09-24 20:09:15 +000032def CMDmovechanges(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000033 """Move changes to a different destination branch."""
34 parser.add_option('-p',
35 '--param',
36 dest='params',
37 action='append',
38 help='repeatable query parameter, format: -p key=value')
39 parser.add_option('--destination_branch',
40 dest='destination_branch',
41 help='where to move changes to')
Josip Sokcevicc39ab992020-09-24 20:09:15 +000042
Mike Frysinger124bb8e2023-09-06 05:48:55 +000043 (opt, args) = parser.parse_args(args)
44 assert opt.destination_branch, "--destination_branch not defined"
45 for p in opt.params:
46 assert '=' in p, '--param is key=value, not "%s"' % p
47 host = urllib.parse.urlparse(opt.host).netloc
Josip Sokcevicc39ab992020-09-24 20:09:15 +000048
Mike Frysinger124bb8e2023-09-06 05:48:55 +000049 limit = 100
50 while True:
51 result = gerrit_util.QueryChanges(
52 host,
53 list(tuple(p.split('=', 1)) for p in opt.params),
54 limit=limit,
55 )
56 for change in result:
57 gerrit_util.MoveChange(host, change['id'], opt.destination_branch)
Josip Sokcevicc39ab992020-09-24 20:09:15 +000058
Mike Frysinger124bb8e2023-09-06 05:48:55 +000059 if len(result) < limit:
60 break
61 logging.info("Done")
Josip Sokcevicc39ab992020-09-24 20:09:15 +000062
63
64@subcommand.usage('[args ...]')
dimu833c94c2017-01-18 17:36:15 -080065def CMDbranchinfo(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000066 """Get information on a gerrit branch."""
67 parser.add_option('--branch', dest='branch', help='branch name')
dimu833c94c2017-01-18 17:36:15 -080068
Mike Frysinger124bb8e2023-09-06 05:48:55 +000069 (opt, args) = parser.parse_args(args)
70 host = urllib.parse.urlparse(opt.host).netloc
71 project = urllib.parse.quote_plus(opt.project)
72 branch = urllib.parse.quote_plus(opt.branch)
73 result = gerrit_util.GetGerritBranch(host, project, branch)
74 logging.info(result)
75 write_result(result, opt)
dimu833c94c2017-01-18 17:36:15 -080076
Quinten Yearsleyd9cbe7a2019-09-03 16:49:11 +000077
dimu833c94c2017-01-18 17:36:15 -080078@subcommand.usage('[args ...]')
Michael Moss9c28af42021-10-25 16:59:05 +000079def CMDrawapi(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +000080 """Call an arbitrary Gerrit REST API endpoint."""
81 parser.add_option('--path',
82 dest='path',
83 help='HTTP path of the API endpoint')
84 parser.add_option('--method',
85 dest='method',
86 help='HTTP method for the API (default: GET)')
87 parser.add_option('--body', dest='body', help='API JSON body contents')
88 parser.add_option('--accept_status',
89 dest='accept_status',
90 help='Comma-delimited list of status codes for success.')
Michael Moss9c28af42021-10-25 16:59:05 +000091
Mike Frysinger124bb8e2023-09-06 05:48:55 +000092 (opt, args) = parser.parse_args(args)
93 assert opt.path, "--path not defined"
Michael Moss9c28af42021-10-25 16:59:05 +000094
Mike Frysinger124bb8e2023-09-06 05:48:55 +000095 host = urllib.parse.urlparse(opt.host).netloc
96 kwargs = {}
97 if opt.method:
98 kwargs['reqtype'] = opt.method.upper()
99 if opt.body:
100 kwargs['body'] = json.loads(opt.body)
101 if opt.accept_status:
102 kwargs['accept_statuses'] = [
103 int(x) for x in opt.accept_status.split(',')
104 ]
105 result = gerrit_util.CallGerritApi(host, opt.path, **kwargs)
106 logging.info(result)
107 write_result(result, opt)
Michael Moss9c28af42021-10-25 16:59:05 +0000108
109
110@subcommand.usage('[args ...]')
dimu833c94c2017-01-18 17:36:15 -0800111def CMDbranch(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000112 """Create a branch in a gerrit project."""
113 parser.add_option('--branch', dest='branch', help='branch name')
114 parser.add_option('--commit', dest='commit', help='commit hash')
115 parser.add_option(
116 '--allow-existent-branch',
117 action='store_true',
118 help=('Accept that the branch alread exists as long as the'
119 ' branch head points the given commit'))
dimu833c94c2017-01-18 17:36:15 -0800120
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000121 (opt, args) = parser.parse_args(args)
122 assert opt.project, "--project not defined"
123 assert opt.branch, "--branch not defined"
124 assert opt.commit, "--commit not defined"
dimu833c94c2017-01-18 17:36:15 -0800125
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000126 project = urllib.parse.quote_plus(opt.project)
127 host = urllib.parse.urlparse(opt.host).netloc
128 branch = urllib.parse.quote_plus(opt.branch)
129 result = gerrit_util.GetGerritBranch(host, project, branch)
130 if result:
131 if not opt.allow_existent_branch:
132 raise gerrit_util.GerritError(200, 'Branch already exists')
133 if result.get('revision') != opt.commit:
134 raise gerrit_util.GerritError(
135 200, ('Branch already exists but '
136 'the branch head is not at the given commit'))
137 else:
138 try:
139 result = gerrit_util.CreateGerritBranch(host, project, branch,
140 opt.commit)
141 except gerrit_util.GerritError as e:
142 result = gerrit_util.GetGerritBranch(host, project, branch)
143 if not result:
144 raise e
145 # If reached here, we hit a real conflict error, because the
146 # branch just created is pointing a different commit.
147 if result.get('revision') != opt.commit:
148 raise gerrit_util.GerritError(
149 200, ('Conflict: branch was created but '
150 'the branch head is not at the given commit'))
151 logging.info(result)
152 write_result(result, opt)
dimu833c94c2017-01-18 17:36:15 -0800153
154
Michael Achenbach6fbf12f2017-07-06 10:54:11 +0200155@subcommand.usage('[args ...]')
Michael Mossb6ce2442021-10-20 04:36:24 +0000156def CMDtag(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000157 """Create a tag in a gerrit project."""
158 parser.add_option('--tag', dest='tag', help='tag name')
159 parser.add_option('--commit', dest='commit', help='commit hash')
Michael Mossb6ce2442021-10-20 04:36:24 +0000160
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000161 (opt, args) = parser.parse_args(args)
162 assert opt.project, "--project not defined"
163 assert opt.tag, "--tag not defined"
164 assert opt.commit, "--commit not defined"
Michael Mossb6ce2442021-10-20 04:36:24 +0000165
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000166 project = urllib.parse.quote_plus(opt.project)
167 host = urllib.parse.urlparse(opt.host).netloc
168 tag = urllib.parse.quote_plus(opt.tag)
169 result = gerrit_util.CreateGerritTag(host, project, tag, opt.commit)
170 logging.info(result)
171 write_result(result, opt)
Michael Mossb6ce2442021-10-20 04:36:24 +0000172
173
174@subcommand.usage('[args ...]')
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000175def CMDhead(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000176 """Update which branch the project HEAD points to."""
177 parser.add_option('--branch', dest='branch', help='branch name')
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000178
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000179 (opt, args) = parser.parse_args(args)
180 assert opt.project, "--project not defined"
181 assert opt.branch, "--branch not defined"
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000182
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000183 project = urllib.parse.quote_plus(opt.project)
184 host = urllib.parse.urlparse(opt.host).netloc
185 branch = urllib.parse.quote_plus(opt.branch)
186 result = gerrit_util.UpdateHead(host, project, branch)
187 logging.info(result)
188 write_result(result, opt)
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000189
190
191@subcommand.usage('[args ...]')
192def CMDheadinfo(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000193 """Retrieves the current HEAD of the project."""
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000194
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000195 (opt, args) = parser.parse_args(args)
196 assert opt.project, "--project not defined"
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000197
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000198 project = urllib.parse.quote_plus(opt.project)
199 host = urllib.parse.urlparse(opt.host).netloc
200 result = gerrit_util.GetHead(host, project)
201 logging.info(result)
202 write_result(result, opt)
Josip Sokcevicdf9a8022020-12-08 00:10:19 +0000203
204
205@subcommand.usage('[args ...]')
Michael Achenbach6fbf12f2017-07-06 10:54:11 +0200206def CMDchanges(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000207 """Queries gerrit for matching changes."""
208 parser.add_option('-p',
209 '--param',
210 dest='params',
211 action='append',
212 default=[],
213 help='repeatable query parameter, format: -p key=value')
214 parser.add_option('--query', help='raw gerrit search query string')
215 parser.add_option('-o',
216 '--o-param',
217 dest='o_params',
218 action='append',
219 help='gerrit output parameters, e.g. ALL_REVISIONS')
220 parser.add_option('--limit',
221 dest='limit',
222 type=int,
223 help='maximum number of results to return')
224 parser.add_option('--start',
225 dest='start',
226 type=int,
227 help='how many changes to skip '
228 '(starting with the most recent)')
Michael Achenbach6fbf12f2017-07-06 10:54:11 +0200229
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000230 (opt, args) = parser.parse_args(args)
231 assert opt.params or opt.query, '--param or --query required'
232 for p in opt.params:
233 assert '=' in p, '--param is key=value, not "%s"' % p
Michael Achenbach6fbf12f2017-07-06 10:54:11 +0200234
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000235 result = gerrit_util.QueryChanges(
236 urllib.parse.urlparse(opt.host).netloc,
237 list(tuple(p.split('=', 1)) for p in opt.params),
238 first_param=opt.query,
239 start=opt.start, # Default: None
240 limit=opt.limit, # Default: None
241 o_params=opt.o_params, # Default: None
242 )
243 logging.info('Change query returned %d changes.', len(result))
244 write_result(result, opt)
Michael Achenbach6fbf12f2017-07-06 10:54:11 +0200245
246
LaMont Jones9eed4232021-04-02 16:29:49 +0000247@subcommand.usage('[args ...]')
Marco Georgaklis85557a02021-06-03 15:56:54 +0000248def CMDrelatedchanges(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000249 """Gets related changes for a given change and revision."""
250 parser.add_option('-c', '--change', type=str, help='change id')
251 parser.add_option('-r', '--revision', type=str, help='revision id')
Marco Georgaklis85557a02021-06-03 15:56:54 +0000252
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000253 (opt, args) = parser.parse_args(args)
Marco Georgaklis85557a02021-06-03 15:56:54 +0000254
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000255 result = gerrit_util.GetRelatedChanges(
256 urllib.parse.urlparse(opt.host).netloc,
257 change=opt.change,
258 revision=opt.revision,
259 )
260 logging.info(result)
261 write_result(result, opt)
Marco Georgaklis85557a02021-06-03 15:56:54 +0000262
263
264@subcommand.usage('[args ...]')
LaMont Jones9eed4232021-04-02 16:29:49 +0000265def CMDcreatechange(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000266 """Create a new change in gerrit."""
267 parser.add_option('-s', '--subject', help='subject for change')
268 parser.add_option('-b',
269 '--branch',
270 default='main',
271 help='target branch for change')
272 parser.add_option(
273 '-p',
274 '--param',
275 dest='params',
276 action='append',
277 help='repeatable field value parameter, format: -p key=value')
LaMont Jones9eed4232021-04-02 16:29:49 +0000278
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000279 parser.add_option('--cc',
280 dest='cc_list',
281 action='append',
282 help='CC address to notify, format: --cc foo@example.com')
Xinan Lin91d2a5d2022-02-04 21:18:32 +0000283
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000284 (opt, args) = parser.parse_args(args)
285 for p in opt.params:
286 assert '=' in p, '--param is key=value, not "%s"' % p
LaMont Jones9eed4232021-04-02 16:29:49 +0000287
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000288 params = list(tuple(p.split('=', 1)) for p in opt.params)
Xinan Lin91d2a5d2022-02-04 21:18:32 +0000289
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000290 if opt.cc_list:
291 params.append(('notify_details', {'CC': {'accounts': opt.cc_list}}))
Xinan Lin91d2a5d2022-02-04 21:18:32 +0000292
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000293 result = gerrit_util.CreateChange(
294 urllib.parse.urlparse(opt.host).netloc,
295 opt.project,
296 branch=opt.branch,
297 subject=opt.subject,
298 params=params,
299 )
300 logging.info(result)
301 write_result(result, opt)
LaMont Jones9eed4232021-04-02 16:29:49 +0000302
303
304@subcommand.usage('[args ...]')
305def CMDchangeedit(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000306 """Puts content of a file into a change edit."""
307 parser.add_option('-c', '--change', type=int, help='change number')
308 parser.add_option('--path', help='path for file')
309 parser.add_option('--file', help='file to place at |path|')
LaMont Jones9eed4232021-04-02 16:29:49 +0000310
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000311 (opt, args) = parser.parse_args(args)
LaMont Jones9eed4232021-04-02 16:29:49 +0000312
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000313 with open(opt.file) as f:
314 data = f.read()
315 result = gerrit_util.ChangeEdit(
316 urllib.parse.urlparse(opt.host).netloc, opt.change, opt.path, data)
317 logging.info(result)
318 write_result(result, opt)
LaMont Jones9eed4232021-04-02 16:29:49 +0000319
320
321@subcommand.usage('[args ...]')
322def CMDpublishchangeedit(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000323 """Publish a Gerrit change edit."""
324 parser.add_option('-c', '--change', type=int, help='change number')
325 parser.add_option('--notify', help='whether to notify')
LaMont Jones9eed4232021-04-02 16:29:49 +0000326
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000327 (opt, args) = parser.parse_args(args)
LaMont Jones9eed4232021-04-02 16:29:49 +0000328
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000329 result = gerrit_util.PublishChangeEdit(
330 urllib.parse.urlparse(opt.host).netloc, opt.change, opt.notify)
331 logging.info(result)
332 write_result(result, opt)
LaMont Jones9eed4232021-04-02 16:29:49 +0000333
334
Xinan Lin6ec7cd82021-07-21 00:53:42 +0000335@subcommand.usage('[args ...]')
336def CMDsubmitchange(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000337 """Submit a Gerrit change."""
338 parser.add_option('-c', '--change', type=int, help='change number')
339 (opt, args) = parser.parse_args(args)
340 result = gerrit_util.SubmitChange(
341 urllib.parse.urlparse(opt.host).netloc, opt.change)
342 logging.info(result)
343 write_result(result, opt)
Xinan Lin6ec7cd82021-07-21 00:53:42 +0000344
345
Xinan Linc2fb26a2021-07-27 18:01:55 +0000346@subcommand.usage('[args ...]')
Xinan Lin2b4ec952021-08-20 17:35:29 +0000347def CMDchangesubmittedtogether(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000348 """Get all changes submitted with the given one."""
349 parser.add_option('-c', '--change', type=int, help='change number')
350 (opt, args) = parser.parse_args(args)
351 result = gerrit_util.GetChangesSubmittedTogether(
352 urllib.parse.urlparse(opt.host).netloc, opt.change)
353 logging.info(result)
354 write_result(result, opt)
Xinan Lin2b4ec952021-08-20 17:35:29 +0000355
356
357@subcommand.usage('[args ...]')
Xinan Linc2fb26a2021-07-27 18:01:55 +0000358def CMDgetcommitincludedin(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000359 """Retrieves the branches and tags for a given commit."""
360 parser.add_option('--commit', dest='commit', help='commit hash')
361 (opt, args) = parser.parse_args(args)
362 result = gerrit_util.GetCommitIncludedIn(
363 urllib.parse.urlparse(opt.host).netloc, opt.project, opt.commit)
364 logging.info(result)
365 write_result(result, opt)
Xinan Linc2fb26a2021-07-27 18:01:55 +0000366
367
Xinan Lin0b0738d2021-07-27 19:13:49 +0000368@subcommand.usage('[args ...]')
369def CMDsetbotcommit(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000370 """Sets bot-commit+1 to a bot generated change."""
371 parser.add_option('-c', '--change', type=int, help='change number')
372 (opt, args) = parser.parse_args(args)
373 result = gerrit_util.SetReview(urllib.parse.urlparse(opt.host).netloc,
374 opt.change,
375 labels={'Bot-Commit': 1},
376 ready=True)
377 logging.info(result)
378 write_result(result, opt)
Xinan Lin0b0738d2021-07-27 19:13:49 +0000379
380
Ben Pastene281edf72021-10-06 01:23:24 +0000381@subcommand.usage('[args ...]')
382def CMDsetlabel(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000383 """Sets a label to a specific value on a given change."""
384 parser.add_option('-c', '--change', type=int, help='change number')
385 parser.add_option('-l',
386 '--label',
387 nargs=2,
388 metavar=('label_name', 'label_value'))
389 (opt, args) = parser.parse_args(args)
390 result = gerrit_util.SetReview(urllib.parse.urlparse(opt.host).netloc,
391 opt.change,
392 labels={opt.label[0]: opt.label[1]})
393 logging.info(result)
394 write_result(result, opt)
Ben Pastene281edf72021-10-06 01:23:24 +0000395
396
Sergiy Belozorovfe347232019-02-27 15:07:33 +0000397@subcommand.usage('')
398def CMDabandon(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000399 """Abandons a Gerrit change."""
400 parser.add_option('-c', '--change', type=int, help='change number')
401 parser.add_option('-m',
402 '--message',
403 default='',
404 help='reason for abandoning')
Sergiy Belozorovfe347232019-02-27 15:07:33 +0000405
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000406 (opt, args) = parser.parse_args(args)
407 assert opt.change, "-c not defined"
408 result = gerrit_util.AbandonChange(
409 urllib.parse.urlparse(opt.host).netloc, opt.change, opt.message)
410 logging.info(result)
411 write_result(result, opt)
Sergiy Belozorovfe347232019-02-27 15:07:33 +0000412
413
Michael Moss5eebf6f2021-07-16 13:18:34 +0000414@subcommand.usage('')
Josip Sokcevice1a98942021-04-07 21:35:29 +0000415def CMDmass_abandon(parser, args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000416 """Mass abandon changes
Michael Moss5eebf6f2021-07-16 13:18:34 +0000417
418 Abandons CLs that match search criteria provided by user. Before any change is
419 actually abandoned, user is presented with a list of CLs that will be affected
420 if user confirms. User can skip confirmation by passing --force parameter.
421
422 The script can abandon up to 100 CLs per invocation.
423
424 Examples:
425 gerrit_client.py mass-abandon --host https://HOST -p 'project=repo2'
426 gerrit_client.py mass-abandon --host https://HOST -p 'message=testing'
427 gerrit_client.py mass-abandon --host https://HOST -p 'is=wip' -p 'age=1y'
428 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000429 parser.add_option('-p',
430 '--param',
431 dest='params',
432 action='append',
433 default=[],
434 help='repeatable query parameter, format: -p key=value')
435 parser.add_option('-m',
436 '--message',
437 default='',
438 help='reason for abandoning')
439 parser.add_option('-f',
440 '--force',
441 action='store_true',
442 help='Don\'t prompt for confirmation')
Josip Sokcevice1a98942021-04-07 21:35:29 +0000443
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000444 opt, args = parser.parse_args(args)
Josip Sokcevice1a98942021-04-07 21:35:29 +0000445
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000446 for p in opt.params:
447 assert '=' in p, '--param is key=value, not "%s"' % p
448 search_query = list(tuple(p.split('=', 1)) for p in opt.params)
449 if not any(t for t in search_query if t[0] == 'owner'):
450 # owner should always be present when abandoning changes
451 search_query.append(('owner', 'me'))
452 search_query.append(('status', 'open'))
453 logging.info("Searching for: %s" % search_query)
Josip Sokcevice1a98942021-04-07 21:35:29 +0000454
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000455 host = urllib.parse.urlparse(opt.host).netloc
Josip Sokcevice1a98942021-04-07 21:35:29 +0000456
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000457 result = gerrit_util.QueryChanges(
458 host,
459 search_query,
460 # abandon at most 100 changes as not all Gerrit instances support
461 # unlimited results.
462 limit=100,
463 )
464 if len(result) == 0:
465 logging.warning("Nothing to abandon")
466 return
Josip Sokcevice1a98942021-04-07 21:35:29 +0000467
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000468 logging.warning("%s CLs match search query: " % len(result))
469 for change in result:
470 logging.warning("[ID: %d] %s" % (change['_number'], change['subject']))
Josip Sokcevice1a98942021-04-07 21:35:29 +0000471
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000472 if not opt.force:
473 q = input('Do you want to move forward with abandoning? [y to confirm] '
474 ).strip()
475 if q not in ['y', 'Y']:
476 logging.warning("Aborting...")
477 return
Josip Sokcevice1a98942021-04-07 21:35:29 +0000478
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000479 for change in result:
480 logging.warning("Abandoning: %s" % change['subject'])
481 gerrit_util.AbandonChange(host, change['id'], opt.message)
Josip Sokcevice1a98942021-04-07 21:35:29 +0000482
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000483 logging.warning("Done")
Josip Sokcevice1a98942021-04-07 21:35:29 +0000484
485
dimu833c94c2017-01-18 17:36:15 -0800486class OptionParser(optparse.OptionParser):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000487 """Creates the option parse and add --verbose support."""
488 def __init__(self, *args, **kwargs):
489 optparse.OptionParser.__init__(self,
490 *args,
491 version=__version__,
492 **kwargs)
493 self.add_option('--verbose',
494 action='count',
495 default=0,
496 help='Use 2 times for more debugging info')
497 self.add_option('--host', dest='host', help='Url of host.')
498 self.add_option('--project', dest='project', help='project name')
499 self.add_option('--json_file',
500 dest='json_file',
501 help='output json filepath')
dimu833c94c2017-01-18 17:36:15 -0800502
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000503 def parse_args(self, args=None, values=None):
504 options, args = optparse.OptionParser.parse_args(self, args, values)
505 # Host is always required
506 assert options.host, "--host not defined."
507 levels = [logging.WARNING, logging.INFO, logging.DEBUG]
508 logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)])
509 return options, args
dimu833c94c2017-01-18 17:36:15 -0800510
511
512def main(argv):
Gavin Mak7f5b53f2023-09-07 18:13:01 +0000513 if sys.version_info[0] < 3:
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000514 print('\nYour python version %s is unsupported, please upgrade.\n' %
515 (sys.version.split(' ', 1)[0], ),
516 file=sys.stderr)
517 return 2
518 dispatcher = subcommand.CommandDispatcher(__name__)
519 return dispatcher.execute(OptionParser(), argv)
dimu833c94c2017-01-18 17:36:15 -0800520
521
522if __name__ == '__main__':
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000523 # These affect sys.stdout so do it outside of main() to simplify mocks in
524 # unit testing.
525 fix_encoding.fix_encoding()
526 setup_color.init()
527 try:
528 sys.exit(main(sys.argv[1:]))
529 except KeyboardInterrupt:
530 sys.stderr.write('interrupted\n')
531 sys.exit(1)