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:
parent
21b09a7451
commit
8e863b8cf5
47 changed files with 1835 additions and 1068 deletions
|
@ -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 []
|
||||
|
||||
|
|
Reference in a new issue