summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGauvain Pocentek <gauvain@pocentek.net>2017-08-18 10:25:00 +0200
committerGauvain Pocentek <gauvain@pocentek.net>2017-08-18 10:34:05 +0200
commitabade405af9099a136b68d0eb19027d038dab60b (patch)
tree8f2877a69f5e0134ed7f39c899909d0f79e6325b
parent9783207f4577bd572f09c25707981ed5aa83b116 (diff)
downloadgitlab-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.rst23
-rw-r--r--gitlab/cli.py20
-rw-r--r--gitlab/v4/cli.py59
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)