diff --git a/rhodecode/integrations/__init__.py b/rhodecode/integrations/__init__.py --- a/rhodecode/integrations/__init__.py +++ b/rhodecode/integrations/__init__.py @@ -21,8 +21,7 @@ import logging from rhodecode.integrations.registry import IntegrationTypeRegistry -from rhodecode.integrations.types import webhook, slack, hipchat, email - +from rhodecode.integrations.types import webhook, slack, hipchat, email, base log = logging.getLogger(__name__) @@ -41,6 +40,13 @@ integration_type_registry.register_integ email.EmailIntegrationType) +# dummy EE integration to show users what we have in EE edition +integration_type_registry.register_integration_type( + base.EEIntegration('Jira Issues integration', 'jira')) +integration_type_registry.register_integration_type( + base.EEIntegration('Redmine Tracker integration', 'redmine')) + + def integrations_event_handler(event): """ Takes an event and passes it to all enabled integrations diff --git a/rhodecode/integrations/registry.py b/rhodecode/integrations/registry.py --- a/rhodecode/integrations/registry.py +++ b/rhodecode/integrations/registry.py @@ -18,11 +18,12 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ import logging +import collections log = logging.getLogger(__name__) -class IntegrationTypeRegistry(dict): +class IntegrationTypeRegistry(collections.OrderedDict): """ Registry Class to hold IntegrationTypes """ diff --git a/rhodecode/integrations/tests/test_integrations.py b/rhodecode/integrations/tests/test_integrations.py --- a/rhodecode/integrations/tests/test_integrations.py +++ b/rhodecode/integrations/tests/test_integrations.py @@ -43,15 +43,15 @@ class TestGlobalIntegrationsView(TestInt response = self.app.get(url) assert response.status_code == 200 - assert 'exist yet' in response.body + response.mustcontain('exist yet') def test_index_with_integrations(self, global_integration_stub): url = ADMIN_PREFIX + '/integrations' response = self.app.get(url) assert response.status_code == 200 - assert 'exist yet' not in response.body - assert global_integration_stub.name in response.body + response.mustcontain(no=['exist yet']) + response.mustcontain(global_integration_stub.name) @pytest.mark.parametrize( 'IntegrationType', integration_type_registry.values()) @@ -59,27 +59,29 @@ class TestGlobalIntegrationsView(TestInt url = ADMIN_PREFIX + '/integrations/new' response = self.app.get(url, status=200) - - url = (ADMIN_PREFIX + '/integrations/{integration}/new').format( - integration=IntegrationType.key) - assert url in response.body + if not IntegrationType.is_dummy: + url = (ADMIN_PREFIX + '/integrations/{integration}/new').format( + integration=IntegrationType.key) + response.mustcontain(url) @pytest.mark.parametrize( 'IntegrationType', integration_type_registry.values()) def test_get_create_integration_page(self, IntegrationType): url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format( integration_key=IntegrationType.key) - - response = self.app.get(url, status=200) - - assert IntegrationType.display_name in response.body + if IntegrationType.is_dummy: + self.app.get(url, status=404) + else: + response = self.app.get(url, status=200) + response.mustcontain(IntegrationType.display_name) def test_post_integration_page(self, StubIntegrationType, csrf_token, test_repo_group, backend_random): url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format( integration_key=StubIntegrationType.key) - _post_integration_test_helper(self.app, url, csrf_token, admin_view=True, + _post_integration_test_helper( + self.app, url, csrf_token, admin_view=True, repo=backend_random.repo, repo_group=test_repo_group) @@ -90,7 +92,7 @@ class TestRepoIntegrationsView(TestInteg response = self.app.get(url) assert response.status_code == 200 - assert 'exist yet' in response.body + response.mustcontain('exist yet') def test_index_with_integrations(self, repo_integration_stub): url = '/{repo_name}/settings/integrations'.format( @@ -100,8 +102,8 @@ class TestRepoIntegrationsView(TestInteg response = self.app.get(url) assert response.status_code == 200 - assert stub_name in response.body - assert 'exist yet' not in response.body + response.mustcontain(stub_name) + response.mustcontain(no=['exist yet']) @pytest.mark.parametrize( 'IntegrationType', integration_type_registry.values()) @@ -115,8 +117,8 @@ class TestRepoIntegrationsView(TestInteg url = '/{repo_name}/settings/integrations/{integration}/new'.format( repo_name=repo_name, integration=IntegrationType.key) - - assert url in response.body + if not IntegrationType.is_dummy: + response.mustcontain(url) @pytest.mark.parametrize( 'IntegrationType', integration_type_registry.values()) @@ -124,10 +126,11 @@ class TestRepoIntegrationsView(TestInteg repo_name = backend_random.repo.repo_name url = '/{repo_name}/settings/integrations/{integration_key}/new'.format( repo_name=repo_name, integration_key=IntegrationType.key) - - response = self.app.get(url, status=200) - - assert IntegrationType.display_name in response.body + if IntegrationType.is_dummy: + self.app.get(url, status=404) + else: + response = self.app.get(url, status=200) + response.mustcontain(IntegrationType.display_name) def test_post_integration_page(self, backend_random, test_repo_group, StubIntegrationType, csrf_token): @@ -147,7 +150,7 @@ class TestRepoGroupIntegrationsView(Test response = self.app.get(url) assert response.status_code == 200 - assert 'exist yet' in response.body + response.mustcontain('exist yet') def test_index_with_integrations( self, test_repo_group, repogroup_integration_stub): @@ -159,8 +162,8 @@ class TestRepoGroupIntegrationsView(Test response = self.app.get(url) assert response.status_code == 200 - assert 'exist yet' not in response.body - assert stub_name in response.body + response.mustcontain(no=['exist yet']) + response.mustcontain(stub_name) def test_new_integration_page(self, test_repo_group): repo_group_name = test_repo_group.group_name @@ -171,12 +174,13 @@ class TestRepoGroupIntegrationsView(Test assert response.status_code == 200 - for integration_key in integration_type_registry: - nurl = ('/{repo_group_name}/settings/integrations/{integration}/new').format( + for integration_key, integration_obj in integration_type_registry.items(): + if not integration_obj.is_dummy: + nurl = ( + '/{repo_group_name}/settings/integrations/{integration}/new').format( repo_group_name=repo_group_name, integration=integration_key) - - assert nurl in response.body + response.mustcontain(nurl) @pytest.mark.parametrize( 'IntegrationType', integration_type_registry.values()) @@ -188,10 +192,11 @@ class TestRepoGroupIntegrationsView(Test ).format(repo_group_name=repo_group_name, integration_key=IntegrationType.key) - response = self.app.get(url) - - assert response.status_code == 200 - assert IntegrationType.display_name in response.body + if not IntegrationType.is_dummy: + response = self.app.get(url, status=200) + response.mustcontain(IntegrationType.display_name) + else: + self.app.get(url, status=404) def test_post_integration_page(self, test_repo_group, backend_random, StubIntegrationType, csrf_token): @@ -217,7 +222,7 @@ def _post_integration_test_helper(app, u app.post(url, params={}, status=403) # missing csrf check response = app.post(url, params={'csrf_token': csrf_token}) assert response.status_code == 200 - assert 'Errors exist' in response.body + response.mustcontain('Errors exist') scopes_destinations = [ ('global', diff --git a/rhodecode/integrations/types/base.py b/rhodecode/integrations/types/base.py --- a/rhodecode/integrations/types/base.py +++ b/rhodecode/integrations/types/base.py @@ -24,7 +24,7 @@ from rhodecode.translation import _ class IntegrationTypeBase(object): """ Base class for IntegrationType plugins """ - + is_dummy = False description = '' icon = ''' @@ -99,3 +99,12 @@ class IntegrationTypeBase(object): A colander schema of settings for the integration type """ return colander.Schema() + + +class EEIntegration(IntegrationTypeBase): + description = 'Integration available in RhodeCode EE edition.' + is_dummy = True + + def __init__(self, name, key, settings=None): + self.display_name = name + self.key = key diff --git a/rhodecode/integrations/views.py b/rhodecode/integrations/views.py --- a/rhodecode/integrations/views.py +++ b/rhodecode/integrations/views.py @@ -23,7 +23,7 @@ import logging import peppercorn import webhelpers.paginate -from pyramid.httpexceptions import HTTPFound, HTTPForbidden +from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPNotFound from rhodecode.apps._base import BaseAppView from rhodecode.integrations import integration_type_registry @@ -76,7 +76,12 @@ class IntegrationSettingsViewBase(BaseAp if 'integration' in request.matchdict: # integration type context integration_type = request.matchdict['integration'] + if integration_type not in integration_type_registry: + raise HTTPNotFound() + self.IntegrationType = integration_type_registry[integration_type] + if self.IntegrationType.is_dummy: + raise HTTPNotFound() if 'integration_id' in request.matchdict: # single integration context integration_id = request.matchdict['integration_id'] diff --git a/rhodecode/public/css/main.less b/rhodecode/public/css/main.less --- a/rhodecode/public/css/main.less +++ b/rhodecode/public/css/main.less @@ -1195,6 +1195,9 @@ table.integrations { min-width: 140px; } } + a.integration-box.dummy-integration { + color: @grey4 + } } //Permissions Settings diff --git a/rhodecode/templates/admin/integrations/list.mako b/rhodecode/templates/admin/integrations/list.mako --- a/rhodecode/templates/admin/integrations/list.mako +++ b/rhodecode/templates/admin/integrations/list.mako @@ -64,23 +64,25 @@ ${_('All')} %for integration_key, IntegrationType in c.available_integrations.items(): - <% - if c.repo: - list_url = request.route_path('repo_integrations_list', - repo_name=c.repo.repo_name, - integration=integration_key) - elif c.repo_group: - list_url = request.route_path('repo_group_integrations_list', - repo_group_name=c.repo_group.group_name, - integration=integration_key) - else: - list_url = request.route_path('global_integrations_list', - integration=integration_key) - %> - - ${IntegrationType.display_name} - + % if not IntegrationType.is_dummy: + <% + if c.repo: + list_url = request.route_path('repo_integrations_list', + repo_name=c.repo.repo_name, + integration=integration_key) + elif c.repo_group: + list_url = request.route_path('repo_group_integrations_list', + repo_group_name=c.repo_group.group_name, + integration=integration_key) + else: + list_url = request.route_path('global_integrations_list', + integration=integration_key) + %> + + ${IntegrationType.display_name} + + % endif %endfor <% diff --git a/rhodecode/templates/admin/integrations/new.mako b/rhodecode/templates/admin/integrations/new.mako --- a/rhodecode/templates/admin/integrations/new.mako +++ b/rhodecode/templates/admin/integrations/new.mako @@ -36,7 +36,7 @@ %endif - %for integration, IntegrationType in c.available_integrations.items(): + %for integration, IntegrationObject in c.available_integrations.items(): <% if c.repo: create_url = request.route_path('repo_integrations_create', @@ -49,16 +49,18 @@ else: create_url = request.route_path('global_integrations_create', integration=integration) + if IntegrationObject.is_dummy: + create_url = request.current_route_path() %> - + <%widgets:panel>

- ${IntegrationType.icon|n} + ${IntegrationObject.icon|n}
- ${IntegrationType.display_name} + ${IntegrationObject.display_name}

- ${IntegrationType.description or _('No description available')} + ${IntegrationObject.description or _('No description available')}
%endfor