diff --git a/gitlab/cli.py b/gitlab/cli.py index 4c205581e..fc4c029d0 100644 --- a/gitlab/cli.py +++ b/gitlab/cli.py @@ -63,69 +63,6 @@ def _cls_to_what(cls): return camel_re.sub(r'\1-\2', cls.__name__).lower() -def _populate_sub_parser_by_class(cls, sub_parser): - for action_name in ['list', 'get', 'create', 'update', 'delete']: - attr = 'can' + action_name.capitalize() - if not getattr(cls, attr): - continue - sub_parser_action = sub_parser.add_parser(action_name) - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=True) - for x in cls.requiredUrlAttrs] - sub_parser_action.add_argument("--sudo", required=False) - - if action_name == "list": - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=True) - for x in cls.requiredListAttrs] - sub_parser_action.add_argument("--page", required=False) - sub_parser_action.add_argument("--per-page", required=False) - - elif action_name in ["get", "delete"]: - if cls not in [gitlab.CurrentUser]: - if cls.getRequiresId: - id_attr = cls.idAttr.replace('_', '-') - sub_parser_action.add_argument("--%s" % id_attr, - required=True) - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=True) - for x in cls.requiredGetAttrs if x != cls.idAttr] - - elif action_name == "create": - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=True) - for x in cls.requiredCreateAttrs] - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=False) - for x in cls.optionalCreateAttrs] - - elif action_name == "update": - id_attr = cls.idAttr.replace('_', '-') - sub_parser_action.add_argument("--%s" % id_attr, - required=True) - - attrs = (cls.requiredUpdateAttrs - if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs) - else cls.requiredCreateAttrs) - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=True) - for x in attrs if x != cls.idAttr] - - attrs = (cls.optionalUpdateAttrs - if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs) - else cls.optionalCreateAttrs) - [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), - required=False) - for x in attrs] - - if cls in EXTRA_ACTIONS: - for action_name in sorted(EXTRA_ACTIONS[cls]): - sub_parser_action = sub_parser.add_parser(action_name) - d = EXTRA_ACTIONS[cls][action_name] - [sub_parser_action.add_argument("--%s" % arg, required=True) - for arg in d.get('required', [])] - - def do_auth(gitlab_id, config_files): try: gl = gitlab.Gitlab.from_config(gitlab_id, config_files) @@ -286,11 +223,70 @@ def do_project_milestone_issues(self, cls, gl, what, args): _die("Impossible to get milestone issues (%s)" % str(e)) -def main(): - if "--version" in sys.argv: - print(gitlab.__version__) - exit(0) +def _populate_sub_parser_by_class(cls, sub_parser): + for action_name in ['list', 'get', 'create', 'update', 'delete']: + attr = 'can' + action_name.capitalize() + if not getattr(cls, attr): + continue + sub_parser_action = sub_parser.add_parser(action_name) + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=True) + for x in cls.requiredUrlAttrs] + sub_parser_action.add_argument("--sudo", required=False) + + if action_name == "list": + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=True) + for x in cls.requiredListAttrs] + sub_parser_action.add_argument("--page", required=False) + sub_parser_action.add_argument("--per-page", required=False) + elif action_name in ["get", "delete"]: + if cls not in [gitlab.CurrentUser]: + if cls.getRequiresId: + id_attr = cls.idAttr.replace('_', '-') + sub_parser_action.add_argument("--%s" % id_attr, + required=True) + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=True) + for x in cls.requiredGetAttrs if x != cls.idAttr] + + elif action_name == "create": + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=True) + for x in cls.requiredCreateAttrs] + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=False) + for x in cls.optionalCreateAttrs] + + elif action_name == "update": + id_attr = cls.idAttr.replace('_', '-') + sub_parser_action.add_argument("--%s" % id_attr, + required=True) + + attrs = (cls.requiredUpdateAttrs + if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs) + else cls.requiredCreateAttrs) + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=True) + for x in attrs if x != cls.idAttr] + + attrs = (cls.optionalUpdateAttrs + if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs) + else cls.optionalCreateAttrs) + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), + required=False) + for x in attrs] + + if cls in EXTRA_ACTIONS: + for action_name in sorted(EXTRA_ACTIONS[cls]): + sub_parser_action = sub_parser.add_parser(action_name) + d = EXTRA_ACTIONS[cls][action_name] + [sub_parser_action.add_argument("--%s" % arg, required=True) + for arg in d.get('required', [])] + + +def _build_parser(args=sys.argv[1:]): parser = argparse.ArgumentParser( description="GitLab API Command Line Interface") parser.add_argument("--version", help="Display the version.", @@ -330,7 +326,20 @@ def main(): _populate_sub_parser_by_class(cls, object_subparsers) object_subparsers.required = True - arg = parser.parse_args() + return parser + + +def _parse_args(args=sys.argv[1:]): + parser = _build_parser() + return parser.parse_args(args) + + +def main(): + if "--version" in sys.argv: + print(gitlab.__version__) + exit(0) + + arg = _parse_args() args = arg.__dict__ config_files = arg.config_file diff --git a/gitlab/tests/test_cli.py b/gitlab/tests/test_cli.py new file mode 100644 index 000000000..c32ad5018 --- /dev/null +++ b/gitlab/tests/test_cli.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2016 Gauvain Pocentek +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +from __future__ import print_function +from __future__ import absolute_import + +import argparse + +import six +try: + import unittest +except ImportError: + import unittest2 as unittest + +from gitlab import cli + + +class TestCLI(unittest.TestCase): + def test_what_to_cls(self): + self.assertEqual("Foo", cli._what_to_cls("foo")) + self.assertEqual("FooBar", cli._what_to_cls("foo-bar")) + + def test_cls_to_what(self): + class Class(object): + pass + + class TestClass(object): + pass + + self.assertEqual("test-class", cli._cls_to_what(TestClass)) + self.assertEqual("class", cli._cls_to_what(Class)) + + def test_die(self): + with self.assertRaises(SystemExit) as test: + cli._die("foobar") + + self.assertEqual(test.exception.code, 1) + + def test_extra_actions(self): + for cls, data in six.iteritems(cli.EXTRA_ACTIONS): + for key in data: + self.assertIsInstance(data[key], dict) + + def test_parsing(self): + args = cli._parse_args(['-v', '-g', 'gl_id', + '-c', 'foo.cfg', '-c', 'bar.cfg', + 'project', 'list']) + self.assertTrue(args.verbose) + self.assertEqual(args.gitlab, 'gl_id') + self.assertEqual(args.config_file, ['foo.cfg', 'bar.cfg']) + self.assertEqual(args.what, 'project') + self.assertEqual(args.action, 'list') + + def test_parser(self): + parser = cli._build_parser() + subparsers = None + for action in parser._actions: + if type(action) == argparse._SubParsersAction: + subparsers = action + break + self.assertIsNotNone(subparsers) + self.assertIn('user', subparsers.choices) + + user_subparsers = None + for action in subparsers.choices['user']._actions: + if type(action) == argparse._SubParsersAction: + user_subparsers = action + break + self.assertIsNotNone(user_subparsers) + self.assertIn('list', user_subparsers.choices) + self.assertIn('get', user_subparsers.choices) + self.assertIn('delete', user_subparsers.choices) + self.assertIn('update', user_subparsers.choices) + self.assertIn('create', user_subparsers.choices) + self.assertIn('block', user_subparsers.choices) + self.assertIn('unblock', user_subparsers.choices) + + actions = user_subparsers.choices['create']._option_string_actions + self.assertFalse(actions['--twitter'].required) + self.assertTrue(actions['--username'].required) diff --git a/gitlab/tests/test_gitlabobject.py b/gitlab/tests/test_gitlabobject.py index e001a8c80..aea80ca28 100644 --- a/gitlab/tests/test_gitlabobject.py +++ b/gitlab/tests/test_gitlabobject.py @@ -492,7 +492,3 @@ def test_content(self): def test_blob_fail(self): with HTTMock(self.resp_content_fail): self.assertRaises(GitlabGetError, self.obj.Content) - - -if __name__ == "__main__": - main()