trigger: initial custom git trigger

This commit is contained in:
Jimmy Zelinskie 2015-03-26 16:20:53 -04:00
parent 9c55aca011
commit 998c6007cd
4 changed files with 143 additions and 8 deletions

View file

@ -212,15 +212,12 @@ class BuildTriggerActivate(RepositoryParamResource):
token = model.create_delegate_token(namespace, repository, token_name,
'write')
# Generate an SSH keypair
new_config_dict['public_key'], trigger.private_key = generate_ssh_keypair()
try:
path = url_for('webhooks.build_trigger_webhook', trigger_uuid=trigger.uuid)
authed_url = _prepare_webhook_url(app.config['PREFERRED_URL_SCHEME'], '$token', token.code,
app.config['SERVER_HOSTNAME'], path)
final_config = handler.activate(trigger.uuid, authed_url,
final_config, trigger.private_key = handler.activate(trigger.uuid, authed_url,
trigger.auth_token, new_config_dict)
except TriggerActivationException as exc:
token.delete_instance()
@ -512,3 +509,12 @@ class BuildTriggerSources(RepositoryParamResource):
}
else:
raise Unauthorized()
@resource('/v1/repository/<repopath:repository>/trigger/redirect')
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
@internal_only
class CustomBuildTriggerRedirect(RepositoryParamResource):
""" Custom verb to properly handle redirecting users using their own custom git hook. """
@nickname('customTriggerRedirect')
def get(self, namespace, repository):
pass

View file

@ -11,6 +11,7 @@ from tempfile import SpooledTemporaryFile
from app import app, userfiles as user_files, github_trigger
from util.tarfileappender import TarfileAppender
from util.ssh import generate_ssh_keypair
client = app.config['HTTPCLIENT']
@ -26,6 +27,8 @@ CHUNK_SIZE = 512 * 1024
def should_skip_commit(message):
return '[skip build]' in message or '[build skip]' in message
class InvalidPayloadException(Exception):
pass
class BuildArchiveException(Exception):
pass
@ -185,6 +188,7 @@ class GithubBuildTrigger(BuildTrigger):
# Add a deploy key to the GitHub repository.
try:
config['public_key'], private_key = generate_ssh_keypair()
deploy_key = gh_repo.create_key('Quay.io Builder', config['public_key'])
config['deploy_key_id'] = deploy_key.id
except GithubException:
@ -206,7 +210,7 @@ class GithubBuildTrigger(BuildTrigger):
msg = 'Unable to create webhook on repository: %s' % new_build_source
raise TriggerActivationException(msg)
return config
return config, private_key
def deactivate(self, auth_token, config):
gh_client = self._get_client(auth_token)
@ -541,3 +545,102 @@ class GithubBuildTrigger(BuildTrigger):
return branches
return None
class CustomBuildTrigger(BuildTrigger):
@classmethod
def service_name(cls):
return 'custom'
def is_active(self, config):
return 'public_key' in config
@staticmethod
def _metadata_from_payload(payload):
try:
metadata = {
'commit_sha': payload['commit'],
'ref': payload['ref'],
'default_branch': payload.get('default_branch', 'master'),
}
except KeyError:
raise InvalidPayloadException()
commit_info = payload['commit_info']
if commit_info is not None:
try:
metadata['commit_info'] = {
'url': commit_info['url'],
'message': commit_info['message'],
'date': commit_info['date'],
}
except KeyError:
raise InvalidPayloadException()
author = commit_info['author']
if author is not None:
try:
metadata['commit_info']['author'] = {
'username': author['username'],
'avatar_url': author['avatar_url'],
'url': author['url'],
}
except KeyError:
raise InvalidPayloadException()
committer = commit_info['committer']
if committer is not None:
try:
metadata['commit_info']['committer'] = {
'username': committer['username'],
'avatar_url': committer['avatar_url'],
'url': committer['url'],
}
except KeyError:
raise InvalidPayloadException()
return metadata
def handle_trigger_request(self, request, trigger):
payload = request.get_json()
if not payload:
raise SkipRequestException()
logger.debug('Payload %s', payload)
metadata = self._metadata_from_payload(payload)
# The build source is the canonical git URL used to clone.
config = get_trigger_config(trigger)
metadata['git_url'] = config['build_source']
branch = metadata['ref'].split('/')[-1]
tags = {branch}
build_name = metadata['commit_sha'][:6]
dockerfile_id = None
return dockerfile_id, tags, build_name, trigger.config['subdir'], metadata
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
config['public_key'], private_key = generate_ssh_keypair()
return config, private_key
def deactivate(self, auth_token, config):
config.pop('public_key', None)
return config
def manual_start(self, trigger, run_parameters=None):
for parameter in ['branch_name', 'commit_sha',]:
if parameter not in run_parameters:
raise TriggerStartException
dockerfile_id = None
branch = run_parameters.get('branch_name', None)
tags = {branch} if branch is not None else {}
build_name = 'HEAD'
metadata = {
'commit_sha': run_parameters['commit_sha'],
'default_branch': branch,
'ref': 'refs/heads/%s' % branch,
}
return dockerfile_id, tags, build_name, trigger.config['subdir'], metadata

View file

@ -9,7 +9,7 @@ from auth.permissions import ModifyRepositoryPermission
from util.invoice import renderInvoiceToHtml
from util.useremails import send_invoice_email, send_subscription_change, send_payment_failed
from util.http import abort
from endpoints.trigger import BuildTrigger, ValidationRequestException, SkipRequestException
from endpoints.trigger import BuildTrigger, ValidationRequestException, SkipRequestException, InvalidPayloadException
from endpoints.common import start_build
@ -88,14 +88,15 @@ def build_trigger_webhook(trigger_uuid, **kwargs):
try:
specs = handler.handle_trigger_request(request, trigger)
dockerfile_id, tags, name, subdir, metadata = specs
except ValidationRequestException:
# This was just a validation request, we don't need to build anything
return make_response('Okay')
except SkipRequestException:
# The build was requested to be skipped
return make_response('Okay')
except InvalidPayloadException:
# The payload was malformed
abort(400)
pull_robot_name = model.get_pull_robot_name(trigger)
repo = model.get_repository(namespace, repository)

View file

@ -49,6 +49,31 @@ angular.module('quay').factory('TriggerService', ['UtilService', '$sanitize', 'K
return 'GitHub Repository Push';
}
},
'custom': {
'description': function(config) {
var source = UtilService.textToSafeHtml(config['build_source']);
var desc = '<i class"fa fa-git fa-lg" style="margin-left:2px; margin-right: 2px"></i> Push to Custom Git Repository ' + source;
desc += '<br>Dockerfile folder: //' + UtilService.textToSafeHtml(config['subdir']);
return desc;
},
'run_parameters': [
{
'title': 'Branch',
'type': 'string',
'name': 'branch_name'
},
{
'title': 'Commit SHA1',
'type': 'string',
'name': 'commit_sha'
}
],
'get_redirect_url': function() {},
'is_enabled': function() { return true; },
'icon': 'fa-git',
'title': function() { return 'Custom Git Repository Push'; }
}
}