From 01ade72edf9d5dec27b5676c7fb05e9a995c775a Mon Sep 17 00:00:00 2001 From: itxaka Date: Thu, 7 Nov 2013 00:36:58 +0100 Subject: [PATCH 01/14] fixed the requirements auto install from setup.py --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4783ffe82..4222b07e2 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -from distutils.core import setup +from setuptools import setup def get_version(): f = open('gitlab.py') @@ -22,6 +22,7 @@ def get_version(): url='https://github.com/gpocentek/python-gitlab', py_modules=['gitlab'], scripts=['gitlab'], + install_requires=['requests'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', From 6705928406667ee010f448e41c14cfa63c263178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=20S=C3=B5mermaa?= Date: Tue, 19 Nov 2013 09:13:38 +0200 Subject: [PATCH 02/14] Fix comments. --- gitlab.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gitlab.py b/gitlab.py index c6dfed2a4..6365d8009 100644 --- a/gitlab.py +++ b/gitlab.py @@ -315,9 +315,9 @@ def Hook(self, id=None, **kwargs): If id is None, returns a list of hooks. - If id is an integer, test the matching hook. + If id is an integer, tests the matching hook. - If id is a dict, create a new object using attributes provided. The + If id is a dict, creates a new object using attributes provided. The object is NOT saved on the server. Use the save() method on the object to write it on the server. """ @@ -328,42 +328,46 @@ def Project(self, id=None, **kwargs): If id is None, returns a list of projects. - If id is an integer, returns the matching project (or raise a + If id is an integer, returns the matching project (or raises a GitlabGetError if not found) - If id is a dict, create a new object using attributes provided. The + If id is a dict, creates a new object using attributes provided. The object is NOT saved on the server. Use the save() method on the object to write it on the server. """ return self._getListOrObject(Project, id, **kwargs) def Group(self, id=None, **kwargs): - """Creates/gets/lists groups(s) known by the GitLab server. + """Creates/gets/lists group(s) known by the GitLab server. - If id is None, returns a list of projects. + If id is None, returns a list of groups. - If id is an integer, returns the matching project (or raise a + If id is an integer, returns the matching group (or raises a GitlabGetError if not found) - If id is a dict, create a new object using attributes provided. The + If id is a dict, creates a new object using attributes provided. The object is NOT saved on the server. Use the save() method on the object to write it on the server. """ return self._getListOrObject(Group, id, **kwargs) def Issue(self, id=None, **kwargs): - """Lists issues(s) known by the GitLab server.""" + """Lists issues(s) known by the GitLab server. + + Does not support creation or getting a single issue unlike other + methods in this class yet. + """ return self._getListOrObject(Issue, id, **kwargs) def User(self, id=None, **kwargs): """Creates/gets/lists users(s) known by the GitLab server. - If id is None, returns a list of projects. + If id is None, returns a list of users. - If id is an integer, returns the matching project (or raise a + If id is an integer, returns the matching user (or raises a GitlabGetError if not found) - If id is a dict, create a new object using attributes provided. The + If id is a dict, creates a new object using attributes provided. The object is NOT saved on the server. Use the save() method on the object to write it on the server. """ @@ -374,7 +378,7 @@ def Team(self, id=None, **kwargs): If id is None, returns a list of teams. - If id is an integer, returns the matching project (or raise a + If id is an integer, returns the matching team (or raises a GitlabGetError if not found) If id is a dict, create a new object using attributes provided. The From 32d422445388766e7cc4913a51bf8890487d4ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=20S=C3=B5mermaa?= Date: Tue, 19 Nov 2013 09:39:31 +0200 Subject: [PATCH 03/14] Add support for project events. --- gitlab.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gitlab.py b/gitlab.py index 6365d8009..ac86bef5c 100644 --- a/gitlab.py +++ b/gitlab.py @@ -683,6 +683,16 @@ class ProjectKey(GitlabObject): requiredCreateAttrs = ['project_id', 'title', 'key'] +class ProjectEvent(GitlabObject): + _url = '/projects/%(project_id)s/events' + canGet = False + canDelete = False + canUpdate = False + canCreate = False + requiredListAttrs = ['project_id'] + shortPrintAttr = 'target_title' + + class ProjectHook(GitlabObject): _url = '/projects/%(project_id)s/hooks' requiredListAttrs = ['project_id'] @@ -844,6 +854,11 @@ def Commit(self, id=None, **kwargs): project_id=self.id, **kwargs) + def Event(self, id=None, **kwargs): + return self._getListOrObject(ProjectEvent, id, + project_id=self.id, + **kwargs) + def Hook(self, id=None, **kwargs): return self._getListOrObject(ProjectHook, id, project_id=self.id, From 909c10e0d155b0fcfcd63129e2f5921a11d9c017 Mon Sep 17 00:00:00 2001 From: Koen Smets Date: Wed, 27 Nov 2013 12:03:48 +0100 Subject: [PATCH 04/14] Add SSH key for user --- gitlab.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gitlab.py b/gitlab.py index c6dfed2a4..368e9097a 100644 --- a/gitlab.py +++ b/gitlab.py @@ -549,6 +549,15 @@ class User(GitlabObject): 'extern_uid', 'provider', 'bio'] +class UserKey(GitlabObject): + _url = '/users/%(user_id)s/keys' + canGet = False + canList = False + canUpdate = False + canDelete = False + requiredCreateAttrs = ['user_id', 'title', 'key'] + + class CurrentUserKey(GitlabObject): _url = '/user/keys' canUpdate = False From 1969abb3bbb61c4cbb8499496be9f48bd74cf558 Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 13:21:12 +0100 Subject: [PATCH 05/14] add a Key() method for User objects --- AUTHORS | 1 + ChangeLog | 4 ++++ gitlab.py | 21 +++++++++++++-------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 635ddd8d0..1ef4b2ba5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,3 +9,4 @@ Contributors Daniel Kimsey Erik Weatherwax Andrew Austin +Koen Smets diff --git a/ChangeLog b/ChangeLog index 9da1715be..ec1229974 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Version 0.5 + + * Add SSH key for user + Version 0.4 * Fix strings encoding (Closes #6) diff --git a/gitlab.py b/gitlab.py index 368e9097a..1bd6aff18 100644 --- a/gitlab.py +++ b/gitlab.py @@ -541,14 +541,6 @@ def json(self): return json.dumps(self.__dict__, cls=jsonEncoder) -class User(GitlabObject): - _url = '/users' - shortPrintAttr = 'username' - requiredCreateAttrs = ['email', 'password', 'username', 'name'] - optionalCreateAttrs = ['skype', 'linkedin', 'twitter', 'projects_limit', - 'extern_uid', 'provider', 'bio'] - - class UserKey(GitlabObject): _url = '/users/%(user_id)s/keys' canGet = False @@ -558,6 +550,19 @@ class UserKey(GitlabObject): requiredCreateAttrs = ['user_id', 'title', 'key'] +class User(GitlabObject): + _url = '/users' + shortPrintAttr = 'username' + requiredCreateAttrs = ['email', 'password', 'username', 'name'] + optionalCreateAttrs = ['skype', 'linkedin', 'twitter', 'projects_limit', + 'extern_uid', 'provider', 'bio'] + + def Key(self, id=None, **kwargs): + return self._getListOrObject(UserKey, id, + user_id=self.id, + **kwargs) + + class CurrentUserKey(GitlabObject): _url = '/user/keys' canUpdate = False From 962e806412293cfd44e3c37240b5fc1817e5b9db Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 13:30:14 +0100 Subject: [PATCH 06/14] update AUTHORS and Changelog --- AUTHORS | 1 + ChangeLog | 2 ++ 2 files changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index 1ef4b2ba5..d6130439c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,3 +10,4 @@ Daniel Kimsey Erik Weatherwax Andrew Austin Koen Smets +Mart Sõmermaa diff --git a/ChangeLog b/ChangeLog index ec1229974..33cafd2fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ Version 0.5 * Add SSH key for user + * Fix comments + * Add support for project events Version 0.4 From 7afd2329e3ff3f8cbe13504627a4d24b123acea5 Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 13:50:34 +0100 Subject: [PATCH 07/14] provide constants for access permissions in groups --- gitlab.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gitlab.py b/gitlab.py index e3af9fced..87728e0b6 100644 --- a/gitlab.py +++ b/gitlab.py @@ -604,6 +604,12 @@ class Group(GitlabObject): requiredCreateAttrs = ['name', 'path'] shortPrintAttr = 'name' + GUEST_ACCESS = 10 + REPORTER_ACCESS = 20 + DEVELOPER_ACCESS = 30 + MASTER_ACCESS = 40 + OWNER_ACCESS = 50 + def Member(self, id=None, **kwargs): return self._getListOrObject(GroupMember, id, group_id=self.id, From 1cc7b176d80e58c1fb5eda2b79a27674b65c0a65 Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 13:51:39 +0100 Subject: [PATCH 08/14] define new optional attributes for user creation --- gitlab.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitlab.py b/gitlab.py index 87728e0b6..7d2df8fef 100644 --- a/gitlab.py +++ b/gitlab.py @@ -559,7 +559,8 @@ class User(GitlabObject): shortPrintAttr = 'username' requiredCreateAttrs = ['email', 'password', 'username', 'name'] optionalCreateAttrs = ['skype', 'linkedin', 'twitter', 'projects_limit', - 'extern_uid', 'provider', 'bio'] + 'extern_uid', 'provider', 'bio', 'admin', + 'can_create_group'] def Key(self, id=None, **kwargs): return self._getListOrObject(UserKey, id, From debe41aee6eb53c11ea0e6870becc116947fe17d Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 14:02:21 +0100 Subject: [PATCH 09/14] Project.archive(): download tarball of the project --- gitlab.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gitlab.py b/gitlab.py index 7d2df8fef..a9447ca57 100644 --- a/gitlab.py +++ b/gitlab.py @@ -943,6 +943,16 @@ def blob(self, sha, filepath): raise GitlabGetError + def archive(self, sha=None): + url = '/projects/%s/repository/archive' % self.id + if sha: + url += '?sha=%s' % sha + r = self.gitlab.rawGet(url) + if r.status_code == 200: + return r.content + + raise GitlabGetError + class TeamMember(GitlabObject): _url = '/user_teams/%(team_id)s/members' From 2b4924e2fb5ddf32f7ed5e4d9dc055e57612f9c2 Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 14:20:58 +0100 Subject: [PATCH 10/14] system hooks can't be updated --- gitlab.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gitlab.py b/gitlab.py index a9447ca57..919e98582 100644 --- a/gitlab.py +++ b/gitlab.py @@ -625,6 +625,7 @@ def transfer_project(self, id): class Hook(GitlabObject): _url = '/hooks' + canUpdate = False requiredCreateAttrs = ['url'] shortPrintAttr = 'url' From bd6b4aca6dea4b533c4ab15ee649be7b9aabd761 Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 14:56:33 +0100 Subject: [PATCH 11/14] support projects listing: search, all, owned --- gitlab | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- gitlab.py | 26 ++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/gitlab b/gitlab index 370cef170..4c8fb198c 100755 --- a/gitlab +++ b/gitlab @@ -33,8 +33,13 @@ camel_re = re.compile('(.)([A-Z])') extra_actions = { gitlab.ProjectBranch: { - 'protect': { 'requiredAttrs': ['id', 'project-id'] }, - 'unprotect': { 'requiredAttrs': ['id', 'project-id'] } + 'protect': {'requiredAttrs': ['id', 'project-id']}, + 'unprotect': {'requiredAttrs': ['id', 'project-id']} + }, + gitlab.Project: { + 'search': {'requiredAttrs': ['query']}, + 'owned': {'requiredAttrs': []}, + 'all': {'requiredAttrs': []} }, } @@ -203,6 +208,24 @@ def do_update(cls, d): return o +def do_project_search(d): + try: + return gl.search_projects(d['query']) + except: + die("Impossible to search projects (%s)" % str(e)) + +def do_project_all(): + try: + return gl.all_projects() + except Exception as e: + die("Impossible to list all projects (%s)" % str(e)) + +def do_project_owned(): + try: + return gl.owned_projects() + except: + die("Impossible to list owned projects (%s)" % str(e)) + ssl_verify = True gitlab_id = None @@ -338,6 +361,27 @@ elif action == "unprotect": o = do_get(cls, d) o.unprotect() +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) + +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) + +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) + else: die("Unknown action: %s. Use \"gitlab %s help\" to get details." % (action, what)) diff --git a/gitlab.py b/gitlab.py index 919e98582..32d7ae552 100644 --- a/gitlab.py +++ b/gitlab.py @@ -337,6 +337,32 @@ def Project(self, id=None, **kwargs): """ return self._getListOrObject(Project, id, **kwargs) + def _list_projects(self, url): + r = self.rawGet(url) + if r.status_code != 200: + raise GitlabListError + + l = [] + for o in r.json(): + l.append(Project(self, o)) + + return l + + def search_projects(self, query): + """Searches projects by name. + + Returns a list of matching projects. + """ + return self._list_projects("/projects/search/" + query) + + def all_projects(self): + """Lists all the projects (need admin rights).""" + return self._list_projects("/projects/all") + + def owned_projects(self): + """Lists owned projects.""" + return self._list_projects("/projects/owned") + def Group(self, id=None, **kwargs): """Creates/gets/lists group(s) known by the GitLab server. From ba39e88e215b6a5ef16c58efb26e33148a7fa19e Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 14:18:40 +0100 Subject: [PATCH 12/14] Project: add methods for create/update/delete files --- gitlab.py | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/gitlab.py b/gitlab.py index a9447ca57..c84482d12 100644 --- a/gitlab.py +++ b/gitlab.py @@ -141,7 +141,7 @@ def rawGet(self, path): raise GitlabConnectionError( "Can't connect to GitLab server (%s)" % self._url) - def rawPost(self, path, data): + def rawPost(self, path, data=None): url = '%s%s' % (self._url, path) try: return requests.post(url, data, @@ -162,6 +162,17 @@ def rawPut(self, path): raise GitlabConnectionError( "Can't connect to GitLab server (%s)" % self._url) + def rawDelete(self, path): + url = '%s%s' % (self._url, path) + + try: + return requests.delete(url, + headers=self.headers, + verify=self.ssl_verify) + except: + raise GitlabConnectionError( + "Can't connect to GitLab server (%s)" % self._url) + def list(self, obj_class, **kwargs): missing = [] for k in obj_class.requiredListAttrs: @@ -880,6 +891,11 @@ def Event(self, id=None, **kwargs): project_id=self.id, **kwargs) + def File(self, id=None, **kwargs): + return self._getListOrObject(ProjectFile, id, + project_id=self.id, + **kwargs) + def Hook(self, id=None, **kwargs): return self._getListOrObject(ProjectHook, id, project_id=self.id, @@ -953,6 +969,30 @@ def archive(self, sha=None): raise GitlabGetError + def create_file(self, path, branch, content, message): + url = "/projects/%s/repository/files" % self.id + url += "?file_path=%s&branch_name=%s&content=%s&commit_message=%s" % \ + (path, branch, content, message) + r = self.gitlab.rawPost(url) + if r.status_code != 201: + raise GitlabCreateError + + def update_file(self, path, branch, content, message): + url = "/projects/%s/repository/files" % self.id + url += "?file_path=%s&branch_name=%s&content=%s&commit_message=%s" % \ + (path, branch, content, message) + r = self.gitlab.rawPut(url) + if r.status_code != 200: + raise GitlabUpdateError + + def delete_file(self, path, branch, message): + url = "/projects/%s/repository/files" % self.id + url += "?file_path=%s&branch_name=%s&commit_message=%s" % \ + (path, branch, message) + r = self.gitlab.rawDelete(url) + if r.status_code != 200: + raise GitlabDeleteError + class TeamMember(GitlabObject): _url = '/user_teams/%(team_id)s/members' From dc2bf5ea5ae827178e1e7a058e39b491ddebc01a Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 15:27:53 +0100 Subject: [PATCH 13/14] support creation of projects for users --- gitlab.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/gitlab.py b/gitlab.py index c78cdb2e4..370c224d5 100644 --- a/gitlab.py +++ b/gitlab.py @@ -348,6 +348,13 @@ def Project(self, id=None, **kwargs): """ return self._getListOrObject(Project, id, **kwargs) + def UserProject(self, id=None, **kwargs): + """Creates a project for a user. + + id must be a dict. + """ + return self._getListOrObject(UserProject, id, **kwargs) + def _list_projects(self, url): r = self.rawGet(url) if r.status_code != 200: @@ -892,6 +899,20 @@ def Note(self, id=None, **kwargs): **kwargs) +class UserProject(GitlabObject): + _url = '/projects/user/%(user_id)s' + _constructorTypes = {'owner': 'User', 'namespace': 'Group'} + canUpdate = False + canDelete = False + canList = False + canGet = False + requiredCreateAttrs = ['name', 'user_id'] + optionalCreateAttrs = ['default_branch', 'issues_enabled', 'wall_enabled', + 'merge_requests_enabled', 'wiki_enabled', + 'snippets_enabled', 'public', 'visibility_level', + 'description'] + + class Project(GitlabObject): _url = '/projects' _constructorTypes = {'owner': 'User', 'namespace': 'Group'} @@ -900,7 +921,8 @@ class Project(GitlabObject): requiredCreateAttrs = ['name'] optionalCreateAttrs = ['default_branch', 'issues_enabled', 'wall_enabled', 'merge_requests_enabled', 'wiki_enabled', - 'namespace_id'] + 'snippets_enabled', 'public', 'visibility_level', + 'namespace_id', 'description'] shortPrintAttr = 'path' def Branch(self, id=None, **kwargs): From 04574f381d3d50afa86ec890681105f8f5a2a31e Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Thu, 26 Dec 2013 15:40:00 +0100 Subject: [PATCH 14/14] version bump --- ChangeLog | 7 +++++++ gitlab.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 33cafd2fb..b9766ea52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,13 @@ Version 0.5 * Add SSH key for user * Fix comments * Add support for project events + * Support creation of projects for users + * Project: add methods for create/update/delete files + * Support projects listing: search, all, owned + * System hooks can't be updated + * Project.archive(): download tarball of the project + * Define new optional attributes for user creation + * Provide constants for access permissions in groups Version 0.4 diff --git a/gitlab.py b/gitlab.py index 370c224d5..f827a5b72 100644 --- a/gitlab.py +++ b/gitlab.py @@ -21,7 +21,7 @@ import sys __title__ = 'python-gitlab' -__version__ = '0.4' +__version__ = '0.5' __author__ = 'Gauvain Pocentek' __email__ = 'gauvain@pocentek.net' __license__ = 'LGPL3'