8000 CLI: yaml and json outputs for v4 · allamand/python-gitlab@abade40 · GitHub
[go: up one dir, main page]

Skip to content

Commit abade40

Browse files
author
Gauvain Pocentek
committed
CLI: yaml and json outputs for v4
Verbose mode only works with the legacy output. Also add support for filtering the output by defining the list of fields that need to be displayed (yaml and json only).
1 parent 9783207 commit abade40

File tree

3 files changed

+76
-26
lines changed

3 files changed

+76
-26
lines changed

docs/cli.rst

Lines changed: 15 additions & 8 deletions
150
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ section.
8080
* - ``url``
8181
- URL for the GitLab server
8282
* - ``private_token``
83-
- Your user token. Login/password is not supported.
84-
Refer `the official documentation`__ to learn how to obtain a token.
83+
- Your user token. Login/password is not supported. Refer to `the official
84+
documentation`__ to learn how to obtain a token.
8585
* - ``api_version``
86-
- API version to use (``3`` or ``4``), defaults to ``3``
86+
- GitLab API version to use (``3`` or ``4``). Defaults to ``3`` for now,
87+
but will switch to ``4`` eventually.
8788
* - ``http_username``
8889
- Username for optional HTTP authentication
8990
* - ``http_password``
@@ -126,19 +127,27 @@ Use the following optional arguments to change the behavior of ``gitlab``.
126127
These options must be defined before the mandatory arguments.
127128

128129
``--verbose``, ``-v``
129-
Outputs detail about retrieved objects.
130+
Outputs detail about retrieved objects. Available for legacy (default)
131+
output only.
130132

131133
``--config-file``, ``-c``
132134
Path to a configuration file.
133135

134136
``--gitlab``, ``-g``
135137
ID of a GitLab server defined in the configuration file.
136138

139+
``--output``, ``-o``
140+
Output format. Defaults to a custom format. Can also be ``yaml`` or ``json``.
141+
142+
``--fields``, ``-f``
143+
Comma-separated list of fields to display (``yaml`` and ``json`` formats
144+
only). If not used, all the object fields are displayed.
145+
137146
Example:
138147

139148
.. code-block:: console
140149
141-
$ gitlab -v -g elsewhere -c /tmp/gl.cfg project list
+
$ gitlab -o yaml -f id,permissions -g elsewhere -c /tmp/gl.cfg project list
142151
143152
144153
Examples
@@ -168,12 +177,11 @@ Get a specific project (id 2):
168177
169178
$ gitlab project get --id 2
170179
171-
Get a specific user by id or by username:
180+
Get a specific user by id:
172181

173182
.. code-block:: console
174183
175184
$ gitlab user get --id 3
176-
$ gitlab user get-by-username --query jdoe
177185
178186
Get a list of snippets for this project:
179187

@@ -200,7 +208,6 @@ Create a snippet:
200208
201209
$ gitlab project-snippet create --project-id 2
202210
Impossible to create object (Missing attribute(s): title, file-name, code)
203-
204211
$ # oops, let's add the attributes:
205212
$ gitlab project-snippet create --project-id 2 --title "the title" \
206213
--file-name "the name" --code "the code"

gitlab/cli.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ def wrapped_f(*args, **kwargs):
5151
custom_actions[final_name] = {}
5252

5353
action = f.__name__
54-
5554
custom_actions[final_name][action] = (mandatory, optional, in_obj)
5655

5756
return wrapped_f
@@ -79,7 +78,7 @@ def _get_base_parser():
7978
parser.add_argument("--version", help="Display the version.",
8079
action="store_true")
8180
parser.add_argument("-v", "--verbose", "--fancy",
82-
help="Verbose mode",
81+
help="Verbose mode (legacy format only)",
8382
action="store_true")
8483
parser.add_argument("-d", "--debug",
8584
help="Debug mode (display HTTP requests",
@@ -92,6 +91,15 @@ def _get_base_parser():
9291
"be used. If not defined, the default selection "
9392
"will be used."),
9493
required=False)
94+
parser.add_argument("-o", "--output",
95+
help=("Output format (v4 only): json|legacy|yaml"),
96+
required=False,
97+
choices=['json', 'legacy', 'yaml'],
98+
default="legacy")
99+
parser.add_argument("-f", "--fields",
100+
help=("Fields to display in the output (comma "
101+
"separated). Not used with legacy output"),
102+
required=False)
95103

96104
return parser
97105

