Pass trigger information on build status. Set up a trigger for the sample building repository. Allow to list the builds started from a trigger. Protect the callback with the proper auth for creating a trigger on a repo.
This commit is contained in:
parent
f60f9eb62a
commit
9e426816a5
7 changed files with 94 additions and 43 deletions
|
@ -230,6 +230,7 @@ class RepositoryBuild(BaseModel):
|
||||||
phase = CharField(default='waiting')
|
phase = CharField(default='waiting')
|
||||||
started = DateTimeField(default=datetime.now)
|
started = DateTimeField(default=datetime.now)
|
||||||
display_name = CharField()
|
display_name = CharField()
|
||||||
|
trigger = ForeignKeyField(RepositoryBuildTrigger, null=True, index=True)
|
||||||
|
|
||||||
|
|
||||||
class QueueItem(BaseModel):
|
class QueueItem(BaseModel):
|
||||||
|
|
|
@ -1299,35 +1299,38 @@ def load_token_data(code):
|
||||||
|
|
||||||
|
|
||||||
def get_repository_build(namespace_name, repository_name, build_uuid):
|
def get_repository_build(namespace_name, repository_name, build_uuid):
|
||||||
joined = RepositoryBuild.select().join(Repository)
|
try:
|
||||||
fetched = list(joined.where(Repository.name == repository_name,
|
query = list_repository_builds(namespace_name, repository_name)
|
||||||
Repository.namespace == namespace_name,
|
return query.where(RepositoryBuild.uuid == build_uuid).get()
|
||||||
RepositoryBuild.uuid == build_uuid))
|
|
||||||
|
|
||||||
if not fetched:
|
except RepositoryBuild.DoesNotExist:
|
||||||
msg = 'Unable to locate a build by id: %s' % build_uuid
|
msg = 'Unable to locate a build by id: %s' % build_uuid
|
||||||
raise InvalidRepositoryBuildException(msg)
|
raise InvalidRepositoryBuildException(msg)
|
||||||
|
|
||||||
return fetched[0]
|
|
||||||
|
|
||||||
|
|
||||||
def list_repository_builds(namespace_name, repository_name,
|
def list_repository_builds(namespace_name, repository_name,
|
||||||
include_inactive=True):
|
include_inactive=True):
|
||||||
joined = RepositoryBuild.select().join(Repository)
|
query = (RepositoryBuild
|
||||||
filtered = joined
|
.select(RepositoryBuild, RepositoryBuildTrigger, BuildTriggerService)
|
||||||
|
.join(Repository)
|
||||||
|
.switch(RepositoryBuild)
|
||||||
|
.join(RepositoryBuildTrigger, JOIN_LEFT_OUTER)
|
||||||
|
.join(BuildTriggerService, JOIN_LEFT_OUTER)
|
||||||
|
.where(Repository.name == repository_name,
|
||||||
|
Repository.namespace == namespace_name))
|
||||||
|
|
||||||
if not include_inactive:
|
if not include_inactive:
|
||||||
filtered = filtered.where(RepositoryBuild.phase != 'error',
|
query = query.where(RepositoryBuild.phase != 'error',
|
||||||
RepositoryBuild.phase != 'complete')
|
RepositoryBuild.phase != 'complete')
|
||||||
fetched = list(filtered.where(Repository.name == repository_name,
|
|
||||||
Repository.namespace == namespace_name))
|
return query
|
||||||
return fetched
|
|
||||||
|
|
||||||
|
|
||||||
def create_repository_build(repo, access_token, resource_key, tag,
|
def create_repository_build(repo, access_token, resource_key, tag,
|
||||||
display_name):
|
display_name, trigger=None):
|
||||||
return RepositoryBuild.create(repository=repo, access_token=access_token,
|
return RepositoryBuild.create(repository=repo, access_token=access_token,
|
||||||
resource_key=resource_key, tag=tag,
|
resource_key=resource_key, tag=tag,
|
||||||
display_name=display_name)
|
display_name=display_name, trigger=trigger)
|
||||||
|
|
||||||
|
|
||||||
def create_webhook(repo, params_obj):
|
def create_webhook(repo, params_obj):
|
||||||
|
@ -1386,11 +1389,8 @@ def log_action(kind_name, user_or_organization_name, performer=None,
|
||||||
metadata_json=json.dumps(metadata), datetime=timestamp)
|
metadata_json=json.dumps(metadata), datetime=timestamp)
|
||||||
|
|
||||||
|
|
||||||
def create_build_trigger(namespace_name, repository_name, service_name,
|
def create_build_trigger(repo, service_name, auth_token, user):
|
||||||
auth_token, user):
|
|
||||||
service = BuildTriggerService.get(name=service_name)
|
service = BuildTriggerService.get(name=service_name)
|
||||||
repo = Repository.get(namespace=namespace_name, name=repository_name)
|
|
||||||
|
|
||||||
trigger = RepositoryBuildTrigger.create(repository=repo, service=service,
|
trigger = RepositoryBuildTrigger.create(repository=repo, service=service,
|
||||||
auth_token=auth_token,
|
auth_token=auth_token,
|
||||||
connected_user=user)
|
connected_user=user)
|
||||||
|
@ -1428,3 +1428,14 @@ 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)
|
||||||
trigger.delete_instance()
|
trigger.delete_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def list_trigger_builds(namespace_name, repository_name, trigger_uuid,
|
||||||
|
limit=None):
|
||||||
|
query = (list_repository_builds(namespace_name, repository_name)
|
||||||
|
.where(RepositoryBuildTrigger.uuid == trigger_uuid))
|
||||||
|
|
||||||
|
if limit:
|
||||||
|
return query.limit(limit)
|
||||||
|
else:
|
||||||
|
return query
|
||||||
|
|
|
@ -1110,7 +1110,7 @@ def get_repo(namespace, repository):
|
||||||
'can_write': can_write,
|
'can_write': can_write,
|
||||||
'can_admin': can_admin,
|
'can_admin': can_admin,
|
||||||
'is_public': is_public,
|
'is_public': is_public,
|
||||||
'is_building': len(active_builds) > 0,
|
'is_building': len(list(active_builds)) > 0,
|
||||||
'is_organization': bool(organization)
|
'is_organization': bool(organization)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1118,6 +1118,18 @@ def get_repo(namespace, repository):
|
||||||
abort(403) # Permission denied
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_view(trigger):
|
||||||
|
if trigger and trigger.uuid:
|
||||||
|
return {
|
||||||
|
'service': trigger.service.name,
|
||||||
|
'config': json.loads(trigger.config),
|
||||||
|
'id': trigger.uuid,
|
||||||
|
'connected_user': trigger.connected_user.username,
|
||||||
|
}
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def build_status_view(build_obj, can_write=False):
|
def build_status_view(build_obj, can_write=False):
|
||||||
status = build_logs.get_status(build_obj.uuid)
|
status = build_logs.get_status(build_obj.uuid)
|
||||||
return {
|
return {
|
||||||
|
@ -1127,7 +1139,8 @@ def build_status_view(build_obj, can_write=False):
|
||||||
'display_name': build_obj.display_name,
|
'display_name': build_obj.display_name,
|
||||||
'status': status,
|
'status': status,
|
||||||
'resource_key': build_obj.resource_key if can_write else None,
|
'resource_key': build_obj.resource_key if can_write else None,
|
||||||
'is_writer': can_write
|
'is_writer': can_write,
|
||||||
|
'trigger': trigger_view(build_obj.trigger),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1328,15 +1341,6 @@ def delete_webhook(namespace, repository, public_id):
|
||||||
abort(403) # Permission denied
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
|
||||||
def trigger_view(trigger):
|
|
||||||
return {
|
|
||||||
'service': trigger.service.name,
|
|
||||||
'config': json.loads(trigger.config),
|
|
||||||
'id': trigger.uuid,
|
|
||||||
'connected_user': trigger.connected_user.username,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>',
|
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>',
|
||||||
methods=['GET'])
|
methods=['GET'])
|
||||||
@api_login_required
|
@api_login_required
|
||||||
|
@ -1354,6 +1358,22 @@ def get_build_trigger(namespace, repository, trigger_uuid):
|
||||||
abort(403) # Permission denied
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
|
||||||
|
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/builds',
|
||||||
|
methods=['GET'])
|
||||||
|
@api_login_required
|
||||||
|
@parse_repository_name
|
||||||
|
def list_trigger_recent_builds(namespace, repository, trigger_uuid):
|
||||||
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
|
if permission.can():
|
||||||
|
limit = request.args.get('limit', 5)
|
||||||
|
builds = model.list_trigger_builds(namespace, repository, trigger_uuid,
|
||||||
|
limit)
|
||||||
|
return jsonify({
|
||||||
|
'builds': [build_status_view(build, True) for build in builds]
|
||||||
|
})
|
||||||
|
|
||||||
|
abort(403) # Permission denied
|
||||||
|
|
||||||
@api.route('/repository/<path:repository>/trigger/', methods=['GET'])
|
@api.route('/repository/<path:repository>/trigger/', methods=['GET'])
|
||||||
@api_login_required
|
@api_login_required
|
||||||
@parse_repository_name
|
@parse_repository_name
|
||||||
|
|
|
@ -7,6 +7,8 @@ from endpoints.common import render_page_template, common_login
|
||||||
from app import app, mixpanel
|
from app import app, mixpanel
|
||||||
from data import model
|
from data import model
|
||||||
from util.names import parse_repository_name
|
from util.names import parse_repository_name
|
||||||
|
from util.http import abort
|
||||||
|
from auth.permissions import AdministerRepositoryPermission
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -113,10 +115,18 @@ def github_oauth_attach():
|
||||||
@login_required
|
@login_required
|
||||||
@parse_repository_name
|
@parse_repository_name
|
||||||
def attach_github_build_trigger(namespace, repository):
|
def attach_github_build_trigger(namespace, repository):
|
||||||
token = exchange_github_code_for_token(request.args.get('code'))
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
model.create_build_trigger(namespace, repository, 'github', token,
|
if permission.can():
|
||||||
current_user.db_user())
|
token = exchange_github_code_for_token(request.args.get('code'))
|
||||||
admin_path = '%s/%s/%s' % (namespace, repository, 'admin')
|
repo = model.get_repository(namespace, repository)
|
||||||
full_url = url_for('web.repository', path=admin_path) + '?tab=trigger'
|
if not repo:
|
||||||
logger.debug('Redirecting to full url: %s' % full_url)
|
msg = 'Invalid repository: %s/%s' % (namespace, repository)
|
||||||
return redirect(full_url)
|
abort(404, message=msg)
|
||||||
|
|
||||||
|
model.create_build_trigger(repo, 'github', token, current_user.db_user())
|
||||||
|
admin_path = '%s/%s/%s' % (namespace, repository, 'admin')
|
||||||
|
full_url = url_for('web.repository', path=admin_path) + '?tab=trigger'
|
||||||
|
logger.debug('Redirecting to full url: %s' % full_url)
|
||||||
|
return redirect(full_url)
|
||||||
|
|
||||||
|
abort(403)
|
|
@ -30,10 +30,10 @@ class BuildTrigger(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def list_repositories(self, auth_token):
|
def list_build_sources(self, auth_token):
|
||||||
"""
|
"""
|
||||||
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 repositories.
|
list of build sources(repositories).
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
def service_name(cls):
|
def service_name(cls):
|
||||||
return 'github'
|
return 'github'
|
||||||
|
|
||||||
def list_repositories(self, auth_token):
|
def list_build_sources(self, auth_token):
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client(auth_token)
|
||||||
usr = gh_client.get_user()
|
usr = gh_client.get_user()
|
||||||
|
|
||||||
|
|
13
initdb.py
13
initdb.py
|
@ -281,8 +281,17 @@ def populate_database():
|
||||||
|
|
||||||
token = model.create_access_token(building, 'write')
|
token = model.create_access_token(building, 'write')
|
||||||
tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name)
|
tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name)
|
||||||
build = model.create_repository_build(building, token, '701dcc3724fb4f2ea6c31400528343cd',
|
|
||||||
tag, 'build-name')
|
trigger = model.create_build_trigger(building, 'github', '123authtoken',
|
||||||
|
new_user_1)
|
||||||
|
trigger.config = json.dumps({
|
||||||
|
'build_source': 'jakedt/testconnect',
|
||||||
|
})
|
||||||
|
trigger.save()
|
||||||
|
|
||||||
|
build = model.create_repository_build(building, token,
|
||||||
|
'701dcc3724fb4f2ea6c31400528343cd',
|
||||||
|
tag, 'build-name', trigger)
|
||||||
build.uuid = 'deadbeef-dead-beef-dead-beefdeadbeef'
|
build.uuid = 'deadbeef-dead-beef-dead-beefdeadbeef'
|
||||||
build.save()
|
build.save()
|
||||||
|
|
||||||
|
|
Binary file not shown.
Reference in a new issue