Write triggers are successfully installing on GitHub, noice!
This commit is contained in:
parent
a6400171b3
commit
86e93a2c0f
7 changed files with 76 additions and 32 deletions
|
@ -206,6 +206,8 @@ class TestConfig(FlaskConfig, FakeStorage, EphemeralDB, FakeUserfiles,
|
||||||
LOGGING_CONFIG = logs_init_builder(logging.WARN)
|
LOGGING_CONFIG = logs_init_builder(logging.WARN)
|
||||||
POPULATE_DB_TEST_DATA = True
|
POPULATE_DB_TEST_DATA = True
|
||||||
TESTING = True
|
TESTING = True
|
||||||
|
URL_SCHEME = 'http'
|
||||||
|
URL_HOST = 'localhost:5000'
|
||||||
|
|
||||||
|
|
||||||
class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB,
|
class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB,
|
||||||
|
@ -215,6 +217,8 @@ class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB,
|
||||||
LOGGING_CONFIG = logs_init_builder(formatter=logging.Formatter())
|
LOGGING_CONFIG = logs_init_builder(formatter=logging.Formatter())
|
||||||
SEND_FILE_MAX_AGE_DEFAULT = 0
|
SEND_FILE_MAX_AGE_DEFAULT = 0
|
||||||
POPULATE_DB_TEST_DATA = True
|
POPULATE_DB_TEST_DATA = True
|
||||||
|
URL_SCHEME = 'http'
|
||||||
|
URL_HOST = 'ci.devtable.com:5000'
|
||||||
|
|
||||||
|
|
||||||
class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL,
|
class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL,
|
||||||
|
@ -224,6 +228,8 @@ class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL,
|
||||||
UserEventConfig, LargePoolHttpClient):
|
UserEventConfig, LargePoolHttpClient):
|
||||||
LOGGING_CONFIG = logs_init_builder()
|
LOGGING_CONFIG = logs_init_builder()
|
||||||
SEND_FILE_MAX_AGE_DEFAULT = 0
|
SEND_FILE_MAX_AGE_DEFAULT = 0
|
||||||
|
URL_SCHEME = 'http'
|
||||||
|
URL_HOST = 'ci.devtable.com:5000'
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(FlaskProdConfig, MailConfig, S3Storage, RDSMySQL,
|
class ProductionConfig(FlaskProdConfig, MailConfig, S3Storage, RDSMySQL,
|
||||||
|
@ -234,3 +240,5 @@ class ProductionConfig(FlaskProdConfig, MailConfig, S3Storage, RDSMySQL,
|
||||||
|
|
||||||
LOGGING_CONFIG = logs_init_builder()
|
LOGGING_CONFIG = logs_init_builder()
|
||||||
SEND_FILE_MAX_AGE_DEFAULT = 0
|
SEND_FILE_MAX_AGE_DEFAULT = 0
|
||||||
|
URL_SCHEME = 'https'
|
||||||
|
URL_HOST = 'quay.io'
|
||||||
|
|
|
@ -110,19 +110,6 @@ class Repository(BaseModel):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BuildTriggerService(BaseModel):
|
|
||||||
name = CharField(index=True)
|
|
||||||
|
|
||||||
|
|
||||||
class RepositoryBuildTrigger(BaseModel):
|
|
||||||
uuid = CharField(default=uuid_generator)
|
|
||||||
service = ForeignKeyField(BuildTriggerService, index=True)
|
|
||||||
repository = ForeignKeyField(Repository, index=True)
|
|
||||||
connected_user = ForeignKeyField(User)
|
|
||||||
auth_token = CharField()
|
|
||||||
config = TextField(default='{}')
|
|
||||||
|
|
||||||
|
|
||||||
class Role(BaseModel):
|
class Role(BaseModel):
|
||||||
name = CharField(index=True)
|
name = CharField(index=True)
|
||||||
|
|
||||||
|
@ -176,6 +163,20 @@ class AccessToken(BaseModel):
|
||||||
temporary = BooleanField(default=True)
|
temporary = BooleanField(default=True)
|
||||||
|
|
||||||
|
|
||||||
|
class BuildTriggerService(BaseModel):
|
||||||
|
name = CharField(index=True)
|
||||||
|
|
||||||
|
|
||||||
|
class RepositoryBuildTrigger(BaseModel):
|
||||||
|
uuid = CharField(default=uuid_generator)
|
||||||
|
service = ForeignKeyField(BuildTriggerService, index=True)
|
||||||
|
repository = ForeignKeyField(Repository, index=True)
|
||||||
|
connected_user = ForeignKeyField(User)
|
||||||
|
auth_token = CharField()
|
||||||
|
config = TextField(default='{}')
|
||||||
|
write_token = ForeignKeyField(AccessToken, null=True)
|
||||||
|
|
||||||
|
|
||||||
class EmailConfirmation(BaseModel):
|
class EmailConfirmation(BaseModel):
|
||||||
code = CharField(default=random_string_generator(), unique=True, index=True)
|
code = CharField(default=random_string_generator(), unique=True, index=True)
|
||||||
user = ForeignKeyField(User)
|
user = ForeignKeyField(User)
|
||||||
|
|
|
@ -1320,8 +1320,9 @@ def create_access_token(repository, role):
|
||||||
return new_token
|
return new_token
|
||||||
|
|
||||||
|
|
||||||
def create_delegate_token(namespace_name, repository_name, friendly_name):
|
def create_delegate_token(namespace_name, repository_name, friendly_name,
|
||||||
read_only = Role.get(name='read')
|
role='read'):
|
||||||
|
read_only = Role.get(name=role)
|
||||||
repo = Repository.get(Repository.name == repository_name,
|
repo = Repository.get(Repository.name == repository_name,
|
||||||
Repository.namespace == namespace_name)
|
Repository.namespace == namespace_name)
|
||||||
new_token = AccessToken.create(repository=repo, role=read_only,
|
new_token = AccessToken.create(repository=repo, role=read_only,
|
||||||
|
@ -1509,6 +1510,11 @@ def list_build_triggers(namespace_name, repository_name):
|
||||||
|
|
||||||
def delete_build_trigger(namespace_name, repository_name, trigger_uuid):
|
def delete_build_trigger(namespace_name, repository_name, trigger_uuid):
|
||||||
trigger = get_build_trigger(namespace_name, repository_name, trigger_uuid)
|
trigger = get_build_trigger(namespace_name, repository_name, trigger_uuid)
|
||||||
|
|
||||||
|
# Delete the access token created for this trigger, and the trigger itself
|
||||||
|
if trigger.write_token and trigger.write_token.code:
|
||||||
|
trigger.write_token.delete_instance()
|
||||||
|
|
||||||
trigger.delete_instance()
|
trigger.delete_instance()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ from flask.ext.login import current_user, logout_user
|
||||||
from flask.ext.principal import identity_changed, AnonymousIdentity
|
from flask.ext.principal import identity_changed, AnonymousIdentity
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from urllib import quote
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
from data.queue import dockerfile_build_queue
|
from data.queue import dockerfile_build_queue
|
||||||
|
@ -1363,6 +1364,11 @@ def get_build_trigger(namespace, repository, trigger_uuid):
|
||||||
abort(403) # Permission denied
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_webhook_url(scheme, username, password, hostname, path):
|
||||||
|
auth_hostname = '%s:%s@%s' % (quote(username), quote(password), hostname)
|
||||||
|
return urlparse.urlunparse((scheme, auth_hostname, path, '', '', ''))
|
||||||
|
|
||||||
|
|
||||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/activate',
|
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/activate',
|
||||||
methods=['POST'])
|
methods=['POST'])
|
||||||
@api_login_required
|
@api_login_required
|
||||||
|
@ -1386,20 +1392,29 @@ def activate_build_trigger(namespace, repository, trigger_uuid):
|
||||||
if user_permission.can():
|
if user_permission.can():
|
||||||
new_config_dict = request.get_json()
|
new_config_dict = request.get_json()
|
||||||
|
|
||||||
|
token_name = 'Build Trigger: %s' % trigger.service.name
|
||||||
|
token = model.create_delegate_token(namespace, repository, token_name,
|
||||||
|
'write')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
repository = '%s/%s' % (trigger.repository.namespace,
|
repository = '%s/%s' % (trigger.repository.namespace,
|
||||||
trigger.repository.name)
|
trigger.repository.name)
|
||||||
webhook_url = url_for('webhooks.build_trigger_webhook',
|
path = url_for('webhooks.build_trigger_webhook', repository=repository,
|
||||||
repository=repository, trigger_uuid=trigger.uuid,
|
trigger_uuid=trigger.uuid)
|
||||||
_external=True)
|
authed_url = _prepare_webhook_url(app.config['URL_SCHEME'], '$token',
|
||||||
handler.activate(trigger.uuid, webhook_url, trigger.auth_token,
|
token.code, app.config['URL_HOST'],
|
||||||
|
path)
|
||||||
|
|
||||||
|
handler.activate(trigger.uuid, authed_url, trigger.auth_token,
|
||||||
new_config_dict)
|
new_config_dict)
|
||||||
except TriggerActivationException as e:
|
except TriggerActivationException as e:
|
||||||
|
token.delete_instance()
|
||||||
abort(400, message = e.msg)
|
abort(400, message = e.msg)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Save the updated config.
|
# Save the updated config.
|
||||||
trigger.config = json.dumps(new_config_dict)
|
trigger.config = json.dumps(new_config_dict)
|
||||||
|
trigger.write_token = token
|
||||||
trigger.save()
|
trigger.save()
|
||||||
|
|
||||||
return jsonify(trigger_view(trigger))
|
return jsonify(trigger_view(trigger))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import io
|
import io
|
||||||
|
|
||||||
from github import Github
|
from github import Github, UnknownObjectException, GithubException
|
||||||
from tempfile import SpooledTemporaryFile
|
from tempfile import SpooledTemporaryFile
|
||||||
|
|
||||||
from app import app
|
from app import app
|
||||||
|
@ -27,6 +27,9 @@ class InvalidServiceException(Exception):
|
||||||
class TriggerActivationException(Exception):
|
class TriggerActivationException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ValidationRequestException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BuildTrigger(object):
|
class BuildTrigger(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -97,17 +100,20 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
to_add_webhook = gh_client.get_repo(new_build_source)
|
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 = {
|
webhook_config = {
|
||||||
'url': standard_webhook_url,
|
'url': standard_webhook_url,
|
||||||
'content_type': 'json',
|
'content_type': 'json',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
to_add_webhook.create_hook('web', webhook_config)
|
to_add_webhook.create_hook('web', webhook_config)
|
||||||
|
except GithubException:
|
||||||
|
msg = 'Unable to create webhook on repository: %s'
|
||||||
except Exception:
|
raise TriggerActivationException(msg % new_build_source)
|
||||||
pass
|
|
||||||
|
|
||||||
def list_build_sources(self, auth_token):
|
def list_build_sources(self, auth_token):
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client(auth_token)
|
||||||
|
@ -142,6 +148,10 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
|
|
||||||
def handle_trigger_request(self, request, auth_token, config):
|
def handle_trigger_request(self, request, auth_token, config):
|
||||||
payload = request.get_json()
|
payload = request.get_json()
|
||||||
|
|
||||||
|
if 'zen' in payload:
|
||||||
|
raise ValidationRequestException()
|
||||||
|
|
||||||
logger.debug('Payload %s', payload)
|
logger.debug('Payload %s', payload)
|
||||||
ref = payload['ref']
|
ref = payload['ref']
|
||||||
commit_id = payload['head_commit']['id'][0:7]
|
commit_id = payload['head_commit']['id'][0:7]
|
||||||
|
|
|
@ -11,7 +11,7 @@ from util.invoice import renderInvoiceToHtml
|
||||||
from util.email import send_invoice_email
|
from util.email import send_invoice_email
|
||||||
from util.names import parse_repository_name
|
from util.names import parse_repository_name
|
||||||
from util.http import abort
|
from util.http import abort
|
||||||
from endpoints.trigger import BuildTrigger
|
from endpoints.trigger import BuildTrigger, ValidationRequestException
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -61,9 +61,13 @@ def build_trigger_webhook(namespace, repository, trigger_uuid):
|
||||||
handler = BuildTrigger.get_trigger_for_service(trigger.service.name)
|
handler = BuildTrigger.get_trigger_for_service(trigger.service.name)
|
||||||
|
|
||||||
logger.debug('Passing webhook request to handler %s', handler)
|
logger.debug('Passing webhook request to handler %s', handler)
|
||||||
df_id, tag, name = handler.handle_trigger_request(request,
|
try:
|
||||||
trigger.auth_token,
|
df_id, tag, name = handler.handle_trigger_request(request,
|
||||||
trigger.config)
|
trigger.auth_token,
|
||||||
|
trigger.config)
|
||||||
|
except ValidationRequestException:
|
||||||
|
# This was just a validation request, don't need to build anything
|
||||||
|
return make_response('Okay')
|
||||||
|
|
||||||
host = urlparse.urlparse(request.url).netloc
|
host = urlparse.urlparse(request.url).netloc
|
||||||
full_tag = '%s/%s/%s:%s' % (host, trigger.repository.namespace,
|
full_tag = '%s/%s/%s:%s' % (host, trigger.repository.namespace,
|
||||||
|
|
Binary file not shown.
Reference in a new issue