integrations: add repo group integrations, fixes #4175

This commit is contained in:
Daniel Dourvaris 2016-08-15 13:24:16 +03:00
parent 2a0ed7c3dc
commit 2e3256ff49
7 changed files with 138 additions and 13 deletions

View file

@ -20,7 +20,7 @@
import logging
from rhodecode.model.db import Repository, Integration
from rhodecode.model.db import Repository, Integration, RepoGroup
from rhodecode.config.routing import (
ADMIN_PREFIX, add_route_requirements, URL_NAME_REQUIREMENTS)
from rhodecode.integrations import integration_type_registry
@ -29,6 +29,8 @@ log = logging.getLogger(__name__)
def includeme(config):
# global integrations
config.add_route('global_integrations_home',
ADMIN_PREFIX + '/integrations')
config.add_route('global_integrations_list',
@ -58,6 +60,8 @@ def includeme(config):
request_method='POST',
route_name=route_name)
# repo integrations
config.add_route('repo_integrations_home',
add_route_requirements(
'{repo_name}/settings/integrations',
@ -101,26 +105,87 @@ def includeme(config):
route_name=route_name)
# repo group integrations
config.add_route('repo_group_integrations_home',
add_route_requirements(
'{repo_group_name}/settings/integrations',
URL_NAME_REQUIREMENTS
),
custom_predicates=(valid_repo_group,))
config.add_route('repo_group_integrations_list',
add_route_requirements(
'{repo_group_name}/settings/integrations/{integration}',
URL_NAME_REQUIREMENTS
),
custom_predicates=(valid_repo_group, valid_integration))
for route_name in ['repo_group_integrations_home', 'repo_group_integrations_list']:
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='index',
request_method='GET',
route_name=route_name)
config.add_route('repo_group_integrations_create',
add_route_requirements(
'{repo_group_name}/settings/integrations/{integration}/new',
URL_NAME_REQUIREMENTS
),
custom_predicates=(valid_repo_group, valid_integration))
config.add_route('repo_group_integrations_edit',
add_route_requirements(
'{repo_group_name}/settings/integrations/{integration}/{integration_id}',
URL_NAME_REQUIREMENTS
),
custom_predicates=(valid_repo_group, valid_integration))
for route_name in ['repo_group_integrations_edit', 'repo_group_integrations_create']:
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_get',
renderer='rhodecode:templates/admin/integrations/edit.html',
request_method='GET',
route_name=route_name)
config.add_view('rhodecode.integrations.views.RepoGroupIntegrationsView',
attr='settings_post',
renderer='rhodecode:templates/admin/integrations/edit.html',
request_method='POST',
route_name=route_name)
def valid_repo(info, request):
repo = Repository.get_by_repo_name(info['match']['repo_name'])
if repo:
return True
def valid_repo_group(info, request):
repo_group = RepoGroup.get_by_group_name(info['match']['repo_group_name'])
if repo_group:
return True
return False
def valid_integration(info, request):
integration_type = info['match']['integration']
integration_id = info['match'].get('integration_id')
repo_name = info['match'].get('repo_name')
repo_group_name = info['match'].get('repo_group_name')
if integration_type not in integration_type_registry:
return False
repo = None
repo, repo_group = None, None
if repo_name:
repo = Repository.get_by_repo_name(info['match']['repo_name'])
repo = Repository.get_by_repo_name(repo_name)
if not repo:
return False
if repo_group_name:
repo_group = RepoGroup.get_by_group_name(repo_group_name)
if not repo_group:
return False
if repo_name and repo_group:
raise Exception('Either repo or repo_group can be set, not both')
if integration_id:
integration = Integration.get(integration_id)
if not integration:
@ -129,5 +194,7 @@ def valid_integration(info, request):
return False
if repo and repo.repo_id != integration.repo_id:
return False
if repo_group and repo_group.repo_group_id != integration.repo_group_id:
return False
return True

View file

