From 9439ce472815db51f67187eeb2c0d6d3ee32f516 Mon Sep 17 00:00:00 2001 From: massimone88 Date: Mon, 27 Apr 2015 12:11:09 +0200 Subject: [PATCH 1/7] implement argparse library for parsing the arguments create constans for action name clean the code --- gitlab | 375 +++++++++++++++++++++++---------------------------------- 1 file changed, 152 insertions(+), 223 deletions(-) diff --git a/gitlab b/gitlab index a626d1884..c1b2ed814 100755 --- a/gitlab +++ b/gitlab @@ -17,6 +17,7 @@ # along with this program. If not, see . from __future__ import print_function, division, absolute_import +import argparse import os import sys @@ -32,15 +33,27 @@ from inspect import getmro, getmembers, isclass import gitlab camel_re = re.compile('(.)([A-Z])') +LIST = 'list' +GET = 'get' +CREATE = 'create' +UPDATE = 'update' +DELETE = 'delete' +PROTECT = 'protect' +UNPROTECT = 'unprotect' +SEARCH = 'search' +OWNED = 'owned' +ALL = 'all' +ACTION = [LIST, GET, CREATE, UPDATE, DELETE] +EXTRA_ACTION = [PROTECT, UNPROTECT, SEARCH, OWNED, ALL] extra_actions = { - gitlab.ProjectBranch: {'protect': {'requiredAttrs': ['id', 'project-id']}, - 'unprotect': {'requiredAttrs': ['id', 'project-id']} - }, - gitlab.Project: {'search': {'requiredAttrs': ['query']}, - 'owned': {'requiredAttrs': []}, - 'all': {'requiredAttrs': []} - }, + gitlab.ProjectBranch: {PROTECT: {'requiredAttrs': ['id', 'project-id']}, + UNPROTECT: {'requiredAttrs': ['id', 'project-id']} + }, + gitlab.Project: {SEARCH: {'requiredAttrs': ['query']}, + OWNED: {'requiredAttrs': []}, + ALL: {'requiredAttrs': []} + }, } @@ -57,85 +70,44 @@ def clsToWhat(cls): return camel_re.sub(r'\1-\2', cls.__name__).lower() -def actionHelpList(cls): - l = [] - for action in 'list', 'get', 'create', 'update', 'delete': - attr = 'can' + action.capitalize() +def populate_sub_parser_by_class(cls, sub_parser): + sub_parser_class = sub_parser.add_subparsers( + dest='action', + title="action", + description='action to do', + help='action to do' + ) + for action_name in ACTION: + attr = 'can' + action_name.capitalize() try: y = cls.__dict__[attr] except: y = gitlab.GitlabObject.__dict__[attr] if not y: continue - - detail = '' - if action == 'list': - detail = " ".join(["--%s=ARG" % x.replace('_', '-') - for x in cls.requiredListAttrs]) - if detail: - detail += " " - detail += "--page=ARG --per-page=ARG" - elif action in ['get', 'delete']: + sub_parser_action = sub_parser_class.add_parser(action_name) + if action_name == LIST: + [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) 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]: - detail = "--id=ARG " - detail += " ".join(["--%s=ARG" % x.replace('_', '-') - for x in cls.requiredGetAttrs]) - elif action == 'create': - detail = " ".join(["--%s=ARG" % x.replace('_', '-') - for x in cls.requiredCreateAttrs]) - if detail: - detail += " " - detail += " ".join(["[--%s=ARG]" % x.replace('_', '-') - for x in cls.optionalCreateAttrs]) - elif action == 'update': - detail = " ".join(["[--%s=ARG]" % x.replace('_', '-') - for x in cls.requiredCreateAttrs]) - if detail: - detail += " " - detail += " ".join(["[--%s=ARG]" % x.replace('_', '-') - for x in cls.optionalCreateAttrs]) - l.append("%s %s" % (action, detail)) + sub_parser_action.add_argument("--id", required=True) + [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredGetAttrs] + elif action_name == CREATE: + [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredCreateAttrs] + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), required=False) for x in + cls.optionalCreateAttrs] + elif action_name == UPDATE: + [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredCreateAttrs] + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), required=False) for x in + cls.optionalCreateAttrs] if cls in extra_actions: - for action in sorted(extra_actions[cls]): - d = extra_actions[cls][action] - detail = " ".join(["--%s=ARG" % arg for arg in d['requiredAttrs']]) - l.append("%s %s" % (action, detail)) - - return (l) - - -def usage(): - print("usage: gitlab [--help|-h] [--fancy|--verbose|-v] [--gitlab=GITLAB] " - "WHAT ACTION [options]") - print("") - print("--gitlab=GITLAB") - print(" Specifies which python-gitlab.cfg configuration section should " - "be used.") - print(" If not defined, the default selection will be used.") - print("") - print("--fancy, --verbose, -v") - print(" More verbose output.") - print("") - print("--help, -h") - print(" Displays this message.") - print("") - print("Available `options` depend on which WHAT/ACTION couple is used.") - print("If `ACTION` is \"help\", available actions and options will be " - "listed for `ACTION`.") - print("") - print("Available `WHAT` values are:") - - classes = [] - for name, o in getmembers(gitlab): - if not isclass(o): - continue - if gitlab.GitlabObject in getmro(o) and o != gitlab.GitlabObject: - classes.append(o) - - classes.sort(key=lambda x: x.__name__) - for cls in classes: - print(" %s" % clsToWhat(cls)) + for action_name in sorted(extra_actions[cls]): + sub_parser_action = sub_parser_class.add_parser(action_name) + d = extra_actions[cls][action_name] + [sub_parser_action.add_argument("--%s" % arg) for arg in d['requiredAttrs']] def do_auth(): @@ -143,11 +115,10 @@ def do_auth(): gl = gitlab.Gitlab(gitlab_url, private_token=gitlab_token, ssl_verify=ssl_verify, timeout=timeout) gl.auth() + return gl except: die("Could not connect to GitLab (%s)" % gitlab_url) - return gl - def get_id(): try: @@ -246,174 +217,132 @@ def do_project_owned(): die("Impossible to list owned projects (%s)" % str(e)) -ssl_verify = True -timeout = 60 -gitlab_id = None -verbose = False - -args = [] -d = {} -keep_looping = False -for idx, arg in enumerate(sys.argv[1:], 1): - if keep_looping: - keep_looping = False - continue - - if arg.startswith('--'): - arg = arg[2:] - - if arg == 'help': - usage() - sys.exit(0) - elif arg in ['verbose', 'fancy']: - verbose = True - continue - +if __name__ == "__main__": + ssl_verify = True + timeout = 60 + parser = argparse.ArgumentParser(description='Useful GitLab Command Line Interface') + parser.add_argument("-v", "--verbosity", "--fancy", help="increase output verbosity", action="store_true") + parser.add_argument("--gitlab", metavar='gitlab', + help="Specifies which python-gitlab.cfg configuration section should be used. " + "If not defined, the default selection will be used.", required=False) + subparsers = parser.add_subparsers( + dest='what', + title="what", + description='GitLab object', + help='GitLab object' + ) + #populate argparse for all Gitlab Object + for cls in gitlab.__dict__.values(): + if gitlab.GitlabObject in getmro(cls): + sub_parser = subparsers.add_parser(clsToWhat(cls)) + populate_sub_parser_by_class(cls, sub_parser) + + arg = parser.parse_args() + d = arg.__dict__ + # read the config + config = ConfigParser() + config.read(['/etc/python-gitlab.cfg', + os.path.expanduser('~/.python-gitlab.cfg')]) + gitlab_id = arg.gitlab + verbose = arg.verbosity + action = arg.action + what = arg.what + + if gitlab_id is None: try: - k, v = arg.split('=', 1) - v.strip() + gitlab_id = config.get('global', 'default') except: - k = arg - try: - v = sys.argv[idx + 1] - except: - die("--%s argument requires a value" % arg) - keep_looping = True - - k = k.strip().replace('-', '_') - - if k == 'gitlab': - gitlab_id = v - else: - d[k] = v - elif arg.startswith('-'): - arg = arg[1:] - - if arg == 'h': - usage() - sys.exit(0) - elif arg == 'v': - verbose = True - else: - die("Unknown argument: -%s" % arg) - else: - args.append(arg) - -# read the config -config = ConfigParser() -config.read(['/etc/python-gitlab.cfg', - os.path.expanduser('~/.python-gitlab.cfg')]) + die("Impossible to get the gitlab id (not specified in config file)") -if gitlab_id is None: try: - gitlab_id = config.get('global', 'default') + gitlab_url = config.get(gitlab_id, 'url') + gitlab_token = config.get(gitlab_id, 'private_token') except: - die("Impossible to get the gitlab id (not specified in config file)") - -try: - gitlab_url = config.get(gitlab_id, 'url') - gitlab_token = config.get(gitlab_id, 'private_token') -except: - die("Impossible to get gitlab informations from configuration (%s)" % - gitlab_id) - -try: - ssl_verify = config.getboolean('global', 'ssl_verify') -except: - pass -try: - ssl_verify = config.getboolean(gitlab_id, 'ssl_verify') -except: - pass - -try: - timeout = config.getint('global', 'timeout') -except: - pass -try: - timeout = config.getint(gitlab_id, 'timeout') -except: - pass + die("Impossible to get gitlab informations from configuration (%s)" % + gitlab_id) -try: - what = args.pop(0) - action = args.pop(0) -except: - die("Missing arguments. Use `gitlab -h` for help.") - -try: - cls = gitlab.__dict__[whatToCls(what)] -except: - die("Unknown object: %s" % what) + try: + ssl_verify = config.getboolean('global', 'ssl_verify') + except: + pass + try: + ssl_verify = config.getboolean(gitlab_id, 'ssl_verify') + except: + pass -if gitlab.GitlabObject not in getmro(cls): - die("Unknown object: %s" % what) + try: + timeout = config.getint('global', 'timeout') + except: + pass + try: + timeout = config.getint(gitlab_id, 'timeout') + except: + pass -if action == "help": - print("%s options:" % what) - for item in actionHelpList(cls): - print(" %s %s" % (what, item)) + cls = None + try: + cls = gitlab.__dict__[whatToCls(what)] + except: + die("Unknown object: %s" % what) - sys.exit(0) + gl = do_auth() -gl = do_auth() + if action == CREATE or action == GET: + o = globals()['do_%s' % action.lower()](cls, d) + o.display(verbose) -if action == "create": - o = do_create(cls, d) - o.display(verbose) + elif action == LIST: + for o in do_list(cls, d): + o.display(verbose) + print("") -elif action == "list": - for o in do_list(cls, d): + elif action == GET: + o = do_get(cls, d) o.display(verbose) - print("") - -elif action == "get": - o = do_get(cls, d) - o.display(verbose) -elif action == "delete": - o = do_delete(cls, d) + elif action == DELETE: + o = do_delete(cls, d) -elif action == "update": - o = do_update(cls, d) + elif action == UPDATE: + o = do_update(cls, d) -elif action == "protect": - if cls != gitlab.ProjectBranch: - die("%s objects can't be protected" % what) + elif action == PROTECT: + if cls != gitlab.ProjectBranch: + die("%s objects can't be protected" % what) - o = do_get(cls, d) - o.protect() + o = do_get(cls, d) + o.protect() -elif action == "unprotect": - if cls != gitlab.ProjectBranch: - die("%s objects can't be protected" % what) + elif action == UNPROTECT: + if cls != gitlab.ProjectBranch: + die("%s objects can't be protected" % what) - o = do_get(cls, d) - o.unprotect() + o = do_get(cls, d) + o.unprotect() -elif action == "search": - if cls != gitlab.Project: - die("%s objects don't support this request" % what) + elif action == SEARCH: + if cls != gitlab.Project: + die("%s objects don't support this request" % what) - for o in do_project_search(d): - o.display(verbose) + for o in do_project_search(d): + o.display(verbose) -elif action == "owned": - if cls != gitlab.Project: - die("%s objects don't support this request" % what) + elif action == OWNED: + if cls != gitlab.Project: + die("%s objects don't support this request" % what) - for o in do_project_owned(): - o.display(verbose) + for o in do_project_owned(): + o.display(verbose) -elif action == "all": - if cls != gitlab.Project: - die("%s objects don't support this request" % what) + elif action == ALL: + if cls != gitlab.Project: + die("%s objects don't support this request" % what) - for o in do_project_all(): - o.display(verbose) + for o in do_project_all(): + o.display(verbose) -else: - die("Unknown action: %s. Use \"gitlab %s help\" to get details." % - (action, what)) + else: + die("Unknown action: %s. Use \"gitlab -h %s\" to get details." % + (action, what)) -sys.exit(0) + sys.exit(0) \ No newline at end of file From 2792091085b8977cd3564aa231bb1c0534b73a15 Mon Sep 17 00:00:00 2001 From: massimone88 Date: Mon, 27 Apr 2015 13:59:26 +0200 Subject: [PATCH 2/7] improvement argument required for each action add try/catch for error of parsing of not gitlabObject --- gitlab | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/gitlab b/gitlab index c1b2ed814..466ee5a57 100755 --- a/gitlab +++ b/gitlab @@ -73,8 +73,8 @@ def clsToWhat(cls): def populate_sub_parser_by_class(cls, sub_parser): sub_parser_class = sub_parser.add_subparsers( dest='action', - title="action", - description='action to do', + title="positional argument", + description='action with %s' % cls.__name__, help='action to do' ) for action_name in ACTION: @@ -87,7 +87,7 @@ def populate_sub_parser_by_class(cls, sub_parser): continue sub_parser_action = sub_parser_class.add_parser(action_name) if action_name == LIST: - [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredListAttrs] + [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]: @@ -95,11 +95,13 @@ def populate_sub_parser_by_class(cls, sub_parser): sub_parser_action.add_argument("--id", required=True) [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredGetAttrs] elif action_name == CREATE: - [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredCreateAttrs] + [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: - [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredCreateAttrs] + [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] @@ -107,7 +109,7 @@ def populate_sub_parser_by_class(cls, sub_parser): for action_name in sorted(extra_actions[cls]): sub_parser_action = sub_parser_class.add_parser(action_name) d = extra_actions[cls][action_name] - [sub_parser_action.add_argument("--%s" % arg) for arg in d['requiredAttrs']] + [sub_parser_action.add_argument("--%s" % arg, required=True) for arg in d['requiredAttrs']] def do_auth(): @@ -228,14 +230,18 @@ if __name__ == "__main__": subparsers = parser.add_subparsers( dest='what', title="what", + title="positional argument", description='GitLab object', help='GitLab object' ) #populate argparse for all Gitlab Object for cls in gitlab.__dict__.values(): - if gitlab.GitlabObject in getmro(cls): - sub_parser = subparsers.add_parser(clsToWhat(cls)) - populate_sub_parser_by_class(cls, sub_parser) + try: + if gitlab.GitlabObject in getmro(cls): + sub_parser = subparsers.add_parser(clsToWhat(cls)) + populate_sub_parser_by_class(cls, sub_parser) + except: + pass arg = parser.parse_args() d = arg.__dict__ From e6c85b57405473784cd2dedd36df1bb906191e8f Mon Sep 17 00:00:00 2001 From: massimone88 Date: Mon, 27 Apr 2015 14:05:48 +0200 Subject: [PATCH 3/7] remove forgotten argument --- gitlab | 1 - 1 file changed, 1 deletion(-) diff --git a/gitlab b/gitlab index 466ee5a57..40a15db03 100755 --- a/gitlab +++ b/gitlab @@ -229,7 +229,6 @@ if __name__ == "__main__": "If not defined, the default selection will be used.", required=False) subparsers = parser.add_subparsers( dest='what', - title="what", title="positional argument", description='GitLab object', help='GitLab object' From bdc6f73ca54cea41022c99cbb7f894f1eb04d545 Mon Sep 17 00:00:00 2001 From: Stefano Mandruzzato Date: Mon, 27 Apr 2015 22:33:11 +0200 Subject: [PATCH 4/7] remove "gitlab" of arguments because conflicts with "gitlab" attribute with GitlabObject class --- gitlab | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitlab b/gitlab index 40a15db03..0638112ae 100755 --- a/gitlab +++ b/gitlab @@ -18,6 +18,7 @@ from __future__ import print_function, division, absolute_import import argparse +import inspect import os import sys @@ -249,6 +250,8 @@ if __name__ == "__main__": config.read(['/etc/python-gitlab.cfg', os.path.expanduser('~/.python-gitlab.cfg')]) gitlab_id = arg.gitlab + #conflicts with "gitlab" attribute with GitlabObject class + d.pop("gitlab") verbose = arg.verbosity action = arg.action what = arg.what From d099b112dbb25c7cc219d8304adfaf4c8eb19eb7 Mon Sep 17 00:00:00 2001 From: Stefano Mandruzzato Date: Mon, 27 Apr 2015 22:49:46 +0200 Subject: [PATCH 5/7] bug fixed on requiredArguments --- gitlab | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/gitlab b/gitlab index 0638112ae..c6887c6ba 100755 --- a/gitlab +++ b/gitlab @@ -44,7 +44,7 @@ UNPROTECT = 'unprotect' SEARCH = 'search' OWNED = 'owned' ALL = 'all' -ACTION = [LIST, GET, CREATE, UPDATE, DELETE] +ACTIONS = [LIST, GET, CREATE, UPDATE, DELETE] EXTRA_ACTION = [PROTECT, UNPROTECT, SEARCH, OWNED, ALL] extra_actions = { @@ -78,7 +78,7 @@ def populate_sub_parser_by_class(cls, sub_parser): description='action with %s' % cls.__name__, help='action to do' ) - for action_name in ACTION: + for action_name in ACTIONS: attr = 'can' + action_name.capitalize() try: y = cls.__dict__[attr] @@ -87,6 +87,7 @@ def populate_sub_parser_by_class(cls, sub_parser): if not y: continue sub_parser_action = sub_parser_class.add_parser(action_name) + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), required=True) for x in cls.requiredUrlAttrs] 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) @@ -94,7 +95,7 @@ def populate_sub_parser_by_class(cls, sub_parser): elif action_name in [GET, DELETE]: if cls not in [gitlab.CurrentUser]: sub_parser_action.add_argument("--id", required=True) - [sub_parser_action.add_argument("--%s" % x.replace('_', '-')) for x in cls.requiredGetAttrs] + [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), required=True) for x in cls.requiredGetAttrs] elif action_name == CREATE: [sub_parser_action.add_argument("--%s" % x.replace('_', '-'), required=True) for x in cls.requiredCreateAttrs] @@ -304,29 +305,15 @@ if __name__ == "__main__": o.display(verbose) print("") - elif action == GET: - o = do_get(cls, d) - o.display(verbose) - - elif action == DELETE: - o = do_delete(cls, d) - - elif action == UPDATE: - o = do_update(cls, d) - - elif action == PROTECT: - if cls != gitlab.ProjectBranch: - die("%s objects can't be protected" % what) - - o = do_get(cls, d) - o.protect() + elif action == DELETE or action == UPDATE: + o = globals()['do_%s' % action.lower()](cls, d) - elif action == UNPROTECT: + elif action == PROTECT or action == UNPROTECT: if cls != gitlab.ProjectBranch: die("%s objects can't be protected" % what) o = do_get(cls, d) - o.unprotect() + getattr(o, action)() elif action == SEARCH: if cls != gitlab.Project: From 23fe3c9a87263b14c9c882bd1060de7232543616 Mon Sep 17 00:00:00 2001 From: Stefano Mandruzzato Date: Fri, 1 May 2015 11:36:09 +0200 Subject: [PATCH 6/7] *clean import package +add folder .idea to gitignore --- .gitignore | 1 + gitlab | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 82a6006e2..c79b96d07 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ dist/ MANIFEST .*.swp *.egg-info +.idea/ \ No newline at end of file diff --git a/gitlab b/gitlab index c6887c6ba..e12e25537 100755 --- a/gitlab +++ b/gitlab @@ -18,21 +18,16 @@ from __future__ import print_function, division, absolute_import import argparse -import inspect - import os import sys import re - +import gitlab +from inspect import getmro try: from ConfigParser import ConfigParser except: from configparser import ConfigParser -from inspect import getmro, getmembers, isclass - -import gitlab - camel_re = re.compile('(.)([A-Z])') LIST = 'list' GET = 'get' From 0d5b988e56794d8c52fa2c0e9d4023a8554d86fb Mon Sep 17 00:00:00 2001 From: massimone88 Date: Tue, 5 May 2015 15:07:58 +0200 Subject: [PATCH 7/7] change changelog, change, add my name on collaborators, change version --- AUTHORS | 1 + ChangeLog | 5 +++++ gitlab.py | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 6553ec6a7..221f4f7de 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,3 +15,4 @@ Mart Sõmermaa Diego Giovane Pasqualin Crestez Dan Leonard Patrick Miller +Stefano Mandruzzato \ No newline at end of file diff --git a/ChangeLog b/ChangeLog index 6ed622f06..d2343bb08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Version 0.8.1 + + * Implemented argparse libray for parsing argument on CLI + * add custom action for InfoCert + Version 0.8 * Better python 2.6 and python 3 support diff --git a/gitlab.py b/gitlab.py index 1ba23d639..ca94aa042 100644 --- a/gitlab.py +++ b/gitlab.py @@ -26,7 +26,7 @@ from itertools import chain __title__ = 'python-gitlab' -__version__ = '0.8' +__version__ = '0.8.1' __author__ = 'Gauvain Pocentek' __email__ = 'gauvain@pocentek.net' __license__ = 'LGPL3'