diff options
Diffstat (limited to 'gitlab.py')
| -rw-r--r-- | gitlab.py | 221 |
1 files changed, 189 insertions, 32 deletions
@@ -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, |