@ -29,7 +29,7 @@ from pyramid.response import Response
from rhodecode.lib import auth
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
from rhodecode.model.db import Repository, Session, Integration
from rhodecode.model.db import Repository, RepoGroup, Session, Integration
from rhodecode.model.scm import ScmModel
from rhodecode.model.integration import IntegrationModel
from rhodecode.admin.navigation import navigation_list
@ -59,6 +59,7 @@ class IntegrationSettingsViewBase(object):
self.IntegrationType = None
self.repo = None
self.repo_group = None
self.integration = None
self.integrations = {}
@ -68,6 +69,10 @@ class IntegrationSettingsViewBase(object):
repo_name = request.matchdict['repo_name']
self.repo = Repository.get_by_repo_name(repo_name)
if 'repo_group_name' in request.matchdict: # we're in repo_group context
repo_group_name = request.matchdict['repo_group_name']
self.repo_group = RepoGroup.get_by_group_name(repo_group_name)
if 'integration' in request.matchdict: # we're in integration context
integration_type = request.matchdict['integration']
self.IntegrationType = integration_type_registry[integration_type]
@ -76,7 +81,10 @@ class IntegrationSettingsViewBase(object):
integration_id = request.matchdict['integration_id']
self.integration = Integration.get(integration_id)
else: # list integrations context
for integration in IntegrationModel().get_integrations(self.repo):
integrations = IntegrationModel().get_integrations(
repo=self.repo, repo_group=self.repo_group)
for integration in integrations:
self.integrations.setdefault(integration.integration_type, []
).append(integration)
@ -91,7 +99,9 @@ class IntegrationSettingsViewBase(object):
c.active = 'integrations'
c.rhodecode_user = self.request.user
c.repo = self.repo
c.repo_group = self.repo_group
c.repo_name = self.repo and self.repo.repo_name or None
c.repo_group_name = self.repo_group and self.repo_group.group_name or None
if self.repo:
c.repo_info = self.repo
c.rhodecode_db_repo = self.repo
@ -121,7 +131,11 @@ class IntegrationSettingsViewBase(object):
defaults['enabled'] = self.integration.enabled
else:
if self.repo:
scope = self.repo.repo_name
scope = _('{repo_name} repository').format(
repo_name=self.repo.repo_name)
elif self.repo_group:
scope = _('{repo_group_name} repo group').format(
repo_group_name=self.repo_group.group_name)
else:
scope = _('Global')
@ -207,6 +221,8 @@ class IntegrationSettingsViewBase(object):
self.integration.integration_type = self.IntegrationType.key
if self.repo:
self.integration.repo = self.repo
elif self.repo_group:
self.integration.repo_group = self.repo_group
Session().add(self.integration)
self.integration.enabled = valid_data.pop('enabled', False)
@ -226,6 +242,12 @@ class IntegrationSettingsViewBase(object):
'repo_integrations_edit', repo_name=self.repo.repo_name,
integration=self.integration.integration_type,
integration_id=self.integration.integration_id)
elif self.repo:
redirect_to = self.request.route_url(
'repo_group_integrations_edit',
repo_group_name=self.repo_group.group_name,
integration=self.integration.integration_type,
integration_id=self.integration.integration_id)
else:
redirect_to = self.request.route_url(
'global_integrations_edit',
@ -270,3 +292,8 @@ class RepoIntegrationsView(IntegrationSettingsViewBase):
def perm_check(self, user):
return auth.HasRepoPermissionAll('repository.admin'
)(repo_name=self.repo.repo_name, user=user)
class RepoGroupIntegrationsView(IntegrationSettingsViewBase):
def perm_check(self, user):
return auth.HasRepoGroupPermissionAll('group.admin'
)(group_name=self.repo_group.group_name, user=user)

View file

@ -3490,9 +3490,16 @@ class Integration(Base, BaseModel):
nullable=True, unique=None, default=None)
repo = relationship('Repository', lazy='joined')
repo_group_id = Column(
'repo_group_id', Integer(), ForeignKey('groups.group_id'),
nullable=True, unique=None, default=None)
repo_group = relationship('RepoGroup', lazy='joined')
def __repr__(self):
if self.repo:
scope = 'repo=%r' % self.repo
elif self.repo_group:
scope = 'repo_group=%r' % self.repo_group
else:
scope = 'global'

