##// END OF EJS Templates
integrations: add recursive repo group scope to allow integrations...
dan -
r793:fc8d2069 default
parent child Browse files
Show More
@@ -40,7 +40,7 b' from rhodecode.admin.navigation import n'
40 from rhodecode.translation import _
40 from rhodecode.translation import _
41 from rhodecode.integrations import integration_type_registry
41 from rhodecode.integrations import integration_type_registry
42 from rhodecode.model.validation_schema.schemas.integration_schema import (
42 from rhodecode.model.validation_schema.schemas.integration_schema import (
43 make_integration_schema)
43 make_integration_schema, IntegrationScopeType)
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
@@ -151,7 +151,11 b' class IntegrationSettingsViewBase(object'
151 defaults['options'] = {
151 defaults['options'] = {
152 'name': self.integration.name,
152 'name': self.integration.name,
153 'enabled': self.integration.enabled,
153 'enabled': self.integration.enabled,
154 'scope': self.integration.scope,
154 'scope': {
155 'repo': self.integration.repo,
156 'repo_group': self.integration.repo_group,
157 'child_repos_only': self.integration.child_repos_only,
158 },
155 }
159 }
156 else:
160 else:
157 if self.repo:
161 if self.repo:
@@ -168,10 +172,10 b' class IntegrationSettingsViewBase(object'
168 'name': _('{name} integration').format(
172 'name': _('{name} integration').format(
169 name=self.IntegrationType.display_name),
173 name=self.IntegrationType.display_name),
170 }
174 }
171 if self.repo:
175 defaults['options']['scope'] = {
172 defaults['options']['scope'] = self.repo
176 'repo': self.repo,
173 elif self.repo_group:
177 'repo_group': self.repo_group,
174 defaults['options']['scope'] = self.repo_group
178 }
175
179
176 return defaults
180 return defaults
177
181
@@ -250,11 +254,10 b' class IntegrationSettingsViewBase(object'
250 # scope is read only field in these cases, and has to be added
254 # scope is read only field in these cases, and has to be added
251 options = pstruct.setdefault('options', {})
255 options = pstruct.setdefault('options', {})
252 if 'scope' not in options:
256 if 'scope' not in options:
253 if self.repo:
257 options['scope'] = IntegrationScopeType().serialize(None, {
254 options['scope'] = 'repo:{}'.format(self.repo.repo_name)
258 'repo': self.repo,
255 elif self.repo_group:
259 'repo_group': self.repo_group,
256 options['scope'] = 'repogroup:{}'.format(
260 })
257 self.repo_group.group_name)
258
261
259 try:
262 try:
260 valid_data = form.validate_pstruct(pstruct)
263 valid_data = form.validate_pstruct(pstruct)
@@ -276,7 +279,11 b' class IntegrationSettingsViewBase(object'
276 name=valid_data['options']['name'],
279 name=valid_data['options']['name'],
277 enabled=valid_data['options']['enabled'],
280 enabled=valid_data['options']['enabled'],
278 settings=valid_data['settings'],
281 settings=valid_data['settings'],
279 scope=scope)
282 repo=scope['repo'],
283 repo_group=scope['repo_group'],
284 child_repos_only=scope['child_repos_only'],
285 )
286
280
287
281 self.integration.settings = valid_data['settings']
288 self.integration.settings = valid_data['settings']
282 Session().commit()
289 Session().commit()
@@ -291,16 +298,16 b' class IntegrationSettingsViewBase(object'
291 # keeping in mind if the original view was for /repo/ or /_admin/
298 # keeping in mind if the original view was for /repo/ or /_admin/
292 admin_view = not (self.repo or self.repo_group)
299 admin_view = not (self.repo or self.repo_group)
293
300
294 if isinstance(self.integration.scope, Repository) and not admin_view:
301 if self.integration.repo and not admin_view:
295 redirect_to = self.request.route_path(
302 redirect_to = self.request.route_path(
296 'repo_integrations_edit',
303 'repo_integrations_edit',
297 repo_name=self.integration.scope.repo_name,
304 repo_name=self.integration.repo.repo_name,
298 integration=self.integration.integration_type,
305 integration=self.integration.integration_type,
299 integration_id=self.integration.integration_id)
306 integration_id=self.integration.integration_id)
300 elif isinstance(self.integration.scope, RepoGroup) and not admin_view:
307 elif self.integration.repo_group and not admin_view:
301 redirect_to = self.request.route_path(
308 redirect_to = self.request.route_path(
302 'repo_group_integrations_edit',
309 'repo_group_integrations_edit',
303 repo_group_name=self.integration.scope.group_name,
310 repo_group_name=self.integration.repo_group.group_name,
304 integration=self.integration.integration_type,
311 integration=self.integration.integration_type,
305 integration_id=self.integration.integration_id)
312 integration_id=self.integration.integration_id)
306 else:
313 else:
@@ -3499,36 +3499,18 b' class Integration(Base, BaseModel):'
3499 nullable=True, unique=None, default=None)
3499 nullable=True, unique=None, default=None)
3500 repo_group = relationship('RepoGroup', lazy='joined')
3500 repo_group = relationship('RepoGroup', lazy='joined')
3501
3501
3502 @hybrid_property
3502 @property
3503 def scope(self):
3503 def scope(self):
3504 if self.repo:
3504 if self.repo:
3505 return self.repo
3505 return repr(self.repo)
3506 if self.repo_group:
3506 if self.repo_group:
3507 return self.repo_group
3507 if self.child_repos_only:
3508 return repr(self.repo_group) + ' (child repos only)'
3509 else:
3510 return repr(self.repo_group) + ' (recursive)'
3508 if self.child_repos_only:
3511 if self.child_repos_only:
3509 return 'root_repos'
3512 return 'root_repos'
3510 return 'global'
3513 return 'global'
3511
3514
3512 @scope.setter
3513 def scope(self, value):
3514 self.repo = None
3515 self.repo_id = None
3516 self.repo_group_id = None
3517 self.repo_group = None
3518 self.child_repos_only = False
3519 if isinstance(value, Repository):
3520 self.repo_id = value.repo_id
3521 self.repo = value
3522 elif isinstance(value, RepoGroup):
3523 self.repo_group_id = value.group_id
3524 self.repo_group = value
3525 elif value == 'root_repos':
3526 self.child_repos_only = True
3527 elif value == 'global':
3528 pass
3529 else:
3530 raise Exception("invalid scope: %s, must be one of "
3531 "['global', 'root_repos', <RepoGroup>. <Repository>]" % value)
3532
3533 def __repr__(self):
3515 def __repr__(self):
3534 return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
3516 return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
@@ -61,23 +61,24 b' class IntegrationModel(BaseModel):'
61 raise Exception('integration must be int, long or Instance'
61 raise Exception('integration must be int, long or Instance'
62 ' of Integration got %s' % type(integration))
62 ' of Integration got %s' % type(integration))
63
63
64 def create(self, IntegrationType, name, enabled, scope, settings):
64 def create(self, IntegrationType, name, enabled, repo, repo_group,
65 child_repos_only, settings):
65 """ Create an IntegrationType integration """
66 """ Create an IntegrationType integration """
66 integration = Integration()
67 integration = Integration()
67 integration.integration_type = IntegrationType.key
68 integration.integration_type = IntegrationType.key
68 self.sa.add(integration)
69 self.sa.add(integration)
69 self.update_integration(integration, name, enabled, scope, settings)
70 self.update_integration(integration, name, enabled, repo, repo_group,
71 child_repos_only, settings)
70 self.sa.commit()
72 self.sa.commit()
71 return integration
73 return integration
72
74
73 def update_integration(self, integration, name, enabled, scope, settings):
75 def update_integration(self, integration, name, enabled, repo, repo_group,
74 """
76 child_repos_only, settings):
75 :param scope: one of ['global', 'root_repos', <RepoGroup>. <Repository>]
76 """
77
78 integration = self.__get_integration(integration)
77 integration = self.__get_integration(integration)
79
78
80 integration.scope = scope
79 integration.repo = repo
80 integration.repo_group = repo_group
81 integration.child_repos_only = child_repos_only
81 integration.name = name
82 integration.name = name
82 integration.enabled = enabled
83 integration.enabled = enabled
83 integration.settings = settings
84 integration.settings = settings
@@ -127,7 +128,7 b' class IntegrationModel(BaseModel):'
127 query = self.sa.query(Integration).filter(
128 query = self.sa.query(Integration).filter(
128 and_(Integration.repo_id==None, Integration.repo_group_id==None)
129 and_(Integration.repo_id==None, Integration.repo_group_id==None)
129 )
130 )
130 elif scope == 'root_repos':
131 elif scope == 'root-repos':
131 query = self.sa.query(Integration).filter(
132 query = self.sa.query(Integration).filter(
132 and_(Integration.repo_id==None,
133 and_(Integration.repo_id==None,
133 Integration.repo_group_id==None,
134 Integration.repo_group_id==None,
@@ -185,13 +186,21 b' class IntegrationModel(BaseModel):'
185
186
186 if event.repo.group:
187 if event.repo.group:
187 clauses.append(
188 clauses.append(
188 Integration.repo_group_id == event.repo.group.group_id
189 and_(
190 Integration.repo_group_id==event.repo.group.group_id,
191 Integration.child_repos_only==True
192 )
189 )
193 )
190 # repo group cascade to kids (maybe implement this sometime?)
194 # repo group cascade to kids
191 # clauses.append(Integration.repo_group_id.in_(
195 clauses.append(
192 # [group.group_id for group in
196 and_(
193 # event.repo.groups_with_parents]
197 Integration.repo_group_id.in_(
194 # ))
198 [group.group_id for group in
199 event.repo.groups_with_parents]
200 ),
201 Integration.child_repos_only==False
202 )
203 )
195
204
196
205
197 if not event.repo.group: # root repo
206 if not event.repo.group: # root repo
@@ -37,7 +37,7 b' def integration_scope_choices(permission'
37 if 'hg.admin' in permissions['global']:
37 if 'hg.admin' in permissions['global']:
38 result.extend([
38 result.extend([
39 ('global', _('Global (all repositories)')),
39 ('global', _('Global (all repositories)')),
40 ('root_repos', _('Top level repositories only')),
40 ('root-repos', _('Top level repositories only')),
41 ])
41 ])
42
42
43 repo_choices = [
43 repo_choices = [
@@ -47,13 +47,19 b' def integration_scope_choices(permission'
47 if repo_perm == 'repository.admin'
47 if repo_perm == 'repository.admin'
48 ]
48 ]
49 repogroup_choices = [
49 repogroup_choices = [
50 ('repogroup:%s' % repo_group_name, '/' + repo_group_name + ' (group)')
50 ('repogroup:%s' % repo_group_name, '/' + repo_group_name + '/ (child repos only)')
51 for repo_group_name, repo_group_perm
52 in permissions['repositories_groups'].items()
53 if repo_group_perm == 'group.admin'
54 ]
55 repogroup_recursive_choices = [
56 ('repogroup-recursive:%s' % repo_group_name, '/' + repo_group_name + '/ (recursive)')
51 for repo_group_name, repo_group_perm
57 for repo_group_name, repo_group_perm
52 in permissions['repositories_groups'].items()
58 in permissions['repositories_groups'].items()
53 if repo_group_perm == 'group.admin'
59 if repo_group_perm == 'group.admin'
54 ]
60 ]
55 result.extend(
61 result.extend(
56 sorted(repogroup_choices + repo_choices,
62 sorted(repogroup_recursive_choices + repogroup_choices + repo_choices,
57 key=lambda (choice, label): choice.split(':', 1)[1]
63 key=lambda (choice, label): choice.split(':', 1)[1]
58 )
64 )
59 )
65 )
@@ -66,27 +72,24 b' def deferred_integration_scopes_validato'
66 def _scope_validator(_node, scope):
72 def _scope_validator(_node, scope):
67 is_super_admin = 'hg.admin' in perms['global']
73 is_super_admin = 'hg.admin' in perms['global']
68
74
69 if scope in ('global', 'root_repos'):
75 if scope.get('repo'):
76 if (is_super_admin or perms['repositories'].get(
77 scope['repo'].repo_name) == 'repository.admin'):
78 return True
79 msg = _('Only repo admins can create integrations')
80 raise colander.Invalid(_node, msg)
81 elif scope.get('repo_group'):
82 if (is_super_admin or perms['repositories_groups'].get(
83 scope['repo_group'].group_name) == 'group.admin'):
84 return True
85
86 msg = _('Only repogroup admins can create integrations')
87 raise colander.Invalid(_node, msg)
88 else:
70 if is_super_admin:
89 if is_super_admin:
71 return True
90 return True
72 msg = _('Only superadmins can create global integrations')
91 msg = _('Only superadmins can create global integrations')
73 raise colander.Invalid(_node, msg)
92 raise colander.Invalid(_node, msg)
74 elif isinstance(scope, Repository):
75 if (is_super_admin or perms['repositories'].get(
76 scope.repo_name) == 'repository.admin'):
77 return True
78 msg = _('Only repo admins can create integrations')
79 raise colander.Invalid(_node, msg)
80 elif isinstance(scope, RepoGroup):
81 if (is_super_admin or perms['repositories_groups'].get(
82 scope.group_name) == 'group.admin'):
83 return True
84
85 msg = _('Only repogroup admins can create integrations')
86 raise colander.Invalid(_node, msg)
87
88 msg = _('Invalid integration scope: %s' % scope)
89 raise colander.Invalid(node, msg)
90
93
91 return _scope_validator
94 return _scope_validator
92
95
@@ -100,17 +103,26 b' def deferred_integration_scopes_widget(n'
100 widget = deform.widget.Select2Widget(values=choices)
103 widget = deform.widget.Select2Widget(values=choices)
101 return widget
104 return widget
102
105
103 class IntegrationScope(colander.SchemaType):
106
107 class IntegrationScopeType(colander.SchemaType):
104 def serialize(self, node, appstruct):
108 def serialize(self, node, appstruct):
105 if appstruct is colander.null:
109 if appstruct is colander.null:
106 return colander.null
110 return colander.null
107
111
108 if isinstance(appstruct, Repository):
112 if appstruct.get('repo'):
109 return 'repo:%s' % appstruct.repo_name
113 return 'repo:%s' % appstruct['repo'].repo_name
110 elif isinstance(appstruct, RepoGroup):
114 elif appstruct.get('repo_group'):
111 return 'repogroup:%s' % appstruct.group_name
115 if appstruct.get('child_repos_only'):
112 elif appstruct in ('global', 'root_repos'):
116 return 'repogroup:%s' % appstruct['repo_group'].group_name
113 return appstruct
117 else:
118 return 'repogroup-recursive:%s' % (
119 appstruct['repo_group'].group_name)
120 else:
121 if appstruct.get('child_repos_only'):
122 return 'root-repos'
123 else:
124 return 'global'
125
114 raise colander.Invalid(node, '%r is not a valid scope' % appstruct)
126 raise colander.Invalid(node, '%r is not a valid scope' % appstruct)
115
127
116 def deserialize(self, node, cstruct):
128 def deserialize(self, node, cstruct):
@@ -120,16 +132,43 b' class IntegrationScope(colander.SchemaTy'
120 if cstruct.startswith('repo:'):
132 if cstruct.startswith('repo:'):
121 repo = Repository.get_by_repo_name(cstruct.split(':')[1])
133 repo = Repository.get_by_repo_name(cstruct.split(':')[1])
122 if repo:
134 if repo:
123 return repo
135 return {
136 'repo': repo,
137 'repo_group': None,
138 'child_repos_only': None,
139 }
140 elif cstruct.startswith('repogroup-recursive:'):
141 repo_group = RepoGroup.get_by_group_name(cstruct.split(':')[1])
142 if repo_group:
143 return {
144 'repo': None,
145 'repo_group': repo_group,
146 'child_repos_only': False
147 }
124 elif cstruct.startswith('repogroup:'):
148 elif cstruct.startswith('repogroup:'):
125 repo_group = RepoGroup.get_by_group_name(cstruct.split(':')[1])
149 repo_group = RepoGroup.get_by_group_name(cstruct.split(':')[1])
126 if repo_group:
150 if repo_group:
127 return repo_group
151 return {
128 elif cstruct in ('global', 'root_repos'):
152 'repo': None,
129 return cstruct
153 'repo_group': repo_group,
154 'child_repos_only': True
155 }
156 elif cstruct == 'global':
157 return {
158 'repo': None,
159 'repo_group': None,
160 'child_repos_only': False
161 }
162 elif cstruct == 'root-repos':
163 return {
164 'repo': None,
165 'repo_group': None,
166 'child_repos_only': True
167 }
130
168
131 raise colander.Invalid(node, '%r is not a valid scope' % cstruct)
169 raise colander.Invalid(node, '%r is not a valid scope' % cstruct)
132
170
171
133 class IntegrationOptionsSchemaBase(colander.MappingSchema):
172 class IntegrationOptionsSchemaBase(colander.MappingSchema):
134
173
135 name = colander.SchemaNode(
174 name = colander.SchemaNode(
@@ -140,10 +179,10 b' class IntegrationOptionsSchemaBase(colan'
140 )
179 )
141
180
142 scope = colander.SchemaNode(
181 scope = colander.SchemaNode(
143 IntegrationScope(),
182 IntegrationScopeType(),
144 description=_(
183 description=_(
145 'Scope of the integration. Group scope means the integration '
184 'Scope of the integration. Recursive means the integration '
146 ' runs on all child repos of that group.'),
185 ' runs on all repos of that group and children recursively.'),
147 title=_('Integration scope'),
186 title=_('Integration scope'),
148 validator=deferred_integration_scopes_validator,
187 validator=deferred_integration_scopes_validator,
149 widget=deferred_integration_scopes_widget,
188 widget=deferred_integration_scopes_widget,
@@ -166,14 +166,17 b''
166 %elif integration.repo_group:
166 %elif integration.repo_group:
167 <a href="${h.url('repo_group_home', group_name=integration.repo_group.group_name)}">
167 <a href="${h.url('repo_group_home', group_name=integration.repo_group.group_name)}">
168 ${_('repogroup')}:${integration.repo_group.group_name}
168 ${_('repogroup')}:${integration.repo_group.group_name}
169 %if integration.child_repos_only:
170 ${_('child repos only')}
171 %else:
172 ${_('cascade to all')}
173 %endif
169 </a>
174 </a>
170 %else:
175 %else:
171 %if integration.scope == 'root_repos':
176 %if integration.child_repos_only:
172 ${_('top level repos only')}
177 ${_('top level repos only')}
173 %elif integration.scope == 'global':
178 %else:
174 ${_('global')}
179 ${_('global')}
175 %else:
176 ${_('unknown scope')}: ${integration.scope}
177 %endif
180 %endif
178 </td>
181 </td>
179 %endif
182 %endif
@@ -222,12 +222,14 b' def _post_integration_test_helper(app, u'
222 scopes_destinations = [
222 scopes_destinations = [
223 ('global',
223 ('global',
224 ADMIN_PREFIX + '/integrations'),
224 ADMIN_PREFIX + '/integrations'),
225 ('root_repos',
225 ('root-repos',
226 ADMIN_PREFIX + '/integrations'),
226 ADMIN_PREFIX + '/integrations'),
227 ('repo:%s' % repo.repo_name,
227 ('repo:%s' % repo.repo_name,
228 '/%s/settings/integrations' % repo.repo_name),
228 '/%s/settings/integrations' % repo.repo_name),
229 ('repogroup:%s' % repo_group.group_name,
229 ('repogroup:%s' % repo_group.group_name,
230 '/%s/settings/integrations' % repo_group.group_name),
230 '/%s/settings/integrations' % repo_group.group_name),
231 ('repogroup-recursive:%s' % repo_group.group_name,
232 '/%s/settings/integrations' % repo_group.group_name),
231 ]
233 ]
232
234
233 for scope, destination in scopes_destinations:
235 for scope, destination in scopes_destinations:
@@ -51,75 +51,84 b' class TestDeleteScopesDeletesIntegration'
51 def integration_repos(request, StubIntegrationType, stub_integration_settings):
51 def integration_repos(request, StubIntegrationType, stub_integration_settings):
52 """
52 """
53 Create repositories and integrations for testing, and destroy them after
53 Create repositories and integrations for testing, and destroy them after
54
55 Structure:
56 root_repo
57 parent_group/
58 parent_repo
59 child_group/
60 child_repo
61 other_group/
62 other_repo
54 """
63 """
55 fixture = Fixture()
64 fixture = Fixture()
56
65
57 repo_group_1_id = 'int_test_repo_group_1_%s' % time.time()
66
58 repo_group_1 = fixture.create_repo_group(repo_group_1_id)
67 parent_group_id = 'int_test_parent_group_%s' % time.time()
59 repo_group_2_id = 'int_test_repo_group_2_%s' % time.time()
68 parent_group = fixture.create_repo_group(parent_group_id)
60 repo_group_2 = fixture.create_repo_group(repo_group_2_id)
69
70 other_group_id = 'int_test_other_group_%s' % time.time()
71 other_group = fixture.create_repo_group(other_group_id)
61
72
62 repo_1_id = 'int_test_repo_1_%s' % time.time()
73 child_group_id = (
63 repo_1 = fixture.create_repo(repo_1_id, repo_group=repo_group_1)
74 parent_group_id + '/' + 'int_test_child_group_%s' % time.time())
64 repo_2_id = 'int_test_repo_2_%s' % time.time()
75 child_group = fixture.create_repo_group(child_group_id)
65 repo_2 = fixture.create_repo(repo_2_id, repo_group=repo_group_2)
76
77 parent_repo_id = 'int_test_parent_repo_%s' % time.time()
78 parent_repo = fixture.create_repo(parent_repo_id, repo_group=parent_group)
79
80 child_repo_id = 'int_test_child_repo_%s' % time.time()
81 child_repo = fixture.create_repo(child_repo_id, repo_group=child_group)
82
83 other_repo_id = 'int_test_other_repo_%s' % time.time()
84 other_repo = fixture.create_repo(other_repo_id, repo_group=other_group)
66
85
67 root_repo_id = 'int_test_repo_root_%s' % time.time()
86 root_repo_id = 'int_test_repo_root_%s' % time.time()
68 root_repo = fixture.create_repo(root_repo_id)
87 root_repo = fixture.create_repo(root_repo_id)
69
88
70 integration_global = IntegrationModel().create(
89 integrations = {}
71 StubIntegrationType, settings=stub_integration_settings,
90 for name, repo, repo_group, child_repos_only in [
72 enabled=True, name='test global integration', scope='global')
91 ('global', None, None, None),
73 integration_root_repos = IntegrationModel().create(
92 ('root_repos', None, None, True),
74 StubIntegrationType, settings=stub_integration_settings,
93 ('parent_repo', parent_repo, None, None),
75 enabled=True, name='test root repos integration', scope='root_repos')
94 ('child_repo', child_repo, None, None),
76 integration_repo_1 = IntegrationModel().create(
95 ('other_repo', other_repo, None, None),
96 ('root_repo', root_repo, None, None),
97 ('parent_group', None, parent_group, True),
98 ('parent_group_recursive', None, parent_group, False),
99 ('child_group', None, child_group, True),
100 ('child_group_recursive', None, child_group, False),
101 ('other_group', None, other_group, True),
102 ('other_group_recursive', None, other_group, False),
103 ]:
104 integrations[name] = IntegrationModel().create(
77 StubIntegrationType, settings=stub_integration_settings,
105 StubIntegrationType, settings=stub_integration_settings,
78 enabled=True, name='test repo 1 integration', scope=repo_1)
106 enabled=True, name='test %s integration' % name,
79 integration_repo_group_1 = IntegrationModel().create(
107 repo=repo, repo_group=repo_group, child_repos_only=child_repos_only)
80 StubIntegrationType, settings=stub_integration_settings,
81 enabled=True, name='test repo group 1 integration', scope=repo_group_1)
82 integration_repo_2 = IntegrationModel().create(
83 StubIntegrationType, settings=stub_integration_settings,
84 enabled=True, name='test repo 2 integration', scope=repo_2)
85 integration_repo_group_2 = IntegrationModel().create(
86 StubIntegrationType, settings=stub_integration_settings,
87 enabled=True, name='test repo group 2 integration', scope=repo_group_2)
88
108
89 Session().commit()
109 Session().commit()
90
110
91 def _cleanup():
111 def _cleanup():
92 Session().delete(integration_global)
112 for integration in integrations.values():
93 Session().delete(integration_root_repos)
113 Session.delete(integration)
94 Session().delete(integration_repo_1)
114
95 Session().delete(integration_repo_group_1)
96 Session().delete(integration_repo_2)
97 Session().delete(integration_repo_group_2)
98 fixture.destroy_repo(root_repo)
115 fixture.destroy_repo(root_repo)
99 fixture.destroy_repo(repo_1)
116 fixture.destroy_repo(child_repo)
100 fixture.destroy_repo(repo_2)
117 fixture.destroy_repo(parent_repo)
101 fixture.destroy_repo_group(repo_group_1)
118 fixture.destroy_repo(other_repo)
102 fixture.destroy_repo_group(repo_group_2)
119 fixture.destroy_repo_group(child_group)
120 fixture.destroy_repo_group(parent_group)
121 fixture.destroy_repo_group(other_group)
103
122
104 request.addfinalizer(_cleanup)
123 request.addfinalizer(_cleanup)
105
124
106 return {
125 return {
126 'integrations': integrations,
107 'repos': {
127 'repos': {
108 'repo_1': repo_1,
109 'repo_2': repo_2,
110 'root_repo': root_repo,
128 'root_repo': root_repo,
111 },
129 'other_repo': other_repo,
112 'repo_groups': {
130 'parent_repo': parent_repo,
113 'repo_group_1': repo_group_1,
131 'child_repo': child_repo,
114 'repo_group_2': repo_group_2,
115 },
116 'integrations': {
117 'global': integration_global,
118 'root_repos': integration_root_repos,
119 'repo_1': integration_repo_1,
120 'repo_2': integration_repo_2,
121 'repo_group_1': integration_repo_group_1,
122 'repo_group_2': integration_repo_group_2,
123 }
132 }
124 }
133 }
125
134
@@ -133,27 +142,41 b' def test_enabled_integration_repo_scopes'
133
142
134 assert triggered_integrations == [
143 assert triggered_integrations == [
135 integrations['global'],
144 integrations['global'],
136 integrations['root_repos']
145 integrations['root_repos'],
146 integrations['root_repo'],
147 ]
148
149
150 triggered_integrations = IntegrationModel().get_for_event(
151 events.RepoEvent(repos['other_repo']))
152
153 assert triggered_integrations == [
154 integrations['global'],
155 integrations['other_repo'],
156 integrations['other_group'],
157 integrations['other_group_recursive'],
137 ]
158 ]
138
159
139
160
140 triggered_integrations = IntegrationModel().get_for_event(
161 triggered_integrations = IntegrationModel().get_for_event(
141 events.RepoEvent(repos['repo_1']))
162 events.RepoEvent(repos['parent_repo']))
142
163
143 assert triggered_integrations == [
164 assert triggered_integrations == [
144 integrations['global'],
165 integrations['global'],
145 integrations['repo_1'],
166 integrations['parent_repo'],
146 integrations['repo_group_1']
167 integrations['parent_group'],
168 integrations['parent_group_recursive'],
147 ]
169 ]
148
170
149
150 triggered_integrations = IntegrationModel().get_for_event(
171 triggered_integrations = IntegrationModel().get_for_event(
151 events.RepoEvent(repos['repo_2']))
172 events.RepoEvent(repos['child_repo']))
152
173
153 assert triggered_integrations == [
174 assert triggered_integrations == [
154 integrations['global'],
175 integrations['global'],
155 integrations['repo_2'],
176 integrations['child_repo'],
156 integrations['repo_group_2'],
177 integrations['parent_group_recursive'],
178 integrations['child_group'],
179 integrations['child_group_recursive'],
157 ]
180 ]
158
181
159
182
@@ -172,17 +195,24 b' def test_disabled_integration_repo_scope'
172
195
173
196
174 triggered_integrations = IntegrationModel().get_for_event(
197 triggered_integrations = IntegrationModel().get_for_event(
175 events.RepoEvent(repos['repo_1']))
198 events.RepoEvent(repos['parent_repo']))
176
199
177 assert triggered_integrations == []
200 assert triggered_integrations == []
178
201
179
202
180 triggered_integrations = IntegrationModel().get_for_event(
203 triggered_integrations = IntegrationModel().get_for_event(
181 events.RepoEvent(repos['repo_2']))
204 events.RepoEvent(repos['child_repo']))
182
205
183 assert triggered_integrations == []
206 assert triggered_integrations == []
184
207
185
208
209 triggered_integrations = IntegrationModel().get_for_event(
210 events.RepoEvent(repos['other_repo']))
211
212 assert triggered_integrations == []
213
214
215
186 def test_enabled_non_repo_integrations(integration_repos):
216 def test_enabled_non_repo_integrations(integration_repos):
187 integrations = integration_repos['integrations']
217 integrations = integration_repos['integrations']
188
218
@@ -47,8 +47,15 b' class TestIntegrationSchema(object):'
47 'repositories_groups': {},
47 'repositories_groups': {},
48 }
48 }
49
49
50 perms_tests = {
50 perms_tests = [
51 ('repo:%s' % repo.repo_name, repo): [
51 (
52 'repo:%s' % repo.repo_name,
53 {
54 'child_repos_only': None,
55 'repo_group': None,
56 'repo': repo,
57 },
58 [
52 ({}, False),
59 ({}, False),
53 ({'global': ['hg.admin']}, True),
60 ({'global': ['hg.admin']}, True),
54 ({'global': []}, False),
61 ({'global': []}, False),
@@ -56,8 +63,16 b' class TestIntegrationSchema(object):'
56 ({'repositories': {repo.repo_name: 'repository.read'}}, False),
63 ({'repositories': {repo.repo_name: 'repository.read'}}, False),
57 ({'repositories': {repo.repo_name: 'repository.write'}}, False),
64 ({'repositories': {repo.repo_name: 'repository.write'}}, False),
58 ({'repositories': {repo.repo_name: 'repository.none'}}, False),
65 ({'repositories': {repo.repo_name: 'repository.none'}}, False),
59 ],
66 ]
60 ('repogroup:%s' % repo_group.group_name, repo_group): [
67 ),
68 (
69 'repogroup:%s' % repo_group.group_name,
70 {
71 'repo': None,
72 'repo_group': repo_group,
73 'child_repos_only': True,
74 },
75 [
61 ({}, False),
76 ({}, False),
62 ({'global': ['hg.admin']}, True),
77 ({'global': ['hg.admin']}, True),
63 ({'global': []}, False),
78 ({'global': []}, False),
@@ -69,20 +84,56 b' class TestIntegrationSchema(object):'
69 {repo_group.group_name: 'group.write'}}, False),
84 {repo_group.group_name: 'group.write'}}, False),
70 ({'repositories_groups':
85 ({'repositories_groups':
71 {repo_group.group_name: 'group.none'}}, False),
86 {repo_group.group_name: 'group.none'}}, False),
72 ],
87 ]
73 ('global', 'global'): [
88 ),
89 (
90 'repogroup-recursive:%s' % repo_group.group_name,
91 {
92 'repo': None,
93 'repo_group': repo_group,
94 'child_repos_only': False,
95 },
96 [
74 ({}, False),
97 ({}, False),
75 ({'global': ['hg.admin']}, True),
98 ({'global': ['hg.admin']}, True),
76 ({'global': []}, False),
99 ({'global': []}, False),
77 ],
100 ({'repositories_groups':
78 ('root_repos', 'root_repos'): [
101 {repo_group.group_name: 'group.admin'}}, True),
102 ({'repositories_groups':
103 {repo_group.group_name: 'group.read'}}, False),
104 ({'repositories_groups':
105 {repo_group.group_name: 'group.write'}}, False),
106 ({'repositories_groups':
107 {repo_group.group_name: 'group.none'}}, False),
108 ]
109 ),
110 (
111 'global',
112 {
113 'repo': None,
114 'repo_group': None,
115 'child_repos_only': False,
116 }, [
79 ({}, False),
117 ({}, False),
80 ({'global': ['hg.admin']}, True),
118 ({'global': ['hg.admin']}, True),
81 ({'global': []}, False),
119 ({'global': []}, False),
82 ],
120 ]
83 }
121 ),
122 (
123 'root-repos',
124 {
125 'repo': None,
126 'repo_group': None,
127 'child_repos_only': True,
128 }, [
129 ({}, False),
130 ({'global': ['hg.admin']}, True),
131 ({'global': []}, False),
132 ]
133 ),
134 ]
84
135
85 for (scope_input, scope_output), perms_allowed in perms_tests.items():
136 for scope_input, scope_output, perms_allowed in perms_tests:
86 for perms_update, allowed in perms_allowed:
137 for perms_update, allowed in perms_allowed:
87 perms = dict(empty_perms_dict, **perms_update)
138 perms = dict(empty_perms_dict, **perms_update)
88
139
@@ -1709,7 +1709,8 b' def repo_integration_stub(request, repo_'
1709 stub_integration_settings):
1709 stub_integration_settings):
1710 integration = IntegrationModel().create(
1710 integration = IntegrationModel().create(
1711 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1711 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1712 name='test repo integration', scope=repo_stub)
1712 name='test repo integration',
1713 repo=repo_stub, repo_group=None, child_repos_only=None)
1713
1714
1714 @request.addfinalizer
1715 @request.addfinalizer
1715 def cleanup():
1716 def cleanup():
@@ -1723,7 +1724,23 b' def repogroup_integration_stub(request, '
1723 stub_integration_settings):
1724 stub_integration_settings):
1724 integration = IntegrationModel().create(
1725 integration = IntegrationModel().create(
1725 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1726 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1726 name='test repogroup integration', scope=test_repo_group)
1727 name='test repogroup integration',
1728 repo=None, repo_group=test_repo_group, child_repos_only=True)
1729
1730 @request.addfinalizer
1731 def cleanup():
1732 IntegrationModel().delete(integration)
1733
1734 return integration
1735
1736
1737 @pytest.fixture
1738 def repogroup_recursive_integration_stub(request, test_repo_group,
1739 StubIntegrationType, stub_integration_settings):
1740 integration = IntegrationModel().create(
1741 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1742 name='test recursive repogroup integration',
1743 repo=None, repo_group=test_repo_group, child_repos_only=False)
1727
1744
1728 @request.addfinalizer
1745 @request.addfinalizer
1729 def cleanup():
1746 def cleanup():
@@ -1737,7 +1754,8 b' def global_integration_stub(request, Stu'
1737 stub_integration_settings):
1754 stub_integration_settings):
1738 integration = IntegrationModel().create(
1755 integration = IntegrationModel().create(
1739 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1756 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1740 name='test global integration', scope='global')
1757 name='test global integration',
1758 repo=None, repo_group=None, child_repos_only=None)
1741
1759
1742 @request.addfinalizer
1760 @request.addfinalizer
1743 def cleanup():
1761 def cleanup():
@@ -1751,7 +1769,8 b' def root_repos_integration_stub(request,'
1751 stub_integration_settings):
1769 stub_integration_settings):
1752 integration = IntegrationModel().create(
1770 integration = IntegrationModel().create(
1753 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1771 StubIntegrationType, settings=stub_integration_settings, enabled=True,
1754 name='test global integration', scope='root_repos')
1772 name='test global integration',
1773 repo=None, repo_group=None, child_repos_only=True)
1755
1774
1756 @request.addfinalizer
1775 @request.addfinalizer
1757 def cleanup():
1776 def cleanup():
General Comments 0
You need to be logged in to leave comments. Login now