##// END OF EJS Templates
integrations: expose EE integrations as dummy objects to show...
marcink -
r2138:cfe7604e default
parent child Browse files
Show More
@@ -21,8 +21,7 b''
21 import logging
21 import logging
22
22
23 from rhodecode.integrations.registry import IntegrationTypeRegistry
23 from rhodecode.integrations.registry import IntegrationTypeRegistry
24 from rhodecode.integrations.types import webhook, slack, hipchat, email
24 from rhodecode.integrations.types import webhook, slack, hipchat, email, base
25
26 log = logging.getLogger(__name__)
25 log = logging.getLogger(__name__)
27
26
28
27
@@ -41,6 +40,13 b' integration_type_registry.register_integ'
41 email.EmailIntegrationType)
40 email.EmailIntegrationType)
42
41
43
42
43 # dummy EE integration to show users what we have in EE edition
44 integration_type_registry.register_integration_type(
45 base.EEIntegration('Jira Issues integration', 'jira'))
46 integration_type_registry.register_integration_type(
47 base.EEIntegration('Redmine Tracker integration', 'redmine'))
48
49
44 def integrations_event_handler(event):
50 def integrations_event_handler(event):
45 """
51 """
46 Takes an event and passes it to all enabled integrations
52 Takes an event and passes it to all enabled integrations
@@ -18,11 +18,12 b''
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
19
20 import logging
20 import logging
21 import collections
21
22
22 log = logging.getLogger(__name__)
23 log = logging.getLogger(__name__)
23
24
24
25
25 class IntegrationTypeRegistry(dict):
26 class IntegrationTypeRegistry(collections.OrderedDict):
26 """
27 """
27 Registry Class to hold IntegrationTypes
28 Registry Class to hold IntegrationTypes
28 """
29 """
@@ -43,15 +43,15 b' class TestGlobalIntegrationsView(TestInt'
43 response = self.app.get(url)
43 response = self.app.get(url)
44
44
45 assert response.status_code == 200
45 assert response.status_code == 200
46 assert 'exist yet' in response.body
46 response.mustcontain('exist yet')
47
47
48 def test_index_with_integrations(self, global_integration_stub):
48 def test_index_with_integrations(self, global_integration_stub):
49 url = ADMIN_PREFIX + '/integrations'
49 url = ADMIN_PREFIX + '/integrations'
50 response = self.app.get(url)
50 response = self.app.get(url)
51
51
52 assert response.status_code == 200
52 assert response.status_code == 200
53 assert 'exist yet' not in response.body
53 response.mustcontain(no=['exist yet'])
54 assert global_integration_stub.name in response.body
54 response.mustcontain(global_integration_stub.name)
55
55
56 @pytest.mark.parametrize(
56 @pytest.mark.parametrize(
57 'IntegrationType', integration_type_registry.values())
57 'IntegrationType', integration_type_registry.values())
@@ -59,27 +59,29 b' class TestGlobalIntegrationsView(TestInt'
59 url = ADMIN_PREFIX + '/integrations/new'
59 url = ADMIN_PREFIX + '/integrations/new'
60
60
61 response = self.app.get(url, status=200)
61 response = self.app.get(url, status=200)
62
62 if not IntegrationType.is_dummy:
63 url = (ADMIN_PREFIX + '/integrations/{integration}/new').format(
63 url = (ADMIN_PREFIX + '/integrations/{integration}/new').format(
64 integration=IntegrationType.key)
64 integration=IntegrationType.key)
65 assert url in response.body
65 response.mustcontain(url)
66
66
67 @pytest.mark.parametrize(
67 @pytest.mark.parametrize(
68 'IntegrationType', integration_type_registry.values())
68 'IntegrationType', integration_type_registry.values())
69 def test_get_create_integration_page(self, IntegrationType):
69 def test_get_create_integration_page(self, IntegrationType):
70 url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format(
70 url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format(
71 integration_key=IntegrationType.key)
71 integration_key=IntegrationType.key)
72
72 if IntegrationType.is_dummy:
73 response = self.app.get(url, status=200)
73 self.app.get(url, status=404)
74
74 else:
75 assert IntegrationType.display_name in response.body
75 response = self.app.get(url, status=200)
76 response.mustcontain(IntegrationType.display_name)
76
77
77 def test_post_integration_page(self, StubIntegrationType, csrf_token,
78 def test_post_integration_page(self, StubIntegrationType, csrf_token,
78 test_repo_group, backend_random):
79 test_repo_group, backend_random):
79 url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format(
80 url = ADMIN_PREFIX + '/integrations/{integration_key}/new'.format(
80 integration_key=StubIntegrationType.key)
81 integration_key=StubIntegrationType.key)
81
82
82 _post_integration_test_helper(self.app, url, csrf_token, admin_view=True,
83 _post_integration_test_helper(
84 self.app, url, csrf_token, admin_view=True,
83 repo=backend_random.repo, repo_group=test_repo_group)
85 repo=backend_random.repo, repo_group=test_repo_group)
84
86
85
87
@@ -90,7 +92,7 b' class TestRepoIntegrationsView(TestInteg'
90 response = self.app.get(url)
92 response = self.app.get(url)
91
93
92 assert response.status_code == 200
94 assert response.status_code == 200
93 assert 'exist yet' in response.body
95 response.mustcontain('exist yet')
94
96
95 def test_index_with_integrations(self, repo_integration_stub):
97 def test_index_with_integrations(self, repo_integration_stub):
96 url = '/{repo_name}/settings/integrations'.format(
98 url = '/{repo_name}/settings/integrations'.format(
@@ -100,8 +102,8 b' class TestRepoIntegrationsView(TestInteg'
100 response = self.app.get(url)
102 response = self.app.get(url)
101
103
102 assert response.status_code == 200
104 assert response.status_code == 200
103 assert stub_name in response.body
105 response.mustcontain(stub_name)
104 assert 'exist yet' not in response.body
106 response.mustcontain(no=['exist yet'])
105
107
106 @pytest.mark.parametrize(
108 @pytest.mark.parametrize(
107 'IntegrationType', integration_type_registry.values())
109 'IntegrationType', integration_type_registry.values())
@@ -115,8 +117,8 b' class TestRepoIntegrationsView(TestInteg'
115 url = '/{repo_name}/settings/integrations/{integration}/new'.format(
117 url = '/{repo_name}/settings/integrations/{integration}/new'.format(
116 repo_name=repo_name,
118 repo_name=repo_name,
117 integration=IntegrationType.key)
119 integration=IntegrationType.key)
118
120 if not IntegrationType.is_dummy:
119 assert url in response.body
121 response.mustcontain(url)
120
122
121 @pytest.mark.parametrize(
123 @pytest.mark.parametrize(
122 'IntegrationType', integration_type_registry.values())
124 'IntegrationType', integration_type_registry.values())
@@ -124,10 +126,11 b' class TestRepoIntegrationsView(TestInteg'
124 repo_name = backend_random.repo.repo_name
126 repo_name = backend_random.repo.repo_name
125 url = '/{repo_name}/settings/integrations/{integration_key}/new'.format(
127 url = '/{repo_name}/settings/integrations/{integration_key}/new'.format(
126 repo_name=repo_name, integration_key=IntegrationType.key)
128 repo_name=repo_name, integration_key=IntegrationType.key)
127
129 if IntegrationType.is_dummy:
128 response = self.app.get(url, status=200)
130 self.app.get(url, status=404)
129
131 else:
130 assert IntegrationType.display_name in response.body
132 response = self.app.get(url, status=200)
133 response.mustcontain(IntegrationType.display_name)
131
134
132 def test_post_integration_page(self, backend_random, test_repo_group,
135 def test_post_integration_page(self, backend_random, test_repo_group,
133 StubIntegrationType, csrf_token):
136 StubIntegrationType, csrf_token):
@@ -147,7 +150,7 b' class TestRepoGroupIntegrationsView(Test'
147 response = self.app.get(url)
150 response = self.app.get(url)
148
151
149 assert response.status_code == 200
152 assert response.status_code == 200
150 assert 'exist yet' in response.body
153 response.mustcontain('exist yet')
151
154
152 def test_index_with_integrations(
155 def test_index_with_integrations(
153 self, test_repo_group, repogroup_integration_stub):
156 self, test_repo_group, repogroup_integration_stub):
@@ -159,8 +162,8 b' class TestRepoGroupIntegrationsView(Test'
159 response = self.app.get(url)
162 response = self.app.get(url)
160
163
161 assert response.status_code == 200
164 assert response.status_code == 200
162 assert 'exist yet' not in response.body
165 response.mustcontain(no=['exist yet'])
163 assert stub_name in response.body
166 response.mustcontain(stub_name)
164
167
165 def test_new_integration_page(self, test_repo_group):
168 def test_new_integration_page(self, test_repo_group):
166 repo_group_name = test_repo_group.group_name
169 repo_group_name = test_repo_group.group_name
@@ -171,12 +174,13 b' class TestRepoGroupIntegrationsView(Test'
171
174
172 assert response.status_code == 200
175 assert response.status_code == 200
173
176
174 for integration_key in integration_type_registry:
177 for integration_key, integration_obj in integration_type_registry.items():
175 nurl = ('/{repo_group_name}/settings/integrations/{integration}/new').format(
178 if not integration_obj.is_dummy:
179 nurl = (
180 '/{repo_group_name}/settings/integrations/{integration}/new').format(
176 repo_group_name=repo_group_name,
181 repo_group_name=repo_group_name,
177 integration=integration_key)
182 integration=integration_key)
178
183 response.mustcontain(nurl)
179 assert nurl in response.body
180
184
181 @pytest.mark.parametrize(
185 @pytest.mark.parametrize(
182 'IntegrationType', integration_type_registry.values())
186 'IntegrationType', integration_type_registry.values())
@@ -188,10 +192,11 b' class TestRepoGroupIntegrationsView(Test'
188 ).format(repo_group_name=repo_group_name,
192 ).format(repo_group_name=repo_group_name,
189 integration_key=IntegrationType.key)
193 integration_key=IntegrationType.key)
190
194
191 response = self.app.get(url)
195 if not IntegrationType.is_dummy:
192
196 response = self.app.get(url, status=200)
193 assert response.status_code == 200
197 response.mustcontain(IntegrationType.display_name)
194 assert IntegrationType.display_name in response.body
198 else:
199 self.app.get(url, status=404)
195
200
196 def test_post_integration_page(self, test_repo_group, backend_random,
201 def test_post_integration_page(self, test_repo_group, backend_random,
197 StubIntegrationType, csrf_token):
202 StubIntegrationType, csrf_token):
@@ -217,7 +222,7 b' def _post_integration_test_helper(app, u'
217 app.post(url, params={}, status=403) # missing csrf check
222 app.post(url, params={}, status=403) # missing csrf check
218 response = app.post(url, params={'csrf_token': csrf_token})
223 response = app.post(url, params={'csrf_token': csrf_token})
219 assert response.status_code == 200
224 assert response.status_code == 200
220 assert 'Errors exist' in response.body
225 response.mustcontain('Errors exist')
221
226
222 scopes_destinations = [
227 scopes_destinations = [
223 ('global',
228 ('global',
@@ -24,7 +24,7 b' from rhodecode.translation import _'
24
24
25 class IntegrationTypeBase(object):
25 class IntegrationTypeBase(object):
26 """ Base class for IntegrationType plugins """
26 """ Base class for IntegrationType plugins """
27
27 is_dummy = False
28 description = ''
28 description = ''
29 icon = '''
29 icon = '''
30 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
30 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
@@ -99,3 +99,12 b' class IntegrationTypeBase(object):'
99 A colander schema of settings for the integration type
99 A colander schema of settings for the integration type
100 """
100 """
101 return colander.Schema()
101 return colander.Schema()
102
103
104 class EEIntegration(IntegrationTypeBase):
105 description = 'Integration available in RhodeCode EE edition.'
106 is_dummy = True
107
108 def __init__(self, name, key, settings=None):
109 self.display_name = name
110 self.key = key
@@ -23,7 +23,7 b' import logging'
23 import peppercorn
23 import peppercorn
24 import webhelpers.paginate
24 import webhelpers.paginate
25
25
26 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
26 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPNotFound
27
27
28 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps._base import BaseAppView
29 from rhodecode.integrations import integration_type_registry
29 from rhodecode.integrations import integration_type_registry
@@ -76,7 +76,12 b' class IntegrationSettingsViewBase(BaseAp'
76
76
77 if 'integration' in request.matchdict: # integration type context
77 if 'integration' in request.matchdict: # integration type context
78 integration_type = request.matchdict['integration']
78 integration_type = request.matchdict['integration']
79 if integration_type not in integration_type_registry:
80 raise HTTPNotFound()
81
79 self.IntegrationType = integration_type_registry[integration_type]
82 self.IntegrationType = integration_type_registry[integration_type]
83 if self.IntegrationType.is_dummy:
84 raise HTTPNotFound()
80
85
81 if 'integration_id' in request.matchdict: # single integration context
86 if 'integration_id' in request.matchdict: # single integration context
82 integration_id = request.matchdict['integration_id']
87 integration_id = request.matchdict['integration_id']
@@ -1195,6 +1195,9 b' table.integrations {'
1195 min-width: 140px;
1195 min-width: 140px;
1196 }
1196 }
1197 }
1197 }
1198 a.integration-box.dummy-integration {
1199 color: @grey4
1200 }
1198 }
1201 }
1199
1202
1200 //Permissions Settings
1203 //Permissions Settings
@@ -64,23 +64,25 b''
64 <a href="${home_url}" class="btn ${not c.current_IntegrationType and 'btn-primary' or ''}">${_('All')}</a>
64 <a href="${home_url}" class="btn ${not c.current_IntegrationType and 'btn-primary' or ''}">${_('All')}</a>
65
65
66 %for integration_key, IntegrationType in c.available_integrations.items():
66 %for integration_key, IntegrationType in c.available_integrations.items():
67 <%
67 % if not IntegrationType.is_dummy:
68 if c.repo:
68 <%
69 list_url = request.route_path('repo_integrations_list',
69 if c.repo:
70 repo_name=c.repo.repo_name,
70 list_url = request.route_path('repo_integrations_list',
71 integration=integration_key)
71 repo_name=c.repo.repo_name,
72 elif c.repo_group:
72 integration=integration_key)
73 list_url = request.route_path('repo_group_integrations_list',
73 elif c.repo_group:
74 repo_group_name=c.repo_group.group_name,
74 list_url = request.route_path('repo_group_integrations_list',
75 integration=integration_key)
75 repo_group_name=c.repo_group.group_name,
76 else:
76 integration=integration_key)
77 list_url = request.route_path('global_integrations_list',
77 else:
78 integration=integration_key)
78 list_url = request.route_path('global_integrations_list',
79 %>
79 integration=integration_key)
80 <a href="${list_url}"
80 %>
81 class="btn ${c.current_IntegrationType and integration_key == c.current_IntegrationType.key and 'btn-primary' or ''}">
81 <a href="${list_url}"
82 ${IntegrationType.display_name}
82 class="btn ${c.current_IntegrationType and integration_key == c.current_IntegrationType.key and 'btn-primary' or ''}">
83 </a>
83 ${IntegrationType.display_name}
84 </a>
85 % endif
84 %endfor
86 %endfor
85
87
86 <%
88 <%
@@ -36,7 +36,7 b''
36 %endif
36 %endif
37 </%def>
37 </%def>
38
38
39 %for integration, IntegrationType in c.available_integrations.items():
39 %for integration, IntegrationObject in c.available_integrations.items():
40 <%
40 <%
41 if c.repo:
41 if c.repo:
42 create_url = request.route_path('repo_integrations_create',
42 create_url = request.route_path('repo_integrations_create',
@@ -49,16 +49,18 b''
49 else:
49 else:
50 create_url = request.route_path('global_integrations_create',
50 create_url = request.route_path('global_integrations_create',
51 integration=integration)
51 integration=integration)
52 if IntegrationObject.is_dummy:
53 create_url = request.current_route_path()
52 %>
54 %>
53 <a href="${create_url}" class="integration-box">
55 <a href="${create_url}" class="integration-box ${'dummy-integration' if IntegrationObject.is_dummy else ''}">
54 <%widgets:panel>
56 <%widgets:panel>
55 <h2>
57 <h2>
56 <div class="integration-icon">
58 <div class="integration-icon">
57 ${IntegrationType.icon|n}
59 ${IntegrationObject.icon|n}
58 </div>
60 </div>
59 ${IntegrationType.display_name}
61 ${IntegrationObject.display_name}
60 </h2>
62 </h2>
61 ${IntegrationType.description or _('No description available')}
63 ${IntegrationObject.description or _('No description available')}
62 </%widgets:panel>
64 </%widgets:panel>
63 </a>
65 </a>
64 %endfor
66 %endfor
General Comments 0
You need to be logged in to leave comments. Login now