Skip to content

Commit

Permalink
Refactor the CLI
Browse files Browse the repository at this point in the history
v3 and v4 CLI will be very different, so start moving things in their
own folders.

For now v4 isn't working at all.
  • Loading branch information
Gauvain Pocentek committed Jun 25, 2017
1 parent fd5ac4d commit e3d50b5
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 177 deletions.
105 changes: 105 additions & 0 deletions gitlab/cli.py
@@ -0,0 +1,105 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013-2017 Gauvain Pocentek <gauvain@pocentek.net>
#
# 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 <http://www.gnu.org/licenses/>.

from __future__ import print_function
from __future__ import absolute_import
import argparse
import importlib
import re
import sys

import gitlab.config

camel_re = re.compile('(.)([A-Z])')


def die(msg, e=None):
if e:
msg = "%s (%s)" % (msg, e)
sys.stderr.write(msg + "\n")
sys.exit(1)


def what_to_cls(what):
return "".join([s.capitalize() for s in what.split("-")])


def cls_to_what(cls):
return camel_re.sub(r'\1-\2', cls.__name__).lower()


def _get_base_parser():
parser = argparse.ArgumentParser(
description="GitLab API Command Line Interface")
parser.add_argument("--version", help="Display the version.",
action="store_true")
parser.add_argument("-v", "--verbose", "--fancy",
help="Verbose mode",
action="store_true")
parser.add_argument("-c", "--config-file", action='append',
help=("Configuration file to use. Can be used "
"multiple times."))
parser.add_argument("-g", "--gitlab",
help=("Which configuration section should "
"be used. If not defined, the default selection "
"will be used."),
required=False)

return parser


def _get_parser(cli_module):
parser = _get_base_parser()
return cli_module.extend_parser(parser)


def main():
if "--version" in sys.argv:
print(gitlab.__version__)
exit(0)

parser = _get_base_parser()
(options, args) = parser.parse_known_args(sys.argv)

config = gitlab.config.GitlabConfigParser(options.gitlab,
options.config_file)
cli_module = importlib.import_module('gitlab.v%s.cli' % config.api_version)
parser = _get_parser(cli_module)
args = parser.parse_args(sys.argv[1:])
config_files = args.config_file
gitlab_id = args.gitlab
verbose = args.verbose
action = args.action
what = args.what

args = args.__dict__
# Remove CLI behavior-related args
for item in ('gitlab', 'config_file', 'verbose', 'what', 'action',
'version'):
args.pop(item)
args = {k: v for k, v in args.items() if v is not None}

try:
gl = gitlab.Gitlab.from_config(gitlab_id, config_files)
gl.auth()
except Exception as e:
die(str(e))

cli_module.run(gl, what, action, args, verbose)

sys.exit(0)
37 changes: 22 additions & 15 deletions gitlab/tests/test_cli.py
Expand Up @@ -28,12 +28,13 @@
import unittest2 as unittest

from gitlab import cli
import gitlab.v3.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"))
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):
Expand All @@ -42,32 +43,33 @@ class Class(object):
class TestClass(object):
pass

self.assertEqual("test-class", cli._cls_to_what(TestClass))
self.assertEqual("class", cli._cls_to_what(Class))
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")
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'])
def test_base_parser(self):
parser = cli._get_base_parser()
args = parser.parse_args(['-v', '-g', 'gl_id',
'-c', 'foo.cfg', '-c', 'bar.cfg'])
self.assertTrue(args.verbose)
self.assertEqual(args.gitlab, 'gl_id')
self.assertEqual(args.config_file, ['foo.cfg', 'bar.cfg'])


class TestV3CLI(unittest.TestCase):
def test_parse_args(self):
parser = cli._get_parser(gitlab.v3.cli)
args = parser.parse_args(['project', 'list'])
self.assertEqual(args.what, 'project')
self.assertEqual(args.action, 'list')

def test_parser(self):
parser = cli._build_parser()
parser = cli._get_parser(gitlab.v3.cli)
subparsers = None
for action in parser._actions:
if type(action) == argparse._SubParsersAction:
Expand All @@ -93,3 +95,8 @@ def test_parser(self):
actions = user_subparsers.choices['create']._option_string_actions
self.assertFalse(actions['--twitter'].required)
self.assertTrue(actions['--username'].required)

def test_extra_actions(self):
for cls, data in six.iteritems(gitlab.v3.cli.EXTRA_ACTIONS):
for key in data:
self.assertIsInstance(data[key], dict)

0 comments on commit e3d50b5

Please sign in to comment.