summaryrefslogtreecommitdiff
path: root/gitlab.py
diff options
context:
space:
mode:
Diffstat (limited to 'gitlab.py')
-rw-r--r--gitlab.py221
1 files changed, 189 insertions, 32 deletions
diff --git a/gitlab.py b/gitlab.py
index c1f2813..5b9a592 100644
--- a/gitlab.py
+++ b/gitlab.py
@@ -40,6 +40,10 @@ class GitlabConnectionError(Exception):
pass
+class GitlabListError(Exception):
+ pass
+
+
class GitlabGetError(Exception):
pass
@@ -129,6 +133,19 @@ class Gitlab(object):
self.email = email
self.password = password
+ def rawGet(self, path, with_token=False):
+ url = '%s%s' % (self._url, path)
+ if with_token:
+ url += "?private_token=%s" % self.private_token
+
+ try:
+ r = requests.get(url)
+ except:
+ raise GitlabConnectionError(
+ "Can't connect to GitLab server (%s)" % self._url)
+
+ return r
+
def rawPost(self, path, data):
url = '%s%s' % (self._url, path)
try:
@@ -153,6 +170,14 @@ class Gitlab(object):
return r
def list(self, obj_class, **kwargs):
+ missing = []
+ for k in obj_class.requiredListAttrs:
+ if k not in kwargs:
+ missing.append (k)
+ if missing:
+ raise GitlabListError('Missing attribute(s): %s' % \
+ ", ".join(missing))
+
url = obj_class._url
if kwargs:
url = obj_class._url % kwargs
@@ -177,7 +202,7 @@ class Gitlab(object):
if k in ('page', 'per_page'):
continue
for obj in l:
- obj.__dict__[k] = v
+ obj.__dict__[k] = str(v)
return l
elif r.status_code == 401:
raise GitlabAuthenticationError(r.json()['message'])
@@ -185,6 +210,14 @@ class Gitlab(object):
raise GitlabGetError('%d: %s' % (r.status_code, r.text))
def get(self, obj_class, id=None, **kwargs):
+ missing = []
+ for k in obj_class.requiredGetAttrs:
+ if k not in kwargs:
+ missing.append (k)
+ if missing:
+ raise GitlabListError('Missing attribute(s): %s' % \
+ ", ".join(missing))
+
url = obj_class._url
if kwargs:
url = obj_class._url % kwargs
@@ -209,6 +242,8 @@ class Gitlab(object):
return r.json()
elif r.status_code == 401:
raise GitlabAuthenticationError(r.json()['message'])
+ elif r.status_code == 404:
+ raise GitlabGetError("Object doesn't exist")
else:
raise GitlabGetError('%d: %s' % (r.status_code, r.text))
@@ -227,6 +262,8 @@ class Gitlab(object):
return True
elif r.status_code == 401:
raise GitlabAuthenticationError(r.json()['message'])
+ else:
+ raise GitlabDeleteError(r.json()['message'])
return False
def create(self, obj):
@@ -241,6 +278,9 @@ class Gitlab(object):
url = obj._url % obj.__dict__
url = '%s%s?private_token=%s' % (self._url, url, self.private_token)
+ print url
+ print obj.__dict__
+
try:
# TODO: avoid too much work on the server side by filtering the
# __dict__ keys
@@ -265,7 +305,7 @@ class Gitlab(object):
d = {}
for k, v in obj.__dict__.items():
if type(v) in (int, str, unicode, bool):
- d[k] = v
+ d[k] = str(v)
try:
r = requests.put(url, d)
@@ -365,16 +405,20 @@ class GitlabObject(object):
_returnClass = None
_constructorTypes = None
canGet = True
- canGetList = True
+ canList = True
canCreate = True
canUpdate = True
canDelete = True
+ requiredListAttrs = []
+ requiredGetAttrs = []
requiredCreateAttrs = []
optionalCreateAttrs = []
+ idAttr = 'id'
+ shortPrintAttr = None
@classmethod
def list(cls, gl, **kwargs):
- if not cls.canGetList:
+ if not cls.canList:
raise NotImplementedError
if not cls._url:
@@ -384,10 +428,15 @@ class GitlabObject(object):
def _getListOrObject(self, cls, id, **kwargs):
if id is None:
- if not cls.canGetList:
+ if not cls.canList:
raise GitlabGetError
return cls.list(self.gitlab, **kwargs)
+ elif isinstance(id, dict):
+ if not cls.canCreate:
+ raise GitlabCreateError
+
+ return cls(self.gitlab, id, **kwargs)
else:
if not cls.canGet:
raise GitlabGetError
@@ -455,12 +504,58 @@ class GitlabObject(object):
def __str__(self):
return '%s => %s' % (type(self), str(self.__dict__))
+ def display(self, pretty):
+ if pretty:
+ self.pretty_print()
+ else:
+ self.short_print()
+
+ def short_print(self, depth=0):
+ id = self.__dict__[self.idAttr]
+ print("%s%s: %s" % (" " * depth * 2, self.idAttr, id))
+ if self.shortPrintAttr:
+ print ("%s%s: %s" % (" " * depth * 2,
+ self.shortPrintAttr.replace('_', '-'),
+ self.__dict__[self.shortPrintAttr]))
+
+ @staticmethod
+ def _obj_to_str(obj):
+ if isinstance(obj, dict):
+ s = ", ".join(["%s: %s" % (x, GitlabObject._obj_to_str(y)) for (x, y) in obj.items()])
+ return "{ %s }" % s
+ elif isinstance(obj, list):
+ s = ", ".join([GitlabObject._obj_to_str(x) for x in obj])
+ return "[ %s ]" %s
+ else:
+ return str(obj)
+
+ def pretty_print(self, depth=0):
+ id = self.__dict__[self.idAttr]
+ print("%s%s: %s" % (" " * depth * 2, self.idAttr, id))
+ for k in sorted(self.__dict__.keys()):
+ if k == self.idAttr:
+ continue
+ v = self.__dict__[k]
+ pretty_k = k.replace('_', '-')
+ if isinstance(v, GitlabObject):
+ if depth == 0:
+ print("%s:" % pretty_k)
+ v.pretty_print(1)
+ else:
+ print("%s: %s" % (pretty_k, v.id))
+ else:
+ if isinstance(v, Gitlab):
+ continue
+ v = GitlabObject._obj_to_str(v)
+ print("%s%s: %s" % (" " * depth * 2, pretty_k, v))
+
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']
@@ -469,14 +564,17 @@ class User(GitlabObject):
class CurrentUserKey(GitlabObject):
_url = '/user/keys'
canUpdate = False
+ shortPrintAttr = 'title'
+ requiredCreateAttrs = ['title', 'key']
class CurrentUser(GitlabObject):
_url = '/user'
- canGetList = False
+ canList = False
canCreate = False
canUpdate = False
canDelete = False
+ shortPrintAttr = 'username'
def Key(self, id=None, **kwargs):
if id is None:
@@ -489,6 +587,7 @@ class Group(GitlabObject):
_url = '/groups'
_constructorTypes = {'projects': 'Project'}
requiredCreateAttrs = ['name', 'path']
+ shortPrintAttr = 'name'
def transfer_project(self, id):
url = '/groups/%d/projects/%d?private_token=%s' % \
@@ -501,6 +600,7 @@ class Group(GitlabObject):
class Hook(GitlabObject):
_url = '/hooks'
requiredCreateAttrs = ['url']
+ shortPrintAttr = 'url'
class Issue(GitlabObject):
@@ -511,13 +611,18 @@ class Issue(GitlabObject):
canDelete = False
canUpdate = False
canCreate = False
+ shortPrintAttr = 'title'
class ProjectBranch(GitlabObject):
- _url = '/projects/%(project_id)d/repository/branches'
+ _url = '/projects/%(project_id)s/repository/branches'
+ idAttr = 'name'
canDelete = False
canUpdate = False
canCreate = False
+ requiredGetAttrs = ['project_id']
+ requiredListAttrs = ['project_id']
+ _constructorTypes = {'commit': 'ProjectCommit'}
def protect(self, protect=True):
url = self._url % {'project_id': self.project_id}
@@ -540,30 +645,39 @@ class ProjectBranch(GitlabObject):
class ProjectCommit(GitlabObject):
- _url = '/projects/%(project_id)d/repository/commits'
+ _url = '/projects/%(project_id)s/repository/commits'
canGet = False
canDelete = False
canUpdate = False
canCreate = False
+ requiredListAttrs = ['project_id']
+ shortPrintAttr = 'title'
class ProjectKey(GitlabObject):
- _url = '/projects/%(project_id)d/keys'
+ _url = '/projects/%(project_id)s/keys'
canUpdate = False
- requiredCreateAttrs = ['title', 'key']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'title', 'key']
class ProjectHook(GitlabObject):
- _url = '/projects/%(project_id)d/hooks'
- requiredCreateAttrs = ['url']
+ _url = '/projects/%(project_id)s/hooks'
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'url']
+ shortPrintAttr = 'url'
class ProjectIssueNote(GitlabObject):
- _url = '/projects/%(project_id)d/issues/%(issue_id)d/notes'
+ _url = '/projects/%(project_id)s/issues/%(issue_id)s/notes'
_constructorTypes = {'author': 'User'}
canUpdate = False
canDelete = False
- requiredCreateAttrs = ['body']
+ requiredListAttrs = ['project_id', 'issue_id']
+ requiredGetAttrs = ['project_id', 'issue_id']
+ requiredCreateAttrs = ['project_id', 'body']
class ProjectIssue(GitlabObject):
@@ -571,9 +685,12 @@ class ProjectIssue(GitlabObject):
_constructorTypes = {'author': 'User', 'assignee': 'User',
'milestone': 'ProjectMilestone'}
canDelete = False
- requiredCreateAttrs = ['title']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'title']
optionalCreateAttrs = ['description', 'assignee_id', 'milestone_id',
'labels']
+ shortPrintAttr = 'title'
def Note(self, id=None, **kwargs):
return self._getListOrObject(ProjectIssueNote, id,
@@ -583,41 +700,52 @@ class ProjectIssue(GitlabObject):
class ProjectMember(GitlabObject):
- _url = '/projects/%(project_id)d/members'
+ _url = '/projects/%(project_id)s/members'
_returnClass = User
- requiredCreateAttrs = ['user_id', 'access_level']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'user_id', 'access_level']
+ shortPrintAttr = 'username'
class ProjectNote(GitlabObject):
- _url = '/projects/%(project_id)d/notes'
+ _url = '/projects/%(project_id)s/notes'
_constructorTypes = {'author': 'User'}
canUpdate = False
canDelete = False
- requiredCreateAttrs = ['body']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'body']
class ProjectTag(GitlabObject):
- _url = '/projects/%(project_id)d/repository/tags'
+ _url = '/projects/%(project_id)s/repository/tags'
+ idAttr = 'name'
canGet = False
canDelete = False
canUpdate = False
canCreate = False
+ requiredListAttrs = ['project_id']
+ shortPrintAttr = 'name'
class ProjectMergeRequestNote(GitlabObject):
- _url = '/projects/%(project_id)d/merge_requests/%(merge_request_id)d/notes'
+ _url = '/projects/%(project_id)s/merge_requests/%(merge_request_id)s/notes'
_constructorTypes = {'author': 'User'}
canGet = False
canCreate = False
canUpdate = False
canDelete = False
+ requiredListAttrs = ['project_id', 'merge_request_id']
class ProjectMergeRequest(GitlabObject):
- _url = '/projects/%(project_id)d/merge_request'
+ _url = '/projects/%(project_id)s/merge_request'
_constructorTypes = {'author': 'User', 'assignee': 'User'}
canDelete = False
- requiredCreateAttrs = ['source_branch', 'target_branch', 'title']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'source_branch', 'target_branch', 'title']
optionalCreateAttrs = ['assignee_id']
def Note(self, id=None, **kwargs):
@@ -630,23 +758,41 @@ class ProjectMergeRequest(GitlabObject):
class ProjectMilestone(GitlabObject):
_url = '/projects/%(project_id)s/milestones'
canDelete = False
- requiredCreateAttrs = ['title']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'title']
optionalCreateAttrs = ['description', 'due_date']
+ shortPrintAttr = 'title'
class ProjectSnippetNote(GitlabObject):
- _url = '/projects/%(project_id)d/snippets/%(snippet_id)d/notes'
+ _url = '/projects/%(project_id)s/snippets/%(snippet_id)s/notes'
_constructorTypes = {'author': 'User'}
canUpdate = False
canDelete = False
- requiredCreateAttrs = ['body']
+ requiredListAttrs = ['project_id', 'snippet_id']
+ requiredGetAttrs = ['project_id', 'snippet_id']
+ requiredCreateAttrs = ['project_id', 'snippet_id', 'body']
class ProjectSnippet(GitlabObject):
- _url = '/projects/%(project_id)d/snippets'
+ _url = '/projects/%(project_id)s/snippets'
_constructorTypes = {'author': 'User'}
- requiredCreateAttrs = ['title', 'file_name', 'code']
+ requiredListAttrs = ['project_id']
+ requiredGetAttrs = ['project_id']
+ requiredCreateAttrs = ['project_id', 'title', 'file_name', 'code']
optionalCreateAttrs = ['lifetime']
+ shortPrintAttr = 'title'
+
+ def Content(self):
+ url = "/projects/%(project_id)s/snippets/%(snippet_id)s/raw" % \
+ {'project_id': self.project_id, 'snippet_id': self.id}
+ r = self.gitlab.rawGet(url, True)
+
+ if r.status_code == 200:
+ return r.content
+ else:
+ raise GitlabGetError
def Note(self, id=None, **kwargs):
return self._getListOrObject(ProjectSnippetNote, id,
@@ -664,6 +810,7 @@ class Project(GitlabObject):
optionalCreateAttrs = ['default_branch', 'issues_enabled', 'wall_enabled',
'merge_requests_enabled', 'wiki_enabled',
'namespace_id']
+ shortPrintAttr = 'path'
def Branch(self, id=None, **kwargs):
return self._getListOrObject(ProjectBranch, id,
@@ -722,21 +869,31 @@ class Project(GitlabObject):
class TeamMember(GitlabObject):
- _url = '/user_teams/%(team_id)d/members'
- requiredCreateAttrs = ['user_id', 'access_level']
+ _url = '/user_teams/%(team_id)s/members'
canUpdate = False
+ requiredCreateAttrs = ['team_id', 'user_id', 'access_level']
+ requiredDeleteAttrs = ['team_id']
+ requiredGetAttrs = ['team_id']
+ requiredListAttrs = ['team_id']
+ shortPrintAttr = 'username'
class TeamProject(GitlabObject):
- _url = '/user_teams/%(team_id)d/projects'
+ _url = '/user_teams/%(team_id)s/projects'
_constructorTypes = {'owner': 'User', 'namespace': 'Group'}
- requiredCreateAttrs = ['project_id', 'greatest_access_level']
canUpdate = False
+ requiredCreateAttrs = ['team_id', 'project_id', 'greatest_access_level']
+ requiredDeleteAttrs = ['team_id', 'project_id']
+ requiredGetAttrs = ['team_id']
+ requiredListAttrs = ['team_id']
+ shortPrintAttr = 'name'
class Team(GitlabObject):
_url = '/user_teams'
+ shortPrintAttr = 'name'
requiredCreateAttrs = ['name', 'path']
+ canUpdate = False
def Member(self, id=None, **kwargs):
return self._getListOrObject(TeamMember, id,