##// END OF EJS Templates
mercurial: allow editing largefile store from web interface.
marcink -
r1563:d4c84e02 default
parent child Browse files
Show More
@@ -1,32 +1,14 b''
1 1 .. _hg-lrg-loc:
2 2
3 3 Change the |hg| Large Files Location
4 4 ------------------------------------
5 5
6 6 |RCE| manages |hg| larges files from the following default location
7 7 :file:`/home/{user}/repos/.cache/largefiles`. If you wish to change this, use
8 8 the following steps:
9 9
10 1. Open ishell from the terminal and use it to log into the |RCE| database by
11 specifying the instance :file:`rhodecode.ini` file.
12
13 .. code-block:: bash
14
15 # Open iShell from the terminal and set ini file
16 $ rccontrol ishell enterprise-1
17
18 2. Run the following commands, and ensure that |RCE| has write access to the
19 new directory:
10 1. Open :menuselection:`Admin --> Settings --> VCS` as super-admin.
20 11
21 .. code-block:: bash
12 In section called `Mercurial Settings` you can change where the largefiles
13 objects should be stored.
22 14
23 # Once logged into the database, use SQL to redirect
24 # the large files location
25 In [1]: from rhodecode.model.settings import SettingsModel
26 In [2]: SettingsModel().get_ui_by_key('usercache')
27 Out[2]: <RhodeCodeUi[largefiles]usercache=>/mnt/hgfs/shared/workspace/xxxx/.cache/largefiles]>
28
29 In [3]: largefiles_cache = SettingsModel().get_ui_by_key('usercache')
30 In [4]: largefiles_cache.ui_value = '/new/path’
31 In [5]: Session().add(largefiles_cache);Session().commit()
32
@@ -1,80 +1,84 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import shlex
23 23 import platform
24 24
25 25 from rhodecode.model import init_model
26 26
27 27
28 28
29 29 def configure_vcs(config):
30 30 """
31 31 Patch VCS config with some RhodeCode specific stuff
32 32 """
33 33 from rhodecode.lib.vcs import conf
34 34 conf.settings.BACKENDS = {
35 35 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
36 36 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
37 37 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository',
38 38 }
39 39
40 40 conf.settings.HOOKS_PROTOCOL = config['vcs.hooks.protocol']
41 41 conf.settings.HOOKS_DIRECT_CALLS = config['vcs.hooks.direct_calls']
42 42 conf.settings.GIT_REV_FILTER = shlex.split(config['git_rev_filter'])
43 43 conf.settings.DEFAULT_ENCODINGS = config['default_encoding']
44 44 conf.settings.ALIASES[:] = config['vcs.backends']
45 45 conf.settings.SVN_COMPATIBLE_VERSION = config['vcs.svn.compatible_version']
46 46
47 47
48 48 def initialize_database(config):
49 49 from rhodecode.lib.utils2 import engine_from_config, get_encryption_key
50 50 engine = engine_from_config(config, 'sqlalchemy.db1.')
51 51 init_model(engine, encryption_key=get_encryption_key(config))
52 52
53 53
54 54 def initialize_test_environment(settings, test_env=None):
55 55 if test_env is None:
56 56 test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0))
57 57
58 58 from rhodecode.lib.utils import (
59 59 create_test_directory, create_test_database, create_test_repositories,
60 60 create_test_index)
61 61 from rhodecode.tests import TESTS_TMP_PATH
62 from rhodecode.lib.vcs.backends.hg import largefiles_store
62 63 # test repos
63 64 if test_env:
64 65 create_test_directory(TESTS_TMP_PATH)
66 # large object stores
67 create_test_directory(largefiles_store(TESTS_TMP_PATH))
68
65 69 create_test_database(TESTS_TMP_PATH, settings)
66 70 create_test_repositories(TESTS_TMP_PATH, settings)
67 71 create_test_index(TESTS_TMP_PATH, settings)
68 72
69 73
70 74 def get_vcs_server_protocol(config):
71 75 return config['vcs.server.protocol']
72 76
73 77
74 78 def set_instance_id(config):
75 79 """ Sets a dynamic generated config['instance_id'] if missing or '*' """
76 80
77 81 config['instance_id'] = config.get('instance_id') or ''
78 82 if config['instance_id'] == '*' or not config['instance_id']:
79 83 _platform_id = platform.uname()[1] or 'instance'
80 84 config['instance_id'] = '%s-%s' % (_platform_id, os.getpid())
@@ -1,549 +1,553 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 this is forms validation classes
23 23 http://formencode.org/module-formencode.validators.html
24 24 for list off all availible validators
25 25
26 26 we can create our own validators
27 27
28 28 The table below outlines the options which can be used in a schema in addition to the validators themselves
29 29 pre_validators [] These validators will be applied before the schema
30 30 chained_validators [] These validators will be applied after the schema
31 31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
32 32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
33 33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
34 34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
35 35
36 36
37 37 <name> = formencode.validators.<name of validator>
38 38 <name> must equal form name
39 39 list=[1,2,3,4,5]
40 40 for SELECT use formencode.All(OneOf(list), Int())
41 41
42 42 """
43 43
44 44 import deform
45 45 import logging
46 46 import formencode
47 47
48 48 from pkg_resources import resource_filename
49 49 from formencode import All, Pipe
50 50
51 51 from pylons.i18n.translation import _
52 52
53 53 from rhodecode import BACKENDS
54 54 from rhodecode.lib import helpers
55 55 from rhodecode.model import validators as v
56 56
57 57 log = logging.getLogger(__name__)
58 58
59 59
60 60 deform_templates = resource_filename('deform', 'templates')
61 61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
62 62 search_path = (rhodecode_templates, deform_templates)
63 63
64 64
65 65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
66 66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
67 67 def __call__(self, template_name, **kw):
68 68 kw['h'] = helpers
69 69 return self.load(template_name)(**kw)
70 70
71 71
72 72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
73 73 deform.Form.set_default_renderer(form_renderer)
74 74
75 75
76 76 def LoginForm():
77 77 class _LoginForm(formencode.Schema):
78 78 allow_extra_fields = True
79 79 filter_extra_fields = True
80 80 username = v.UnicodeString(
81 81 strip=True,
82 82 min=1,
83 83 not_empty=True,
84 84 messages={
85 85 'empty': _(u'Please enter a login'),
86 86 'tooShort': _(u'Enter a value %(min)i characters long or more')
87 87 }
88 88 )
89 89
90 90 password = v.UnicodeString(
91 91 strip=False,
92 92 min=3,
93 93 not_empty=True,
94 94 messages={
95 95 'empty': _(u'Please enter a password'),
96 96 'tooShort': _(u'Enter %(min)i characters or more')}
97 97 )
98 98
99 99 remember = v.StringBoolean(if_missing=False)
100 100
101 101 chained_validators = [v.ValidAuth()]
102 102 return _LoginForm
103 103
104 104
105 105 def UserForm(edit=False, available_languages=[], old_data={}):
106 106 class _UserForm(formencode.Schema):
107 107 allow_extra_fields = True
108 108 filter_extra_fields = True
109 109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
110 110 v.ValidUsername(edit, old_data))
111 111 if edit:
112 112 new_password = All(
113 113 v.ValidPassword(),
114 114 v.UnicodeString(strip=False, min=6, not_empty=False)
115 115 )
116 116 password_confirmation = All(
117 117 v.ValidPassword(),
118 118 v.UnicodeString(strip=False, min=6, not_empty=False),
119 119 )
120 120 admin = v.StringBoolean(if_missing=False)
121 121 else:
122 122 password = All(
123 123 v.ValidPassword(),
124 124 v.UnicodeString(strip=False, min=6, not_empty=True)
125 125 )
126 126 password_confirmation = All(
127 127 v.ValidPassword(),
128 128 v.UnicodeString(strip=False, min=6, not_empty=False)
129 129 )
130 130
131 131 password_change = v.StringBoolean(if_missing=False)
132 132 create_repo_group = v.StringBoolean(if_missing=False)
133 133
134 134 active = v.StringBoolean(if_missing=False)
135 135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
137 137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
138 138 extern_name = v.UnicodeString(strip=True)
139 139 extern_type = v.UnicodeString(strip=True)
140 140 language = v.OneOf(available_languages, hideList=False,
141 141 testValueList=True, if_missing=None)
142 142 chained_validators = [v.ValidPasswordsMatch()]
143 143 return _UserForm
144 144
145 145
146 146 def UserGroupForm(edit=False, old_data=None, allow_disabled=False):
147 147 old_data = old_data or {}
148 148
149 149 class _UserGroupForm(formencode.Schema):
150 150 allow_extra_fields = True
151 151 filter_extra_fields = True
152 152
153 153 users_group_name = All(
154 154 v.UnicodeString(strip=True, min=1, not_empty=True),
155 155 v.ValidUserGroup(edit, old_data)
156 156 )
157 157 user_group_description = v.UnicodeString(strip=True, min=1,
158 158 not_empty=False)
159 159
160 160 users_group_active = v.StringBoolean(if_missing=False)
161 161
162 162 if edit:
163 163 # this is user group owner
164 164 user = All(
165 165 v.UnicodeString(not_empty=True),
166 166 v.ValidRepoUser(allow_disabled))
167 167 return _UserGroupForm
168 168
169 169
170 170 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
171 171 can_create_in_root=False, allow_disabled=False):
172 172 old_data = old_data or {}
173 173 available_groups = available_groups or []
174 174
175 175 class _RepoGroupForm(formencode.Schema):
176 176 allow_extra_fields = True
177 177 filter_extra_fields = False
178 178
179 179 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
180 180 v.SlugifyName(),)
181 181 group_description = v.UnicodeString(strip=True, min=1,
182 182 not_empty=False)
183 183 group_copy_permissions = v.StringBoolean(if_missing=False)
184 184
185 185 group_parent_id = v.OneOf(available_groups, hideList=False,
186 186 testValueList=True, not_empty=True)
187 187 enable_locking = v.StringBoolean(if_missing=False)
188 188 chained_validators = [
189 189 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
190 190
191 191 if edit:
192 192 # this is repo group owner
193 193 user = All(
194 194 v.UnicodeString(not_empty=True),
195 195 v.ValidRepoUser(allow_disabled))
196 196
197 197 return _RepoGroupForm
198 198
199 199
200 200 def RegisterForm(edit=False, old_data={}):
201 201 class _RegisterForm(formencode.Schema):
202 202 allow_extra_fields = True
203 203 filter_extra_fields = True
204 204 username = All(
205 205 v.ValidUsername(edit, old_data),
206 206 v.UnicodeString(strip=True, min=1, not_empty=True)
207 207 )
208 208 password = All(
209 209 v.ValidPassword(),
210 210 v.UnicodeString(strip=False, min=6, not_empty=True)
211 211 )
212 212 password_confirmation = All(
213 213 v.ValidPassword(),
214 214 v.UnicodeString(strip=False, min=6, not_empty=True)
215 215 )
216 216 active = v.StringBoolean(if_missing=False)
217 217 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
218 218 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
219 219 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
220 220
221 221 chained_validators = [v.ValidPasswordsMatch()]
222 222
223 223 return _RegisterForm
224 224
225 225
226 226 def PasswordResetForm():
227 227 class _PasswordResetForm(formencode.Schema):
228 228 allow_extra_fields = True
229 229 filter_extra_fields = True
230 230 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
231 231 return _PasswordResetForm
232 232
233 233
234 234 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
235 235 allow_disabled=False):
236 236 old_data = old_data or {}
237 237 repo_groups = repo_groups or []
238 238 landing_revs = landing_revs or []
239 239 supported_backends = BACKENDS.keys()
240 240
241 241 class _RepoForm(formencode.Schema):
242 242 allow_extra_fields = True
243 243 filter_extra_fields = False
244 244 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
245 245 v.SlugifyName())
246 246 repo_group = All(v.CanWriteGroup(old_data),
247 247 v.OneOf(repo_groups, hideList=True))
248 248 repo_type = v.OneOf(supported_backends, required=False,
249 249 if_missing=old_data.get('repo_type'))
250 250 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
251 251 repo_private = v.StringBoolean(if_missing=False)
252 252 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
253 253 repo_copy_permissions = v.StringBoolean(if_missing=False)
254 254 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
255 255
256 256 repo_enable_statistics = v.StringBoolean(if_missing=False)
257 257 repo_enable_downloads = v.StringBoolean(if_missing=False)
258 258 repo_enable_locking = v.StringBoolean(if_missing=False)
259 259
260 260 if edit:
261 261 # this is repo owner
262 262 user = All(
263 263 v.UnicodeString(not_empty=True),
264 264 v.ValidRepoUser(allow_disabled))
265 265 clone_uri_change = v.UnicodeString(
266 266 not_empty=False, if_missing=v.Missing)
267 267
268 268 chained_validators = [v.ValidCloneUri(),
269 269 v.ValidRepoName(edit, old_data)]
270 270 return _RepoForm
271 271
272 272
273 273 def RepoPermsForm():
274 274 class _RepoPermsForm(formencode.Schema):
275 275 allow_extra_fields = True
276 276 filter_extra_fields = False
277 277 chained_validators = [v.ValidPerms(type_='repo')]
278 278 return _RepoPermsForm
279 279
280 280
281 281 def RepoGroupPermsForm(valid_recursive_choices):
282 282 class _RepoGroupPermsForm(formencode.Schema):
283 283 allow_extra_fields = True
284 284 filter_extra_fields = False
285 285 recursive = v.OneOf(valid_recursive_choices)
286 286 chained_validators = [v.ValidPerms(type_='repo_group')]
287 287 return _RepoGroupPermsForm
288 288
289 289
290 290 def UserGroupPermsForm():
291 291 class _UserPermsForm(formencode.Schema):
292 292 allow_extra_fields = True
293 293 filter_extra_fields = False
294 294 chained_validators = [v.ValidPerms(type_='user_group')]
295 295 return _UserPermsForm
296 296
297 297
298 298 def RepoFieldForm():
299 299 class _RepoFieldForm(formencode.Schema):
300 300 filter_extra_fields = True
301 301 allow_extra_fields = True
302 302
303 303 new_field_key = All(v.FieldKey(),
304 304 v.UnicodeString(strip=True, min=3, not_empty=True))
305 305 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
306 306 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
307 307 if_missing='str')
308 308 new_field_label = v.UnicodeString(not_empty=False)
309 309 new_field_desc = v.UnicodeString(not_empty=False)
310 310
311 311 return _RepoFieldForm
312 312
313 313
314 314 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
315 315 repo_groups=[], landing_revs=[]):
316 316 class _RepoForkForm(formencode.Schema):
317 317 allow_extra_fields = True
318 318 filter_extra_fields = False
319 319 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
320 320 v.SlugifyName())
321 321 repo_group = All(v.CanWriteGroup(),
322 322 v.OneOf(repo_groups, hideList=True))
323 323 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
324 324 description = v.UnicodeString(strip=True, min=1, not_empty=True)
325 325 private = v.StringBoolean(if_missing=False)
326 326 copy_permissions = v.StringBoolean(if_missing=False)
327 327 fork_parent_id = v.UnicodeString()
328 328 chained_validators = [v.ValidForkName(edit, old_data)]
329 329 landing_rev = v.OneOf(landing_revs, hideList=True)
330 330
331 331 return _RepoForkForm
332 332
333 333
334 334 def ApplicationSettingsForm():
335 335 class _ApplicationSettingsForm(formencode.Schema):
336 336 allow_extra_fields = True
337 337 filter_extra_fields = False
338 338 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
339 339 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
340 340 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
341 341 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
342 342 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
343 343 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
344 344 rhodecode_create_personal_repo_group = v.StringBoolean(if_missing=False)
345 345 rhodecode_personal_repo_group_pattern = v.UnicodeString(strip=True, min=1, not_empty=False)
346 346
347 347 return _ApplicationSettingsForm
348 348
349 349
350 350 def ApplicationVisualisationForm():
351 351 class _ApplicationVisualisationForm(formencode.Schema):
352 352 allow_extra_fields = True
353 353 filter_extra_fields = False
354 354 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
355 355 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
356 356 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
357 357
358 358 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
359 359 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
360 360 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
361 361 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
362 362 rhodecode_show_version = v.StringBoolean(if_missing=False)
363 363 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
364 364 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
365 365 rhodecode_gravatar_url = v.UnicodeString(min=3)
366 366 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
367 367 rhodecode_support_url = v.UnicodeString()
368 368 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
369 369 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
370 370
371 371 return _ApplicationVisualisationForm
372 372
373 373
374 374 class _BaseVcsSettingsForm(formencode.Schema):
375 375 allow_extra_fields = True
376 376 filter_extra_fields = False
377 377 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
378 378 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
379 379 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
380 380
381 381 extensions_largefiles = v.StringBoolean(if_missing=False)
382 382 phases_publish = v.StringBoolean(if_missing=False)
383 383
384 384 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
385 385 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
386 386 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
387 387
388 388 vcs_svn_proxy_http_requests_enabled = v.StringBoolean(if_missing=False)
389 389 vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None)
390 390
391 391
392 392 def ApplicationUiSettingsForm():
393 393 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
394 394 web_push_ssl = v.StringBoolean(if_missing=False)
395 395 paths_root_path = All(
396 396 v.ValidPath(),
397 397 v.UnicodeString(strip=True, min=1, not_empty=True)
398 398 )
399 largefiles_usercache = All(
400 v.ValidPath(),
401 v.UnicodeString(strip=True, min=2, not_empty=True)
402 )
399 403 extensions_hgsubversion = v.StringBoolean(if_missing=False)
400 404 extensions_hggit = v.StringBoolean(if_missing=False)
401 405 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
402 406 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
403 407
404 408 return _ApplicationUiSettingsForm
405 409
406 410
407 411 def RepoVcsSettingsForm(repo_name):
408 412 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
409 413 inherit_global_settings = v.StringBoolean(if_missing=False)
410 414 new_svn_branch = v.ValidSvnPattern(
411 415 section='vcs_svn_branch', repo_name=repo_name)
412 416 new_svn_tag = v.ValidSvnPattern(
413 417 section='vcs_svn_tag', repo_name=repo_name)
414 418
415 419 return _RepoVcsSettingsForm
416 420
417 421
418 422 def LabsSettingsForm():
419 423 class _LabSettingsForm(formencode.Schema):
420 424 allow_extra_fields = True
421 425 filter_extra_fields = False
422 426
423 427 return _LabSettingsForm
424 428
425 429
426 430 def ApplicationPermissionsForm(
427 431 register_choices, password_reset_choices, extern_activate_choices):
428 432 class _DefaultPermissionsForm(formencode.Schema):
429 433 allow_extra_fields = True
430 434 filter_extra_fields = True
431 435
432 436 anonymous = v.StringBoolean(if_missing=False)
433 437 default_register = v.OneOf(register_choices)
434 438 default_register_message = v.UnicodeString()
435 439 default_password_reset = v.OneOf(password_reset_choices)
436 440 default_extern_activate = v.OneOf(extern_activate_choices)
437 441
438 442 return _DefaultPermissionsForm
439 443
440 444
441 445 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
442 446 user_group_perms_choices):
443 447 class _ObjectPermissionsForm(formencode.Schema):
444 448 allow_extra_fields = True
445 449 filter_extra_fields = True
446 450 overwrite_default_repo = v.StringBoolean(if_missing=False)
447 451 overwrite_default_group = v.StringBoolean(if_missing=False)
448 452 overwrite_default_user_group = v.StringBoolean(if_missing=False)
449 453 default_repo_perm = v.OneOf(repo_perms_choices)
450 454 default_group_perm = v.OneOf(group_perms_choices)
451 455 default_user_group_perm = v.OneOf(user_group_perms_choices)
452 456
453 457 return _ObjectPermissionsForm
454 458
455 459
456 460 def UserPermissionsForm(create_choices, create_on_write_choices,
457 461 repo_group_create_choices, user_group_create_choices,
458 462 fork_choices, inherit_default_permissions_choices):
459 463 class _DefaultPermissionsForm(formencode.Schema):
460 464 allow_extra_fields = True
461 465 filter_extra_fields = True
462 466
463 467 anonymous = v.StringBoolean(if_missing=False)
464 468
465 469 default_repo_create = v.OneOf(create_choices)
466 470 default_repo_create_on_write = v.OneOf(create_on_write_choices)
467 471 default_user_group_create = v.OneOf(user_group_create_choices)
468 472 default_repo_group_create = v.OneOf(repo_group_create_choices)
469 473 default_fork_create = v.OneOf(fork_choices)
470 474 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
471 475
472 476 return _DefaultPermissionsForm
473 477
474 478
475 479 def UserIndividualPermissionsForm():
476 480 class _DefaultPermissionsForm(formencode.Schema):
477 481 allow_extra_fields = True
478 482 filter_extra_fields = True
479 483
480 484 inherit_default_permissions = v.StringBoolean(if_missing=False)
481 485
482 486 return _DefaultPermissionsForm
483 487
484 488
485 489 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
486 490 class _DefaultsForm(formencode.Schema):
487 491 allow_extra_fields = True
488 492 filter_extra_fields = True
489 493 default_repo_type = v.OneOf(supported_backends)
490 494 default_repo_private = v.StringBoolean(if_missing=False)
491 495 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
492 496 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
493 497 default_repo_enable_locking = v.StringBoolean(if_missing=False)
494 498
495 499 return _DefaultsForm
496 500
497 501
498 502 def AuthSettingsForm():
499 503 class _AuthSettingsForm(formencode.Schema):
500 504 allow_extra_fields = True
501 505 filter_extra_fields = True
502 506 auth_plugins = All(v.ValidAuthPlugins(),
503 507 v.UniqueListFromString()(not_empty=True))
504 508
505 509 return _AuthSettingsForm
506 510
507 511
508 512 def UserExtraEmailForm():
509 513 class _UserExtraEmailForm(formencode.Schema):
510 514 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
511 515 return _UserExtraEmailForm
512 516
513 517
514 518 def UserExtraIpForm():
515 519 class _UserExtraIpForm(formencode.Schema):
516 520 ip = v.ValidIp()(not_empty=True)
517 521 return _UserExtraIpForm
518 522
519 523
520 524
521 525 def PullRequestForm(repo_id):
522 526 class ReviewerForm(formencode.Schema):
523 527 user_id = v.Int(not_empty=True)
524 528 reasons = All()
525 529
526 530 class _PullRequestForm(formencode.Schema):
527 531 allow_extra_fields = True
528 532 filter_extra_fields = True
529 533
530 534 user = v.UnicodeString(strip=True, required=True)
531 535 source_repo = v.UnicodeString(strip=True, required=True)
532 536 source_ref = v.UnicodeString(strip=True, required=True)
533 537 target_repo = v.UnicodeString(strip=True, required=True)
534 538 target_ref = v.UnicodeString(strip=True, required=True)
535 539 revisions = All(#v.NotReviewedRevisions(repo_id)(),
536 540 v.UniqueList()(not_empty=True))
537 541 review_members = formencode.ForEach(ReviewerForm())
538 542 pullrequest_title = v.UnicodeString(strip=True, required=True)
539 543 pullrequest_desc = v.UnicodeString(strip=True, required=False)
540 544
541 545 return _PullRequestForm
542 546
543 547
544 548 def IssueTrackerPatternsForm():
545 549 class _IssueTrackerPatternsForm(formencode.Schema):
546 550 allow_extra_fields = True
547 551 filter_extra_fields = False
548 552 chained_validators = [v.ValidPattern()]
549 553 return _IssueTrackerPatternsForm
@@ -1,731 +1,737 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import hashlib
22 22 import logging
23 23 from collections import namedtuple
24 24 from functools import wraps
25 25
26 26 from rhodecode.lib import caches
27 27 from rhodecode.lib.utils2 import (
28 28 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
29 29 from rhodecode.lib.vcs.backends import base
30 30 from rhodecode.model import BaseModel
31 31 from rhodecode.model.db import (
32 32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
33 33 from rhodecode.model.meta import Session
34 34
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 UiSetting = namedtuple(
40 40 'UiSetting', ['section', 'key', 'value', 'active'])
41 41
42 42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
43 43
44 44
45 45 class SettingNotFound(Exception):
46 46 def __init__(self):
47 47 super(SettingNotFound, self).__init__('Setting is not found')
48 48
49 49
50 50 class SettingsModel(BaseModel):
51 51 BUILTIN_HOOKS = (
52 52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
53 53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
54 54 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL)
55 55 HOOKS_SECTION = 'hooks'
56 56
57 57 def __init__(self, sa=None, repo=None):
58 58 self.repo = repo
59 59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
60 60 self.SettingsDbModel = (
61 61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
62 62 super(SettingsModel, self).__init__(sa)
63 63
64 64 def get_ui_by_key(self, key):
65 65 q = self.UiDbModel.query()
66 66 q = q.filter(self.UiDbModel.ui_key == key)
67 67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
68 68 return q.scalar()
69 69
70 70 def get_ui_by_section(self, section):
71 71 q = self.UiDbModel.query()
72 72 q = q.filter(self.UiDbModel.ui_section == section)
73 73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
74 74 return q.all()
75 75
76 76 def get_ui_by_section_and_key(self, section, key):
77 77 q = self.UiDbModel.query()
78 78 q = q.filter(self.UiDbModel.ui_section == section)
79 79 q = q.filter(self.UiDbModel.ui_key == key)
80 80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
81 81 return q.scalar()
82 82
83 83 def get_ui(self, section=None, key=None):
84 84 q = self.UiDbModel.query()
85 85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
86 86
87 87 if section:
88 88 q = q.filter(self.UiDbModel.ui_section == section)
89 89 if key:
90 90 q = q.filter(self.UiDbModel.ui_key == key)
91 91
92 92 # TODO: mikhail: add caching
93 93 result = [
94 94 UiSetting(
95 95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
96 96 value=safe_str(r.ui_value), active=r.ui_active
97 97 )
98 98 for r in q.all()
99 99 ]
100 100 return result
101 101
102 102 def get_builtin_hooks(self):
103 103 q = self.UiDbModel.query()
104 104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
105 105 return self._get_hooks(q)
106 106
107 107 def get_custom_hooks(self):
108 108 q = self.UiDbModel.query()
109 109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
110 110 return self._get_hooks(q)
111 111
112 112 def create_ui_section_value(self, section, val, key=None, active=True):
113 113 new_ui = self.UiDbModel()
114 114 new_ui.ui_section = section
115 115 new_ui.ui_value = val
116 116 new_ui.ui_active = active
117 117
118 118 if self.repo:
119 119 repo = self._get_repo(self.repo)
120 120 repository_id = repo.repo_id
121 121 new_ui.repository_id = repository_id
122 122
123 123 if not key:
124 124 # keys are unique so they need appended info
125 125 if self.repo:
126 126 key = hashlib.sha1(
127 127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
128 128 else:
129 129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
130 130
131 131 new_ui.ui_key = key
132 132
133 133 Session().add(new_ui)
134 134 return new_ui
135 135
136 136 def create_or_update_hook(self, key, value):
137 137 ui = (
138 138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
139 139 self.UiDbModel())
140 140 ui.ui_section = self.HOOKS_SECTION
141 141 ui.ui_active = True
142 142 ui.ui_key = key
143 143 ui.ui_value = value
144 144
145 145 if self.repo:
146 146 repo = self._get_repo(self.repo)
147 147 repository_id = repo.repo_id
148 148 ui.repository_id = repository_id
149 149
150 150 Session().add(ui)
151 151 return ui
152 152
153 153 def delete_ui(self, id_):
154 154 ui = self.UiDbModel.get(id_)
155 155 if not ui:
156 156 raise SettingNotFound()
157 157 Session().delete(ui)
158 158
159 159 def get_setting_by_name(self, name):
160 160 q = self._get_settings_query()
161 161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
162 162 return q.scalar()
163 163
164 164 def create_or_update_setting(
165 165 self, name, val=Optional(''), type_=Optional('unicode')):
166 166 """
167 167 Creates or updates RhodeCode setting. If updates is triggered it will
168 168 only update parameters that are explicityl set Optional instance will
169 169 be skipped
170 170
171 171 :param name:
172 172 :param val:
173 173 :param type_:
174 174 :return:
175 175 """
176 176
177 177 res = self.get_setting_by_name(name)
178 178 repo = self._get_repo(self.repo) if self.repo else None
179 179
180 180 if not res:
181 181 val = Optional.extract(val)
182 182 type_ = Optional.extract(type_)
183 183
184 184 args = (
185 185 (repo.repo_id, name, val, type_)
186 186 if repo else (name, val, type_))
187 187 res = self.SettingsDbModel(*args)
188 188
189 189 else:
190 190 if self.repo:
191 191 res.repository_id = repo.repo_id
192 192
193 193 res.app_settings_name = name
194 194 if not isinstance(type_, Optional):
195 195 # update if set
196 196 res.app_settings_type = type_
197 197 if not isinstance(val, Optional):
198 198 # update if set
199 199 res.app_settings_value = val
200 200
201 201 Session().add(res)
202 202 return res
203 203
204 204 def invalidate_settings_cache(self):
205 205 namespace = 'rhodecode_settings'
206 206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
207 207 caches.clear_cache_manager(cache_manager)
208 208
209 209 def get_all_settings(self, cache=False):
210 210 def _compute():
211 211 q = self._get_settings_query()
212 212 if not q:
213 213 raise Exception('Could not get application settings !')
214 214
215 215 settings = {
216 216 'rhodecode_' + result.app_settings_name: result.app_settings_value
217 217 for result in q
218 218 }
219 219 return settings
220 220
221 221 if cache:
222 222 log.debug('Fetching app settings using cache')
223 223 repo = self._get_repo(self.repo) if self.repo else None
224 224 namespace = 'rhodecode_settings'
225 225 cache_manager = caches.get_cache_manager(
226 226 'sql_cache_short', namespace)
227 227 _cache_key = (
228 228 "get_repo_{}_settings".format(repo.repo_id)
229 229 if repo else "get_app_settings")
230 230
231 231 return cache_manager.get(_cache_key, createfunc=_compute)
232 232
233 233 else:
234 234 return _compute()
235 235
236 236 def get_auth_settings(self):
237 237 q = self._get_settings_query()
238 238 q = q.filter(
239 239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
240 240 rows = q.all()
241 241 auth_settings = {
242 242 row.app_settings_name: row.app_settings_value for row in rows}
243 243 return auth_settings
244 244
245 245 def get_auth_plugins(self):
246 246 auth_plugins = self.get_setting_by_name("auth_plugins")
247 247 return auth_plugins.app_settings_value
248 248
249 249 def get_default_repo_settings(self, strip_prefix=False):
250 250 q = self._get_settings_query()
251 251 q = q.filter(
252 252 self.SettingsDbModel.app_settings_name.startswith('default_'))
253 253 rows = q.all()
254 254
255 255 result = {}
256 256 for row in rows:
257 257 key = row.app_settings_name
258 258 if strip_prefix:
259 259 key = remove_prefix(key, prefix='default_')
260 260 result.update({key: row.app_settings_value})
261 261 return result
262 262
263 263 def get_repo(self):
264 264 repo = self._get_repo(self.repo)
265 265 if not repo:
266 266 raise Exception(
267 267 'Repository `{}` cannot be found inside the database'.format(
268 268 self.repo))
269 269 return repo
270 270
271 271 def _filter_by_repo(self, model, query):
272 272 if self.repo:
273 273 repo = self.get_repo()
274 274 query = query.filter(model.repository_id == repo.repo_id)
275 275 return query
276 276
277 277 def _get_hooks(self, query):
278 278 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
279 279 query = self._filter_by_repo(RepoRhodeCodeUi, query)
280 280 return query.all()
281 281
282 282 def _get_settings_query(self):
283 283 q = self.SettingsDbModel.query()
284 284 return self._filter_by_repo(RepoRhodeCodeSetting, q)
285 285
286 286 def list_enabled_social_plugins(self, settings):
287 287 enabled = []
288 288 for plug in SOCIAL_PLUGINS_LIST:
289 289 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
290 290 )):
291 291 enabled.append(plug)
292 292 return enabled
293 293
294 294
295 295 def assert_repo_settings(func):
296 296 @wraps(func)
297 297 def _wrapper(self, *args, **kwargs):
298 298 if not self.repo_settings:
299 299 raise Exception('Repository is not specified')
300 300 return func(self, *args, **kwargs)
301 301 return _wrapper
302 302
303 303
304 304 class IssueTrackerSettingsModel(object):
305 305 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
306 306 SETTINGS_PREFIX = 'issuetracker_'
307 307
308 308 def __init__(self, sa=None, repo=None):
309 309 self.global_settings = SettingsModel(sa=sa)
310 310 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
311 311
312 312 @property
313 313 def inherit_global_settings(self):
314 314 if not self.repo_settings:
315 315 return True
316 316 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
317 317 return setting.app_settings_value if setting else True
318 318
319 319 @inherit_global_settings.setter
320 320 def inherit_global_settings(self, value):
321 321 if self.repo_settings:
322 322 settings = self.repo_settings.create_or_update_setting(
323 323 self.INHERIT_SETTINGS, value, type_='bool')
324 324 Session().add(settings)
325 325
326 326 def _get_keyname(self, key, uid, prefix=''):
327 327 return '{0}{1}{2}_{3}'.format(
328 328 prefix, self.SETTINGS_PREFIX, key, uid)
329 329
330 330 def _make_dict_for_settings(self, qs):
331 331 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
332 332
333 333 issuetracker_entries = {}
334 334 # create keys
335 335 for k, v in qs.items():
336 336 if k.startswith(prefix_match):
337 337 uid = k[len(prefix_match):]
338 338 issuetracker_entries[uid] = None
339 339
340 340 # populate
341 341 for uid in issuetracker_entries:
342 342 issuetracker_entries[uid] = AttributeDict({
343 343 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
344 344 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
345 345 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
346 346 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
347 347 })
348 348 return issuetracker_entries
349 349
350 350 def get_global_settings(self, cache=False):
351 351 """
352 352 Returns list of global issue tracker settings
353 353 """
354 354 defaults = self.global_settings.get_all_settings(cache=cache)
355 355 settings = self._make_dict_for_settings(defaults)
356 356 return settings
357 357
358 358 def get_repo_settings(self, cache=False):
359 359 """
360 360 Returns list of issue tracker settings per repository
361 361 """
362 362 if not self.repo_settings:
363 363 raise Exception('Repository is not specified')
364 364 all_settings = self.repo_settings.get_all_settings(cache=cache)
365 365 settings = self._make_dict_for_settings(all_settings)
366 366 return settings
367 367
368 368 def get_settings(self, cache=False):
369 369 if self.inherit_global_settings:
370 370 return self.get_global_settings(cache=cache)
371 371 else:
372 372 return self.get_repo_settings(cache=cache)
373 373
374 374 def delete_entries(self, uid):
375 375 if self.repo_settings:
376 376 all_patterns = self.get_repo_settings()
377 377 settings_model = self.repo_settings
378 378 else:
379 379 all_patterns = self.get_global_settings()
380 380 settings_model = self.global_settings
381 381 entries = all_patterns.get(uid)
382 382
383 383 for del_key in entries:
384 384 setting_name = self._get_keyname(del_key, uid)
385 385 entry = settings_model.get_setting_by_name(setting_name)
386 386 if entry:
387 387 Session().delete(entry)
388 388
389 389 Session().commit()
390 390
391 391 def create_or_update_setting(
392 392 self, name, val=Optional(''), type_=Optional('unicode')):
393 393 if self.repo_settings:
394 394 setting = self.repo_settings.create_or_update_setting(
395 395 name, val, type_)
396 396 else:
397 397 setting = self.global_settings.create_or_update_setting(
398 398 name, val, type_)
399 399 return setting
400 400
401 401
402 402 class VcsSettingsModel(object):
403 403
404 404 INHERIT_SETTINGS = 'inherit_vcs_settings'
405 405 GENERAL_SETTINGS = (
406 406 'use_outdated_comments',
407 407 'pr_merge_enabled',
408 408 'hg_use_rebase_for_merging')
409 409
410 410 HOOKS_SETTINGS = (
411 411 ('hooks', 'changegroup.repo_size'),
412 412 ('hooks', 'changegroup.push_logger'),
413 413 ('hooks', 'outgoing.pull_logger'))
414 414 HG_SETTINGS = (
415 415 ('extensions', 'largefiles'),
416 416 ('phases', 'publish'))
417 417 GLOBAL_HG_SETTINGS = (
418 418 ('extensions', 'largefiles'),
419 ('largefiles', 'usercache'),
419 420 ('phases', 'publish'),
420 421 ('extensions', 'hgsubversion'))
421 422 GLOBAL_SVN_SETTINGS = (
422 423 ('vcs_svn_proxy', 'http_requests_enabled'),
423 424 ('vcs_svn_proxy', 'http_server_url'))
424 425
425 426 SVN_BRANCH_SECTION = 'vcs_svn_branch'
426 427 SVN_TAG_SECTION = 'vcs_svn_tag'
427 428 SSL_SETTING = ('web', 'push_ssl')
428 429 PATH_SETTING = ('paths', '/')
429 430
430 431 def __init__(self, sa=None, repo=None):
431 432 self.global_settings = SettingsModel(sa=sa)
432 433 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
433 434 self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS
434 435 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
435 436
436 437 @property
437 438 @assert_repo_settings
438 439 def inherit_global_settings(self):
439 440 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
440 441 return setting.app_settings_value if setting else True
441 442
442 443 @inherit_global_settings.setter
443 444 @assert_repo_settings
444 445 def inherit_global_settings(self, value):
445 446 self.repo_settings.create_or_update_setting(
446 447 self.INHERIT_SETTINGS, value, type_='bool')
447 448
448 449 def get_global_svn_branch_patterns(self):
449 450 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
450 451
451 452 @assert_repo_settings
452 453 def get_repo_svn_branch_patterns(self):
453 454 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
454 455
455 456 def get_global_svn_tag_patterns(self):
456 457 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
457 458
458 459 @assert_repo_settings
459 460 def get_repo_svn_tag_patterns(self):
460 461 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
461 462
462 463 def get_global_settings(self):
463 464 return self._collect_all_settings(global_=True)
464 465
465 466 @assert_repo_settings
466 467 def get_repo_settings(self):
467 468 return self._collect_all_settings(global_=False)
468 469
469 470 @assert_repo_settings
470 471 def create_or_update_repo_settings(
471 472 self, data, inherit_global_settings=False):
472 473 from rhodecode.model.scm import ScmModel
473 474
474 475 self.inherit_global_settings = inherit_global_settings
475 476
476 477 repo = self.repo_settings.get_repo()
477 478 if not inherit_global_settings:
478 479 if repo.repo_type == 'svn':
479 480 self.create_repo_svn_settings(data)
480 481 else:
481 482 self.create_or_update_repo_hook_settings(data)
482 483 self.create_or_update_repo_pr_settings(data)
483 484
484 485 if repo.repo_type == 'hg':
485 486 self.create_or_update_repo_hg_settings(data)
486 487
487 488 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
488 489
489 490 @assert_repo_settings
490 491 def create_or_update_repo_hook_settings(self, data):
491 492 for section, key in self.HOOKS_SETTINGS:
492 493 data_key = self._get_form_ui_key(section, key)
493 494 if data_key not in data:
494 495 raise ValueError(
495 496 'The given data does not contain {} key'.format(data_key))
496 497
497 498 active = data.get(data_key)
498 499 repo_setting = self.repo_settings.get_ui_by_section_and_key(
499 500 section, key)
500 501 if not repo_setting:
501 502 global_setting = self.global_settings.\
502 503 get_ui_by_section_and_key(section, key)
503 504 self.repo_settings.create_ui_section_value(
504 505 section, global_setting.ui_value, key=key, active=active)
505 506 else:
506 507 repo_setting.ui_active = active
507 508 Session().add(repo_setting)
508 509
509 510 def update_global_hook_settings(self, data):
510 511 for section, key in self.HOOKS_SETTINGS:
511 512 data_key = self._get_form_ui_key(section, key)
512 513 if data_key not in data:
513 514 raise ValueError(
514 515 'The given data does not contain {} key'.format(data_key))
515 516 active = data.get(data_key)
516 517 repo_setting = self.global_settings.get_ui_by_section_and_key(
517 518 section, key)
518 519 repo_setting.ui_active = active
519 520 Session().add(repo_setting)
520 521
521 522 @assert_repo_settings
522 523 def create_or_update_repo_pr_settings(self, data):
523 524 return self._create_or_update_general_settings(
524 525 self.repo_settings, data)
525 526
526 527 def create_or_update_global_pr_settings(self, data):
527 528 return self._create_or_update_general_settings(
528 529 self.global_settings, data)
529 530
530 531 @assert_repo_settings
531 532 def create_repo_svn_settings(self, data):
532 533 return self._create_svn_settings(self.repo_settings, data)
533 534
534 535 @assert_repo_settings
535 536 def create_or_update_repo_hg_settings(self, data):
536 537 largefiles, phases = self.HG_SETTINGS
537 538 largefiles_key, phases_key = self._get_settings_keys(
538 539 self.HG_SETTINGS, data)
539 540 self._create_or_update_ui(
540 541 self.repo_settings, *largefiles, value='',
541 542 active=data[largefiles_key])
542 543 self._create_or_update_ui(
543 544 self.repo_settings, *phases, value=safe_str(data[phases_key]))
544 545
545 546 def create_or_update_global_hg_settings(self, data):
546 largefiles, phases, hgsubversion = self.GLOBAL_HG_SETTINGS
547 largefiles_key, phases_key, subversion_key = self._get_settings_keys(
548 self.GLOBAL_HG_SETTINGS, data)
547 largefiles, largefiles_store, phases, hgsubversion \
548 = self.GLOBAL_HG_SETTINGS
549 largefiles_key, largefiles_store_key, phases_key, subversion_key \
550 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS, data)
551
549 552 self._create_or_update_ui(
550 553 self.global_settings, *largefiles, value='',
551 554 active=data[largefiles_key])
552 555 self._create_or_update_ui(
556 self.global_settings, *largefiles_store,
557 value=data[largefiles_store_key])
558 self._create_or_update_ui(
553 559 self.global_settings, *phases, value=safe_str(data[phases_key]))
554 560 self._create_or_update_ui(
555 561 self.global_settings, *hgsubversion, active=data[subversion_key])
556 562
557 563 def create_or_update_global_svn_settings(self, data):
558 564 # branch/tags patterns
559 565 self._create_svn_settings(self.global_settings, data)
560 566
561 567 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
562 568 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
563 569 self.GLOBAL_SVN_SETTINGS, data)
564 570
565 571 self._create_or_update_ui(
566 572 self.global_settings, *http_requests_enabled,
567 573 value=safe_str(data[http_requests_enabled_key]))
568 574 self._create_or_update_ui(
569 575 self.global_settings, *http_server_url,
570 576 value=data[http_server_url_key])
571 577
572 578 def update_global_ssl_setting(self, value):
573 579 self._create_or_update_ui(
574 580 self.global_settings, *self.SSL_SETTING, value=value)
575 581
576 582 def update_global_path_setting(self, value):
577 583 self._create_or_update_ui(
578 584 self.global_settings, *self.PATH_SETTING, value=value)
579 585
580 586 @assert_repo_settings
581 587 def delete_repo_svn_pattern(self, id_):
582 588 self.repo_settings.delete_ui(id_)
583 589
584 590 def delete_global_svn_pattern(self, id_):
585 591 self.global_settings.delete_ui(id_)
586 592
587 593 @assert_repo_settings
588 594 def get_repo_ui_settings(self, section=None, key=None):
589 595 global_uis = self.global_settings.get_ui(section, key)
590 596 repo_uis = self.repo_settings.get_ui(section, key)
591 597 filtered_repo_uis = self._filter_ui_settings(repo_uis)
592 598 filtered_repo_uis_keys = [
593 599 (s.section, s.key) for s in filtered_repo_uis]
594 600
595 601 def _is_global_ui_filtered(ui):
596 602 return (
597 603 (ui.section, ui.key) in filtered_repo_uis_keys
598 604 or ui.section in self._svn_sections)
599 605
600 606 filtered_global_uis = [
601 607 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
602 608
603 609 return filtered_global_uis + filtered_repo_uis
604 610
605 611 def get_global_ui_settings(self, section=None, key=None):
606 612 return self.global_settings.get_ui(section, key)
607 613
608 614 def get_ui_settings_as_config_obj(self, section=None, key=None):
609 615 config = base.Config()
610 616
611 617 ui_settings = self.get_ui_settings(section=section, key=key)
612 618
613 619 for entry in ui_settings:
614 620 config.set(entry.section, entry.key, entry.value)
615 621
616 622 return config
617 623
618 624 def get_ui_settings(self, section=None, key=None):
619 625 if not self.repo_settings or self.inherit_global_settings:
620 626 return self.get_global_ui_settings(section, key)
621 627 else:
622 628 return self.get_repo_ui_settings(section, key)
623 629
624 630 def get_svn_patterns(self, section=None):
625 631 if not self.repo_settings:
626 632 return self.get_global_ui_settings(section)
627 633 else:
628 634 return self.get_repo_ui_settings(section)
629 635
630 636 @assert_repo_settings
631 637 def get_repo_general_settings(self):
632 638 global_settings = self.global_settings.get_all_settings()
633 639 repo_settings = self.repo_settings.get_all_settings()
634 640 filtered_repo_settings = self._filter_general_settings(repo_settings)
635 641 global_settings.update(filtered_repo_settings)
636 642 return global_settings
637 643
638 644 def get_global_general_settings(self):
639 645 return self.global_settings.get_all_settings()
640 646
641 647 def get_general_settings(self):
642 648 if not self.repo_settings or self.inherit_global_settings:
643 649 return self.get_global_general_settings()
644 650 else:
645 651 return self.get_repo_general_settings()
646 652
647 653 def get_repos_location(self):
648 654 return self.global_settings.get_ui_by_key('/').ui_value
649 655
650 656 def _filter_ui_settings(self, settings):
651 657 filtered_settings = [
652 658 s for s in settings if self._should_keep_setting(s)]
653 659 return filtered_settings
654 660
655 661 def _should_keep_setting(self, setting):
656 662 keep = (
657 663 (setting.section, setting.key) in self._ui_settings or
658 664 setting.section in self._svn_sections)
659 665 return keep
660 666
661 667 def _filter_general_settings(self, settings):
662 668 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
663 669 return {
664 670 k: settings[k]
665 671 for k in settings if k in keys}
666 672
667 673 def _collect_all_settings(self, global_=False):
668 674 settings = self.global_settings if global_ else self.repo_settings
669 675 result = {}
670 676
671 677 for section, key in self._ui_settings:
672 678 ui = settings.get_ui_by_section_and_key(section, key)
673 679 result_key = self._get_form_ui_key(section, key)
674 680 if ui:
675 681 if section in ('hooks', 'extensions'):
676 682 result[result_key] = ui.ui_active
677 683 else:
678 684 result[result_key] = ui.ui_value
679 685
680 686 for name in self.GENERAL_SETTINGS:
681 687 setting = settings.get_setting_by_name(name)
682 688 if setting:
683 689 result_key = 'rhodecode_{}'.format(name)
684 690 result[result_key] = setting.app_settings_value
685 691
686 692 return result
687 693
688 694 def _get_form_ui_key(self, section, key):
689 695 return '{section}_{key}'.format(
690 696 section=section, key=key.replace('.', '_'))
691 697
692 698 def _create_or_update_ui(
693 699 self, settings, section, key, value=None, active=None):
694 700 ui = settings.get_ui_by_section_and_key(section, key)
695 701 if not ui:
696 702 active = True if active is None else active
697 703 settings.create_ui_section_value(
698 704 section, value, key=key, active=active)
699 705 else:
700 706 if active is not None:
701 707 ui.ui_active = active
702 708 if value is not None:
703 709 ui.ui_value = value
704 710 Session().add(ui)
705 711
706 712 def _create_svn_settings(self, settings, data):
707 713 svn_settings = {
708 714 'new_svn_branch': self.SVN_BRANCH_SECTION,
709 715 'new_svn_tag': self.SVN_TAG_SECTION
710 716 }
711 717 for key in svn_settings:
712 718 if data.get(key):
713 719 settings.create_ui_section_value(svn_settings[key], data[key])
714 720
715 721 def _create_or_update_general_settings(self, settings, data):
716 722 for name in self.GENERAL_SETTINGS:
717 723 data_key = 'rhodecode_{}'.format(name)
718 724 if data_key not in data:
719 725 raise ValueError(
720 726 'The given data does not contain {} key'.format(data_key))
721 727 setting = settings.create_or_update_setting(
722 728 name, data[data_key], 'bool')
723 729 Session().add(setting)
724 730
725 731 def _get_settings_keys(self, settings, data):
726 732 data_keys = [self._get_form_ui_key(*s) for s in settings]
727 733 for data_key in data_keys:
728 734 if data_key not in data:
729 735 raise ValueError(
730 736 'The given data does not contain {} key'.format(data_key))
731 737 return data_keys
@@ -1,275 +1,291 b''
1 1 ## snippet for displaying vcs settings
2 2 ## usage:
3 3 ## <%namespace name="vcss" file="/base/vcssettings.mako"/>
4 4 ## ${vcss.vcs_settings_fields()}
5 5
6 6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)">
7 7 % if display_globals:
8 8 <div class="panel panel-default">
9 9 <div class="panel-heading" id="general">
10 10 <h3 class="panel-title">${_('General')}</h3>
11 11 </div>
12 12 <div class="panel-body">
13 13 <div class="field">
14 14 <div class="checkbox">
15 15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
16 16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
17 17 </div>
18 18 <div class="label">
19 19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
20 20 </div>
21 21 </div>
22 22 </div>
23 23 </div>
24 24 % endif
25 25
26 26 % if display_globals:
27 27 <div class="panel panel-default">
28 28 <div class="panel-heading">
29 29 <h3 class="panel-title">${_('Main Storage Location')}</h3>
30 30 </div>
31 31 <div class="panel-body">
32 32 <div class="field">
33 33 <div class="inputx locked_input">
34 34 %if allow_repo_location_change:
35 35 ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")}
36 36 <span id="path_unlock" class="tooltip"
37 37 title="${h.tooltip(_('Click to unlock. You must restart RhodeCode in order to make this setting take effect.'))}">
38 38 <div class="btn btn-default lock_input_button"><i id="path_unlock_icon" class="icon-lock"></i></div>
39 39 </span>
40 40 %else:
41 41 ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')}
42 42 ## form still requires this but we cannot internally change it anyway
43 43 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
44 44 %endif
45 45 </div>
46 46 </div>
47 47 <div class="label">
48 48 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
49 49 </div>
50 50 </div>
51 51 </div>
52 52 % endif
53 53
54 54 % if display_globals or repo_type in ['git', 'hg']:
55 55 <div class="panel panel-default">
56 56 <div class="panel-heading" id="general">
57 57 <h3 class="panel-title">${_('Internal Hooks')}</h3>
58 58 </div>
59 59 <div class="panel-body">
60 60 <div class="field">
61 61 <div class="checkbox">
62 62 ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)}
63 63 <label for="hooks_changegroup_repo_size${suffix}">${_('Show repository size after push')}</label>
64 64 </div>
65 65
66 66 <div class="label">
67 67 <span class="help-block">${_('Trigger a hook that calculates repository size after each push.')}</span>
68 68 </div>
69 69 <div class="checkbox">
70 70 ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)}
71 71 <label for="hooks_changegroup_push_logger${suffix}">${_('Execute pre/post push hooks')}</label>
72 72 </div>
73 73 <div class="label">
74 74 <span class="help-block">${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')}</span>
75 75 </div>
76 76 <div class="checkbox">
77 77 ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)}
78 78 <label for="hooks_outgoing_pull_logger${suffix}">${_('Execute pre/post pull hooks')}</label>
79 79 </div>
80 80 <div class="label">
81 81 <span class="help-block">${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')}</span>
82 82 </div>
83 83 </div>
84 84 </div>
85 85 </div>
86 86 % endif
87 87
88 88 % if display_globals or repo_type in ['hg']:
89 89 <div class="panel panel-default">
90 90 <div class="panel-heading">
91 91 <h3 class="panel-title">${_('Mercurial Settings')}</h3>
92 92 </div>
93 93 <div class="panel-body">
94 94 <div class="checkbox">
95 95 ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)}
96 96 <label for="extensions_largefiles${suffix}">${_('Enable largefiles extension')}</label>
97 97 </div>
98 98 <div class="label">
99 % if display_globals:
99 100 <span class="help-block">${_('Enable Largefiles extensions for all repositories.')}</span>
101 % else:
102 <span class="help-block">${_('Enable Largefiles extensions for this repository.')}</span>
103 % endif
100 104 </div>
105
106 % if display_globals:
107 <div class="field">
108 <div class="input">
109 ${h.text('largefiles_usercache' + suffix, size=59)}
110 </div>
111 </div>
112 <div class="label">
113 <span class="help-block">${_('Filesystem location where Mercurial largefile objects should be stored.')}</span>
114 </div>
115 % endif
116
101 117 <div class="checkbox">
102 118 ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)}
103 119 <label for="phases_publish${suffix}">${_('Set repositories as publishing') if display_globals else _('Set repository as publishing')}</label>
104 120 </div>
105 121 <div class="label">
106 122 <span class="help-block">${_('When this is enabled all commits in the repository are seen as public commits by clients.')}</span>
107 123 </div>
108 124 % if display_globals:
109 125 <div class="checkbox">
110 126 ${h.checkbox('extensions_hgsubversion' + suffix,'True')}
111 127 <label for="extensions_hgsubversion${suffix}">${_('Enable hgsubversion extension')}</label>
112 128 </div>
113 129 <div class="label">
114 130 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
115 131 </div>
116 132 % endif
117 133 </div>
118 134 </div>
119 135 ## LABS for HG
120 136 % if c.labs_active:
121 137 <div class="panel panel-danger">
122 138 <div class="panel-heading">
123 139 <h3 class="panel-title">${_('Mercurial Labs Settings')} (${_('These features are considered experimental and may not work as expected.')})</h3>
124 140 </div>
125 141 <div class="panel-body">
126 142
127 143 <div class="checkbox">
128 144 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
129 145 <label for="rhodecode_hg_use_rebase_for_merging${suffix}">${_('Use rebase as merge strategy')}</label>
130 146 </div>
131 147 <div class="label">
132 148 <span class="help-block">${_('Use rebase instead of creating a merge commit when merging via web interface.')}</span>
133 149 </div>
134 150
135 151 </div>
136 152 </div>
137 153 % endif
138 154
139 155 % endif
140 156
141 157 % if display_globals:
142 158 <div class="panel panel-default">
143 159 <div class="panel-heading">
144 160 <h3 class="panel-title">${_('Global Subversion Settings')}</h3>
145 161 </div>
146 162 <div class="panel-body">
147 163 <div class="field">
148 164 <div class="checkbox">
149 165 ${h.checkbox('vcs_svn_proxy_http_requests_enabled' + suffix, 'True', **kwargs)}
150 166 <label for="vcs_svn_proxy_http_requests_enabled${suffix}">${_('Proxy subversion HTTP requests')}</label>
151 167 </div>
152 168 <div class="label">
153 169 <span class="help-block">
154 170 ${_('Subversion HTTP Support. Enables communication with SVN over HTTP protocol.')}
155 171 <a href="${h.url('enterprise_svn_setup')}" target="_blank">${_('SVN Protocol setup Documentation')}</a>.
156 172 </span>
157 173 </div>
158 174 </div>
159 175 <div class="field">
160 176 <div class="label">
161 177 <label for="vcs_svn_proxy_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
162 178 </div>
163 179 <div class="input">
164 180 ${h.text('vcs_svn_proxy_http_server_url',size=59)}
165 181 % if c.svn_proxy_generate_config:
166 182 <span class="buttons">
167 183 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
168 184 </span>
169 185 % endif
170 186 </div>
171 187 </div>
172 188 </div>
173 189 </div>
174 190 % endif
175 191
176 192 % if display_globals or repo_type in ['svn']:
177 193 <div class="panel panel-default">
178 194 <div class="panel-heading">
179 195 <h3 class="panel-title">${_('Subversion Settings')}</h3>
180 196 </div>
181 197 <div class="panel-body">
182 198 <div class="field">
183 199 <div class="content" >
184 200 <label>${_('Repository patterns')}</label><br/>
185 201 </div>
186 202 </div>
187 203 <div class="label">
188 204 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
189 205 </div>
190 206
191 207 <div class="field branch_patterns">
192 208 <div class="input" >
193 209 <label>${_('Branches')}:</label><br/>
194 210 </div>
195 211 % if svn_branch_patterns:
196 212 % for branch in svn_branch_patterns:
197 213 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
198 214 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
199 215 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
200 216 % if kwargs.get('disabled') != 'disabled':
201 217 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
202 218 ${_('Delete')}
203 219 </span>
204 220 % endif
205 221 </div>
206 222 % endfor
207 223 %endif
208 224 </div>
209 225 % if kwargs.get('disabled') != 'disabled':
210 226 <div class="field branch_patterns">
211 227 <div class="input" >
212 228 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
213 229 </div>
214 230 </div>
215 231 % endif
216 232 <div class="field tag_patterns">
217 233 <div class="input" >
218 234 <label>${_('Tags')}:</label><br/>
219 235 </div>
220 236 % if svn_tag_patterns:
221 237 % for tag in svn_tag_patterns:
222 238 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
223 239 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
224 240 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
225 241 % if kwargs.get('disabled') != 'disabled':
226 242 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
227 243 ${_('Delete')}
228 244 </span>
229 245 %endif
230 246 </div>
231 247 % endfor
232 248 % endif
233 249 </div>
234 250 % if kwargs.get('disabled') != 'disabled':
235 251 <div class="field tag_patterns">
236 252 <div class="input" >
237 253 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
238 254 </div>
239 255 </div>
240 256 %endif
241 257 </div>
242 258 </div>
243 259 % else:
244 260 ${h.hidden('new_svn_branch' + suffix, '')}
245 261 ${h.hidden('new_svn_tag' + suffix, '')}
246 262 % endif
247 263
248 264
249 265
250 266
251 267 % if display_globals or repo_type in ['hg', 'git']:
252 268 <div class="panel panel-default">
253 269 <div class="panel-heading">
254 270 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
255 271 </div>
256 272 <div class="panel-body">
257 273 <div class="checkbox">
258 274 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
259 275 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
260 276 </div>
261 277 <div class="label">
262 278 <span class="help-block">${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')}</span>
263 279 </div>
264 280 <div class="checkbox">
265 281 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
266 282 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
267 283 </div>
268 284 <div class="label">
269 285 <span class="help-block">${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')}</span>
270 286 </div>
271 287 </div>
272 288 </div>
273 289 % endif
274 290
275 291 </%def>
@@ -1,1029 +1,1034 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import mock
22 22 import pytest
23 23
24 24 from rhodecode.lib.utils2 import str2bool
25 25 from rhodecode.model.meta import Session
26 26 from rhodecode.model.settings import VcsSettingsModel, UiSetting
27 27
28 28
29 29 HOOKS_FORM_DATA = {
30 30 'hooks_changegroup_repo_size': True,
31 31 'hooks_changegroup_push_logger': True,
32 32 'hooks_outgoing_pull_logger': True
33 33 }
34 34
35 35 SVN_FORM_DATA = {
36 36 'new_svn_branch': 'test-branch',
37 37 'new_svn_tag': 'test-tag'
38 38 }
39 39
40 40 GENERAL_FORM_DATA = {
41 41 'rhodecode_pr_merge_enabled': True,
42 42 'rhodecode_use_outdated_comments': True,
43 43 'rhodecode_hg_use_rebase_for_merging': True,
44 44 }
45 45
46 46
47 47 class TestInheritGlobalSettingsProperty(object):
48 48 def test_get_raises_exception_when_repository_not_specified(self):
49 49 model = VcsSettingsModel()
50 50 with pytest.raises(Exception) as exc_info:
51 51 model.inherit_global_settings
52 52 assert exc_info.value.message == 'Repository is not specified'
53 53
54 54 def test_true_is_returned_when_value_is_not_found(self, repo_stub):
55 55 model = VcsSettingsModel(repo=repo_stub.repo_name)
56 56 assert model.inherit_global_settings is True
57 57
58 58 def test_value_is_returned(self, repo_stub, settings_util):
59 59 model = VcsSettingsModel(repo=repo_stub.repo_name)
60 60 settings_util.create_repo_rhodecode_setting(
61 61 repo_stub, VcsSettingsModel.INHERIT_SETTINGS, False, 'bool')
62 62 assert model.inherit_global_settings is False
63 63
64 64 def test_value_is_set(self, repo_stub):
65 65 model = VcsSettingsModel(repo=repo_stub.repo_name)
66 66 model.inherit_global_settings = False
67 67 setting = model.repo_settings.get_setting_by_name(
68 68 VcsSettingsModel.INHERIT_SETTINGS)
69 69 try:
70 70 assert setting.app_settings_type == 'bool'
71 71 assert setting.app_settings_value is False
72 72 finally:
73 73 Session().delete(setting)
74 74 Session().commit()
75 75
76 76 def test_set_raises_exception_when_repository_not_specified(self):
77 77 model = VcsSettingsModel()
78 78 with pytest.raises(Exception) as exc_info:
79 79 model.inherit_global_settings = False
80 80 assert exc_info.value.message == 'Repository is not specified'
81 81
82 82
83 83 class TestVcsSettingsModel(object):
84 84 def test_global_svn_branch_patterns(self):
85 85 model = VcsSettingsModel()
86 86 expected_result = {'test': 'test'}
87 87 with mock.patch.object(model, 'global_settings') as settings_mock:
88 88 get_settings = settings_mock.get_ui_by_section
89 89 get_settings.return_value = expected_result
90 90 settings_mock.return_value = expected_result
91 91 result = model.get_global_svn_branch_patterns()
92 92
93 93 get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION)
94 94 assert expected_result == result
95 95
96 96 def test_repo_svn_branch_patterns(self):
97 97 model = VcsSettingsModel()
98 98 expected_result = {'test': 'test'}
99 99 with mock.patch.object(model, 'repo_settings') as settings_mock:
100 100 get_settings = settings_mock.get_ui_by_section
101 101 get_settings.return_value = expected_result
102 102 settings_mock.return_value = expected_result
103 103 result = model.get_repo_svn_branch_patterns()
104 104
105 105 get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION)
106 106 assert expected_result == result
107 107
108 108 def test_repo_svn_branch_patterns_raises_exception_when_repo_is_not_set(
109 109 self):
110 110 model = VcsSettingsModel()
111 111 with pytest.raises(Exception) as exc_info:
112 112 model.get_repo_svn_branch_patterns()
113 113 assert exc_info.value.message == 'Repository is not specified'
114 114
115 115 def test_global_svn_tag_patterns(self):
116 116 model = VcsSettingsModel()
117 117 expected_result = {'test': 'test'}
118 118 with mock.patch.object(model, 'global_settings') as settings_mock:
119 119 get_settings = settings_mock.get_ui_by_section
120 120 get_settings.return_value = expected_result
121 121 settings_mock.return_value = expected_result
122 122 result = model.get_global_svn_tag_patterns()
123 123
124 124 get_settings.assert_called_once_with(model.SVN_TAG_SECTION)
125 125 assert expected_result == result
126 126
127 127 def test_repo_svn_tag_patterns(self):
128 128 model = VcsSettingsModel()
129 129 expected_result = {'test': 'test'}
130 130 with mock.patch.object(model, 'repo_settings') as settings_mock:
131 131 get_settings = settings_mock.get_ui_by_section
132 132 get_settings.return_value = expected_result
133 133 settings_mock.return_value = expected_result
134 134 result = model.get_repo_svn_tag_patterns()
135 135
136 136 get_settings.assert_called_once_with(model.SVN_TAG_SECTION)
137 137 assert expected_result == result
138 138
139 139 def test_repo_svn_tag_patterns_raises_exception_when_repo_is_not_set(self):
140 140 model = VcsSettingsModel()
141 141 with pytest.raises(Exception) as exc_info:
142 142 model.get_repo_svn_tag_patterns()
143 143 assert exc_info.value.message == 'Repository is not specified'
144 144
145 145 def test_get_global_settings(self):
146 146 expected_result = {'test': 'test'}
147 147 model = VcsSettingsModel()
148 148 with mock.patch.object(model, '_collect_all_settings') as collect_mock:
149 149 collect_mock.return_value = expected_result
150 150 result = model.get_global_settings()
151 151
152 152 collect_mock.assert_called_once_with(global_=True)
153 153 assert result == expected_result
154 154
155 155 def test_get_repo_settings(self, repo_stub):
156 156 model = VcsSettingsModel(repo=repo_stub.repo_name)
157 157 expected_result = {'test': 'test'}
158 158 with mock.patch.object(model, '_collect_all_settings') as collect_mock:
159 159 collect_mock.return_value = expected_result
160 160 result = model.get_repo_settings()
161 161
162 162 collect_mock.assert_called_once_with(global_=False)
163 163 assert result == expected_result
164 164
165 165 @pytest.mark.parametrize('settings, global_', [
166 166 ('global_settings', True),
167 167 ('repo_settings', False)
168 168 ])
169 169 def test_collect_all_settings(self, settings, global_):
170 170 model = VcsSettingsModel()
171 171 result_mock = self._mock_result()
172 172
173 173 settings_patch = mock.patch.object(model, settings)
174 174 with settings_patch as settings_mock:
175 175 settings_mock.get_ui_by_section_and_key.return_value = result_mock
176 176 settings_mock.get_setting_by_name.return_value = result_mock
177 177 result = model._collect_all_settings(global_=global_)
178 178
179 179 ui_settings = model.HG_SETTINGS + model.HOOKS_SETTINGS
180 180 self._assert_get_settings_calls(
181 181 settings_mock, ui_settings, model.GENERAL_SETTINGS)
182 182 self._assert_collect_all_settings_result(
183 183 ui_settings, model.GENERAL_SETTINGS, result)
184 184
185 185 @pytest.mark.parametrize('settings, global_', [
186 186 ('global_settings', True),
187 187 ('repo_settings', False)
188 188 ])
189 189 def test_collect_all_settings_without_empty_value(self, settings, global_):
190 190 model = VcsSettingsModel()
191 191
192 192 settings_patch = mock.patch.object(model, settings)
193 193 with settings_patch as settings_mock:
194 194 settings_mock.get_ui_by_section_and_key.return_value = None
195 195 settings_mock.get_setting_by_name.return_value = None
196 196 result = model._collect_all_settings(global_=global_)
197 197
198 198 assert result == {}
199 199
200 200 def _mock_result(self):
201 201 result_mock = mock.Mock()
202 202 result_mock.ui_value = 'ui_value'
203 203 result_mock.ui_active = True
204 204 result_mock.app_settings_value = 'setting_value'
205 205 return result_mock
206 206
207 207 def _assert_get_settings_calls(
208 208 self, settings_mock, ui_settings, general_settings):
209 209 assert (
210 210 settings_mock.get_ui_by_section_and_key.call_count ==
211 211 len(ui_settings))
212 212 assert (
213 213 settings_mock.get_setting_by_name.call_count ==
214 214 len(general_settings))
215 215
216 216 for section, key in ui_settings:
217 217 expected_call = mock.call(section, key)
218 218 assert (
219 219 expected_call in
220 220 settings_mock.get_ui_by_section_and_key.call_args_list)
221 221
222 222 for name in general_settings:
223 223 expected_call = mock.call(name)
224 224 assert (
225 225 expected_call in
226 226 settings_mock.get_setting_by_name.call_args_list)
227 227
228 228 def _assert_collect_all_settings_result(
229 229 self, ui_settings, general_settings, result):
230 230 expected_result = {}
231 231 for section, key in ui_settings:
232 232 key = '{}_{}'.format(section, key.replace('.', '_'))
233 233 value = True if section in ('extensions', 'hooks') else 'ui_value'
234 234 expected_result[key] = value
235 235
236 236 for name in general_settings:
237 237 key = 'rhodecode_' + name
238 238 expected_result[key] = 'setting_value'
239 239
240 240 assert expected_result == result
241 241
242 242
243 243 class TestCreateOrUpdateRepoHookSettings(object):
244 244 def test_create_when_no_repo_object_found(self, repo_stub):
245 245 model = VcsSettingsModel(repo=repo_stub.repo_name)
246 246
247 247 self._create_settings(model, HOOKS_FORM_DATA)
248 248
249 249 cleanup = []
250 250 try:
251 251 for section, key in model.HOOKS_SETTINGS:
252 252 ui = model.repo_settings.get_ui_by_section_and_key(
253 253 section, key)
254 254 assert ui.ui_active is True
255 255 cleanup.append(ui)
256 256 finally:
257 257 for ui in cleanup:
258 258 Session().delete(ui)
259 259 Session().commit()
260 260
261 261 def test_create_raises_exception_when_data_incomplete(self, repo_stub):
262 262 model = VcsSettingsModel(repo=repo_stub.repo_name)
263 263
264 264 deleted_key = 'hooks_changegroup_repo_size'
265 265 data = HOOKS_FORM_DATA.copy()
266 266 data.pop(deleted_key)
267 267
268 268 with pytest.raises(ValueError) as exc_info:
269 269 model.create_or_update_repo_hook_settings(data)
270 270 assert (
271 271 exc_info.value.message ==
272 272 'The given data does not contain {} key'.format(deleted_key))
273 273
274 274 def test_update_when_repo_object_found(self, repo_stub, settings_util):
275 275 model = VcsSettingsModel(repo=repo_stub.repo_name)
276 276 for section, key in model.HOOKS_SETTINGS:
277 277 settings_util.create_repo_rhodecode_ui(
278 278 repo_stub, section, None, key=key, active=False)
279 279 model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA)
280 280 for section, key in model.HOOKS_SETTINGS:
281 281 ui = model.repo_settings.get_ui_by_section_and_key(section, key)
282 282 assert ui.ui_active is True
283 283
284 284 def _create_settings(self, model, data):
285 285 global_patch = mock.patch.object(model, 'global_settings')
286 286 global_setting = mock.Mock()
287 287 global_setting.ui_value = 'Test value'
288 288 with global_patch as global_mock:
289 289 global_mock.get_ui_by_section_and_key.return_value = global_setting
290 290 model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA)
291 291
292 292
293 293 class TestUpdateGlobalHookSettings(object):
294 294 def test_update_raises_exception_when_data_incomplete(self):
295 295 model = VcsSettingsModel()
296 296
297 297 deleted_key = 'hooks_changegroup_repo_size'
298 298 data = HOOKS_FORM_DATA.copy()
299 299 data.pop(deleted_key)
300 300
301 301 with pytest.raises(ValueError) as exc_info:
302 302 model.update_global_hook_settings(data)
303 303 assert (
304 304 exc_info.value.message ==
305 305 'The given data does not contain {} key'.format(deleted_key))
306 306
307 307 def test_update_global_hook_settings(self, settings_util):
308 308 model = VcsSettingsModel()
309 309 setting_mock = mock.MagicMock()
310 310 setting_mock.ui_active = False
311 311 get_settings_patcher = mock.patch.object(
312 312 model.global_settings, 'get_ui_by_section_and_key',
313 313 return_value=setting_mock)
314 314 session_patcher = mock.patch('rhodecode.model.settings.Session')
315 315 with get_settings_patcher as get_settings_mock, session_patcher:
316 316 model.update_global_hook_settings(HOOKS_FORM_DATA)
317 317 assert setting_mock.ui_active is True
318 318 assert get_settings_mock.call_count == 3
319 319
320 320
321 321 class TestCreateOrUpdateRepoGeneralSettings(object):
322 322 def test_calls_create_or_update_general_settings(self, repo_stub):
323 323 model = VcsSettingsModel(repo=repo_stub.repo_name)
324 324 create_patch = mock.patch.object(
325 325 model, '_create_or_update_general_settings')
326 326 with create_patch as create_mock:
327 327 model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA)
328 328 create_mock.assert_called_once_with(
329 329 model.repo_settings, GENERAL_FORM_DATA)
330 330
331 331 def test_raises_exception_when_repository_is_not_specified(self):
332 332 model = VcsSettingsModel()
333 333 with pytest.raises(Exception) as exc_info:
334 334 model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA)
335 335 assert exc_info.value.message == 'Repository is not specified'
336 336
337 337
338 338 class TestCreateOrUpdatGlobalGeneralSettings(object):
339 339 def test_calls_create_or_update_general_settings(self):
340 340 model = VcsSettingsModel()
341 341 create_patch = mock.patch.object(
342 342 model, '_create_or_update_general_settings')
343 343 with create_patch as create_mock:
344 344 model.create_or_update_global_pr_settings(GENERAL_FORM_DATA)
345 345 create_mock.assert_called_once_with(
346 346 model.global_settings, GENERAL_FORM_DATA)
347 347
348 348
349 349 class TestCreateOrUpdateGeneralSettings(object):
350 350 def test_create_when_no_repo_settings_found(self, repo_stub):
351 351 model = VcsSettingsModel(repo=repo_stub.repo_name)
352 352 model._create_or_update_general_settings(
353 353 model.repo_settings, GENERAL_FORM_DATA)
354 354
355 355 cleanup = []
356 356 try:
357 357 for name in model.GENERAL_SETTINGS:
358 358 setting = model.repo_settings.get_setting_by_name(name)
359 359 assert setting.app_settings_value is True
360 360 cleanup.append(setting)
361 361 finally:
362 362 for setting in cleanup:
363 363 Session().delete(setting)
364 364 Session().commit()
365 365
366 366 def test_create_raises_exception_when_data_incomplete(self, repo_stub):
367 367 model = VcsSettingsModel(repo=repo_stub.repo_name)
368 368
369 369 deleted_key = 'rhodecode_pr_merge_enabled'
370 370 data = GENERAL_FORM_DATA.copy()
371 371 data.pop(deleted_key)
372 372
373 373 with pytest.raises(ValueError) as exc_info:
374 374 model._create_or_update_general_settings(model.repo_settings, data)
375 375 assert (
376 376 exc_info.value.message ==
377 377 'The given data does not contain {} key'.format(deleted_key))
378 378
379 379 def test_update_when_repo_setting_found(self, repo_stub, settings_util):
380 380 model = VcsSettingsModel(repo=repo_stub.repo_name)
381 381 for name in model.GENERAL_SETTINGS:
382 382 settings_util.create_repo_rhodecode_setting(
383 383 repo_stub, name, False, 'bool')
384 384
385 385 model._create_or_update_general_settings(
386 386 model.repo_settings, GENERAL_FORM_DATA)
387 387
388 388 for name in model.GENERAL_SETTINGS:
389 389 setting = model.repo_settings.get_setting_by_name(name)
390 390 assert setting.app_settings_value is True
391 391
392 392
393 393 class TestCreateRepoSvnSettings(object):
394 394 def test_calls_create_svn_settings(self, repo_stub):
395 395 model = VcsSettingsModel(repo=repo_stub.repo_name)
396 396 with mock.patch.object(model, '_create_svn_settings') as create_mock:
397 397 model.create_repo_svn_settings(SVN_FORM_DATA)
398 398 create_mock.assert_called_once_with(model.repo_settings, SVN_FORM_DATA)
399 399
400 400 def test_raises_exception_when_repository_is_not_specified(self):
401 401 model = VcsSettingsModel()
402 402 with pytest.raises(Exception) as exc_info:
403 403 model.create_repo_svn_settings(SVN_FORM_DATA)
404 404 assert exc_info.value.message == 'Repository is not specified'
405 405
406 406
407 407 class TestCreateSvnSettings(object):
408 408 def test_create(self, repo_stub):
409 409 model = VcsSettingsModel(repo=repo_stub.repo_name)
410 410 model._create_svn_settings(model.repo_settings, SVN_FORM_DATA)
411 411 Session().commit()
412 412
413 413 branch_ui = model.repo_settings.get_ui_by_section(
414 414 model.SVN_BRANCH_SECTION)
415 415 tag_ui = model.repo_settings.get_ui_by_section(
416 416 model.SVN_TAG_SECTION)
417 417
418 418 try:
419 419 assert len(branch_ui) == 1
420 420 assert len(tag_ui) == 1
421 421 finally:
422 422 Session().delete(branch_ui[0])
423 423 Session().delete(tag_ui[0])
424 424 Session().commit()
425 425
426 426 def test_create_tag(self, repo_stub):
427 427 model = VcsSettingsModel(repo=repo_stub.repo_name)
428 428 data = SVN_FORM_DATA.copy()
429 429 data.pop('new_svn_branch')
430 430 model._create_svn_settings(model.repo_settings, data)
431 431 Session().commit()
432 432
433 433 branch_ui = model.repo_settings.get_ui_by_section(
434 434 model.SVN_BRANCH_SECTION)
435 435 tag_ui = model.repo_settings.get_ui_by_section(
436 436 model.SVN_TAG_SECTION)
437 437
438 438 try:
439 439 assert len(branch_ui) == 0
440 440 assert len(tag_ui) == 1
441 441 finally:
442 442 Session().delete(tag_ui[0])
443 443 Session().commit()
444 444
445 445 def test_create_nothing_when_no_svn_settings_specified(self, repo_stub):
446 446 model = VcsSettingsModel(repo=repo_stub.repo_name)
447 447 model._create_svn_settings(model.repo_settings, {})
448 448 Session().commit()
449 449
450 450 branch_ui = model.repo_settings.get_ui_by_section(
451 451 model.SVN_BRANCH_SECTION)
452 452 tag_ui = model.repo_settings.get_ui_by_section(
453 453 model.SVN_TAG_SECTION)
454 454
455 455 assert len(branch_ui) == 0
456 456 assert len(tag_ui) == 0
457 457
458 458 def test_create_nothing_when_empty_settings_specified(self, repo_stub):
459 459 model = VcsSettingsModel(repo=repo_stub.repo_name)
460 460 data = {
461 461 'new_svn_branch': '',
462 462 'new_svn_tag': ''
463 463 }
464 464 model._create_svn_settings(model.repo_settings, data)
465 465 Session().commit()
466 466
467 467 branch_ui = model.repo_settings.get_ui_by_section(
468 468 model.SVN_BRANCH_SECTION)
469 469 tag_ui = model.repo_settings.get_ui_by_section(
470 470 model.SVN_TAG_SECTION)
471 471
472 472 assert len(branch_ui) == 0
473 473 assert len(tag_ui) == 0
474 474
475 475
476 476 class TestCreateOrUpdateUi(object):
477 477 def test_create(self, repo_stub):
478 478 model = VcsSettingsModel(repo=repo_stub.repo_name)
479 479 model._create_or_update_ui(
480 480 model.repo_settings, 'test-section', 'test-key', active=False,
481 481 value='False')
482 482 Session().commit()
483 483
484 484 created_ui = model.repo_settings.get_ui_by_section_and_key(
485 485 'test-section', 'test-key')
486 486
487 487 try:
488 488 assert created_ui.ui_active is False
489 489 assert str2bool(created_ui.ui_value) is False
490 490 finally:
491 491 Session().delete(created_ui)
492 492 Session().commit()
493 493
494 494 def test_update(self, repo_stub, settings_util):
495 495 model = VcsSettingsModel(repo=repo_stub.repo_name)
496 496
497 497 largefiles, phases = model.HG_SETTINGS
498 498 section = 'test-section'
499 499 key = 'test-key'
500 500 settings_util.create_repo_rhodecode_ui(
501 501 repo_stub, section, 'True', key=key, active=True)
502 502
503 503 model._create_or_update_ui(
504 504 model.repo_settings, section, key, active=False, value='False')
505 505 Session().commit()
506 506
507 507 created_ui = model.repo_settings.get_ui_by_section_and_key(
508 508 section, key)
509 509 assert created_ui.ui_active is False
510 510 assert str2bool(created_ui.ui_value) is False
511 511
512 512
513 513 class TestCreateOrUpdateRepoHgSettings(object):
514 514 FORM_DATA = {
515 515 'extensions_largefiles': False,
516 516 'phases_publish': False
517 517 }
518 518
519 519 def test_creates_repo_hg_settings_when_data_is_correct(self, repo_stub):
520 520 model = VcsSettingsModel(repo=repo_stub.repo_name)
521 521 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
522 522 model.create_or_update_repo_hg_settings(self.FORM_DATA)
523 523 expected_calls = [
524 524 mock.call(model.repo_settings, 'extensions', 'largefiles',
525 525 active=False, value=''),
526 526 mock.call(model.repo_settings, 'phases', 'publish', value='False'),
527 527 ]
528 528 assert expected_calls == create_mock.call_args_list
529 529
530 530 @pytest.mark.parametrize('field_to_remove', FORM_DATA.keys())
531 531 def test_key_is_not_found(self, repo_stub, field_to_remove):
532 532 model = VcsSettingsModel(repo=repo_stub.repo_name)
533 533 data = self.FORM_DATA.copy()
534 534 data.pop(field_to_remove)
535 535 with pytest.raises(ValueError) as exc_info:
536 536 model.create_or_update_repo_hg_settings(data)
537 537 expected_message = 'The given data does not contain {} key'.format(
538 538 field_to_remove)
539 539 assert exc_info.value.message == expected_message
540 540
541 541 def test_create_raises_exception_when_repository_not_specified(self):
542 542 model = VcsSettingsModel()
543 543 with pytest.raises(Exception) as exc_info:
544 544 model.create_or_update_repo_hg_settings(self.FORM_DATA)
545 545 assert exc_info.value.message == 'Repository is not specified'
546 546
547 547
548 548 class TestUpdateGlobalSslSetting(object):
549 549 def test_updates_global_hg_settings(self):
550 550 model = VcsSettingsModel()
551 551 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
552 552 model.update_global_ssl_setting('False')
553 553 create_mock.assert_called_once_with(
554 554 model.global_settings, 'web', 'push_ssl', value='False')
555 555
556 556
557 557 class TestUpdateGlobalPathSetting(object):
558 558 def test_updates_global_path_settings(self):
559 559 model = VcsSettingsModel()
560 560 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
561 561 model.update_global_path_setting('False')
562 562 create_mock.assert_called_once_with(
563 563 model.global_settings, 'paths', '/', value='False')
564 564
565 565
566 566 class TestCreateOrUpdateGlobalHgSettings(object):
567 567 FORM_DATA = {
568 568 'extensions_largefiles': False,
569 'largefiles_usercache': '/example/largefiles-store',
569 570 'phases_publish': False,
570 571 'extensions_hgsubversion': False
571 572 }
572 573
573 574 def test_creates_repo_hg_settings_when_data_is_correct(self):
574 575 model = VcsSettingsModel()
575 576 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
576 577 model.create_or_update_global_hg_settings(self.FORM_DATA)
577 578 expected_calls = [
578 579 mock.call(model.global_settings, 'extensions', 'largefiles',
579 580 active=False, value=''),
581 mock.call(model.global_settings, 'largefiles', 'usercache',
582 value='/example/largefiles-store'),
580 583 mock.call(model.global_settings, 'phases', 'publish',
581 584 value='False'),
582 585 mock.call(model.global_settings, 'extensions', 'hgsubversion',
583 586 active=False)
584 587 ]
585 588 assert expected_calls == create_mock.call_args_list
586 589
587 590 @pytest.mark.parametrize('field_to_remove', FORM_DATA.keys())
588 591 def test_key_is_not_found(self, repo_stub, field_to_remove):
589 592 model = VcsSettingsModel(repo=repo_stub.repo_name)
590 593 data = self.FORM_DATA.copy()
591 594 data.pop(field_to_remove)
592 595 with pytest.raises(Exception) as exc_info:
593 596 model.create_or_update_global_hg_settings(data)
594 597 expected_message = 'The given data does not contain {} key'.format(
595 598 field_to_remove)
596 599 assert exc_info.value.message == expected_message
597 600
598 601
599 602 class TestDeleteRepoSvnPattern(object):
600 603 def test_success_when_repo_is_set(self, backend_svn):
601 604 repo_name = backend_svn.repo_name
602 605 model = VcsSettingsModel(repo=repo_name)
603 606 delete_ui_patch = mock.patch.object(model.repo_settings, 'delete_ui')
604 607 with delete_ui_patch as delete_ui_mock:
605 608 model.delete_repo_svn_pattern(123)
606 609 delete_ui_mock.assert_called_once_with(123)
607 610
608 611 def test_raises_exception_when_repository_is_not_specified(self):
609 612 model = VcsSettingsModel()
610 613 with pytest.raises(Exception) as exc_info:
611 614 model.delete_repo_svn_pattern(123)
612 615 assert exc_info.value.message == 'Repository is not specified'
613 616
614 617
615 618 class TestDeleteGlobalSvnPattern(object):
616 619 def test_delete_global_svn_pattern_calls_delete_ui(self):
617 620 model = VcsSettingsModel()
618 621 delete_ui_patch = mock.patch.object(model.global_settings, 'delete_ui')
619 622 with delete_ui_patch as delete_ui_mock:
620 623 model.delete_global_svn_pattern(123)
621 624 delete_ui_mock.assert_called_once_with(123)
622 625
623 626
624 627 class TestFilterUiSettings(object):
625 628 def test_settings_are_filtered(self):
626 629 model = VcsSettingsModel()
627 630 repo_settings = [
628 631 UiSetting('extensions', 'largefiles', '', True),
629 632 UiSetting('phases', 'publish', 'True', True),
630 633 UiSetting('hooks', 'changegroup.repo_size', 'hook', True),
631 634 UiSetting('hooks', 'changegroup.push_logger', 'hook', True),
632 635 UiSetting('hooks', 'outgoing.pull_logger', 'hook', True),
633 636 UiSetting(
634 637 'vcs_svn_branch', '84223c972204fa545ca1b22dac7bef5b68d7442d',
635 638 'test_branch', True),
636 639 UiSetting(
637 640 'vcs_svn_tag', '84229c972204fa545ca1b22dac7bef5b68d7442d',
638 641 'test_tag', True),
639 642 ]
640 643 non_repo_settings = [
644 UiSetting('largefiles', 'usercache', '/example/largefiles-store', True),
641 645 UiSetting('test', 'outgoing.pull_logger', 'hook', True),
642 646 UiSetting('hooks', 'test2', 'hook', True),
643 647 UiSetting(
644 648 'vcs_svn_repo', '84229c972204fa545ca1b22dac7bef5b68d7442d',
645 649 'test_tag', True),
646 650 ]
647 651 settings = repo_settings + non_repo_settings
648 652 filtered_settings = model._filter_ui_settings(settings)
649 653 assert sorted(filtered_settings) == sorted(repo_settings)
650 654
651 655
652 656 class TestFilterGeneralSettings(object):
653 657 def test_settings_are_filtered(self):
654 658 model = VcsSettingsModel()
655 659 settings = {
656 660 'rhodecode_abcde': 'value1',
657 661 'rhodecode_vwxyz': 'value2',
658 662 }
659 663 general_settings = {
660 664 'rhodecode_{}'.format(key): 'value'
661 665 for key in VcsSettingsModel.GENERAL_SETTINGS
662 666 }
663 667 settings.update(general_settings)
664 668
665 669 filtered_settings = model._filter_general_settings(general_settings)
666 670 assert sorted(filtered_settings) == sorted(general_settings)
667 671
668 672
669 673 class TestGetRepoUiSettings(object):
670 674 def test_global_uis_are_returned_when_no_repo_uis_found(
671 675 self, repo_stub):
672 676 model = VcsSettingsModel(repo=repo_stub.repo_name)
673 677 result = model.get_repo_ui_settings()
674 678 svn_sections = (
675 679 VcsSettingsModel.SVN_TAG_SECTION,
676 680 VcsSettingsModel.SVN_BRANCH_SECTION)
677 681 expected_result = [
678 682 s for s in model.global_settings.get_ui()
679 683 if s.section not in svn_sections]
680 684 assert sorted(result) == sorted(expected_result)
681 685
682 686 def test_repo_uis_are_overriding_global_uis(
683 687 self, repo_stub, settings_util):
684 688 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
685 689 settings_util.create_repo_rhodecode_ui(
686 690 repo_stub, section, 'repo', key=key, active=False)
687 691 model = VcsSettingsModel(repo=repo_stub.repo_name)
688 692 result = model.get_repo_ui_settings()
689 693 for setting in result:
690 694 locator = (setting.section, setting.key)
691 695 if locator in VcsSettingsModel.HOOKS_SETTINGS:
692 696 assert setting.value == 'repo'
693 697
694 698 assert setting.active is False
695 699
696 700 def test_global_svn_patterns_are_not_in_list(
697 701 self, repo_stub, settings_util):
698 702 svn_sections = (
699 703 VcsSettingsModel.SVN_TAG_SECTION,
700 704 VcsSettingsModel.SVN_BRANCH_SECTION)
701 705 for section in svn_sections:
702 706 settings_util.create_rhodecode_ui(
703 707 section, 'repo', key='deadbeef' + section, active=False)
704 708 model = VcsSettingsModel(repo=repo_stub.repo_name)
705 709 result = model.get_repo_ui_settings()
706 710 for setting in result:
707 711 assert setting.section not in svn_sections
708 712
709 713 def test_repo_uis_filtered_by_section_are_returned(
710 714 self, repo_stub, settings_util):
711 715 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
712 716 settings_util.create_repo_rhodecode_ui(
713 717 repo_stub, section, 'repo', key=key, active=False)
714 718 model = VcsSettingsModel(repo=repo_stub.repo_name)
715 719 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
716 720 result = model.get_repo_ui_settings(section=section)
717 721 for setting in result:
718 722 assert setting.section == section
719 723
720 724 def test_repo_uis_filtered_by_key_are_returned(
721 725 self, repo_stub, settings_util):
722 726 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
723 727 settings_util.create_repo_rhodecode_ui(
724 728 repo_stub, section, 'repo', key=key, active=False)
725 729 model = VcsSettingsModel(repo=repo_stub.repo_name)
726 730 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
727 731 result = model.get_repo_ui_settings(key=key)
728 732 for setting in result:
729 733 assert setting.key == key
730 734
731 735 def test_raises_exception_when_repository_is_not_specified(self):
732 736 model = VcsSettingsModel()
733 737 with pytest.raises(Exception) as exc_info:
734 738 model.get_repo_ui_settings()
735 739 assert exc_info.value.message == 'Repository is not specified'
736 740
737 741
738 742 class TestGetRepoGeneralSettings(object):
739 743 def test_global_settings_are_returned_when_no_repo_settings_found(
740 744 self, repo_stub):
741 745 model = VcsSettingsModel(repo=repo_stub.repo_name)
742 746 result = model.get_repo_general_settings()
743 747 expected_result = model.global_settings.get_all_settings()
744 748 assert sorted(result) == sorted(expected_result)
745 749
746 750 def test_repo_uis_are_overriding_global_uis(
747 751 self, repo_stub, settings_util):
748 752 for key in VcsSettingsModel.GENERAL_SETTINGS:
749 753 settings_util.create_repo_rhodecode_setting(
750 754 repo_stub, key, 'abcde', type_='unicode')
751 755 model = VcsSettingsModel(repo=repo_stub.repo_name)
752 756 result = model.get_repo_ui_settings()
753 757 for key in result:
754 758 if key in VcsSettingsModel.GENERAL_SETTINGS:
755 759 assert result[key] == 'abcde'
756 760
757 761 def test_raises_exception_when_repository_is_not_specified(self):
758 762 model = VcsSettingsModel()
759 763 with pytest.raises(Exception) as exc_info:
760 764 model.get_repo_general_settings()
761 765 assert exc_info.value.message == 'Repository is not specified'
762 766
763 767
764 768 class TestGetGlobalGeneralSettings(object):
765 769 def test_global_settings_are_returned(self, repo_stub):
766 770 model = VcsSettingsModel()
767 771 result = model.get_global_general_settings()
768 772 expected_result = model.global_settings.get_all_settings()
769 773 assert sorted(result) == sorted(expected_result)
770 774
771 775 def test_repo_uis_are_not_overriding_global_uis(
772 776 self, repo_stub, settings_util):
773 777 for key in VcsSettingsModel.GENERAL_SETTINGS:
774 778 settings_util.create_repo_rhodecode_setting(
775 779 repo_stub, key, 'abcde', type_='unicode')
776 780 model = VcsSettingsModel(repo=repo_stub.repo_name)
777 781 result = model.get_global_general_settings()
778 782 expected_result = model.global_settings.get_all_settings()
779 783 assert sorted(result) == sorted(expected_result)
780 784
781 785
782 786 class TestGetGlobalUiSettings(object):
783 787 def test_global_uis_are_returned(self, repo_stub):
784 788 model = VcsSettingsModel()
785 789 result = model.get_global_ui_settings()
786 790 expected_result = model.global_settings.get_ui()
787 791 assert sorted(result) == sorted(expected_result)
788 792
789 793 def test_repo_uis_are_not_overriding_global_uis(
790 794 self, repo_stub, settings_util):
791 795 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
792 796 settings_util.create_repo_rhodecode_ui(
793 797 repo_stub, section, 'repo', key=key, active=False)
794 798 model = VcsSettingsModel(repo=repo_stub.repo_name)
795 799 result = model.get_global_ui_settings()
796 800 expected_result = model.global_settings.get_ui()
797 801 assert sorted(result) == sorted(expected_result)
798 802
799 803 def test_ui_settings_filtered_by_section(
800 804 self, repo_stub, settings_util):
801 805 model = VcsSettingsModel(repo=repo_stub.repo_name)
802 806 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
803 807 result = model.get_global_ui_settings(section=section)
804 808 expected_result = model.global_settings.get_ui(section=section)
805 809 assert sorted(result) == sorted(expected_result)
806 810
807 811 def test_ui_settings_filtered_by_key(
808 812 self, repo_stub, settings_util):
809 813 model = VcsSettingsModel(repo=repo_stub.repo_name)
810 814 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
811 815 result = model.get_global_ui_settings(key=key)
812 816 expected_result = model.global_settings.get_ui(key=key)
813 817 assert sorted(result) == sorted(expected_result)
814 818
815 819
816 820 class TestGetGeneralSettings(object):
817 821 def test_global_settings_are_returned_when_inherited_is_true(
818 822 self, repo_stub, settings_util):
819 823 model = VcsSettingsModel(repo=repo_stub.repo_name)
820 824 model.inherit_global_settings = True
821 825 for key in VcsSettingsModel.GENERAL_SETTINGS:
822 826 settings_util.create_repo_rhodecode_setting(
823 827 repo_stub, key, 'abcde', type_='unicode')
824 828 result = model.get_general_settings()
825 829 expected_result = model.get_global_general_settings()
826 830 assert sorted(result) == sorted(expected_result)
827 831
828 832 def test_repo_settings_are_returned_when_inherited_is_false(
829 833 self, repo_stub, settings_util):
830 834 model = VcsSettingsModel(repo=repo_stub.repo_name)
831 835 model.inherit_global_settings = False
832 836 for key in VcsSettingsModel.GENERAL_SETTINGS:
833 837 settings_util.create_repo_rhodecode_setting(
834 838 repo_stub, key, 'abcde', type_='unicode')
835 839 result = model.get_general_settings()
836 840 expected_result = model.get_repo_general_settings()
837 841 assert sorted(result) == sorted(expected_result)
838 842
839 843 def test_global_settings_are_returned_when_no_repository_specified(self):
840 844 model = VcsSettingsModel()
841 845 result = model.get_general_settings()
842 846 expected_result = model.get_global_general_settings()
843 847 assert sorted(result) == sorted(expected_result)
844 848
845 849
846 850 class TestGetUiSettings(object):
847 851 def test_global_settings_are_returned_when_inherited_is_true(
848 852 self, repo_stub, settings_util):
849 853 model = VcsSettingsModel(repo=repo_stub.repo_name)
850 854 model.inherit_global_settings = True
851 855 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
852 856 settings_util.create_repo_rhodecode_ui(
853 857 repo_stub, section, 'repo', key=key, active=True)
854 858 result = model.get_ui_settings()
855 859 expected_result = model.get_global_ui_settings()
856 860 assert sorted(result) == sorted(expected_result)
857 861
858 862 def test_repo_settings_are_returned_when_inherited_is_false(
859 863 self, repo_stub, settings_util):
860 864 model = VcsSettingsModel(repo=repo_stub.repo_name)
861 865 model.inherit_global_settings = False
862 866 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
863 867 settings_util.create_repo_rhodecode_ui(
864 868 repo_stub, section, 'repo', key=key, active=True)
865 869 result = model.get_ui_settings()
866 870 expected_result = model.get_repo_ui_settings()
867 871 assert sorted(result) == sorted(expected_result)
868 872
869 873 def test_repo_settings_filtered_by_section_and_key(self, repo_stub):
870 874 model = VcsSettingsModel(repo=repo_stub.repo_name)
871 875 model.inherit_global_settings = False
872 876 args = ('section', 'key')
873 877 with mock.patch.object(model, 'get_repo_ui_settings') as settings_mock:
874 878 model.get_ui_settings(*args)
875 879 settings_mock.assert_called_once_with(*args)
876 880
877 881 def test_global_settings_filtered_by_section_and_key(self):
878 882 model = VcsSettingsModel()
879 883 args = ('section', 'key')
880 884 with mock.patch.object(model, 'get_global_ui_settings') as (
881 885 settings_mock):
882 886 model.get_ui_settings(*args)
883 887 settings_mock.assert_called_once_with(*args)
884 888
885 889 def test_global_settings_are_returned_when_no_repository_specified(self):
886 890 model = VcsSettingsModel()
887 891 result = model.get_ui_settings()
888 892 expected_result = model.get_global_ui_settings()
889 893 assert sorted(result) == sorted(expected_result)
890 894
891 895
892 896 class TestGetSvnPatterns(object):
893 897 def test_repo_settings_filtered_by_section_and_key(self, repo_stub):
894 898 model = VcsSettingsModel(repo=repo_stub.repo_name)
895 899 args = ('section', )
896 900 with mock.patch.object(model, 'get_repo_ui_settings') as settings_mock:
897 901 model.get_svn_patterns(*args)
898 902 settings_mock.assert_called_once_with(*args)
899 903
900 904 def test_global_settings_filtered_by_section_and_key(self):
901 905 model = VcsSettingsModel()
902 906 args = ('section', )
903 907 with mock.patch.object(model, 'get_global_ui_settings') as (
904 908 settings_mock):
905 909 model.get_svn_patterns(*args)
906 910 settings_mock.assert_called_once_with(*args)
907 911
908 912
909 913 class TestGetReposLocation(object):
910 914 def test_returns_repos_location(self, repo_stub):
911 915 model = VcsSettingsModel()
912 916
913 917 result_mock = mock.Mock()
914 918 result_mock.ui_value = '/tmp'
915 919
916 920 with mock.patch.object(model, 'global_settings') as settings_mock:
917 921 settings_mock.get_ui_by_key.return_value = result_mock
918 922 result = model.get_repos_location()
919 923
920 924 settings_mock.get_ui_by_key.assert_called_once_with('/')
921 925 assert result == '/tmp'
922 926
923 927
924 928 class TestCreateOrUpdateRepoSettings(object):
925 929 FORM_DATA = {
926 930 'inherit_global_settings': False,
927 931 'hooks_changegroup_repo_size': False,
928 932 'hooks_changegroup_push_logger': False,
929 933 'hooks_outgoing_pull_logger': False,
930 934 'extensions_largefiles': False,
935 'largefiles_usercache': '/example/largefiles-store',
931 936 'phases_publish': 'false',
932 937 'rhodecode_pr_merge_enabled': False,
933 938 'rhodecode_use_outdated_comments': False,
934 939 'new_svn_branch': '',
935 940 'new_svn_tag': ''
936 941 }
937 942
938 943 def test_get_raises_exception_when_repository_not_specified(self):
939 944 model = VcsSettingsModel()
940 945 with pytest.raises(Exception) as exc_info:
941 946 model.create_or_update_repo_settings(data=self.FORM_DATA)
942 947 assert exc_info.value.message == 'Repository is not specified'
943 948
944 949 def test_only_svn_settings_are_updated_when_type_is_svn(self, backend_svn):
945 950 repo = backend_svn.create_repo()
946 951 model = VcsSettingsModel(repo=repo)
947 952 with self._patch_model(model) as mocks:
948 953 model.create_or_update_repo_settings(
949 954 data=self.FORM_DATA, inherit_global_settings=False)
950 955 mocks['create_repo_svn_settings'].assert_called_once_with(
951 956 self.FORM_DATA)
952 957 non_called_methods = (
953 958 'create_or_update_repo_hook_settings',
954 959 'create_or_update_repo_pr_settings',
955 960 'create_or_update_repo_hg_settings')
956 961 for method in non_called_methods:
957 962 assert mocks[method].call_count == 0
958 963
959 964 def test_non_svn_settings_are_updated_when_type_is_hg(self, backend_hg):
960 965 repo = backend_hg.create_repo()
961 966 model = VcsSettingsModel(repo=repo)
962 967 with self._patch_model(model) as mocks:
963 968 model.create_or_update_repo_settings(
964 969 data=self.FORM_DATA, inherit_global_settings=False)
965 970
966 971 assert mocks['create_repo_svn_settings'].call_count == 0
967 972 called_methods = (
968 973 'create_or_update_repo_hook_settings',
969 974 'create_or_update_repo_pr_settings',
970 975 'create_or_update_repo_hg_settings')
971 976 for method in called_methods:
972 977 mocks[method].assert_called_once_with(self.FORM_DATA)
973 978
974 979 def test_non_svn_and_hg_settings_are_updated_when_type_is_git(
975 980 self, backend_git):
976 981 repo = backend_git.create_repo()
977 982 model = VcsSettingsModel(repo=repo)
978 983 with self._patch_model(model) as mocks:
979 984 model.create_or_update_repo_settings(
980 985 data=self.FORM_DATA, inherit_global_settings=False)
981 986
982 987 assert mocks['create_repo_svn_settings'].call_count == 0
983 988 called_methods = (
984 989 'create_or_update_repo_hook_settings',
985 990 'create_or_update_repo_pr_settings')
986 991 non_called_methods = (
987 992 'create_repo_svn_settings',
988 993 'create_or_update_repo_hg_settings'
989 994 )
990 995 for method in called_methods:
991 996 mocks[method].assert_called_once_with(self.FORM_DATA)
992 997 for method in non_called_methods:
993 998 assert mocks[method].call_count == 0
994 999
995 1000 def test_no_methods_are_called_when_settings_are_inherited(
996 1001 self, backend):
997 1002 repo = backend.create_repo()
998 1003 model = VcsSettingsModel(repo=repo)
999 1004 with self._patch_model(model) as mocks:
1000 1005 model.create_or_update_repo_settings(
1001 1006 data=self.FORM_DATA, inherit_global_settings=True)
1002 1007 for method_name in mocks:
1003 1008 assert mocks[method_name].call_count == 0
1004 1009
1005 1010 def test_cache_is_marked_for_invalidation(self, repo_stub):
1006 1011 model = VcsSettingsModel(repo=repo_stub)
1007 1012 invalidation_patcher = mock.patch(
1008 1013 'rhodecode.controllers.admin.repos.ScmModel.mark_for_invalidation')
1009 1014 with invalidation_patcher as invalidation_mock:
1010 1015 model.create_or_update_repo_settings(
1011 1016 data=self.FORM_DATA, inherit_global_settings=True)
1012 1017 invalidation_mock.assert_called_once_with(
1013 1018 repo_stub.repo_name, delete=True)
1014 1019
1015 1020 def test_inherit_flag_is_saved(self, repo_stub):
1016 1021 model = VcsSettingsModel(repo=repo_stub)
1017 1022 model.inherit_global_settings = True
1018 1023 with self._patch_model(model):
1019 1024 model.create_or_update_repo_settings(
1020 1025 data=self.FORM_DATA, inherit_global_settings=False)
1021 1026 assert model.inherit_global_settings is False
1022 1027
1023 1028 def _patch_model(self, model):
1024 1029 return mock.patch.multiple(
1025 1030 model,
1026 1031 create_repo_svn_settings=mock.DEFAULT,
1027 1032 create_or_update_repo_hook_settings=mock.DEFAULT,
1028 1033 create_or_update_repo_pr_settings=mock.DEFAULT,
1029 1034 create_or_update_repo_hg_settings=mock.DEFAULT)
General Comments 0
You need to be logged in to leave comments. Login now