@@ -117,14 +125,18 @@ def main():
117125
config_files = args.config_file
118126
gitlab_id = args.gitlab
119127
verbose = args.verbose
128+
output = args.output
129+
fields = []
130+
if args.fields:
131+
fields = [x.strip() for x in args.fields.split(',')]
120132
debug = args.debug
121133
action = args.action
122134
what = args.what
123135

124136
args = args.__dict__
125137
# Remove CLI behavior-related args
126138
for item in ('gitlab', 'config_file', 'verbose', 'debug', 'what', 'action',
127-
'version'):
139+
'version', 'output'):
128140
args.pop(item)
129141
args = {k: v for k, v in args.items() if v is not None}
130142

@@ -137,6 +149,6 @@ def main():
137149
if debug:
138150
gl.enable_debug()
139151

140-
cli_module.run(gl, what, action, args, verbose)
152+
cli_module.run(gl, what, action, args, verbose, output, fields)
141153

142154
sys.exit(0)

gitlab/v4/cli.py

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -245,30 +245,47 @@ def extend_parser(parser):
245245
return parser
246246

247247

248+
class JSONPrinter(object):
249+
def display(self, d, **kwargs):
250+
import json # noqa
251+
252+
print(json.dumps(d))
253+
254+
255+
class YAMLPrinter(object):
256+
def display(self, d, **kwargs):
257+
import yaml # noqa
258+
259+
print(yaml.safe_dump(d, default_flow_style=False))
260+
261+
248262
class LegacyPrinter(object):
249-
def display(self, obj, verbose=False, padding=0):
250-
def display_dict(d):
263+
def display(self, d, **kwargs):
264+
verbose = kwargs.get('verbose', False)
265+
padding = kwargs.get('padding', 0)
266+
obj = kwargs.get('obj')
267+
268+
def display_dict(d, padding):
251269
for k in sorted(d.keys()):
252270
v = d[k]
253271
if isinstance(v, dict):
254272
print('%s%s:' % (' ' * padding, k))
255273
new_padding = padding + 2
256-
self.display(v, True, new_padding)
274+
self.display(v, verbose=True, padding=new_padding, obj=v)
257275
continue
258276
print('%s%s: %s' % (' ' * padding, k, v))
259277

260278
if verbose:
261279
if isinstance(obj, dict):
262-
display_dict(obj)
280+
display_dict(obj, padding)
263281
return
264282

265283
# not a dict, we assume it's a RESTObject
266-
id = getattr(obj, obj._id_attr)
284+
id = getattr(obj, obj._id_attr, None)
267285
print('%s: %s' % (obj._id_attr, id))
268286
attrs = obj.attributes
269287
attrs.pop(obj._id_attr)
270-
display_dict(attrs)
271-
print('')
288+
display_dict(attrs, padding)
272289

273290
else:
274291
id = getattr(obj, obj._id_attr)
@@ -278,19 +295,33 @@ def display_dict(d):
278295
print('%s: %s' % (obj._short_print_attr, value))
279296

280297

281-
def run(gl, what, action, args, verbose):
298+
PRINTERS = {
299+
'json': JSONPrinter,
300+
'legacy': LegacyPrinter,
301+
'yaml': YAMLPrinter,
302+
}
303+
304+
305+
def run(gl, what, action, args, verbose, output, fields):
282306
g_cli = GitlabCLI(gl, what, action, args)
283307
ret_val = g_cli()
284308

285-
printer = LegacyPrinter()
309+
printer = PRINTERS[output]()
310+
311+
def get_dict(obj):
312+
if fields:
313+
return {k: v for k, v in obj.attributes.items()
314+
if k in fields}
315+
return obj.attributes
286316

287317
if isinstance(ret_val, list):
288-
for o in ret_val:
289-
if isinstance(o, gitlab.base.RESTObject):
290-
printer.display(o, verbose)
318+
for obj in ret_val:
319+
if isinstance(obj, gitlab.base.RESTObject):
320+
printer.display(get_dict(obj), verbose=verbose, obj=obj)
291321
else:
292-
print(o)
322+
print(obj)
323+
print('')
293324
elif isinstance(ret_val, gitlab.base.RESTObject):
294-
printer.display(ret_val, verbose)
325+
printer.display(get_dict(ret_val), verbose=verbose, obj=ret_val)
295326
elif isinstance(ret_val, six.string_types):
296327
print(ret_val)

0 commit comments

Comments
 (0)
0