180 lines
4.5 KiB
Python
180 lines
4.5 KiB
Python
import logging
|
|
import io
|
|
|
|
from github import Github, UnknownObjectException, GithubException
|
|
from tempfile import SpooledTemporaryFile
|
|
|
|
from app import app
|
|
|
|
|
|
user_files = app.config['USERFILES']
|
|
client = app.config['HTTPCLIENT']
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
ZIPBALL = 'application/zip'
|
|
CHUNK_SIZE = 512 * 1024
|
|
|
|
|
|
class BuildArchiveException(Exception):
|
|
pass
|
|
|
|
class InvalidServiceException(Exception):
|
|
pass
|
|
|
|
class TriggerActivationException(Exception):
|
|
pass
|
|
|
|
class ValidationRequestException(Exception):
|
|
pass
|
|
|
|
|
|
class BuildTrigger(object):
|
|
def __init__(self):
|
|
pass
|
|
|
|
def list_build_sources(self, auth_token):
|
|
"""
|
|
Take the auth information for the specific trigger type and load the
|
|
list of build sources(repositories).
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def handle_trigger_request(self, request, auth_token, config):
|
|
"""
|
|
Transform the incoming request data into a set of actions.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def is_active(self, config):
|
|
"""
|
|
Returns True if the current build trigger is active. Inactive means further
|
|
setup is needed.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
|
|
"""
|
|
Activates the trigger for the service, with the given new configuration.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def service_name(cls):
|
|
"""
|
|
Particular service implemented by subclasses.
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def get_trigger_for_service(cls, service):
|
|
for subc in cls.__subclasses__():
|
|
if subc.service_name() == service:
|
|
return subc()
|
|
|
|
raise InvalidServiceException('Unable to find service: %s' % service)
|
|
|
|
|
|
def raise_unsupported():
|
|
raise io.UnsupportedOperation
|
|
|
|
|
|
class GithubBuildTrigger(BuildTrigger):
|
|
@staticmethod
|
|
def _get_client(auth_token):
|
|
return Github(auth_token, client_id=app.config['GITHUB_CLIENT_ID'],
|
|
client_secret=app.config['GITHUB_CLIENT_SECRET'])
|
|
|
|
@classmethod
|
|
def service_name(cls):
|
|
return 'github'
|
|
|
|
def is_active(self, config):
|
|
return 'build_source' in config and len(config['build_source']) > 0
|
|
|
|
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
|
|
new_build_source = config['build_source']
|
|
gh_client = self._get_client(auth_token)
|
|
|
|
try:
|
|
to_add_webhook = gh_client.get_repo(new_build_source)
|
|
except UnknownObjectException:
|
|
msg = 'Unable to find GitHub repository for source: %s'
|
|
raise TriggerActivationException(msg % new_build_source)
|
|
|
|
webhook_config = {
|
|
'url': standard_webhook_url,
|
|
'content_type': 'json',
|
|
}
|
|
|
|
try:
|
|
to_add_webhook.create_hook('web', webhook_config)
|
|
except GithubException:
|
|
msg = 'Unable to create webhook on repository: %s'
|
|
raise TriggerActivationException(msg % new_build_source)
|
|
|
|
def list_build_sources(self, auth_token):
|
|
gh_client = self._get_client(auth_token)
|
|
usr = gh_client.get_user()
|
|
|
|
personal = {
|
|
'personal': True,
|
|
'repos': [repo.full_name for repo in usr.get_repos()],
|
|
'info': {
|
|
'name': usr.login,
|
|
'avatar_url': usr.avatar_url,
|
|
}
|
|
}
|
|
|
|
repos_by_org = [personal]
|
|
|
|
for org in usr.get_orgs():
|
|
repo_list = []
|
|
for repo in org.get_repos():
|
|
repo_list.append(repo.full_name)
|
|
|
|
repos_by_org.append({
|
|
'personal': False,
|
|
'repos': repo_list,
|
|
'info': {
|
|
'name': org.name,
|
|
'avatar_url': org.avatar_url
|
|
}
|
|
})
|
|
|
|
return repos_by_org
|
|
|
|
def handle_trigger_request(self, request, auth_token, config):
|
|
payload = request.get_json()
|
|
|
|
if 'zen' in payload:
|
|
raise ValidationRequestException()
|
|
|
|
logger.debug('Payload %s', payload)
|
|
ref = payload['ref']
|
|
commit_id = payload['head_commit']['id'][0:7]
|
|
|
|
gh_client = self._get_client(auth_token)
|
|
|
|
repo_full_name = '%s/%s' % (payload['repository']['owner']['name'],
|
|
payload['repository']['name'])
|
|
repo = gh_client.get_repo(repo_full_name)
|
|
|
|
logger.debug('Github repo: %s', repo)
|
|
|
|
# Prepare the download and upload URLs
|
|
branch_name = ref.split('/')[-1]
|
|
archive_link = repo.get_archive_link('zipball', branch_name)
|
|
download_archive = client.get(archive_link, stream=True)
|
|
|
|
with SpooledTemporaryFile(CHUNK_SIZE) as zipball:
|
|
for chunk in download_archive.iter_content(CHUNK_SIZE):
|
|
zipball.write(chunk)
|
|
|
|
dockerfile_id = user_files.store_file(zipball, ZIPBALL)
|
|
|
|
logger.debug('Successfully prepared job')
|
|
|
|
return dockerfile_id, branch_name, commit_id
|