Work in progress: bitbucket support
This commit is contained in:
parent
c480fb2105
commit
5cc91ed202
11 changed files with 352 additions and 259 deletions
|
@ -11,7 +11,7 @@ from endpoints.api import (RepositoryParamResource, parse_args, query_param, nic
|
||||||
ApiResource, internal_only, format_date, api, Unauthorized, NotFound,
|
ApiResource, internal_only, format_date, api, Unauthorized, NotFound,
|
||||||
path_param, InvalidRequest, require_repo_admin)
|
path_param, InvalidRequest, require_repo_admin)
|
||||||
from endpoints.common import start_build
|
from endpoints.common import start_build
|
||||||
from endpoints.trigger import BuildTrigger
|
from endpoints.trigger import BuildTriggerHandler
|
||||||
from data import model, database
|
from data import model, database
|
||||||
from auth.auth_context import get_authenticated_user
|
from auth.auth_context import get_authenticated_user
|
||||||
from auth.permissions import ModifyRepositoryPermission, AdministerOrganizationPermission
|
from auth.permissions import ModifyRepositoryPermission, AdministerOrganizationPermission
|
||||||
|
@ -45,14 +45,13 @@ def user_view(user):
|
||||||
|
|
||||||
def trigger_view(trigger, can_admin=False):
|
def trigger_view(trigger, can_admin=False):
|
||||||
if trigger and trigger.uuid:
|
if trigger and trigger.uuid:
|
||||||
config_dict = get_trigger_config(trigger)
|
build_trigger = BuildTriggerHandler.get_handler(trigger)
|
||||||
build_trigger = BuildTrigger.get_trigger_for_service(trigger.service.name)
|
|
||||||
return {
|
return {
|
||||||
'service': trigger.service.name,
|
'service': trigger.service.name,
|
||||||
'config': config_dict if can_admin else {},
|
'config': build_trigger.config if can_admin else {},
|
||||||
'id': trigger.uuid,
|
'id': trigger.uuid,
|
||||||
'connected_user': trigger.connected_user.username,
|
'connected_user': trigger.connected_user.username,
|
||||||
'is_active': build_trigger.is_active(config_dict),
|
'is_active': build_trigger.is_active(),
|
||||||
'pull_robot': user_view(trigger.pull_robot) if trigger.pull_robot else None
|
'pull_robot': user_view(trigger.pull_robot) if trigger.pull_robot else None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from endpoints.api import (RepositoryParamResource, nickname, resource, require_
|
||||||
from endpoints.api.build import (build_status_view, trigger_view, RepositoryBuildStatus,
|
from endpoints.api.build import (build_status_view, trigger_view, RepositoryBuildStatus,
|
||||||
get_trigger_config)
|
get_trigger_config)
|
||||||
from endpoints.common import start_build
|
from endpoints.common import start_build
|
||||||
from endpoints.trigger import (BuildTrigger as BuildTriggerBase, TriggerDeactivationException,
|
from endpoints.trigger import (BuildTriggerHandler, TriggerDeactivationException,
|
||||||
TriggerActivationException, EmptyRepositoryException,
|
TriggerActivationException, EmptyRepositoryException,
|
||||||
RepositoryReadException, TriggerStartException)
|
RepositoryReadException, TriggerStartException)
|
||||||
from data import model
|
from data import model
|
||||||
|
@ -71,18 +71,17 @@ class BuildTrigger(RepositoryParamResource):
|
||||||
except model.InvalidBuildTriggerException:
|
except model.InvalidBuildTriggerException:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
handler = BuildTriggerHandler.get_handler(trigger)
|
||||||
config_dict = get_trigger_config(trigger)
|
if handler.is_active():
|
||||||
if handler.is_active(config_dict):
|
|
||||||
try:
|
try:
|
||||||
handler.deactivate(trigger.auth_token, config_dict)
|
handler.deactivate()
|
||||||
except TriggerDeactivationException as ex:
|
except TriggerDeactivationException as ex:
|
||||||
# We are just going to eat this error
|
# We are just going to eat this error
|
||||||
logger.warning('Trigger deactivation problem: %s', ex)
|
logger.warning('Trigger deactivation problem: %s', ex)
|
||||||
|
|
||||||
log_action('delete_repo_trigger', namespace,
|
log_action('delete_repo_trigger', namespace,
|
||||||
{'repo': repository, 'trigger_id': trigger_uuid,
|
{'repo': repository, 'trigger_id': trigger_uuid,
|
||||||
'service': trigger.service.name, 'config': config_dict},
|
'service': trigger.service.name},
|
||||||
repo=model.get_repository(namespace, repository))
|
repo=model.get_repository(namespace, repository))
|
||||||
|
|
||||||
trigger.delete_instance(recursive=True)
|
trigger.delete_instance(recursive=True)
|
||||||
|
@ -117,13 +116,13 @@ class BuildTriggerSubdirs(RepositoryParamResource):
|
||||||
except model.InvalidBuildTriggerException:
|
except model.InvalidBuildTriggerException:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
|
||||||
user_permission = UserAdminPermission(trigger.connected_user.username)
|
user_permission = UserAdminPermission(trigger.connected_user.username)
|
||||||
if user_permission.can():
|
if user_permission.can():
|
||||||
new_config_dict = request.get_json()
|
new_config_dict = request.get_json()
|
||||||
|
handler = BuildTriggerHandler.get_handler(trigger, new_config_dict)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subdirs = handler.list_build_subdirs(trigger.auth_token, new_config_dict)
|
subdirs = handler.list_build_subdirs()
|
||||||
return {
|
return {
|
||||||
'subdir': subdirs,
|
'subdir': subdirs,
|
||||||
'status': 'success'
|
'status': 'success'
|
||||||
|
@ -178,9 +177,8 @@ class BuildTriggerActivate(RepositoryParamResource):
|
||||||
except model.InvalidBuildTriggerException:
|
except model.InvalidBuildTriggerException:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
handler = BuildTriggerHandler.get_handler(trigger)
|
||||||
existing_config_dict = get_trigger_config(trigger)
|
if handler.is_active():
|
||||||
if handler.is_active(existing_config_dict):
|
|
||||||
raise InvalidRequest('Trigger config is not sufficient for activation.')
|
raise InvalidRequest('Trigger config is not sufficient for activation.')
|
||||||
|
|
||||||
user_permission = UserAdminPermission(trigger.connected_user.username)
|
user_permission = UserAdminPermission(trigger.connected_user.username)
|
||||||
|
@ -217,8 +215,8 @@ class BuildTriggerActivate(RepositoryParamResource):
|
||||||
'$token', write_token.code,
|
'$token', write_token.code,
|
||||||
app.config['SERVER_HOSTNAME'], path)
|
app.config['SERVER_HOSTNAME'], path)
|
||||||
|
|
||||||
final_config, private_config = handler.activate(trigger.uuid, authed_url,
|
handler = BuildTriggerHandler.get_handler(trigger, new_config_dict)
|
||||||
trigger.auth_token, new_config_dict)
|
final_config, private_config = handler.activate(authed_url)
|
||||||
|
|
||||||
if 'private_key' in private_config:
|
if 'private_key' in private_config:
|
||||||
trigger.private_key = private_config['private_key']
|
trigger.private_key = private_config['private_key']
|
||||||
|
@ -279,12 +277,12 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
||||||
except model.InvalidBuildTriggerException:
|
except model.InvalidBuildTriggerException:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
|
||||||
new_config_dict = request.get_json()['config']
|
new_config_dict = request.get_json()['config']
|
||||||
|
handler = BuildTriggerHandler.get_handler(trigger, new_config_dict)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Load the contents of the Dockerfile.
|
# Load the contents of the Dockerfile.
|
||||||
contents = handler.load_dockerfile_contents(trigger.auth_token, new_config_dict)
|
contents = handler.load_dockerfile_contents()
|
||||||
if not contents:
|
if not contents:
|
||||||
return {
|
return {
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
|
@ -370,7 +368,7 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
||||||
'is_public': found_repository.visibility.name == 'public',
|
'is_public': found_repository.visibility.name == 'public',
|
||||||
'robots': read_robots,
|
'robots': read_robots,
|
||||||
'status': 'analyzed',
|
'status': 'analyzed',
|
||||||
'dockerfile_url': handler.dockerfile_url(trigger.auth_token, new_config_dict)
|
'dockerfile_url': handler.dockerfile_url()
|
||||||
}
|
}
|
||||||
|
|
||||||
except RepositoryReadException as rre:
|
except RepositoryReadException as rre:
|
||||||
|
@ -420,14 +418,13 @@ class ActivateBuildTrigger(RepositoryParamResource):
|
||||||
except model.InvalidBuildTriggerException:
|
except model.InvalidBuildTriggerException:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
handler = BuildTriggerHandler.get_handler(trigger)
|
||||||
config_dict = get_trigger_config(trigger)
|
if not handler.is_active():
|
||||||
if not handler.is_active(config_dict):
|
|
||||||
raise InvalidRequest('Trigger is not active.')
|
raise InvalidRequest('Trigger is not active.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
run_parameters = request.get_json()
|
run_parameters = request.get_json()
|
||||||
specs = handler.manual_start(trigger, run_parameters=run_parameters)
|
specs = handler.manual_start(run_parameters=run_parameters)
|
||||||
dockerfile_id, tags, name, subdir, metadata = specs
|
dockerfile_id, tags, name, subdir, metadata = specs
|
||||||
|
|
||||||
repo = model.get_repository(namespace, repository)
|
repo = model.get_repository(namespace, repository)
|
||||||
|
@ -481,11 +478,11 @@ class BuildTriggerFieldValues(RepositoryParamResource):
|
||||||
except model.InvalidBuildTriggerException:
|
except model.InvalidBuildTriggerException:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
config = request.get_json() or json.loads(trigger.config)
|
config = request.get_json() or None
|
||||||
user_permission = UserAdminPermission(trigger.connected_user.username)
|
user_permission = UserAdminPermission(trigger.connected_user.username)
|
||||||
if user_permission.can():
|
if user_permission.can():
|
||||||
trigger_handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
handler = BuildTriggerHandler.get_handler(trigger, config)
|
||||||
values = trigger_handler.list_field_values(trigger.auth_token, config, field_name)
|
values = handler.list_field_values(field_name)
|
||||||
|
|
||||||
if values is None:
|
if values is None:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
@ -514,10 +511,13 @@ class BuildTriggerSources(RepositoryParamResource):
|
||||||
|
|
||||||
user_permission = UserAdminPermission(trigger.connected_user.username)
|
user_permission = UserAdminPermission(trigger.connected_user.username)
|
||||||
if user_permission.can():
|
if user_permission.can():
|
||||||
trigger_handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
handler = BuildTriggerHandler.get_handler(trigger)
|
||||||
|
|
||||||
return {
|
try:
|
||||||
'sources': trigger_handler.list_build_sources(trigger.auth_token)
|
return {
|
||||||
}
|
'sources': handler.list_build_sources()
|
||||||
|
}
|
||||||
|
except RepositoryReadException as rre:
|
||||||
|
raise InvalidRequest(rre.message)
|
||||||
else:
|
else:
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
|
|
@ -3,7 +3,7 @@ import logging
|
||||||
from flask import request, redirect, url_for, Blueprint
|
from flask import request, redirect, url_for, Blueprint
|
||||||
from flask.ext.login import current_user
|
from flask.ext.login import current_user
|
||||||
|
|
||||||
from endpoints.trigger import BitbucketBuildTrigger
|
from endpoints.trigger import BitbucketBuildTrigger, BuildTriggerHandler
|
||||||
from endpoints.common import route_show_if
|
from endpoints.common import route_show_if
|
||||||
from app import app
|
from app import app
|
||||||
from data import model
|
from data import model
|
||||||
|
@ -30,14 +30,18 @@ def attach_bitbucket_build_trigger(trigger_uuid):
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
verifier = request.args.get('oauth_verifier')
|
verifier = request.args.get('oauth_verifier')
|
||||||
result = BitbucketBuildTrigger.exchange_verifier(trigger, verifier)
|
handler = BuildTriggerHandler.get_handler(trigger)
|
||||||
print result
|
result = handler.exchange_verifier(verifier)
|
||||||
return 'hello'
|
if not result:
|
||||||
|
trigger.delete_instance()
|
||||||
|
return 'Token has expired'
|
||||||
|
|
||||||
|
namespace = trigger.repository.namespace_user.username
|
||||||
|
repository = trigger.repository.name
|
||||||
|
|
||||||
repo_path = '%s/%s' % (namespace, repository)
|
repo_path = '%s/%s' % (namespace, repository)
|
||||||
full_url = '%s%s%s' % (url_for('web.repository', path=repo_path), '?tab=builds&newtrigger=',
|
full_url = '%s%s%s' % (url_for('web.repository', path=repo_path), '?tab=builds&newtrigger=',
|
||||||
trigger.uuid)
|
trigger.uuid)
|
||||||
|
|
||||||
|
|
||||||
logger.debug('Redirecting to full url: %s', full_url)
|
logger.debug('Redirecting to full url: %s', full_url)
|
||||||
return redirect(full_url)
|
return redirect(full_url)
|
|
@ -10,6 +10,7 @@ from github import Github, UnknownObjectException, GithubException
|
||||||
from bitbucket.bitbucket import Bitbucket
|
from bitbucket.bitbucket import Bitbucket
|
||||||
from tempfile import SpooledTemporaryFile
|
from tempfile import SpooledTemporaryFile
|
||||||
from jsonschema import validate
|
from jsonschema import validate
|
||||||
|
from data import model
|
||||||
|
|
||||||
from app import app, userfiles as user_files, github_trigger, get_app_url
|
from app import app, userfiles as user_files, github_trigger, get_app_url
|
||||||
from util.tarfileappender import TarfileAppender
|
from util.tarfileappender import TarfileAppender
|
||||||
|
@ -63,59 +64,75 @@ class TriggerProviderException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildTrigger(object):
|
def raise_unsupported():
|
||||||
def __init__(self):
|
raise io.UnsupportedOperation
|
||||||
pass
|
|
||||||
|
|
||||||
def dockerfile_url(self, auth_token, config):
|
def get_trigger_config(trigger):
|
||||||
|
try:
|
||||||
|
return json.loads(trigger.config)
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class BuildTriggerHandler(object):
|
||||||
|
def __init__(self, trigger, override_config=None):
|
||||||
|
self.trigger = trigger
|
||||||
|
self.config = override_config or get_trigger_config(trigger)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def auth_token(self):
|
||||||
|
""" Returns the auth token for the trigger. """
|
||||||
|
return self.trigger.auth_token
|
||||||
|
|
||||||
|
def dockerfile_url(self):
|
||||||
"""
|
"""
|
||||||
Returns the URL at which the Dockerfile for the trigger is found or None if none/not applicable.
|
Returns the URL at which the Dockerfile for the trigger is found or None if none/not applicable.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def load_dockerfile_contents(self, auth_token, config):
|
def load_dockerfile_contents(self):
|
||||||
"""
|
"""
|
||||||
Loads the Dockerfile found for the trigger's config and returns them or None if none could
|
Loads the Dockerfile found for the trigger's config and returns them or None if none could
|
||||||
be found/loaded.
|
be found/loaded.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def list_build_sources(self, auth_token):
|
def list_build_sources(self):
|
||||||
"""
|
"""
|
||||||
Take the auth information for the specific trigger type and load the
|
Take the auth information for the specific trigger type and load the
|
||||||
list of build sources(repositories).
|
list of build sources(repositories).
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def list_build_subdirs(self, auth_token, config):
|
def list_build_subdirs(self):
|
||||||
"""
|
"""
|
||||||
Take the auth information and the specified config so far and list all of
|
Take the auth information and the specified config so far and list all of
|
||||||
the possible subdirs containing dockerfiles.
|
the possible subdirs containing dockerfiles.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def handle_trigger_request(self, request, trigger):
|
def handle_trigger_request(self):
|
||||||
"""
|
"""
|
||||||
Transform the incoming request data into a set of actions. Returns a tuple
|
Transform the incoming request data into a set of actions. Returns a tuple
|
||||||
of usefiles resource id, docker tags, build name, and resource subdir.
|
of usefiles resource id, docker tags, build name, and resource subdir.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def is_active(self, config):
|
def is_active(self):
|
||||||
"""
|
"""
|
||||||
Returns True if the current build trigger is active. Inactive means further
|
Returns True if the current build trigger is active. Inactive means further
|
||||||
setup is needed.
|
setup is needed.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
|
def activate(self, standard_webhook_url):
|
||||||
"""
|
"""
|
||||||
Activates the trigger for the service, with the given new configuration.
|
Activates the trigger for the service, with the given new configuration.
|
||||||
Returns new public and private config that should be stored if successful.
|
Returns new public and private config that should be stored if successful.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def deactivate(self, auth_token, config):
|
def deactivate(self):
|
||||||
"""
|
"""
|
||||||
Deactivates the trigger for the service, removing any hooks installed in
|
Deactivates the trigger for the service, removing any hooks installed in
|
||||||
the remote service. Returns the new config that should be stored if this
|
the remote service. Returns the new config that should be stored if this
|
||||||
|
@ -123,13 +140,13 @@ class BuildTrigger(object):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def manual_start(self, trigger, run_parameters=None):
|
def manual_start(self, run_parameters=None):
|
||||||
"""
|
"""
|
||||||
Manually creates a repository build for this trigger.
|
Manually creates a repository build for this trigger.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def list_field_values(self, auth_token, config, field_name):
|
def list_field_values(self, field_name):
|
||||||
"""
|
"""
|
||||||
Lists all values for the given custom trigger field. For example, a trigger might have a
|
Lists all values for the given custom trigger field. For example, a trigger might have a
|
||||||
field named "branches", and this method would return all branches.
|
field named "branches", and this method would return all branches.
|
||||||
|
@ -144,25 +161,24 @@ class BuildTrigger(object):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_trigger_for_service(cls, service):
|
def get_handler(cls, trigger, override_config=None):
|
||||||
for subc in cls.__subclasses__():
|
for subc in cls.__subclasses__():
|
||||||
if subc.service_name() == service:
|
if subc.service_name() == trigger.service.name:
|
||||||
return subc()
|
return subc(trigger, override_config)
|
||||||
|
|
||||||
raise InvalidServiceException('Unable to find service: %s' % service)
|
raise InvalidServiceException('Unable to find service: %s' % service)
|
||||||
|
|
||||||
|
def put_config_key(self, key, value):
|
||||||
|
""" Updates a config key in the trigger, saving it to the DB. """
|
||||||
|
self.config[key] = value
|
||||||
|
model.update_build_trigger(self.trigger, self.config)
|
||||||
|
|
||||||
def raise_unsupported():
|
def set_auth_token(self, auth_token):
|
||||||
raise io.UnsupportedOperation
|
""" Sets the auth token for the trigger, saving it to the DB. """
|
||||||
|
model.update_build_trigger(self.trigger, self.config, auth_token=auth_token)
|
||||||
def get_trigger_config(trigger):
|
|
||||||
try:
|
|
||||||
return json.loads(trigger.config)
|
|
||||||
except:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
class BitbucketBuildTrigger(BuildTrigger):
|
class BitbucketBuildTrigger(BuildTriggerHandler):
|
||||||
"""
|
"""
|
||||||
BuildTrigger for Bitbucket.
|
BuildTrigger for Bitbucket.
|
||||||
"""
|
"""
|
||||||
|
@ -170,23 +186,25 @@ class BitbucketBuildTrigger(BuildTrigger):
|
||||||
def service_name(cls):
|
def service_name(cls):
|
||||||
return 'bitbucket'
|
return 'bitbucket'
|
||||||
|
|
||||||
@staticmethod
|
def _get_authorized_client(self, namespace=None):
|
||||||
def _get_authorized_client(trigger_uuid):
|
|
||||||
key = app.config.get('BITBUCKET_TRIGGER_CONFIG', {}).get('CONSUMER_KEY', '')
|
key = app.config.get('BITBUCKET_TRIGGER_CONFIG', {}).get('CONSUMER_KEY', '')
|
||||||
secret = app.config.get('BITBUCKET_TRIGGER_CONFIG', {}).get('CONSUMER_SECRET', '')
|
secret = app.config.get('BITBUCKET_TRIGGER_CONFIG', {}).get('CONSUMER_SECRET', '')
|
||||||
|
|
||||||
|
trigger_uuid = self.trigger.uuid
|
||||||
callback_url = '%s/oauth1/bitbucket/callback/trigger/%s' % (get_app_url(), trigger_uuid)
|
callback_url = '%s/oauth1/bitbucket/callback/trigger/%s' % (get_app_url(), trigger_uuid)
|
||||||
bitbucket_client = Bitbucket()
|
|
||||||
(result, err_message) = bitbucket_client.authorize(key, secret, callback_url)
|
bitbucket_client = Bitbucket(username=namespace or self.config.get('username', ''))
|
||||||
|
|
||||||
|
(result, err_message) = bitbucket_client.authorize(key, secret, callback_url,
|
||||||
|
access_token=self.config.get('access_token'),
|
||||||
|
access_token_secret=self.auth_token)
|
||||||
if not result:
|
if not result:
|
||||||
raise TriggerProviderException(err_message)
|
raise TriggerProviderException(err_message)
|
||||||
|
|
||||||
return bitbucket_client
|
return bitbucket_client
|
||||||
|
|
||||||
|
def get_oauth_url(self):
|
||||||
@staticmethod
|
bitbucket_client = self._get_authorized_client()
|
||||||
def get_oauth_url(trigger_uuid):
|
|
||||||
bitbucket_client = BitbucketBuildTrigger._get_authorized_client(trigger_uuid)
|
|
||||||
url = bitbucket_client.url('AUTHENTICATE', token=bitbucket_client.access_token)
|
url = bitbucket_client.url('AUTHENTICATE', token=bitbucket_client.access_token)
|
||||||
return {
|
return {
|
||||||
'access_token': bitbucket_client.access_token,
|
'access_token': bitbucket_client.access_token,
|
||||||
|
@ -194,62 +212,104 @@ class BitbucketBuildTrigger(BuildTrigger):
|
||||||
'url': url
|
'url': url
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def exchange_verifier(self, verifier):
|
||||||
def exchange_verifier(trigger, verifier):
|
bitbucket_client = self._get_authorized_client()
|
||||||
trigger_config = get_trigger_config(trigger.config)
|
(result, data) = bitbucket_client.verify(verifier,
|
||||||
bitbucket_client = BitbucketBuildTrigger._get_authorized_client(trigger.uuid)
|
access_token=self.config.get('access_token', ''),
|
||||||
print trigger.config
|
access_token_secret=self.auth_token)
|
||||||
print trigger.auth_token
|
|
||||||
print bitbucket_client.verify(verifier, access_token=trigger_config.get('access_token', ''),
|
|
||||||
access_token_secret=trigger.auth_token)
|
|
||||||
return None
|
|
||||||
#(result, _) = bitbucket_client.verify(verifier)
|
|
||||||
|
|
||||||
#if not result:
|
if not result:
|
||||||
# return None
|
return False
|
||||||
|
|
||||||
#return (bitbucket_client.access_token, bitbucket_client.access_token_secret)
|
# Request the user's information and save it and the access token to the config.
|
||||||
|
user_url = bitbucket_client.URLS['BASE'] % 'user'
|
||||||
|
(result, data) = bitbucket_client.dispatch('GET', user_url, auth=bitbucket_client.auth)
|
||||||
|
if not result:
|
||||||
|
return False
|
||||||
|
|
||||||
def is_active(self, config):
|
username = data['user']['username']
|
||||||
|
new_access_token = bitbucket_client.access_token
|
||||||
|
|
||||||
|
self.put_config_key('username', username)
|
||||||
|
self.put_config_key('access_token', new_access_token)
|
||||||
|
self.set_auth_token(bitbucket_client.access_token_secret)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
|
def activate(self, standard_webhook_url):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def deactivate(self, auth_token, config):
|
def deactivate(self):
|
||||||
return config
|
return self.config
|
||||||
|
|
||||||
def list_build_sources(self, auth_token):
|
def list_build_sources(self):
|
||||||
|
bitbucket_client = self._get_authorized_client()
|
||||||
|
success, repositories = bitbucket_client.repository.all()
|
||||||
|
if not success:
|
||||||
|
raise RepositoryReadException('Could not read repository list')
|
||||||
|
|
||||||
|
namespaces = {}
|
||||||
|
|
||||||
|
for repo in repositories:
|
||||||
|
if not repo['scm'] == 'git':
|
||||||
|
continue
|
||||||
|
|
||||||
|
owner = repo['owner']
|
||||||
|
if not owner in namespaces:
|
||||||
|
namespaces[owner] = {
|
||||||
|
'personal': owner == self.config.get('username'),
|
||||||
|
'repos': [],
|
||||||
|
'info': {
|
||||||
|
'name': owner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaces[owner]['repos'].append(owner + '/' + repo['slug'])
|
||||||
|
|
||||||
|
return namespaces.values()
|
||||||
|
|
||||||
|
|
||||||
|
def list_build_subdirs(self):
|
||||||
|
source = self.config['build_source']
|
||||||
|
(namespace, name) = source.split('/')
|
||||||
|
(result, data) = self._get_authorized_client(namespace=namespace).repository.get(name)
|
||||||
|
|
||||||
|
print result
|
||||||
|
print data
|
||||||
|
return []
|
||||||
|
|
||||||
|
def dockerfile_url(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load_dockerfile_contents(self):
|
||||||
|
raise RepositoryReadException('Not supported')
|
||||||
|
|
||||||
|
def handle_trigger_request(self, request):
|
||||||
|
return
|
||||||
|
|
||||||
|
def manual_start(self, run_parameters=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def list_field_values(self, field_name):
|
||||||
|
source = self.config['build_source']
|
||||||
|
(namespace, name) = source.split('/')
|
||||||
|
(result, data) = self._get_authorized_client(namespace=namespace).repository.get(name)
|
||||||
|
|
||||||
|
print result
|
||||||
|
print data
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def list_build_subdirs(self, auth_token, config):
|
class GithubBuildTrigger(BuildTriggerHandler):
|
||||||
raise RepositoryReadException('Not supported')
|
|
||||||
|
|
||||||
def dockerfile_url(self, auth_token, config):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def load_dockerfile_contents(self, auth_token, config):
|
|
||||||
raise RepositoryReadException('Not supported')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _build_commit_info(repo, commit_sha):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def handle_trigger_request(self, request, trigger):
|
|
||||||
return
|
|
||||||
|
|
||||||
def manual_start(self, trigger, run_parameters=None):
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class GithubBuildTrigger(BuildTrigger):
|
|
||||||
"""
|
"""
|
||||||
BuildTrigger for GitHub that uses the archive API and buildpacks.
|
BuildTrigger for GitHub that uses the archive API and buildpacks.
|
||||||
"""
|
"""
|
||||||
@staticmethod
|
def _get_client(self):
|
||||||
def _get_client(auth_token):
|
return Github(self.auth_token,
|
||||||
return Github(auth_token,
|
|
||||||
base_url=github_trigger.api_endpoint(),
|
base_url=github_trigger.api_endpoint(),
|
||||||
client_id=github_trigger.client_id(),
|
client_id=github_trigger.client_id(),
|
||||||
client_secret=github_trigger.client_secret())
|
client_secret=github_trigger.client_secret())
|
||||||
|
@ -258,12 +318,13 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
def service_name(cls):
|
def service_name(cls):
|
||||||
return 'github'
|
return 'github'
|
||||||
|
|
||||||
def is_active(self, config):
|
def is_active(self):
|
||||||
return 'hook_id' in config
|
return 'hook_id' in self.config
|
||||||
|
|
||||||
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
|
def activate(self, standard_webhook_url):
|
||||||
|
config = self.config
|
||||||
new_build_source = config['build_source']
|
new_build_source = config['build_source']
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client()
|
||||||
|
|
||||||
# Find the GitHub repository.
|
# Find the GitHub repository.
|
||||||
try:
|
try:
|
||||||
|
@ -303,8 +364,9 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
return config, {'private_key': private_key}
|
return config, {'private_key': private_key}
|
||||||
|
|
||||||
def deactivate(self, auth_token, config):
|
def deactivate(self):
|
||||||
gh_client = self._get_client(auth_token)
|
config = self.config
|
||||||
|
gh_client = self._get_client()
|
||||||
|
|
||||||
# Find the GitHub repository.
|
# Find the GitHub repository.
|
||||||
try:
|
try:
|
||||||
|
@ -334,11 +396,11 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
raise TriggerDeactivationException(msg)
|
raise TriggerDeactivationException(msg)
|
||||||
|
|
||||||
config.pop('hook_id', None)
|
config.pop('hook_id', None)
|
||||||
|
self.config = config
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def list_build_sources(self, auth_token):
|
def list_build_sources(self):
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client()
|
||||||
usr = gh_client.get_user()
|
usr = gh_client.get_user()
|
||||||
|
|
||||||
personal = {
|
personal = {
|
||||||
|
@ -380,8 +442,9 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
return len(m.group(0)) == len(match_string)
|
return len(m.group(0)) == len(match_string)
|
||||||
|
|
||||||
def list_build_subdirs(self, auth_token, config):
|
def list_build_subdirs(self):
|
||||||
gh_client = self._get_client(auth_token)
|
config = self.config
|
||||||
|
gh_client = self._get_client()
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -411,11 +474,13 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
raise RepositoryReadException(message)
|
raise RepositoryReadException(message)
|
||||||
|
|
||||||
def dockerfile_url(self, auth_token, config):
|
def dockerfile_url(self):
|
||||||
|
config = self.config
|
||||||
|
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
subdirectory = config.get('subdir', '')
|
subdirectory = config.get('subdir', '')
|
||||||
path = subdirectory + '/Dockerfile' if subdirectory else 'Dockerfile'
|
path = subdirectory + '/Dockerfile' if subdirectory else 'Dockerfile'
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
repo = gh_client.get_repo(source)
|
repo = gh_client.get_repo(source)
|
||||||
|
@ -425,8 +490,9 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
logger.exception('Could not load repository for Dockerfile.')
|
logger.exception('Could not load repository for Dockerfile.')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def load_dockerfile_contents(self, auth_token, config):
|
def load_dockerfile_contents(self):
|
||||||
gh_client = self._get_client(auth_token)
|
config = self.config
|
||||||
|
gh_client = self._get_client()
|
||||||
|
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
subdirectory = config.get('subdir', '')
|
subdirectory = config.get('subdir', '')
|
||||||
|
@ -556,7 +622,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
def get_display_name(sha):
|
def get_display_name(sha):
|
||||||
return sha[0:7]
|
return sha[0:7]
|
||||||
|
|
||||||
def handle_trigger_request(self, request, trigger):
|
def handle_trigger_request(self, request):
|
||||||
payload = request.get_json()
|
payload = request.get_json()
|
||||||
if not payload or payload.get('head_commit') is None:
|
if not payload or payload.get('head_commit') is None:
|
||||||
raise SkipRequestException()
|
raise SkipRequestException()
|
||||||
|
@ -570,7 +636,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
commit_message = payload['head_commit'].get('message', '')
|
commit_message = payload['head_commit'].get('message', '')
|
||||||
git_url = payload['repository']['git_url']
|
git_url = payload['repository']['git_url']
|
||||||
|
|
||||||
config = get_trigger_config(trigger)
|
config = self.config
|
||||||
if 'branchtag_regex' in config:
|
if 'branchtag_regex' in config:
|
||||||
try:
|
try:
|
||||||
regex = re.compile(config['branchtag_regex'])
|
regex = re.compile(config['branchtag_regex'])
|
||||||
|
@ -585,7 +651,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
short_sha = GithubBuildTrigger.get_display_name(commit_sha)
|
short_sha = GithubBuildTrigger.get_display_name(commit_sha)
|
||||||
|
|
||||||
gh_client = self._get_client(trigger.auth_token)
|
gh_client = self._get_client()
|
||||||
|
|
||||||
repo_full_name = '%s/%s' % (payload['repository']['owner']['name'],
|
repo_full_name = '%s/%s' % (payload['repository']['owner']['name'],
|
||||||
payload['repository']['name'])
|
payload['repository']['name'])
|
||||||
|
@ -593,16 +659,16 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
logger.debug('Github repo: %s', repo)
|
logger.debug('Github repo: %s', repo)
|
||||||
|
|
||||||
return GithubBuildTrigger._prepare_build(trigger, config, repo, commit_sha,
|
return GithubBuildTrigger._prepare_build(self.trigger, config, repo, commit_sha, short_sha,
|
||||||
short_sha, ref, git_url)
|
ref, git_url)
|
||||||
|
|
||||||
def manual_start(self, trigger, run_parameters=None):
|
def manual_start(self, run_parameters=None):
|
||||||
config = get_trigger_config(trigger)
|
config = self.config
|
||||||
try:
|
try:
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
run_parameters = run_parameters or {}
|
run_parameters = run_parameters or {}
|
||||||
|
|
||||||
gh_client = self._get_client(trigger.auth_token)
|
gh_client = self._get_client()
|
||||||
repo = gh_client.get_repo(source)
|
repo = gh_client.get_repo(source)
|
||||||
branch_name = run_parameters.get('branch_name') or repo.default_branch
|
branch_name = run_parameters.get('branch_name') or repo.default_branch
|
||||||
branch = repo.get_branch(branch_name)
|
branch = repo.get_branch(branch_name)
|
||||||
|
@ -611,27 +677,28 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
ref = 'refs/heads/%s' % (branch_name)
|
ref = 'refs/heads/%s' % (branch_name)
|
||||||
git_url = repo.git_url
|
git_url = repo.git_url
|
||||||
|
|
||||||
return self._prepare_build(trigger, config, repo, branch_sha, short_sha, ref, git_url)
|
return self._prepare_build(self.trigger, config, repo, branch_sha, short_sha, ref, git_url)
|
||||||
except GithubException as ghe:
|
except GithubException as ghe:
|
||||||
raise TriggerStartException(ghe.data['message'])
|
raise TriggerStartException(ghe.data['message'])
|
||||||
|
|
||||||
|
|
||||||
def list_field_values(self, auth_token, config, field_name):
|
def list_field_values(self, field_name):
|
||||||
if field_name == 'refs':
|
if field_name == 'refs':
|
||||||
branches = self.list_field_values(auth_token, config, 'branch_name')
|
branches = self.list_field_values('branch_name')
|
||||||
tags = self.list_field_values(auth_token, config, 'tag_name')
|
tags = self.list_field_values('tag_name')
|
||||||
|
|
||||||
return ([{'kind': 'branch', 'name': b} for b in branches] +
|
return ([{'kind': 'branch', 'name': b} for b in branches] +
|
||||||
[{'kind': 'tag', 'name': tag} for tag in tags])
|
[{'kind': 'tag', 'name': tag} for tag in tags])
|
||||||
|
|
||||||
|
config = self.config
|
||||||
if field_name == 'tag_name':
|
if field_name == 'tag_name':
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client()
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
repo = gh_client.get_repo(source)
|
repo = gh_client.get_repo(source)
|
||||||
return [tag.name for tag in repo.get_tags()]
|
return [tag.name for tag in repo.get_tags()]
|
||||||
|
|
||||||
if field_name == 'branch_name':
|
if field_name == 'branch_name':
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client()
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
repo = gh_client.get_repo(source)
|
repo = gh_client.get_repo(source)
|
||||||
branches = [branch.name for branch in repo.get_branches()]
|
branches = [branch.name for branch in repo.get_branches()]
|
||||||
|
@ -647,7 +714,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class CustomBuildTrigger(BuildTrigger):
|
class CustomBuildTrigger(BuildTriggerHandler):
|
||||||
payload_schema = {
|
payload_schema = {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
|
@ -730,8 +797,8 @@ class CustomBuildTrigger(BuildTrigger):
|
||||||
def service_name(cls):
|
def service_name(cls):
|
||||||
return 'custom-git'
|
return 'custom-git'
|
||||||
|
|
||||||
def is_active(self, config):
|
def is_active(self):
|
||||||
return config.has_key('credentials')
|
return self.config.has_key('credentials')
|
||||||
|
|
||||||
def _metadata_from_payload(self, payload):
|
def _metadata_from_payload(self, payload):
|
||||||
try:
|
try:
|
||||||
|
@ -741,7 +808,7 @@ class CustomBuildTrigger(BuildTrigger):
|
||||||
raise InvalidPayloadException()
|
raise InvalidPayloadException()
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
def handle_trigger_request(self, request, trigger):
|
def handle_trigger_request(self, request):
|
||||||
payload = request.get_json()
|
payload = request.get_json()
|
||||||
if not payload:
|
if not payload:
|
||||||
raise SkipRequestException()
|
raise SkipRequestException()
|
||||||
|
@ -750,7 +817,7 @@ class CustomBuildTrigger(BuildTrigger):
|
||||||
metadata = self._metadata_from_payload(payload)
|
metadata = self._metadata_from_payload(payload)
|
||||||
|
|
||||||
# The build source is the canonical git URL used to clone.
|
# The build source is the canonical git URL used to clone.
|
||||||
config = get_trigger_config(trigger)
|
config = self.config
|
||||||
metadata['git_url'] = config['build_source']
|
metadata['git_url'] = config['build_source']
|
||||||
|
|
||||||
branch = metadata['ref'].split('/')[-1]
|
branch = metadata['ref'].split('/')[-1]
|
||||||
|
@ -759,9 +826,10 @@ class CustomBuildTrigger(BuildTrigger):
|
||||||
build_name = metadata['commit_sha'][:6]
|
build_name = metadata['commit_sha'][:6]
|
||||||
dockerfile_id = None
|
dockerfile_id = None
|
||||||
|
|
||||||
return dockerfile_id, tags, build_name, trigger.config['subdir'], metadata
|
return dockerfile_id, tags, build_name, config['subdir'], metadata
|
||||||
|
|
||||||
def activate(self, trigger_uuid, standard_webhook_url, auth_token, config):
|
def activate(self, standard_webhook_url):
|
||||||
|
config = self.config
|
||||||
public_key, private_key = generate_ssh_keypair()
|
public_key, private_key = generate_ssh_keypair()
|
||||||
config['credentials'] = [
|
config['credentials'] = [
|
||||||
{
|
{
|
||||||
|
@ -773,18 +841,21 @@ class CustomBuildTrigger(BuildTrigger):
|
||||||
'value': standard_webhook_url,
|
'value': standard_webhook_url,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
self.config = config
|
||||||
return config, {'private_key': private_key}
|
return config, {'private_key': private_key}
|
||||||
|
|
||||||
def deactivate(self, auth_token, config):
|
def deactivate(self):
|
||||||
|
config = self.config
|
||||||
config.pop('credentials', None)
|
config.pop('credentials', None)
|
||||||
|
self.config = config
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def manual_start(self, trigger, run_parameters=None):
|
def manual_start(self, run_parameters=None):
|
||||||
# commit_sha is the only required parameter
|
# commit_sha is the only required parameter
|
||||||
if 'commit_sha' not in run_parameters:
|
if 'commit_sha' not in run_parameters:
|
||||||
raise TriggerStartException('missing required parameter')
|
raise TriggerStartException('missing required parameter')
|
||||||
|
|
||||||
config = get_trigger_config(trigger)
|
config = self.config
|
||||||
dockerfile_id = None
|
dockerfile_id = None
|
||||||
tags = {run_parameters['commit_sha']}
|
tags = {run_parameters['commit_sha']}
|
||||||
build_name = run_parameters['commit_sha']
|
build_name = run_parameters['commit_sha']
|
||||||
|
|
|
@ -20,7 +20,8 @@ from util.cache import no_cache
|
||||||
from endpoints.common import common_login, render_page_template, route_show_if, param_required
|
from endpoints.common import common_login, render_page_template, route_show_if, param_required
|
||||||
from endpoints.csrf import csrf_protect, generate_csrf_token, verify_csrf
|
from endpoints.csrf import csrf_protect, generate_csrf_token, verify_csrf
|
||||||
from endpoints.registry import set_cache_headers
|
from endpoints.registry import set_cache_headers
|
||||||
from endpoints.trigger import CustomBuildTrigger, BitbucketBuildTrigger, TriggerProviderException
|
from endpoints.trigger import (CustomBuildTrigger, BitbucketBuildTrigger, TriggerProviderException,
|
||||||
|
BuildTriggerHandler)
|
||||||
from util.names import parse_repository_name, parse_repository_name_and_tag
|
from util.names import parse_repository_name, parse_repository_name_and_tag
|
||||||
from util.useremails import send_email_changed
|
from util.useremails import send_email_changed
|
||||||
from util.systemlogs import build_logs_archive
|
from util.systemlogs import build_logs_archive
|
||||||
|
@ -513,7 +514,7 @@ def attach_bitbucket_trigger(namespace, repository_name):
|
||||||
current_user.db_user())
|
current_user.db_user())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
oauth_info = BitbucketBuildTrigger.get_oauth_url(trigger.uuid)
|
oauth_info = BuildTriggerHandler.get_handler(trigger).get_oauth_url()
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
'access_token': oauth_info['access_token']
|
'access_token': oauth_info['access_token']
|
||||||
|
|
|
@ -9,7 +9,8 @@ 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, InvalidPayloadException
|
from endpoints.trigger import (BuildTriggerHandler, ValidationRequestException,
|
||||||
|
SkipRequestException, InvalidPayloadException)
|
||||||
from endpoints.common import start_build
|
from endpoints.common import start_build
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,11 +83,11 @@ def build_trigger_webhook(trigger_uuid, **kwargs):
|
||||||
repository = trigger.repository.name
|
repository = trigger.repository.name
|
||||||
permission = ModifyRepositoryPermission(namespace, repository)
|
permission = ModifyRepositoryPermission(namespace, repository)
|
||||||
if permission.can():
|
if permission.can():
|
||||||
handler = BuildTrigger.get_trigger_for_service(trigger.service.name)
|
handler = BuildTriggerHandler.get_handler(trigger)
|
||||||
|
|
||||||
logger.debug('Passing webhook request to handler %s', handler)
|
logger.debug('Passing webhook request to handler %s', handler)
|
||||||
try:
|
try:
|
||||||
specs = handler.handle_trigger_request(request, trigger)
|
specs = handler.handle_trigger_request(request)
|
||||||
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
|
||||||
|
|
88
static/css/directives/ui/trigger-setup-githost.css
Normal file
88
static/css/directives/ui/trigger-setup-githost.css
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
.trigger-setup-githost-element .ref-reference {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-reference span {
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-reference:hover {
|
||||||
|
color: #3276b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-reference:hover span {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-reference.match {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-reference.match span {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-filter {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-filter span {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .selected-info {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .org-icon {
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 8px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element li.repo-listing i {
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element li.org-header {
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .matching-refs {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
margin-left: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-matches {
|
||||||
|
padding-left: 70px;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .ref-matches .kind {
|
||||||
|
font-weight: bold;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .matching-refs.tags li:before {
|
||||||
|
content: "\f02b";
|
||||||
|
font-family: FontAwesome;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .matching-refs.branches li:before {
|
||||||
|
content: "\f126";
|
||||||
|
font-family: FontAwesome;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-setup-githost-element .matching-refs li {
|
||||||
|
list-style: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
|
@ -3768,95 +3768,6 @@ pre.command:before {
|
||||||
border-bottom-left-radius: 0px;
|
border-bottom-left-radius: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-reference {
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-reference span {
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-reference:hover {
|
|
||||||
color: #3276b1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-reference:hover span {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-reference.match {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-reference.match span {
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-filter {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-filter span {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .selected-info {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .github-org-icon {
|
|
||||||
width: 20px;
|
|
||||||
margin-right: 8px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element li.github-repo-listing i {
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element li.github-org-header {
|
|
||||||
padding-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .matching-refs {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
margin-left: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-matches {
|
|
||||||
padding-left: 70px;
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .ref-matches .kind {
|
|
||||||
font-weight: bold;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .matching-refs.tags li:before {
|
|
||||||
content: "\f02b";
|
|
||||||
font-family: FontAwesome;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .matching-refs.branches li:before {
|
|
||||||
content: "\f126";
|
|
||||||
font-family: FontAwesome;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-setup-github-element .matching-refs li {
|
|
||||||
list-style: none;
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-trigger-directive-element .dockerfile-found-content {
|
.setup-trigger-directive-element .dockerfile-found-content {
|
||||||
margin-left: 32px;
|
margin-left: 32px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,14 @@
|
||||||
<!-- Trigger-specific setup -->
|
<!-- Trigger-specific setup -->
|
||||||
<div class="trigger-description-element trigger-option-section" ng-switch on="trigger.service">
|
<div class="trigger-description-element trigger-option-section" ng-switch on="trigger.service">
|
||||||
<div ng-switch-when="github">
|
<div ng-switch-when="github">
|
||||||
<div class="trigger-setup-github" repository="repository" trigger="trigger"
|
<div class="trigger-setup-githost" repository="repository" trigger="trigger"
|
||||||
|
kind="github"
|
||||||
|
next-step-counter="nextStepCounter" current-step-valid="state.stepValid"
|
||||||
|
analyze="checkAnalyze(isValid)"></div>
|
||||||
|
</div>
|
||||||
|
<div ng-switch-when="bitbucket">
|
||||||
|
<div class="trigger-setup-githost" repository="repository" trigger="trigger"
|
||||||
|
kind="bitbucket"
|
||||||
next-step-counter="nextStepCounter" current-step-valid="state.stepValid"
|
next-step-counter="nextStepCounter" current-step-valid="state.stepValid"
|
||||||
analyze="checkAnalyze(isValid)"></div>
|
analyze="checkAnalyze(isValid)"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="trigger-setup-github-element">
|
<div class="trigger-setup-githost-element">
|
||||||
<!-- Current selected info -->
|
<!-- Current selected info -->
|
||||||
<div class="selected-info" ng-show="nextStepCounter > 0">
|
<div class="selected-info" ng-show="nextStepCounter > 0">
|
||||||
<table style="width: 100%;">
|
<table style="width: 100%;">
|
||||||
|
@ -8,9 +8,17 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="current-repo">
|
<div class="current-repo">
|
||||||
<img class="dropdown-select-icon github-org-icon"
|
<img class="dropdown-select-icon org-icon"
|
||||||
ng-src="{{ state.currentRepo.avatar_url ? state.currentRepo.avatar_url : '/static/img/empty.png' }}">
|
ng-src="{{ state.currentRepo.avatar_url ? state.currentRepo.avatar_url : '/static/img/empty.png' }}">
|
||||||
<a ng-href="https://github.com/{{ state.currentRepo.repo }}" target="_blank">{{ state.currentRepo.repo }}</a>
|
|
||||||
|
<!-- Kind Switch -->
|
||||||
|
<a ng-href="https://github.com/{{ state.currentRepo.repo }}" target="_blank" ng-if="kind == 'github'">
|
||||||
|
{{ state.currentRepo.repo }}
|
||||||
|
</a>
|
||||||
|
<a ng-href="https://bitbucket.org/{{ state.currentRepo.repo }}" target="_blank" ng-if="kind == 'bitbucket'">
|
||||||
|
{{ state.currentRepo.repo }}
|
||||||
|
</a>
|
||||||
|
<!-- /Kind Switch -->
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -47,21 +55,23 @@
|
||||||
<!-- Repository select -->
|
<!-- Repository select -->
|
||||||
<div class="step-view-step" complete-condition="state.currentRepo" load-callback="loadRepositories(callback)"
|
<div class="step-view-step" complete-condition="state.currentRepo" load-callback="loadRepositories(callback)"
|
||||||
load-message="Loading Repositories">
|
load-message="Loading Repositories">
|
||||||
<div style="margin-bottom: 12px">Please choose the GitHub repository that will trigger the build:</div>
|
<div style="margin-bottom: 12px">Please choose the repository that will trigger the build:</div>
|
||||||
<div class="dropdown-select" placeholder="'Enter or select a repository'" selected-item="state.currentRepo"
|
<div class="dropdown-select" placeholder="'Enter or select a repository'" selected-item="state.currentRepo"
|
||||||
lookahead-items="repoLookahead" allow-custom-input="true">
|
lookahead-items="repoLookahead" allow-custom-input="true">
|
||||||
<!-- Icons -->
|
<!-- Icons -->
|
||||||
<i class="dropdown-select-icon none-icon fa fa-github fa-lg"></i>
|
<i class="dropdown-select-icon none-icon fa fa-lg" ng-class="'fa-' + kind"></i>
|
||||||
<img class="dropdown-select-icon github-org-icon"
|
<img class="dropdown-select-icon org-icon"
|
||||||
ng-src="{{ state.currentRepo.avatar_url ? state.currentRepo.avatar_url : '/static/image/empty.png' }}">
|
ng-src="{{ state.currentRepo.avatar_url ? state.currentRepo.avatar_url : '/static/image/empty.png' }}">
|
||||||
|
|
||||||
<!-- Dropdown menu -->
|
<!-- Dropdown menu -->
|
||||||
<ul class="dropdown-select-menu scrollable-menu" role="menu">
|
<ul class="dropdown-select-menu scrollable-menu" role="menu">
|
||||||
<li ng-repeat-start="org in orgs" role="presentation" class="dropdown-header github-org-header">
|
<li ng-repeat-start="org in orgs" role="presentation" class="dropdown-header org-header">
|
||||||
<img ng-src="{{ org.info.avatar_url }}" class="github-org-icon">{{ org.info.name }}
|
<img ng-src="{{ org.info.avatar_url }}" class="org-icon">{{ org.info.name }}
|
||||||
</li>
|
</li>
|
||||||
<li ng-repeat="repo in org.repos" class="github-repo-listing">
|
<li ng-repeat="repo in org.repos" class="repo-listing">
|
||||||
<a href="javascript:void(0)" ng-click="selectRepo(repo, org)"><i class="fa fa-github fa-lg"></i> {{ repo }}</a>
|
<a href="javascript:void(0)" ng-click="selectRepo(repo, org)">
|
||||||
|
<i class="fa fa-lg" ng-class="'fa-' + kind"></i> {{ repo }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="divider" ng-repeat-end ng-show="$index < orgs.length - 1"></li>
|
<li role="presentation" class="divider" ng-repeat-end ng-show="$index < orgs.length - 1"></li>
|
||||||
</ul>
|
</ul>
|
|
@ -1,16 +1,17 @@
|
||||||
/**
|
/**
|
||||||
* An element which displays github-specific setup information for its build triggers.
|
* An element which displays hosted Git (GitHub, Bitbucket)-specific setup information for its build triggers.
|
||||||
*/
|
*/
|
||||||
angular.module('quay').directive('triggerSetupGithub', function () {
|
angular.module('quay').directive('triggerSetupGithost', function () {
|
||||||
var directiveDefinitionObject = {
|
var directiveDefinitionObject = {
|
||||||
priority: 0,
|
priority: 0,
|
||||||
templateUrl: '/static/directives/trigger-setup-github.html',
|
templateUrl: '/static/directives/trigger-setup-githost.html',
|
||||||
replace: false,
|
replace: false,
|
||||||
transclude: false,
|
transclude: false,
|
||||||
restrict: 'C',
|
restrict: 'C',
|
||||||
scope: {
|
scope: {
|
||||||
'repository': '=repository',
|
'repository': '=repository',
|
||||||
'trigger': '=trigger',
|
'trigger': '=trigger',
|
||||||
|
'kind': '@kind',
|
||||||
|
|
||||||
'nextStepCounter': '=nextStepCounter',
|
'nextStepCounter': '=nextStepCounter',
|
||||||
'currentStepValid': '=currentStepValid',
|
'currentStepValid': '=currentStepValid',
|
Reference in a new issue