diff options
author | Gauvain Pocentek <gauvain@pocentek.net> | 2017-08-18 10:25:00 +0200 |
---|---|---|
committer | Gauvain Pocentek <gauvain@pocentek.net> | 2017-08-18 10:34:05 +0200 |
commit | abade405af9099a136b68d0eb19027d038dab60b (patch) | |
tree | 8f2877a69f5e0134ed7f39c899909d0f79e6325b | |
parent | 9783207f4577bd572f09c25707981ed5aa83b116 (diff) | |
download | gitlab-abade405af9099a136b68d0eb19027d038dab60b.tar.gz |
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).
-rw-r--r-- | docs/cli.rst | 23 | ||||
-rw-r--r-- | gitlab/cli.py | 20 | ||||
-rw-r--r-- | gitlab/v4/cli.py | 59 |
3 files changed, 76 insertions, 26 deletions
diff --git a/docs/cli.rst b/docs/cli.rst index 8d0550b..349ee02 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -80,10 +80,11 @@ section. * - ``url`` - URL for the GitLab server * - ``private_token`` - - Your user token. Login/password is not supported. - Refer `the official documentation`__ to learn how to obtain a token. + - Your user token. Login/password is not supported. Refer to `the official + documentation`__ to learn how to obtain a token. * - ``api_version`` - - API version to use (``3`` or ``4``), defaults to ``3`` + - GitLab API version to use (``3`` or ``4``). Defaults to ``3`` for now, + but will switch to ``4`` eventually. * - ``http_username`` - Username for optional HTTP authentication * - ``http_password`` @@ -126,7 +127,8 @@ Use the following optional arguments to change the behavior of ``gitlab``. These options must be defined before the mandatory arguments. ``--verbose``, ``-v`` - Outputs detail about retrieved objects. + Outputs detail about retrieved objects. Available for legacy (default) + output only. ``--config-file``, ``-c`` Path to a configuration file. @@ -134,11 +136,18 @@ These options must be defined before the mandatory arguments. ``--gitlab``, ``-g`` ID of a GitLab server defined in the configuration file. +``--output``, ``-o`` + Output format. Defaults to a custom format. Can also be ``yaml`` or ``json``. + +``--fields``, ``-f`` + Comma-separated list of fields to display (``yaml`` and ``json`` formats + only). If not used, all the object fields are displayed. + Example: .. code-block:: console - $ gitlab -v -g elsewhere -c /tmp/gl.cfg project list + $ gitlab -o yaml -f id,permissions -g elsewhere -c /tmp/gl.cfg project list Examples @@ -168,12 +177,11 @@ Get a specific project (id 2): $ gitlab project get --id 2 -Get a specific user by id or by username: +Get a specific user by id: .. code-block:: console $ gitlab user get --id 3 - $ gitlab user get-by-username --query jdoe Get a list of snippets for this project: @@ -200,7 +208,6 @@ Create a snippet: $ gitlab project-snippet create --project-id 2 Impossible to create object (Missing attribute(s): title, file-name, code) - $ # oops, let's add the attributes: $ gitlab project-snippet create --project-id 2 --title "the title" \ --file-name "the name" --code "the code" diff --git a/gitlab/cli.py b/gitlab/cli.py index d803eb5..f6b357b 100644 --- a/gitlab/cli.py +++ b/gitlab/cli.py @@ -51,7 +51,6 @@ def register_custom_action(cls_name, mandatory=tuple(), optional=tuple()): custom_actions[final_name] = {} action = f.__name__ - custom_actions[final_name][action] = (mandatory, optional, in_obj) return wrapped_f @@ -79,7 +78,7 @@ def _get_base_parser(): parser.add_argument("--version", help="Display the version.", action="store_true") parser.add_argument("-v", "--verbose", "--fancy", - help="Verbose mode", + help="Verbose mode (legacy format only)", action="store_true") parser.add_argument("-d", "--debug", help="Debug mode (display HTTP requests", @@ -92,6 +91,15 @@ def _get_base_parser(): "be used. If not defined, the default selection " "will be used."), required=False) + parser.add_argument("-o", "--output", + help=("Output format (v4 only): json|legacy|yaml"), + required=False, + choices=['json', 'legacy', 'yaml'], + default="legacy") + parser.add_argument("-f", "--fields", + help=("Fields to display in the output (comma " + "separated). Not used with legacy output"), + required=False) return parser @@ -117,6 +125,10 @@ def main(): config_files = args.config_file gitlab_id = args.gitlab verbose = args.verbose + output = args.output + fields = [] + if args.fields: + fields = [x.strip() for x in args.fields.split(',')] debug = args.debug action = args.action what = args.what @@ -124,7 +136,7 @@ def main(): args = args.__dict__ # Remove CLI behavior-related args for item in ('gitlab', 'config_file', 'verbose', 'debug', 'what', 'action', - 'version'): + 'version', 'output'): args.pop(item) args = {k: v for k, v in args.items() if v is not None} @@ -137,6 +149,6 @@ def main(): if debug: gl.enable_debug() - cli_module.run(gl, what, action, args, verbose) + cli_module.run(gl, what, action, args, verbose, output, fields) sys.exit(0) diff --git a/gitlab/v4/cli.py b/gitlab/v4/cli.py index 821a27d..ca5c6b1 100644 --- a/gitlab/v4/cli.py +++ b/gitlab/v4/cli.py @@ -245,30 +245,47 @@ def extend_parser(parser): return parser +class JSONPrinter(object): + def display(self, d, **kwargs): + import json # noqa + + print(json.dumps(d)) + + +class YAMLPrinter(object): + def display(self, d, **kwargs): + import yaml # noqa + + print(yaml.safe_dump(d, default_flow_style=False)) + + class LegacyPrinter(object): - def display(self, obj, verbose=False, padding=0): - def display_dict(d): + def display(self, d, **kwargs): + verbose = kwargs.get('verbose', False) + padding = kwargs.get('padding', 0) + obj = kwargs.get('obj') + + def display_dict(d, padding): for k in sorted(d.keys()): v = d[k] if isinstance(v, dict): print('%s%s:' % (' ' * padding, k)) new_padding = padding + 2 - self.display(v, True, new_padding) + self.display(v, verbose=True, padding=new_padding, obj=v) continue print('%s%s: %s' % (' ' * padding, k, v)) if verbose: if isinstance(obj, dict): - display_dict(obj) + display_dict(obj, padding) return # not a dict, we assume it's a RESTObject - id = getattr(obj, obj._id_attr) + id = getattr(obj, obj._id_attr, None) print('%s: %s' % (obj._id_attr, id)) attrs = obj.attributes attrs.pop(obj._id_attr) - display_dict(attrs) - print('') + display_dict(attrs, padding) else: id = getattr(obj, obj._id_attr) @@ -278,19 +295,33 @@ class LegacyPrinter(object): print('%s: %s' % (obj._short_print_attr, value)) -def run(gl, what, action, args, verbose): +PRINTERS = { + 'json': JSONPrinter, + 'legacy': LegacyPrinter, + 'yaml': YAMLPrinter, +} + + +def run(gl, what, action, args, verbose, output, fields): g_cli = GitlabCLI(gl, what, action, args) ret_val = g_cli() - printer = LegacyPrinter() + printer = PRINTERS[output]() + + def get_dict(obj): + if fields: + return {k: v for k, v in obj.attributes.items() + if k in fields} + return obj.attributes if isinstance(ret_val, list): - for o in ret_val: - if isinstance(o, gitlab.base.RESTObject): - printer.display(o, verbose) + for obj in ret_val: + if isinstance(obj, gitlab.base.RESTObject): + printer.display(get_dict(obj), verbose=verbose, obj=obj) else: - print(o) + print(obj) + print('') elif isinstance(ret_val, gitlab.base.RESTObject): - printer.display(ret_val, verbose) + printer.display(get_dict(ret_val), verbose=verbose, obj=ret_val) elif isinstance(ret_val, six.string_types): print(ret_val) |