diff options
author | Ben Hutchings <ben.hutchings@codethink.co.uk> | 2020-06-04 20:31:11 +0000 |
---|---|---|
committer | Ben Hutchings <ben.hutchings@codethink.co.uk> | 2020-06-04 20:31:11 +0000 |
commit | 0b603d5dd7664573f8247a735a200451da65013c (patch) | |
tree | 67edadb5e0eda3d6750515173a96ecf72287c094 | |
parent | 2b170e90b0ade469fd69da0b2dc4338243d84eee (diff) | |
parent | 85476070627f6478d236580fc3286f700e30c4ae (diff) | |
download | lorry-controller-0b603d5dd7664573f8247a735a200451da65013c.tar.gz |
Merge branch 'bwh/update-gitlab' into 'master'
Update GitLab support
See merge request CodethinkLabs/lorry-controller!6
-rw-r--r-- | lorrycontroller/gitlab.py | 85 |
1 files changed, 29 insertions, 56 deletions
diff --git a/lorrycontroller/gitlab.py b/lorrycontroller/gitlab.py index 6938cae..13becfe 100644 --- a/lorrycontroller/gitlab.py +++ b/lorrycontroller/gitlab.py @@ -16,7 +16,7 @@ import re import urllib.parse -import itertools + try: import gitlab except ImportError: @@ -45,79 +45,52 @@ class Gitlab(object): raise MissingGitlabModuleError('gitlab module missing\n' '\tpython-gitlab is required with GitLab as the git server') - def first(self, predicate, iterable): - return next(filter(predicate, iterable)) - - def split_and_unslashify_path(self, path): - group, project = path.split('/', 1) - return group, project.replace('/', '_') - def find_project(self, repo_path): - group, project = self.split_and_unslashify_path(repo_path) - predicate = lambda x: x.namespace.name == group and x.name == project - - return self.first(predicate, self.gl.projects.search(project)) + return self.gl.projects.get(repo_path) def has_project(self, repo_path): try: - return bool(self.find_project(repo_path)) - except StopIteration: + self.find_project(repo_path) + return True + except gitlab.GitlabGetError: return False def create_project(self, repo_path): - # GitLab only supports one level of namespacing. - group_name, project_name = self.split_and_unslashify_path(repo_path) - group = None - try: - group = self.gl.groups.get(group_name) - except gitlab.GitlabGetError as e: - if e.response_code == 404: - group = self.gl.groups.create( - {'name': group_name, 'path': group_name}) + path_comps = repo_path.split('/') + + if len(path_comps) < 2: + raise ValueError('cannot create GitLab project outside a group') + + # Create hierarchy of groups as necessary + parent_group = None + for group_name in path_comps[:-1]: + if parent_group is None: + group_path = group_name else: - raise + group_path = parent_group.full_path + '/' + group_name + try: + group = self.gl.groups.get(group_path) + except gitlab.GitlabGetError as e: + if e.response_code != 404: + raise + data = {'name': group_name, 'path': group_name} + if parent_group is not None: + data['parent_id'] = parent_group.id + group = self.gl.groups.create(data) + parent_group = group project = { - 'name': project_name, + 'name': path_comps[-1], 'public': True, 'merge_requests_enabled': False, 'namespace_id': group.id, - # Set the original path in the description. We will use this to - # work around lack of multi-level namespacing. - 'description': 'original_path: %s' % repo_path } self.gl.projects.create(project) - def try_get_original_path(self, project_description): - match = re.search('original_path:\s(.*)', str(project_description)) - if match: - return match.groups()[0] - - def suitable_path(self, project): - '''Return a path for a downstream Lorry Controller instance to consume. - - Should the path that was lorried have contained more than one level of - namespacing (more than one '/' within the repository path), then for - GitLab to handle this, we replace any '/'s (remaining in the project - name after extracting the group name) with underscores (_). To preserve - the original path, we set the 'original_path' within the project - description. - This method will attempt to return 'original_path' if it was set, - otherwise it will return the 'path_with_namespace', being of the format - 'group_name/project_name', rather than 'group_name/project/name'. - ''' - return (self.try_get_original_path(project.description) or - project.path_with_namespace) - def list_projects(self): - '''List projects on a GitLab instance. - - In attempt to handle GitLab's current lack of multi-level namespacing - (see: https://gitlab.com/gitlab-org/gitlab-ce/issues/2772), return - the 'original_path' stored in a project's description, if it exists. - ''' + '''List projects on a GitLab instance.''' - return [self.suitable_path(x) for x in self.gl.projects.list()] + return [x.path_with_namespace for x in self.gl.projects.list()] def get_project_url(self, protocol, project_path): '''Return the clone url for a GitLab project. |