View file

@ -100,10 +100,13 @@ class IntegrationModel(BaseModel):
if handler:
handler.send_event(event)
def get_integrations(self, repo=None):
def get_integrations(self, repo=None, repo_group=None):
if repo:
return self.sa.query(Integration).filter(
Integration.repo_id==repo.repo_id).all()
elif repo_group:
return self.sa.query(Integration).filter(
Integration.repo_group_id==repo_group.group_id).all()
# global integrations
return self.sa.query(Integration).filter(
@ -116,9 +119,14 @@ class IntegrationModel(BaseModel):
query = self.sa.query(Integration).filter(Integration.enabled==True)
if isinstance(event, events.RepoEvent): # global + repo integrations
# + repo_group integrations
parent_groups = event.repo.groups_with_parents
query = query.filter(
or_(Integration.repo_id==None,
Integration.repo_id==event.repo.repo_id))
Integration.repo_id==event.repo.repo_id,
Integration.repo_group_id.in_(
[group.group_id for group in parent_groups]
)))
if cache:
query = query.options(FromCache(
"sql_cache_short",

View file

@ -3,6 +3,8 @@
def inherit(context):
if context['c'].repo:
return "/admin/repos/repo_edit.html"
elif context['c'].repo_group:
return "/admin/repo_groups/repo_group_edit.html"
else:
return "/admin/settings/settings.html"
%>

View file

@ -37,11 +37,15 @@
%for integration in available_integrations:
<%
if c.repo:
create_url = request.route_url('repo_integrations_create',
create_url = request.route_path('repo_integrations_create',
repo_name=c.repo.repo_name,
integration=integration)
elif c.repo_group:
create_url = request.route_path('repo_group_integrations_create',
repo_group_name=c.repo_group.group_name,
integration=integration)
else:
create_url = request.route_url('global_integrations_create',
create_url = request.route_path('global_integrations_create',
integration=integration)
%>
<a href="${create_url}" class="btn">
@ -90,12 +94,17 @@
%else:
<%
if c.repo:
edit_url = request.route_url('repo_integrations_edit',
edit_url = request.route_path('repo_integrations_edit',
repo_name=c.repo.repo_name,
integration=integration.integration_type,
integration_id=integration.integration_id)
elif c.repo_group:
edit_url = request.route_path('repo_group_integrations_edit',
repo_group_name=c.repo_group.group_name,
integration=integration.integration_type,
integration_id=integration.integration_id)
else:
edit_url = request.route_url('global_integrations_edit',
edit_url = request.route_path('global_integrations_edit',
integration=integration.integration_type,
integration_id=integration.integration_id)
%>

View file

@ -30,6 +30,10 @@
${self.menu_items(active='admin')}
</%def>
<%def name="main_content()">
<%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/>
</%def>
<%def name="main()">
<div class="box">
<div class="title">
@ -44,11 +48,12 @@
<li class="${'active' if c.active=='settings' else ''}"><a href="${h.url('edit_repo_group', group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
<li class="${'active' if c.active=='perms' else ''}"><a href="${h.url('edit_repo_group_perms', group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
<li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_repo_group_advanced', group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
<li class="${'active' if c.active=='integrations' else ''}"><a href="${h.route_path('repo_group_integrations_home', repo_group_name=c.repo_group.group_name)}">${_('Integrations')}</a></li>
</ul>
</div>
<div class="main-content-full-width">
<%include file="/admin/repo_groups/repo_group_edit_${c.active}.html"/>
${self.main_content()}
</div>
</div>