Implement new create and manager trigger UI

Implements the new trigger setup user interface, which is now a linear workflow found on its own page, rather than a tiny modal dialog

Fixes #1187
This commit is contained in:
Joseph Schorr 2016-09-27 16:52:34 +02:00
parent 21b09a7451
commit 8e863b8cf5
47 changed files with 1835 additions and 1068 deletions

View file

@ -1,6 +1,10 @@
import logging
from calendar import timegm
from functools import wraps
import dateutil.parser
from app import app, gitlab_trigger
from jsonschema import validate
@ -70,6 +74,17 @@ GITLAB_WEBHOOK_PAYLOAD_SCHEMA = {
'required': ['ref', 'checkout_sha', 'repository'],
}
_ACCESS_LEVEL_MAP = {
50: ("owner", True),
40: ("master", True),
30: ("developer", False),
20: ("reporter", False),
10: ("guest", False),
}
_PER_PAGE_COUNT = 20
def _catch_timeouts(func):
@wraps(func)
def wrapper(*args, **kwargs):
@ -82,6 +97,27 @@ def _catch_timeouts(func):
return wrapper
def _paginated_iterator(func, exc):
""" Returns an iterator over invocations of the given function, automatically handling
pagination.
"""
page = 0
while True:
result = func(page=page, per_page=_PER_PAGE_COUNT)
if result is False:
raise exc
counter = 0
for item in result:
yield item
counter = counter + 1
if counter < _PER_PAGE_COUNT:
break
page = page + 1
def get_transformed_webhook_payload(gl_payload, default_branch=None, lookup_user=None,
lookup_commit=None):
""" Returns the Gitlab webhook JSON payload transformed into our own payload
@ -223,35 +259,57 @@ class GitLabBuildTrigger(BuildTriggerHandler):
config.pop('key_id', None)
self.config = config
return config
@_catch_timeouts
def list_build_sources(self):
def list_build_source_namespaces(self):
gl_client = self._get_authorized_client()
current_user = gl_client.currentuser()
if current_user is False:
raise RepositoryReadException('Unable to get current user')
repositories = gl_client.getprojects()
if repositories is False:
raise RepositoryReadException('Unable to list user repositories')
namespaces = {}
repositories = _paginated_iterator(gl_client.getprojects, RepositoryReadException)
for repo in repositories:
owner = repo['namespace']['name']
if not owner in namespaces:
namespaces[owner] = {
namespace = repo['namespace']
namespace_id = namespace['id']
if namespace_id in namespaces:
namespaces[namespace_id]['score'] = namespaces[namespace_id]['score'] + 1
else:
owner = repo['namespace']['name']
namespaces[namespace_id] = {
'personal': owner == current_user['username'],
'repos': [],
'info': {
'name': owner,
}
'id': namespace['path'],
'title': namespace['name'],
'avatar_url': repo['owner']['avatar_url'],
'score': 0,
}
namespaces[owner]['repos'].append(repo['path_with_namespace'])
return list(namespaces.values())
return namespaces.values()
@_catch_timeouts
def list_build_sources_for_namespace(self, namespace):
def repo_view(repo):
last_modified = dateutil.parser.parse(repo['last_activity_at'])
has_admin_permission = False
if repo.get('permissions'):
access_level = repo['permissions']['project_access']['access_level']
has_admin_permission = _ACCESS_LEVEL_MAP.get(access_level, ("", False))[1]
return {
'name': repo['path'],
'full_name': repo['path_with_namespace'],
'description': repo['description'] or '',
'last_updated': timegm(last_modified.utctimetuple()),
'url': repo['web_url'],
'has_admin_permissions': has_admin_permission,
'private': repo['public'] is False,
}
gl_client = self._get_authorized_client()
repositories = _paginated_iterator(gl_client.getprojects, RepositoryReadException)
return [repo_view(repo) for repo in repositories if repo['namespace']['path'] == namespace]
@_catch_timeouts
def list_build_subdirs(self):
@ -280,7 +338,7 @@ class GitLabBuildTrigger(BuildTriggerHandler):
for node in repo_tree:
if node['name'] == 'Dockerfile':
return ['/']
return ['']
return []