trigger: initial custom git trigger
This commit is contained in:
parent
9c55aca011
commit
998c6007cd
4 changed files with 143 additions and 8 deletions
|
@ -212,15 +212,12 @@ class BuildTriggerActivate(RepositoryParamResource):
|
||||||
token = model.create_delegate_token(namespace, repository, token_name,
|
token = model.create_delegate_token(namespace, repository, token_name,
|
||||||
'write')
|
'write')
|
||||||
|
|
||||||
# Generate an SSH keypair
|
|
||||||
new_config_dict['public_key'], trigger.private_key = generate_ssh_keypair()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
path = url_for('webhooks.build_trigger_webhook', trigger_uuid=trigger.uuid)
|
path = url_for('webhooks.build_trigger_webhook', trigger_uuid=trigger.uuid)
|
||||||
authed_url = _prepare_webhook_url(app.config['PREFERRED_URL_SCHEME'], '$token', token.code,
|
authed_url = _prepare_webhook_url(app.config['PREFERRED_URL_SCHEME'], '$token', token.code,
|
||||||
app.config['SERVER_HOSTNAME'], path)
|
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)
|
trigger.auth_token, new_config_dict)
|
||||||
except TriggerActivationException as exc:
|
except TriggerActivationException as exc:
|
||||||
token.delete_instance()
|
token.delete_instance()
|
||||||
|
@ -512,3 +509,12 @@ class BuildTriggerSources(RepositoryParamResource):
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
raise Unauthorized()
|
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
|
||||||
|
|
|
@ -11,6 +11,7 @@ from tempfile import SpooledTemporaryFile
|
||||||
|
|
||||||
from app import app, userfiles as user_files, github_trigger
|
from app import app, userfiles as user_files, github_trigger
|
||||||
from util.tarfileappender import TarfileAppender
|
from util.tarfileappender import TarfileAppender
|
||||||
|
from util.ssh import generate_ssh_keypair
|
||||||
|
|
||||||
|
|
||||||
client = app.config['HTTPCLIENT']
|
client = app.config['HTTPCLIENT']
|
||||||
|
@ -26,6 +27,8 @@ CHUNK_SIZE = 512 * 1024
|
||||||
def should_skip_commit(message):
|
def should_skip_commit(message):
|
||||||
return '[skip build]' in message or '[build skip]' in message
|
return '[skip build]' in message or '[build skip]' in message
|
||||||
|
|
||||||
|
class InvalidPayloadException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class BuildArchiveException(Exception):
|
class BuildArchiveException(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -185,6 +188,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
# Add a deploy key to the GitHub repository.
|
# Add a deploy key to the GitHub repository.
|
||||||
try:
|
try:
|
||||||
|
config['public_key'], private_key = generate_ssh_keypair()
|
||||||
deploy_key = gh_repo.create_key('Quay.io Builder', config['public_key'])
|
deploy_key = gh_repo.create_key('Quay.io Builder', config['public_key'])
|
||||||
config['deploy_key_id'] = deploy_key.id
|
config['deploy_key_id'] = deploy_key.id
|
||||||
except GithubException:
|
except GithubException:
|
||||||
|
@ -206,7 +210,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
msg = 'Unable to create webhook on repository: %s' % new_build_source
|
msg = 'Unable to create webhook on repository: %s' % new_build_source
|
||||||
raise TriggerActivationException(msg)
|
raise TriggerActivationException(msg)
|
||||||
|
|
||||||
return config
|
return config, private_key
|
||||||
|
|
||||||
def deactivate(self, auth_token, config):
|
def deactivate(self, auth_token, config):
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client(auth_token)
|
||||||
|
@ -541,3 +545,102 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
return branches
|
return branches
|
||||||
|
|
||||||
return None
|
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
|
||||||
|
|
|
@ -9,7 +9,7 @@ from auth.permissions import ModifyRepositoryPermission
|
||||||
from util.invoice import renderInvoiceToHtml
|
from util.invoice import renderInvoiceToHtml
|
||||||
from util.useremails import send_invoice_email, send_subscription_change, send_payment_failed
|
from util.useremails import send_invoice_email, send_subscription_change, send_payment_failed
|
||||||
from util.http import abort
|
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
|
from endpoints.common import start_build
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,14 +88,15 @@ def build_trigger_webhook(trigger_uuid, **kwargs):
|
||||||
try:
|
try:
|
||||||
specs = handler.handle_trigger_request(request, trigger)
|
specs = handler.handle_trigger_request(request, trigger)
|
||||||
dockerfile_id, tags, name, subdir, metadata = specs
|
dockerfile_id, tags, name, subdir, metadata = specs
|
||||||
|
|
||||||
except ValidationRequestException:
|
except ValidationRequestException:
|
||||||
# This was just a validation request, we don't need to build anything
|
# This was just a validation request, we don't need to build anything
|
||||||
return make_response('Okay')
|
return make_response('Okay')
|
||||||
|
|
||||||
except SkipRequestException:
|
except SkipRequestException:
|
||||||
# The build was requested to be skipped
|
# The build was requested to be skipped
|
||||||
return make_response('Okay')
|
return make_response('Okay')
|
||||||
|
except InvalidPayloadException:
|
||||||
|
# The payload was malformed
|
||||||
|
abort(400)
|
||||||
|
|
||||||
pull_robot_name = model.get_pull_robot_name(trigger)
|
pull_robot_name = model.get_pull_robot_name(trigger)
|
||||||
repo = model.get_repository(namespace, repository)
|
repo = model.get_repository(namespace, repository)
|
||||||
|
|
|
@ -49,6 +49,31 @@ angular.module('quay').factory('TriggerService', ['UtilService', '$sanitize', 'K
|
||||||
|
|
||||||
return 'GitHub Repository Push';
|
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'; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue