endpoints.trigger: initial gitlab handler

This commit is contained in:
Jimmy Zelinskie 2015-04-30 17:12:41 -04:00
parent de29a441c8
commit ae83da75ce

View file

@ -6,6 +6,8 @@ import base64
import re
import json
import gitlab
from endpoints.building import PreparedBuild
from github import Github, UnknownObjectException, GithubException
from bitbucket import BitBucket
@ -303,6 +305,7 @@ class BitbucketBuildTrigger(BuildTriggerHandler):
raise TriggerActivationException(msg)
config['hook_id'] = data['id']
self.config = config
return config, {'private_key': private_key}
def deactivate(self):
@ -636,9 +639,14 @@ class GithubBuildTrigger(BuildTriggerHandler):
gh_client = self._get_client()
usr = gh_client.get_user()
try:
repos = usr.get_repos()
except GithubException:
raise RepositoryReadException('Unable to list user repositories')
personal = {
'personal': True,
'repos': [repo.full_name for repo in usr.get_repos()],
'repos': [repo.full_name for repo in repos],
'info': {
'name': usr.login,
'avatar_url': usr.avatar_url,
@ -1075,3 +1083,284 @@ class CustomBuildTrigger(BuildTriggerHandler):
config.pop('credentials', None)
self.config = config
return config
class GitLabBuildTrigger(BuildTriggerHandler):
"""
BuildTrigger for GitLab.
"""
@classmethod
def service_name(cls):
return 'gitlab'
def _get_authorized_client(self):
host = app.config.get('GITLAB_TRIGGER_CONFIG', {}).get('HOSTNAME', '')
auth_token = self.auth_token or 'invalid'
return gitlab.Gitlab(host, oauth_token=auth_token)
def is_active(self):
return 'hook_id' in self.config
def activate(self, standard_webhook_url):
config = self.config
new_build_source = config['build_source']
gl_client = self._get_authorized_client()
# Find the GitLab repository.
repository = gl_client.getproject(new_build_source)
if repository is False:
msg = 'Unable to find GitLab repository for source: %s' % new_build_source
raise TriggerActivationException(msg)
# Add a deploy key to the repository.
public_key, private_key = generate_ssh_keypair()
config['credentials'] = [
{
'name': 'SSH Public Key',
'value': public_key,
},
]
success = gl_client.adddeploykey(repository['id'], '%s Builder' % app.config['REGISTRY_TITLE'],
public_key)
if success is False:
msg = 'Unable to add deploy key to repository: %s' % new_build_source
raise TriggerActivationException(msg)
# Add the webhook to the GitLab repository.
hook = gl_client.addprojecthook(repository['id'], standard_webhook_url, push=True)
if hook is False:
msg = 'Unable to create webhook on repository: %s' % new_build_source
raise TriggerActivationException(msg)
config['hook_id'] = hook['id']
self.config = config
return config, {'private_key': private_key}
def deactivate(self):
config = self.config
gl_client = self._get_authorized_client()
# Find the GitLab repository.
repository = gl_client.getproject(config['build_source'])
if repository is False:
msg = 'Unable to find GitLab repository for source: %s' % config['build_source']
raise TriggerDeactivationException(msg)
# Remove the webhook.
success = gl_client.deleteprojecthook(repository['id'], config['hook_id'])
if success is False:
msg = 'Unable to remove hook: %s' % config['hook_id']
raise TriggerDeactivationException(msg)
config.pop('hook_id', None)
self.config = config
return config
def list_build_sources(self):
gl_client = self._get_authorized_client()
current_user = gl_client.currentuser()
repositories = gl_client.getprojects()
if repositories is False:
raise RepositoryReadException('Unable to list user repositories')
namespaces = {}
for repo in repositories:
owner = repo['namespace']['name']
if not owner in namespaces:
namespaces[owner] = {
'personal': owner == current_user.username,
'repos': [],
'info': {
'name': owner,
}
}
namespaces[owner]['repos'].append(repo['path_with_namespace'])
return namespaces.values()
def list_build_subdirs(self):
config = self.config
gl_client = self._get_authorized_client()
new_build_source = config['build_source']
repository = gl_client.getproject(new_build_source)
if repository is False:
msg = 'Unable to find GitLab repository for source: %s' % new_build_source
raise RepositoryReadException(msg)
repo_branches = gl_client.getbranches(repository['id'])
if repo_branches is False:
msg = 'Unable to find GitLab branches for source: %s' % new_build_source
raise RepositoryReadException(msg)
branches = [branch['name'] for branch in repo_branches]
branches = find_matching_branches(config, branches)
branches = branches or [repository['default_branch'] or 'master']
repo_tree = gl_client.getrepositorytree(repository['id'], ref_name=branches[0])
if repo_tree is False:
msg = 'Unable to find GitLab repository tree for source: %s' % new_build_source
raise RepositoryReadException(msg)
for node in repo_tree:
if node['name'] == 'Dockerfile':
return ['/']
return []
def dockerfile_url(self):
gl_client = self._get_authorized_client()
subdir = self.config.get('subdir', '')
path = subdir + '/Dockerfile' if subdir else 'Dockerfile'
repository = gl_client.getproject(self.config['build_source'])
if repository is False:
return None
branch = repository['default_branch']
return '%s/%s/blob/%s/%s' % (gl_client.host,
repository['path_with_namespace'],
branch,
path)
def load_dockerfile_contents(self):
gl_client = self._get_authorized_client()
subdir = self.config.get('subdir', '')
path = subdir + '/Dockerfile' if subdir else 'Dockerfile'
repository = gl_client.getproject(self.config['build_source'])
if repository is False:
return None
contents = gl_client.getrawfile(repository['id'], repository['default_branch'], path)
if contents is False:
return None
return contents
def list_field_values(self, field_name):
if field_name == 'refs':
branches = self.list_field_values('branch_name')
tags = self.list_field_values('tag_name')
return ([{'kind': 'branch', 'name': b} for b in branches] +
[{'kind': 'tag', 'name': t} for t in tags])
gl_client = self._get_authorized_client()
repo = gl_client.getproject(self.config['build_source'])
if repo is False:
return []
if field_name == 'tag_name':
tags = gl_client.getall(gl_client.getrepositorytags(repo['id']))
if tags is False:
return []
return [tag.name for tag in tags]
if field_name == 'branch_name':
branches = gl_client.getbranches(repo['id'])
if branches is False:
return []
return [branch.name for branch in branches]
return None
def _prepare_build(self, commit, ref, is_manual):
config = self.config
gl_client = self._get_authorized_client()
repo = gl_client.getproject(self.config['build_source'])
if repo is False:
raise TriggerStartException('Could not find repository')
try:
[committer] = gl_client.getusers(search=commit['committer_email'])
except ValueError:
committer = None
try:
[author] = gl_client.getusers(search=commit['author_email'])
except ValueError:
author = None
metadata = {
'commit_sha': commit['id'],
'ref': ref,
'default_branch': repo['default_branch'],
'git_url': repo['ssh_url_to_repo'],
'commit_info': {
'url': '',
'message': commit['message'],
'date': commit['committed_date'],
},
}
if committer is not None:
metadata['commit_info']['committer'] = {
'username': committer['username'],
'avatar_url': committer['avatar_url'],
'url': client.host + '/' + committer['username'],
}
if author is not None:
metadata['commit_info']['author'] = {
'username': author['username'],
'avatar_url': author['avatar_url'],
'url': client.host + '/' + author['username']
}
prepared = PreparedBuild(self.trigger)
prepared.tags_from_ref(ref, repo['default_branch'])
prepared.name_from_sha(commit['id'])
prepared.subdirectory = config['subdir']
prepared.metadata = metadata
prepared.is_manual = is_manual
return prepared
def handle_trigger_request(self, request):
payload = request.get_json()
if not payload:
raise SkipRequestException()
logger.debug('GitLab trigger payload %s', payload)
if not payload.gets('commits'):
raise SkipRequestException()
commit = payload['commits'][0]
commit_message = commit['message']
if should_skip_commit(commit_message):
raise SkipRequestException()
ref = payload['ref']
raise_if_skipped(self.config, ref)
return self._prepare_build(commit, ref, False)
def manual_start(self, run_parameters=None):
run_parameters = run_parameters or {}
gl_client = self._get_authorized_client()
repo = gl_client.getproject(self.config['build_source'])
if repo is False:
raise TriggerStartException('Could not find repository')
branch_name = run_parameters.get('branch_name') or repo['default_branch']
branches = gl_client.getbranches(repo['id'])
if branches is False:
raise TriggerStartException('Could not find branches')
commit = None
for branch in branches:
if branch['name'] is branch_name:
commit = branch['commit']
if commit is None:
raise TriggerStartException('Could not find commit')
ref = 'refs/heads/%s' % branch_name
return self._prepare_build(commit, ref, True)