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:
jakedt 2014-02-19 16:08:33 -05:00
parent f60f9eb62a
commit 9e426816a5
7 changed files with 94 additions and 43 deletions

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -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.