diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py --- a/rhodecode/controllers/admin/settings.py +++ b/rhodecode/controllers/admin/settings.py @@ -82,7 +82,7 @@ class SettingsController(BaseController) rhodecode.CONFIG.get('labs_settings_active', 'true')) c.navlist = navigation_list(request) - def _get_hg_ui_settings(self): + def _get_ui_settings(self): ret = RhodeCodeUi.query().all() if not ret: @@ -94,7 +94,7 @@ class SettingsController(BaseController) if k == '/': k = 'root_path' - if k in ['push_ssl', 'publish']: + if k in ['push_ssl', 'publish', 'enabled']: v = str2bool(v) if k.find('.') != -1: @@ -165,6 +165,7 @@ class SettingsController(BaseController) model.create_or_update_global_svn_settings(form_result) model.create_or_update_global_hg_settings(form_result) + model.create_or_update_global_git_settings(form_result) model.create_or_update_global_pr_settings(form_result) except Exception: log.exception("Exception while updating settings") @@ -668,7 +669,8 @@ class SettingsController(BaseController) def _form_defaults(self): defaults = SettingsModel().get_all_settings() - defaults.update(self._get_hg_ui_settings()) + defaults.update(self._get_ui_settings()) + defaults.update({ 'new_svn_branch': '', 'new_svn_tag': '', diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py --- a/rhodecode/model/forms.py +++ b/rhodecode/model/forms.py @@ -378,13 +378,19 @@ class _BaseVcsSettingsForm(formencode.Sc hooks_changegroup_push_logger = v.StringBoolean(if_missing=False) hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False) + # PR/Code-review + rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False) + rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False) + + # hg extensions_largefiles = v.StringBoolean(if_missing=False) phases_publish = v.StringBoolean(if_missing=False) - - rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False) - rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False) rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False) + # git + vcs_git_lfs_enabled = v.StringBoolean(if_missing=False) + + # svn vcs_svn_proxy_http_requests_enabled = v.StringBoolean(if_missing=False) vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None) @@ -398,8 +404,10 @@ def ApplicationUiSettingsForm(): ) largefiles_usercache = All( v.ValidPath(), - v.UnicodeString(strip=True, min=2, not_empty=True) - ) + v.UnicodeString(strip=True, min=2, not_empty=True)) + vcs_git_lfs_store_location = All( + v.ValidPath(), + v.UnicodeString(strip=True, min=2, not_empty=True)) extensions_hgsubversion = v.StringBoolean(if_missing=False) extensions_hggit = v.StringBoolean(if_missing=False) new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch') diff --git a/rhodecode/model/settings.py b/rhodecode/model/settings.py --- a/rhodecode/model/settings.py +++ b/rhodecode/model/settings.py @@ -410,15 +410,21 @@ class VcsSettingsModel(object): HOOKS_SETTINGS = ( ('hooks', 'changegroup.repo_size'), ('hooks', 'changegroup.push_logger'), - ('hooks', 'outgoing.pull_logger')) + ('hooks', 'outgoing.pull_logger'),) HG_SETTINGS = ( ('extensions', 'largefiles'), - ('phases', 'publish')) + ('phases', 'publish'),) + GIT_SETTINGS = ( + ('vcs_git_lfs', 'enabled'),) + GLOBAL_HG_SETTINGS = ( ('extensions', 'largefiles'), ('largefiles', 'usercache'), ('phases', 'publish'), ('extensions', 'hgsubversion')) + GLOBAL_GIT_SETTINGS = ( + ('vcs_git_lfs', 'enabled'), + ('vcs_git_lfs', 'store_location')) GLOBAL_SVN_SETTINGS = ( ('vcs_svn_proxy', 'http_requests_enabled'), ('vcs_svn_proxy', 'http_server_url')) @@ -431,7 +437,8 @@ class VcsSettingsModel(object): def __init__(self, sa=None, repo=None): self.global_settings = SettingsModel(sa=sa) self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None - self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS + self._ui_settings = ( + self.HG_SETTINGS + self.GIT_SETTINGS + self.HOOKS_SETTINGS) self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION) @property @@ -485,6 +492,9 @@ class VcsSettingsModel(object): if repo.repo_type == 'hg': self.create_or_update_repo_hg_settings(data) + if repo.repo_type == 'git': + self.create_or_update_repo_git_settings(data) + ScmModel().mark_for_invalidation(repo.repo_name, delete=True) @assert_repo_settings @@ -534,9 +544,11 @@ class VcsSettingsModel(object): @assert_repo_settings def create_or_update_repo_hg_settings(self, data): - largefiles, phases = self.HG_SETTINGS - largefiles_key, phases_key = self._get_settings_keys( - self.HG_SETTINGS, data) + largefiles, phases = \ + self.HG_SETTINGS + largefiles_key, phases_key = \ + self._get_settings_keys(self.HG_SETTINGS, data) + self._create_or_update_ui( self.repo_settings, *largefiles, value='', active=data[largefiles_key]) @@ -548,7 +560,6 @@ class VcsSettingsModel(object): = self.GLOBAL_HG_SETTINGS largefiles_key, largefiles_store_key, phases_key, subversion_key \ = self._get_settings_keys(self.GLOBAL_HG_SETTINGS, data) - self._create_or_update_ui( self.global_settings, *largefiles, value='', active=data[largefiles_key]) @@ -560,6 +571,31 @@ class VcsSettingsModel(object): self._create_or_update_ui( self.global_settings, *hgsubversion, active=data[subversion_key]) + def create_or_update_repo_git_settings(self, data): + # NOTE(marcink): # comma make unpack work properly + lfs_enabled, \ + = self.GIT_SETTINGS + + lfs_enabled_key, \ + = self._get_settings_keys(self.GIT_SETTINGS, data) + + self._create_or_update_ui( + self.repo_settings, *lfs_enabled, value=data[lfs_enabled_key], + active=data[lfs_enabled_key]) + + def create_or_update_global_git_settings(self, data): + lfs_enabled, lfs_store_location \ + = self.GLOBAL_GIT_SETTINGS + lfs_enabled_key, lfs_store_location_key \ + = self._get_settings_keys(self.GLOBAL_GIT_SETTINGS, data) + + self._create_or_update_ui( + self.global_settings, *lfs_enabled, value=data[lfs_enabled_key], + active=data[lfs_enabled_key]) + self._create_or_update_ui( + self.global_settings, *lfs_store_location, + value=data[lfs_store_location_key]) + def create_or_update_global_svn_settings(self, data): # branch/tags patterns self._create_svn_settings(self.global_settings, data) @@ -677,9 +713,12 @@ class VcsSettingsModel(object): for section, key in self._ui_settings: ui = settings.get_ui_by_section_and_key(section, key) result_key = self._get_form_ui_key(section, key) + if ui: if section in ('hooks', 'extensions'): result[result_key] = ui.ui_active + elif result_key in ['vcs_git_lfs_enabled']: + result[result_key] = ui.ui_active else: result[result_key] = ui.ui_value diff --git a/rhodecode/templates/base/vcs_settings.mako b/rhodecode/templates/base/vcs_settings.mako --- a/rhodecode/templates/base/vcs_settings.mako +++ b/rhodecode/templates/base/vcs_settings.mako @@ -154,6 +154,39 @@ % endif + % if display_globals or repo_type in ['git']: +
+
+

${_('Git Settings')}

+
+
+
+ ${h.checkbox('vcs_git_lfs_enabled' + suffix, 'True', **kwargs)} + +
+
+ % if display_globals: + ${_('Enable lfs extensions for all repositories.')} + % else: + ${_('Enable lfs extensions for this repository.')} + % endif +
+ + % if display_globals: +
+
+ ${h.text('vcs_git_lfs_store_location' + suffix, size=59)} +
+
+
+ ${_('Filesystem location where Git lfs objects should be stored.')} +
+ % endif +
+
+ % endif + + % if display_globals:
diff --git a/rhodecode/tests/lib/middleware/test_simplegit.py b/rhodecode/tests/lib/middleware/test_simplegit.py --- a/rhodecode/tests/lib/middleware/test_simplegit.py +++ b/rhodecode/tests/lib/middleware/test_simplegit.py @@ -20,7 +20,10 @@ import pytest import urlparse +import mock +import simplejson as json +from rhodecode.lib.vcs.backends.base import Config from rhodecode.tests.lib.middleware import mock_scm_app import rhodecode.lib.middleware.simplegit as simplegit @@ -107,22 +110,24 @@ def test_get_repository_name(url, expect get_environ(url, request_method)) -def test_get_config(pylonsapp): +def test_get_config(pylonsapp, user_util): + repo = user_util.create_repo(repo_type='git') app = simplegit.SimpleGit(application=None, config={'auth_ret_code': '', 'base_path': ''}, registry=None) extras = {'foo': 'FOO', 'bar': 'BAR'} # We copy the extras as the method below will change the contents. - config = app._create_config(dict(extras), repo_name='test-repo') + git_config = app._create_config(dict(extras), repo_name=repo.repo_name) + expected_config = dict(extras) expected_config.update({ 'git_update_server_info': False, - 'git_lfs_enabled': True, - 'git_lfs_store_path': simplegit.default_lfs_store() + 'git_lfs_enabled': False, + 'git_lfs_store_path': git_config['git_lfs_store_path'] }) - assert config == expected_config + assert git_config == expected_config def test_create_wsgi_app_uses_scm_app_from_simplevcs(pylonsapp): diff --git a/rhodecode/tests/lib/middleware/test_simplehg.py b/rhodecode/tests/lib/middleware/test_simplehg.py --- a/rhodecode/tests/lib/middleware/test_simplehg.py +++ b/rhodecode/tests/lib/middleware/test_simplehg.py @@ -78,30 +78,42 @@ def test_get_repository_name(url, expect assert expected_repo_name == app._get_repository_name(get_environ(url)) -def test_get_config(): +def test_get_config(pylonsapp, user_util): + repo = user_util.create_repo(repo_type='git') app = simplehg.SimpleHg(application=None, config={'auth_ret_code': '', 'base_path': ''}, registry=None) extras = {'foo': 'FOO', 'bar': 'BAR'} - mock_config = Config() - mock_config.set('a1', 'b1', 'c1') - mock_config.set('a2', 'b2', 'c2') - # We mock the call to make_db_config, otherwise we need to wait for the - # pylonsaspp - with mock.patch('rhodecode.lib.utils.make_db_config', - return_value=mock_config) as make_db_config_mock: - hg_config = app._create_config(extras, repo_name='test-repo') + hg_config = app._create_config(extras, repo_name=repo.repo_name) + + config = simplehg.utils.make_db_config(repo=repo.repo_name) + config.set('rhodecode', 'RC_SCM_DATA', json.dumps(extras)) + hg_config_org = config - make_db_config_mock.assert_called_once_with(repo='test-repo') - assert isinstance(hg_config, list) - - # Remove the entries from the mock_config so to get only the extras - hg_config.remove(('a1', 'b1', 'c1')) - hg_config.remove(('a2', 'b2', 'c2')) - - assert hg_config[0][:2] == ('rhodecode', 'RC_SCM_DATA') - assert json.loads(hg_config[0][-1]) == extras + expected_config = [ + ('vcs_svn_tag', 'ff89f8c714d135d865f44b90e5413b88de19a55f', '/tags/*'), + ('web', 'push_ssl', 'False'), + ('web', 'allow_push', '*'), + ('web', 'allow_archive', 'gz zip bz2'), + ('web', 'baseurl', '/'), + ('vcs_git_lfs', 'store_location', hg_config_org.get('vcs_git_lfs', 'store_location')), + ('vcs_svn_branch', '9aac1a38c3b8a0cdc4ae0f960a5f83332bc4fa5e', '/branches/*'), + ('vcs_svn_branch', 'c7e6a611c87da06529fd0dd733308481d67c71a8', '/trunk'), + ('largefiles', 'usercache', hg_config_org.get('largefiles', 'usercache')), + ('hooks', 'preoutgoing.pre_pull', 'python:vcsserver.hooks.pre_pull'), + ('hooks', 'prechangegroup.pre_push', 'python:vcsserver.hooks.pre_push'), + ('hooks', 'outgoing.pull_logger', 'python:vcsserver.hooks.log_pull_action'), + ('hooks', 'pretxnchangegroup.pre_push', 'python:vcsserver.hooks.pre_push'), + ('hooks', 'changegroup.push_logger', 'python:vcsserver.hooks.log_push_action'), + ('hooks', 'changegroup.repo_size', 'python:vcsserver.hooks.repo_size'), + ('phases', 'publish', 'True'), + ('extensions', 'largefiles', ''), + ('paths', '/', hg_config_org.get('paths', '/')), + ('rhodecode', 'RC_SCM_DATA', '{"foo": "FOO", "bar": "BAR"}') + ] + for entry in expected_config: + assert entry in hg_config def test_create_wsgi_app_uses_scm_app_from_simplevcs(): diff --git a/rhodecode/tests/models/settings/test_vcs_settings.py b/rhodecode/tests/models/settings/test_vcs_settings.py --- a/rhodecode/tests/models/settings/test_vcs_settings.py +++ b/rhodecode/tests/models/settings/test_vcs_settings.py @@ -176,7 +176,7 @@ class TestVcsSettingsModel(object): settings_mock.get_setting_by_name.return_value = result_mock result = model._collect_all_settings(global_=global_) - ui_settings = model.HG_SETTINGS + model.HOOKS_SETTINGS + ui_settings = model.HG_SETTINGS + model.GIT_SETTINGS + model.HOOKS_SETTINGS self._assert_get_settings_calls( settings_mock, ui_settings, model.GENERAL_SETTINGS) self._assert_collect_all_settings_result( @@ -230,7 +230,13 @@ class TestVcsSettingsModel(object): expected_result = {} for section, key in ui_settings: key = '{}_{}'.format(section, key.replace('.', '_')) - value = True if section in ('extensions', 'hooks') else 'ui_value' + + if section in ('extensions', 'hooks'): + value = True + elif key in ['vcs_git_lfs_enabled']: + value = True + else: + value = 'ui_value' expected_result[key] = value for name in general_settings: @@ -599,6 +605,25 @@ class TestCreateOrUpdateGlobalHgSettings assert exc_info.value.message == expected_message +class TestCreateOrUpdateGlobalGitSettings(object): + FORM_DATA = { + 'vcs_git_lfs_enabled': False, + 'vcs_git_lfs_store_location': '/example/lfs-store', + } + + def test_creates_repo_hg_settings_when_data_is_correct(self): + model = VcsSettingsModel() + with mock.patch.object(model, '_create_or_update_ui') as create_mock: + model.create_or_update_global_git_settings(self.FORM_DATA) + expected_calls = [ + mock.call(model.global_settings, 'vcs_git_lfs', 'enabled', + active=False, value=False), + mock.call(model.global_settings, 'vcs_git_lfs', 'store_location', + value='/example/lfs-store'), + ] + assert expected_calls == create_mock.call_args_list + + class TestDeleteRepoSvnPattern(object): def test_success_when_repo_is_set(self, backend_svn): repo_name = backend_svn.repo_name @@ -933,6 +958,8 @@ class TestCreateOrUpdateRepoSettings(obj 'hooks_outgoing_pull_logger': False, 'extensions_largefiles': False, 'largefiles_usercache': '/example/largefiles-store', + 'vcs_git_lfs_enabled': False, + 'vcs_git_lfs_store_location': '/', 'phases_publish': 'False', 'rhodecode_pr_merge_enabled': False, 'rhodecode_use_outdated_comments': False,