##// END OF EJS Templates
release: Merge default into stable for release preparation
super-admin -
r4770:a5598123 merge stable
parent child Browse files
Show More
@@ -0,0 +1,58 b''
1 |RCE| 4.27.0 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2022-09-01
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13
14 - Git: allow overriding default master branch with an env variable.
15 - VCS settings: when setting landing ref from UI switch default GIT branch too.
16 This allows having non-default branches set as default.
17 - Users: enable full edit mode for super admins.
18 Super-Admins now are allowed to edit even LDAP/OAuth user attributes.
19 We'll enable the users to change their names via external auth for rename cases.
20
21
22 General
23 ^^^^^^^
24
25 - Commits/summary: unify fetching remote attribute in summary and commits page to properly and in the same way show the data.
26 - Caches: updated logging and some timings
27 - Caches: allow regional per repo caches, and invalidate caches via a remote call.
28 - Caches: invalidate cache on remote side from repo settings alongside local cache.
29 - Git: allow setting symbolic ref for repos without master branch.
30 - Sys-info: added helpers for faster loading of sys-info data
31 - Debugging: debug = true flag now prints associated exception and logs right into the error page
32
33
34 Security
35 ^^^^^^^^
36
37 - Healthcheck: Added authentication because we expose DB information
38 - Security: fixed self-xss on archive download page.
39
40
41 Performance
42 ^^^^^^^^^^^
43
44
45
46 Fixes
47 ^^^^^
48
49 - Drafts: show TODO drafts properly in edge cases.
50 - Files: fixed unicode problems in specially encoded paths handler.
51 - Caches: fixed issue with exception on handling non-ascii cache keys.
52 - Git: handle archive generation crash case when submodules are present.
53
54
55 Upgrade notes
56 ^^^^^^^^^^^^^
57
58 - Scheduled release 4.27.0.
@@ -1,5 +1,5 b''
1 [bumpversion]
1 [bumpversion]
2 current_version = 4.26.0
2 current_version = 4.27.0
3 message = release: Bump version {current_version} to {new_version}
3 message = release: Bump version {current_version} to {new_version}
4
4
5 [bumpversion:file:rhodecode/VERSION]
5 [bumpversion:file:rhodecode/VERSION]
@@ -5,26 +5,20 b' done = false'
5 done = true
5 done = true
6
6
7 [task:rc_tools_pinned]
7 [task:rc_tools_pinned]
8 done = true
9
8
10 [task:fixes_on_stable]
9 [task:fixes_on_stable]
11 done = true
12
10
13 [task:pip2nix_generated]
11 [task:pip2nix_generated]
14 done = true
15
12
16 [task:changelog_updated]
13 [task:changelog_updated]
17 done = true
18
14
19 [task:generate_api_docs]
15 [task:generate_api_docs]
20 done = true
21
16
22 [task:updated_translation]
17 [task:updated_translation]
23 done = true
24
18
25 [release]
19 [release]
26 state = prepared
20 state = in_progress
27 version = 4.26.0
21 version = 4.27.0
28
22
29 [task:generate_js_routes]
23 [task:generate_js_routes]
30
24
@@ -169,4 +169,4 b' Deprecated Support'
169 - Internet Explorer 9 support deprecated since version 3.8.0.
169 - Internet Explorer 9 support deprecated since version 3.8.0.
170
170
171 .. _here: https://rhodecode.com/licenses/
171 .. _here: https://rhodecode.com/licenses/
172 .. _Transifex: https://www.transifex.com/projects/p/RhodeCode/
172 .. _Transifex: https://explore.transifex.com/rhodecode/RhodeCode/
@@ -9,6 +9,7 b' Release Notes'
9 .. toctree::
9 .. toctree::
10 :maxdepth: 1
10 :maxdepth: 1
11
11
12 release-notes-4.27.0.rst
12 release-notes-4.26.0.rst
13 release-notes-4.26.0.rst
13 release-notes-4.25.2.rst
14 release-notes-4.25.2.rst
14 release-notes-4.25.1.rst
15 release-notes-4.25.1.rst
@@ -1,6 +1,6 b''
1 diff -rup rhodecode-tools-1.4.0-orig/setup.py rhodecode-tools-1.4.0/setup.py
1 diff -rup rhodecode-tools-1.4.1-orig/setup.py rhodecode-tools-1.4.1/setup.py
2 --- rhodecode-tools-1.4.0/setup-orig.py 2021-03-11 12:34:45.000000000 +0100
2 --- rhodecode-tools-1.4.1/setup-orig.py 2021-03-11 12:34:45.000000000 +0100
3 +++ rhodecode-tools-1.4.0/setup.py 2021-03-11 12:34:56.000000000 +0100
3 +++ rhodecode-tools-1.4.1/setup.py 2021-03-11 12:34:56.000000000 +0100
4 @@ -69,7 +69,7 @@ def _get_requirements(req_filename, excl
4 @@ -69,7 +69,7 @@ def _get_requirements(req_filename, excl
5
5
6
6
@@ -1883,7 +1883,7 b' self: super: {'
1883 };
1883 };
1884 };
1884 };
1885 "rhodecode-enterprise-ce" = super.buildPythonPackage {
1885 "rhodecode-enterprise-ce" = super.buildPythonPackage {
1886 name = "rhodecode-enterprise-ce-4.26.0";
1886 name = "rhodecode-enterprise-ce-4.27.0";
1887 buildInputs = [
1887 buildInputs = [
1888 self."pytest"
1888 self."pytest"
1889 self."py"
1889 self."py"
@@ -2020,7 +2020,7 b' self: super: {'
2020 };
2020 };
2021 };
2021 };
2022 "rhodecode-tools" = super.buildPythonPackage {
2022 "rhodecode-tools" = super.buildPythonPackage {
2023 name = "rhodecode-tools-1.4.0";
2023 name = "rhodecode-tools-1.4.1";
2024 doCheck = false;
2024 doCheck = false;
2025 propagatedBuildInputs = [
2025 propagatedBuildInputs = [
2026 self."click"
2026 self."click"
@@ -2037,8 +2037,8 b' self: super: {'
2037 self."elasticsearch1-dsl"
2037 self."elasticsearch1-dsl"
2038 ];
2038 ];
2039 src = fetchurl {
2039 src = fetchurl {
2040 url = "https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-ed54e749-2ef5-4bc7-ae7f-7900e3c2aa15.tar.gz?sha256=76f024bad3a1e55fdb3d64f13f5b77ff21a12fee699918de2110fe21effd5a3a";
2040 url = "https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-d9ea7914-e475-44af-a80a-7e32edc17e2f.tar.gz?sha256=6e5aaac455b4a0b2dee013a1241b367e2991e345fda6ed0f4a8c66c941a19184";
2041 sha256 = "0fjszppj3zhh47g1i6b9xqps28gzfxdkzwb47pdmzrd1sfx29w3n";
2041 sha256 = "6e5aaac455b4a0b2dee013a1241b367e2991e345fda6ed0f4a8c66c941a19184";
2042 };
2042 };
2043 meta = {
2043 meta = {
2044 license = [ { fullName = "Apache 2.0 and Proprietary"; } ];
2044 license = [ { fullName = "Apache 2.0 and Proprietary"; } ];
@@ -111,7 +111,7 b' ipdb==0.13.2'
111 ipython==5.1.0
111 ipython==5.1.0
112
112
113 ## rhodecode-tools, special case, use file://PATH.tar.gz#egg=rhodecode-tools==X.Y.Z, to test local version
113 ## rhodecode-tools, special case, use file://PATH.tar.gz#egg=rhodecode-tools==X.Y.Z, to test local version
114 https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-ed54e749-2ef5-4bc7-ae7f-7900e3c2aa15.tar.gz?sha256=76f024bad3a1e55fdb3d64f13f5b77ff21a12fee699918de2110fe21effd5a3a#egg=rhodecode-tools==1.4.0
114 https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-d9ea7914-e475-44af-a80a-7e32edc17e2f.tar.gz?sha256=6e5aaac455b4a0b2dee013a1241b367e2991e345fda6ed0f4a8c66c941a19184#egg=rhodecode-tools==1.4.1
115
115
116
116
117 ## appenlight
117 ## appenlight
@@ -1,1 +1,1 b''
1 4.26.0 No newline at end of file
1 4.27.0 No newline at end of file
@@ -389,6 +389,11 b' class RepoAppView(BaseAppView):'
389 return True
389 return True
390 return False
390 return False
391
391
392 def get_commit_preload_attrs(cls):
393 pre_load = ['author', 'branch', 'date', 'message', 'parents',
394 'obsolete', 'phase', 'hidden']
395 return pre_load
396
392
397
393 class PathFilter(object):
398 class PathFilter(object):
394
399
@@ -20,8 +20,7 b''
20
20
21 import logging
21 import logging
22 import urllib2
22 import urllib2
23
23 import os
24
25
24
26 import rhodecode
25 import rhodecode
27 from rhodecode.apps._base import BaseAppView
26 from rhodecode.apps._base import BaseAppView
@@ -40,6 +39,40 b' class AdminSystemInfoSettingsView(BaseAp'
40 c = self._get_local_tmpl_context()
39 c = self._get_local_tmpl_context()
41 return c
40 return c
42
41
42 def get_env_data(self):
43 black_list = [
44 'NIX_LDFLAGS',
45 'NIX_CFLAGS_COMPILE',
46 'propagatedBuildInputs',
47 'propagatedNativeBuildInputs',
48 'postInstall',
49 'buildInputs',
50 'buildPhase',
51 'preShellHook',
52 'preShellHook',
53 'preCheck',
54 'preBuild',
55 'postShellHook',
56 'postFixup',
57 'postCheck',
58 'nativeBuildInputs',
59 'installPhase',
60 'installCheckPhase',
61 'checkPhase',
62 'configurePhase',
63 'shellHook'
64 ]
65 secret_list = [
66 'RHODECODE_USER_PASS'
67 ]
68
69 for k, v in sorted(os.environ.items()):
70 if k in black_list:
71 continue
72 if k in secret_list:
73 v = '*****'
74 yield k, v
75
43 @LoginRequired()
76 @LoginRequired()
44 @HasPermissionAllDecorator('hg.admin')
77 @HasPermissionAllDecorator('hg.admin')
45 def settings_system_info(self):
78 def settings_system_info(self):
@@ -55,6 +88,7 b' class AdminSystemInfoSettingsView(BaseAp'
55 snapshot = str2bool(self.request.params.get('snapshot'))
88 snapshot = str2bool(self.request.params.get('snapshot'))
56
89
57 c.rhodecode_update_url = UpdateModel().get_update_url()
90 c.rhodecode_update_url = UpdateModel().get_update_url()
91 c.env_data = self.get_env_data()
58 server_info = system_info.get_system_info(self.request.environ)
92 server_info = system_info.get_system_info(self.request.environ)
59
93
60 for key, val in server_info.items():
94 for key, val in server_info.items():
@@ -311,13 +311,16 b' class UsersView(UserAppView):'
311 available_languages=available_languages,
311 available_languages=available_languages,
312 old_data={'user_id': user_id,
312 old_data={'user_id': user_id,
313 'email': c.user.email})()
313 'email': c.user.email})()
314
315 c.edit_mode = self.request.POST.get('edit') == '1'
314 form_result = {}
316 form_result = {}
315 old_values = c.user.get_api_data()
317 old_values = c.user.get_api_data()
316 try:
318 try:
317 form_result = _form.to_python(dict(self.request.POST))
319 form_result = _form.to_python(dict(self.request.POST))
318 skip_attrs = ['extern_name']
320 skip_attrs = ['extern_name']
319 # TODO: plugin should define if username can be updated
321 # TODO: plugin should define if username can be updated
320 if c.extern_type != "rhodecode":
322
323 if c.extern_type != "rhodecode" and not c.edit_mode:
321 # forbid updating username for external accounts
324 # forbid updating username for external accounts
322 skip_attrs.append('username')
325 skip_attrs.append('username')
323
326
@@ -485,6 +488,7 b' class UsersView(UserAppView):'
485 c.extern_type = c.user.extern_type
488 c.extern_type = c.user.extern_type
486 c.extern_name = c.user.extern_name
489 c.extern_name = c.user.extern_name
487 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
490 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
491 c.edit_mode = self.request.GET.get('edit') == '1'
488
492
489 defaults = c.user.get_dict()
493 defaults = c.user.get_dict()
490 defaults.update({'language': c.user.user_data.get('language')})
494 defaults.update({'language': c.user.user_data.get('language')})
@@ -66,18 +66,28 b' class RepoCachesView(RepoAppView):'
66 _ = self.request.translate
66 _ = self.request.translate
67 c = self.load_default_context()
67 c = self.load_default_context()
68 c.active = 'caches'
68 c.active = 'caches'
69 invalidated = 0
69
70
70 try:
71 try:
71 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
72 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
72
73 Session().commit()
73 Session().commit()
74
74 invalidated +=1
75 h.flash(_('Cache invalidation successful'),
76 category='success')
77 except Exception:
75 except Exception:
78 log.exception("Exception during cache invalidation")
76 log.exception("Exception during cache invalidation")
79 h.flash(_('An error occurred during cache invalidation'),
77 h.flash(_('An error occurred during cache invalidation'),
80 category='error')
78 category='error')
81
79
80 try:
81 invalidated += 1
82 self.rhodecode_vcs_repo.vcsserver_invalidate_cache(delete=True)
83 except Exception:
84 log.exception("Exception during vcsserver cache invalidation")
85 h.flash(_('An error occurred during vcsserver cache invalidation'),
86 category='error')
87
88 if invalidated:
89 h.flash(_('Cache invalidation successful. Stages {}/2').format(invalidated),
90 category='success')
91
82 raise HTTPFound(h.route_path(
92 raise HTTPFound(h.route_path(
83 'edit_repo_caches', repo_name=self.db_repo_name)) No newline at end of file
93 'edit_repo_caches', repo_name=self.db_repo_name))
@@ -168,11 +168,6 b' class RepoChangelogView(RepoAppView):'
168
168
169 return c
169 return c
170
170
171 def _get_preload_attrs(self):
172 pre_load = ['author', 'branch', 'date', 'message', 'parents',
173 'obsolete', 'phase', 'hidden']
174 return pre_load
175
176 @LoginRequired()
171 @LoginRequired()
177 @HasRepoPermissionAnyDecorator(
172 @HasRepoPermissionAnyDecorator(
178 'repository.read', 'repository.write', 'repository.admin')
173 'repository.read', 'repository.write', 'repository.admin')
@@ -200,7 +195,7 b' class RepoChangelogView(RepoAppView):'
200 self._check_if_valid_branch(branch_name, self.db_repo_name, f_path)
195 self._check_if_valid_branch(branch_name, self.db_repo_name, f_path)
201
196
202 c.changelog_for_path = f_path
197 c.changelog_for_path = f_path
203 pre_load = self._get_preload_attrs()
198 pre_load = self.get_commit_preload_attrs()
204
199
205 partial_xhr = self.request.environ.get('HTTP_X_PARTIAL_XHR')
200 partial_xhr = self.request.environ.get('HTTP_X_PARTIAL_XHR')
206
201
@@ -256,6 +251,8 b' class RepoChangelogView(RepoAppView):'
256 raise HTTPFound(
251 raise HTTPFound(
257 h.route_path('repo_summary', repo_name=self.db_repo_name))
252 h.route_path('repo_summary', repo_name=self.db_repo_name))
258
253
254
255
259 if partial_xhr or self.request.environ.get('HTTP_X_PJAX'):
256 if partial_xhr or self.request.environ.get('HTTP_X_PJAX'):
260 # case when loading dynamic file history in file view
257 # case when loading dynamic file history in file view
261 # loading from ajax, we don't want the first result, it's popped
258 # loading from ajax, we don't want the first result, it's popped
@@ -304,7 +301,7 b' class RepoChangelogView(RepoAppView):'
304 return wrap_for_error(
301 return wrap_for_error(
305 safe_str('Branch: {} is not valid'.format(branch_name)))
302 safe_str('Branch: {} is not valid'.format(branch_name)))
306
303
307 pre_load = self._get_preload_attrs()
304 pre_load = self.get_commit_preload_attrs()
308
305
309 if f_path:
306 if f_path:
310 try:
307 try:
@@ -381,7 +381,7 b' class RepoFilesView(RepoAppView):'
381 try:
381 try:
382 at_path = commit.get_node(at_path).path or default_at_path
382 at_path = commit.get_node(at_path).path or default_at_path
383 except Exception:
383 except Exception:
384 return Response(_('No node at path {} for this repository').format(at_path))
384 return Response(_('No node at path {} for this repository').format(h.escape(at_path)))
385
385
386 # path sha is part of subdir
386 # path sha is part of subdir
387 path_sha = ''
387 path_sha = ''
@@ -65,7 +65,8 b' class RepoSummaryView(RepoAppView):'
65 'repo_summary_commits',
65 'repo_summary_commits',
66 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
66 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
67
67
68 pre_load = ['author', 'branch', 'date', 'message']
68 pre_load = self.get_commit_preload_attrs()
69
69 try:
70 try:
70 collection = self.rhodecode_vcs_repo.get_commits(
71 collection = self.rhodecode_vcs_repo.get_commits(
71 pre_load=pre_load, translate_tags=False)
72 pre_load=pre_load, translate_tags=False)
@@ -154,6 +154,7 b' def not_found_view(request):'
154 def error_handler(exception, request):
154 def error_handler(exception, request):
155 import rhodecode
155 import rhodecode
156 from rhodecode.lib import helpers
156 from rhodecode.lib import helpers
157 from rhodecode.lib.utils2 import str2bool
157
158
158 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
159 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
159
160
@@ -205,6 +206,8 b' def error_handler(exception, request):'
205
206
206 if c.show_exception_id:
207 if c.show_exception_id:
207 store_exception(c.exception_id, exc_info)
208 store_exception(c.exception_id, exc_info)
209 c.exception_debug = str2bool(rhodecode.CONFIG.get('debug'))
210 c.exception_config_ini = rhodecode.CONFIG.get('__file__')
208
211
209 response = render_to_response(
212 response = render_to_response(
210 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
213 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
@@ -95,7 +95,7 b' link_config = ['
95 {
95 {
96 "name": "rhodecode_translations",
96 "name": "rhodecode_translations",
97 "target": "https://rhodecode.com/translate/enterprise",
97 "target": "https://rhodecode.com/translate/enterprise",
98 "external_target": "https://www.transifex.com/rhodecode/RhodeCode/",
98 "external_target": "https://explore.transifex.com/rhodecode/RhodeCode/",
99 },
99 },
100
100
101 ]
101 ]
@@ -4,7 +4,7 b' To create a new language'
4
4
5 Translations are available on transifex under::
5 Translations are available on transifex under::
6
6
7 https://www.transifex.com/projects/p/RhodeCode/
7 https://explore.transifex.com/rhodecode/RhodeCode/
8
8
9 Log into transifex and request new language translation.
9 Log into transifex and request new language translation.
10
10
@@ -221,7 +221,7 b' class Lock(object):'
221 """
221 """
222 logger = loggers["acquire"]
222 logger = loggers["acquire"]
223
223
224 logger.debug("Getting acquire on %r ...", self._name)
224 logger.debug("Getting blocking: %s acquire on %r ...", blocking, self._name)
225
225
226 if self._held:
226 if self._held:
227 owner_id = self.get_owner_id()
227 owner_id = self.get_owner_id()
@@ -337,11 +337,13 b' def files_breadcrumbs(repo_name, repo_ty'
337
337
338
338
339 def files_url_data(request):
339 def files_url_data(request):
340 import urllib
340 matchdict = request.matchdict
341 matchdict = request.matchdict
341
342
342 if 'f_path' not in matchdict:
343 if 'f_path' not in matchdict:
343 matchdict['f_path'] = ''
344 matchdict['f_path'] = ''
344
345 else:
346 matchdict['f_path'] = urllib.quote(safe_str(matchdict['f_path']))
345 if 'commit_id' not in matchdict:
347 if 'commit_id' not in matchdict:
346 matchdict['commit_id'] = 'tip'
348 matchdict['commit_id'] = 'tip'
347
349
@@ -1679,9 +1681,8 b' def process_patterns(text_string, repo_n'
1679 errors = []
1681 errors = []
1680 new_text = text_string
1682 new_text = text_string
1681
1683
1682 log.debug('Got %s entries to process', len(active_entries))
1684 log.debug('Got %s pattern entries to process', len(active_entries))
1683 for uid, entry in active_entries.items():
1685 for uid, entry in active_entries.items():
1684 log.debug('found issue tracker entry with uid %s', uid)
1685
1686
1686 if not (entry['pat'] and entry['url']):
1687 if not (entry['pat'] and entry['url']):
1687 log.debug('skipping due to missing data')
1688 log.debug('skipping due to missing data')
@@ -125,20 +125,34 b' class ColorFormatter(ExceptionAwareForma'
125
125
126 def _inject_req_id(record):
126 def _inject_req_id(record):
127 from pyramid.threadlocal import get_current_request
127 from pyramid.threadlocal import get_current_request
128 dummy = '00000000-0000-0000-0000-000000000000'
129 req_id = None
130
128 req = get_current_request()
131 req = get_current_request()
129 dummy = '00000000-0000-0000-0000-000000000000'
132 if req:
130 req_id = 'req_id:%-36s' % (getattr(req, 'req_id', dummy))
133 req_id = getattr(req, 'req_id', None)
134
135 req_id = 'req_id:%-36s' % (req_id or dummy)
131 record.req_id = req_id
136 record.req_id = req_id
132
137
133
138
139 def _add_log_to_debug_bucket(formatted_record):
140 from pyramid.threadlocal import get_current_request
141 req = get_current_request()
142 if req:
143 req.req_id_bucket.append(formatted_record)
144
145
134 class RequestTrackingFormatter(ExceptionAwareFormatter):
146 class RequestTrackingFormatter(ExceptionAwareFormatter):
135 def format(self, record):
147 def format(self, record):
136 _inject_req_id(record)
148 _inject_req_id(record)
137 def_record = logging.Formatter.format(self, record)
149 def_record = logging.Formatter.format(self, record)
150 _add_log_to_debug_bucket(def_record)
138 return def_record
151 return def_record
139
152
140
153
141 class ColorRequestTrackingFormatter(ColorFormatter):
154 class ColorRequestTrackingFormatter(ColorFormatter):
155
142 def format(self, record):
156 def format(self, record):
143 """
157 """
144 Changes record's levelname to use with COLORS enum
158 Changes record's levelname to use with COLORS enum
@@ -150,6 +164,7 b' class ColorRequestTrackingFormatter(Colo'
150 end = RESET_SEQ
164 end = RESET_SEQ
151
165
152 colored_record = ''.join([start, def_record, end])
166 colored_record = ''.join([start, def_record, end])
167 _add_log_to_debug_bucket(def_record)
153 return colored_record
168 return colored_record
154
169
155
170
@@ -36,6 +36,7 b' from dogpile.cache.util import memoized_'
36 from pyramid.settings import asbool
36 from pyramid.settings import asbool
37
37
38 from rhodecode.lib.memory_lru_dict import LRUDict, LRUDictDebug
38 from rhodecode.lib.memory_lru_dict import LRUDict, LRUDictDebug
39 from rhodecode.lib.utils import safe_str
39
40
40
41
41 _default_max_size = 1024
42 _default_max_size = 1024
@@ -167,7 +168,7 b' class FileNamespaceBackend(PickleSeriali'
167 try:
168 try:
168 super(FileNamespaceBackend, self).__init__(arguments)
169 super(FileNamespaceBackend, self).__init__(arguments)
169 except Exception:
170 except Exception:
170 log.error('Failed to initialize db at: %s', db_file)
171 log.exception('Failed to initialize db at: %s', db_file)
171 raise
172 raise
172
173
173 def __repr__(self):
174 def __repr__(self):
@@ -299,7 +300,7 b' class BaseRedisBackend(redis_backend.Red'
299
300
300 def get_mutex(self, key):
301 def get_mutex(self, key):
301 if self.distributed_lock:
302 if self.distributed_lock:
302 lock_key = redis_backend.u('_lock_{0}').format(key)
303 lock_key = redis_backend.u('_lock_{0}').format(safe_str(key))
303 return get_mutex_lock(self.client, lock_key, self._lock_timeout,
304 return get_mutex_lock(self.client, lock_key, self._lock_timeout,
304 auto_renewal=self._lock_auto_renewal)
305 auto_renewal=self._lock_auto_renewal)
305 else:
306 else:
@@ -24,6 +24,15 b' from pyramid.request import Request as _'
24
24
25
25
26 class Request(_Request):
26 class Request(_Request):
27 _req_id_bucket = list()
28
27 @reify
29 @reify
28 def req_id(self):
30 def req_id(self):
29 return str(uuid4())
31 return str(uuid4())
32
33 @property
34 def req_id_bucket(self):
35 return self._req_id_bucket
36
37 def req_id_records_init(self):
38 self._req_id_bucket = list()
@@ -875,6 +875,9 b' class BaseRepository(object):'
875 def get_hooks_info(self):
875 def get_hooks_info(self):
876 return self._remote.get_hooks_info()
876 return self._remote.get_hooks_info()
877
877
878 def vcsserver_invalidate_cache(self, delete=False):
879 return self._remote.vcsserver_invalidate_cache(delete)
880
878
881
879 class BaseCommit(object):
882 class BaseCommit(object):
880 """
883 """
@@ -54,7 +54,7 b' class GitRepository(BaseRepository):'
54 """
54 """
55 Git repository backend.
55 Git repository backend.
56 """
56 """
57 DEFAULT_BRANCH_NAME = 'master'
57 DEFAULT_BRANCH_NAME = os.environ.get('GIT_DEFAULT_BRANCH_NAME') or 'master'
58
58
59 contact = BaseRepository.DEFAULT_CONTACT
59 contact = BaseRepository.DEFAULT_CONTACT
60
60
@@ -37,6 +37,8 b' import requests'
37 from requests.packages.urllib3.util.retry import Retry
37 from requests.packages.urllib3.util.retry import Retry
38
38
39 import rhodecode
39 import rhodecode
40 from rhodecode.lib import rc_cache
41 from rhodecode.lib.rc_cache.utils import compute_key_from_params
40 from rhodecode.lib.system_info import get_cert_path
42 from rhodecode.lib.system_info import get_cert_path
41 from rhodecode.lib.vcs import exceptions, CurlSession
43 from rhodecode.lib.vcs import exceptions, CurlSession
42
44
@@ -127,7 +129,6 b' class ServiceConnection(object):'
127 def __getattr__(self, name):
129 def __getattr__(self, name):
128 def f(*args, **kwargs):
130 def f(*args, **kwargs):
129 return self._call(name, *args, **kwargs)
131 return self._call(name, *args, **kwargs)
130
131 return f
132 return f
132
133
133 @exceptions.map_vcs_exceptions
134 @exceptions.map_vcs_exceptions
@@ -150,6 +151,12 b' class RemoteVCSMaker(object):'
150 self._session_factory = session_factory
151 self._session_factory = session_factory
151 self.backend_type = backend_type
152 self.backend_type = backend_type
152
153
154 @classmethod
155 def init_cache_region(cls, repo_id):
156 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
157 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
158 return region, cache_namespace_uid
159
153 def __call__(self, path, repo_id, config, with_wire=None):
160 def __call__(self, path, repo_id, config, with_wire=None):
154 log.debug('%s RepoMaker call on %s', self.backend_type.upper(), path)
161 log.debug('%s RepoMaker call on %s', self.backend_type.upper(), path)
155 return RemoteRepo(path, repo_id, config, self, with_wire=with_wire)
162 return RemoteRepo(path, repo_id, config, self, with_wire=with_wire)
@@ -178,6 +185,8 b' class RemoteRepo(object):'
178 self.url = remote_maker.url
185 self.url = remote_maker.url
179 self.stream_url = remote_maker.stream_url
186 self.stream_url = remote_maker.stream_url
180 self._session = remote_maker._session_factory()
187 self._session = remote_maker._session_factory()
188 self._cache_region, self._cache_namespace = \
189 remote_maker.init_cache_region(self._repo_id_sanitizer(repo_id))
181
190
182 with_wire = with_wire or {}
191 with_wire = with_wire or {}
183
192
@@ -200,6 +209,9 b' class RemoteRepo(object):'
200
209
201 self.cert_dir = get_cert_path(rhodecode.CONFIG.get('__file__'))
210 self.cert_dir = get_cert_path(rhodecode.CONFIG.get('__file__'))
202
211
212 def _repo_id_sanitizer(self, repo_id):
213 return repo_id.replace('/', '__')
214
203 def __getattr__(self, name):
215 def __getattr__(self, name):
204
216
205 if name.startswith('stream:'):
217 if name.startswith('stream:'):
@@ -233,11 +245,34 b' class RemoteRepo(object):'
233 url = self.url
245 url = self.url
234
246
235 start = time.time()
247 start = time.time()
236 if self._call_with_logging:
248
237 log.debug('Calling %s@%s with args:%.10240r. wire_context: %s',
249 cache_on = False
238 url, name, args, context_uid)
250 cache_key = ''
251 local_cache_on = rhodecode.CONFIG.get('vcs.methods.cache')
252
253 cache_methods = [
254 'branches', 'tags', 'bookmarks',
255 'is_large_file', 'is_binary', 'fctx_size', 'node_history', 'blob_raw_length',
256 'revision', 'tree_items',
257 'ctx_list',
258 'bulk_request',
259 ]
239
260
240 result = _remote_call(url, payload, EXCEPTIONS_MAP, self._session)
261 if local_cache_on and name in cache_methods:
262 cache_on = True
263 repo_state_uid = self._wire['repo_state_uid']
264 call_args = [a for a in args]
265 cache_key = compute_key_from_params(repo_state_uid, name, *call_args)
266
267 @self._cache_region.conditional_cache_on_arguments(
268 namespace=self._cache_namespace, condition=cache_on and cache_key)
269 def remote_call(_cache_key):
270 if self._call_with_logging:
271 log.debug('Calling %s@%s with args:%.10240r. wire_context: %s cache_on: %s',
272 url, name, args, context_uid, cache_on)
273 return _remote_call(url, payload, EXCEPTIONS_MAP, self._session)
274
275 result = remote_call(cache_key)
241 if self._call_with_logging:
276 if self._call_with_logging:
242 log.debug('Call %s@%s took: %.4fs. wire_context: %s',
277 log.debug('Call %s@%s took: %.4fs. wire_context: %s',
243 url, name, time.time()-start, context_uid)
278 url, name, time.time()-start, context_uid)
@@ -467,6 +467,9 b' class RepoModel(BaseModel):'
467 RepoModel().grant_user_permission(
467 RepoModel().grant_user_permission(
468 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
468 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
469 )
469 )
470 if kwargs.get('repo_landing_rev'):
471 landing_rev_val = kwargs['repo_landing_rev']
472 RepoModel().set_landing_rev(cur_repo, landing_rev_val)
470
473
471 # handle extra fields
474 # handle extra fields
472 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
475 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
@@ -933,6 +936,13 b' class RepoModel(BaseModel):'
933 if field:
936 if field:
934 self.sa.delete(field)
937 self.sa.delete(field)
935
938
939 def set_landing_rev(self, repo, landing_rev_name):
940 if landing_rev_name.startswith('branch:'):
941 landing_rev_name = landing_rev_name.split('branch:')[-1]
942 scm_instance = repo.scm_instance()
943 if scm_instance:
944 return scm_instance._remote.set_head_ref(landing_rev_name)
945
936 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
946 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
937 clone_uri=None, repo_store_location=None,
947 clone_uri=None, repo_store_location=None,
938 use_global_config=False, install_hooks=True):
948 use_global_config=False, install_hooks=True):
@@ -139,7 +139,7 b' class CloneUriValidator(object):'
139 raise colander.Invalid(node, e.message)
139 raise colander.Invalid(node, e.message)
140 except Exception:
140 except Exception:
141 log.exception('Url validation failed')
141 log.exception('Url validation failed')
142 msg = _(u'invalid clone url for {repo_type} repository').format(
142 msg = _(u'invalid clone url or credentials for {repo_type} repository').format(
143 repo_type=self.repo_type)
143 repo_type=self.repo_type)
144 raise colander.Invalid(node, msg)
144 raise colander.Invalid(node, msg)
145
145
@@ -624,7 +624,7 b' def ValidCloneUri(localizer):'
624
624
625 class _validator(formencode.validators.FancyValidator):
625 class _validator(formencode.validators.FancyValidator):
626 messages = {
626 messages = {
627 'clone_uri': _(u'invalid clone url for %(rtype)s repository'),
627 'clone_uri': _(u'invalid clone url or credentials for %(rtype)s repository'),
628 'invalid_clone_uri': _(
628 'invalid_clone_uri': _(
629 u'Invalid clone url, provide a valid clone '
629 u'Invalid clone url, provide a valid clone '
630 u'url starting with one of %(allowed_prefixes)s')
630 u'url starting with one of %(allowed_prefixes)s')
@@ -244,6 +244,7 b' function registerRCRoutes() {'
244 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
244 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
245 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
245 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
246 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
246 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
247 pyroutes.register('ops_healthcheck', '/_admin/ops/status', []);
247 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
248 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
248 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
249 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
249 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
250 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
@@ -106,6 +106,14 b' def add_request_user_context(event):'
106 request.environ['rc_req_id'] = req_id
106 request.environ['rc_req_id'] = req_id
107
107
108
108
109 def reset_log_bucket(event):
110 """
111 reset the log bucket on new request
112 """
113 request = event.request
114 request.req_id_records_init()
115
116
109 def scan_repositories_if_enabled(event):
117 def scan_repositories_if_enabled(event):
110 """
118 """
111 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
119 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
@@ -62,6 +62,25 b''
62 </div>
62 </div>
63 </div>
63 </div>
64
64
65 <div class="panel panel-default">
66 <div class="panel-heading">
67 <h3 class="panel-title">${_('Env Variables')}</h3>
68 </div>
69 <div class="panel-body">
70 <table>
71 <th></th>
72 <th></th>
73 % for env_key, env_val in c.env_data:
74 <tr>
75 <td style="vertical-align: top">${env_key}</td>
76 <td>${env_val}</td>
77 </tr>
78 % endfor
79 </table>
80
81 </div>
82 </div>
83
65 <script>
84 <script>
66 $('#check_for_update').click(function(e){
85 $('#check_for_update').click(function(e){
67 $('#update_notice').show();
86 $('#update_notice').show();
@@ -12,7 +12,10 b''
12 ${h.secure_form(h.route_path('user_update', user_id=c.user.user_id), class_='form', request=request)}
12 ${h.secure_form(h.route_path('user_update', user_id=c.user.user_id), class_='form', request=request)}
13 <% readonly = None %>
13 <% readonly = None %>
14 <% disabled = "" %>
14 <% disabled = "" %>
15 %if c.extern_type != 'rhodecode':
15 % if c.edit_mode:
16 ${h.hidden('edit', '1')}
17 % endif
18 %if c.extern_type != 'rhodecode' and not c.edit_mode:
16 <% readonly = "readonly" %>
19 <% readonly = "readonly" %>
17 <% disabled = " disabled" %>
20 <% disabled = " disabled" %>
18 <div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px">
21 <div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px">
@@ -40,6 +43,12 b''
40 </div>
43 </div>
41 <div class="input">
44 <div class="input">
42 ${h.text('username', class_='%s medium' % disabled, readonly=readonly)}
45 ${h.text('username', class_='%s medium' % disabled, readonly=readonly)}
46 <br/>
47 % if c.extern_type != 'rhodecode' and c.is_super_admin:
48 <p class="help-block">
49 ${_('Super-admin can edit this field by entering ')} <a href="${h.current_route_path(request, edit=1)}">edit mode</a>
50 </p>
51 % endif
43 </div>
52 </div>
44 </div>
53 </div>
45 <div class="field">
54 <div class="field">
@@ -66,7 +66,7 b''
66 % endif
66 % endif
67 % else:
67 % else:
68 ## SKIP TODOs we display them in other area
68 ## SKIP TODOs we display them in other area
69 % if comment_obj.is_todo:
69 % if comment_obj.is_todo and not comment_obj.draft:
70 <% display = 'none' %>
70 <% display = 'none' %>
71 % endif
71 % endif
72 ## Skip outdated comments
72 ## Skip outdated comments
@@ -122,12 +122,21 b''
122 'review_status': (comment_obj.review_status or '')
122 'review_status': (comment_obj.review_status or '')
123 })
123 })
124
124
125 icon = ''
126
125 if comment_obj.outdated:
127 if comment_obj.outdated:
126 icon = 'icon-comment-toggle'
128 icon += ' icon-comment-toggle'
127 elif comment_obj.is_inline:
129 elif comment_obj.is_inline:
128 icon = 'icon-code'
130 icon += ' icon-code'
129 else:
131 else:
130 icon = 'icon-comment'
132 icon += ' icon-comment'
133
134 if comment_obj.draft:
135 if comment_obj.is_todo:
136 icon = 'icon-flag-filled icon-draft'
137 else:
138 icon = 'icon-comment icon-draft'
139
131 %>
140 %>
132
141
133 <i id="commentHovercard${comment_obj.comment_id}"
142 <i id="commentHovercard${comment_obj.comment_id}"
@@ -237,7 +237,7 b' if (show_disabled) {'
237 <time class="timeago" title="<%= created_on %>" datetime="<%= datetime %>"><%= $.timeago(datetime) %></time>
237 <time class="timeago" title="<%= created_on %>" datetime="<%= datetime %>"><%= $.timeago(datetime) %></time>
238
238
239 <% if (is_todo) { %>
239 <% if (is_todo) { %>
240 <div style="text-align: center; padding-top: 5px">
240 <div style="text-align: left; padding-top: 5px">
241 <a class="btn btn-sm" href="#resolveTodo<%- comment_id -%>" onclick="Rhodecode.comments.resolveTodo(this, '<%- comment_id -%>'); return false">
241 <a class="btn btn-sm" href="#resolveTodo<%- comment_id -%>" onclick="Rhodecode.comments.resolveTodo(this, '<%- comment_id -%>'); return false">
242 <strong>Resolve TODO</strong>
242 <strong>Resolve TODO</strong>
243 </a>
243 </a>
@@ -84,6 +84,24 b''
84
84
85 Super-admins can see details of the above error in the exception tracker found under
85 Super-admins can see details of the above error in the exception tracker found under
86 <a href="${h.route_url('admin_settings_exception_tracker')}">admin > settings > exception tracker</a>.
86 <a href="${h.route_url('admin_settings_exception_tracker')}">admin > settings > exception tracker</a>.
87
88 % if c.exception_debug:
89 <pre>
90 <strong>DEBUG MODE ON FOR EXCEPTION: ${c.exception_id}</strong>
91 <strong>REQUEST_ID: ${getattr(request, 'req_id', None)}</strong>
92 ----------------
93 debug mode is controlled by
94 ${c.exception_config_ini}
95 file settings:
96
97 debug = true
98 ----------------
99
100 % for rec in getattr(request, 'req_id_bucket', []):
101 ${rec}
102 % endfor
103 </pre>
104 % endif
87 </p>
105 </p>
88 </div>
106 </div>
89 % endif
107 % endif
@@ -564,7 +564,6 b''
564 <input name="select_all_drafts" type="checkbox" onclick="selectDraftComments(event)">
564 <input name="select_all_drafts" type="checkbox" onclick="selectDraftComments(event)">
565 </span>
565 </span>
566 <span class="sidebar-heading noselect" onclick="refreshDraftComments(); return false">
566 <span class="sidebar-heading noselect" onclick="refreshDraftComments(); return false">
567 <i class="icon-comment icon-draft"></i>
568 ${_('Drafts')}
567 ${_('Drafts')}
569 </span>
568 </span>
570 <span class="block-right action_button last-item" onclick="submitDrafts(event)">${_('Submit')}</span>
569 <span class="block-right action_button last-item" onclick="submitDrafts(event)">${_('Submit')}</span>
@@ -112,6 +112,8 b' def includeme(config):'
112 'pyramid.events.NewRequest')
112 'pyramid.events.NewRequest')
113 config.add_subscriber('rhodecode.subscribers.add_localizer',
113 config.add_subscriber('rhodecode.subscribers.add_localizer',
114 'pyramid.events.NewRequest')
114 'pyramid.events.NewRequest')
115 config.add_subscriber('rhodecode.subscribers.reset_log_bucket',
116 'pyramid.events.NewRequest')
115 config.add_subscriber('rhodecode.subscribers.add_request_user_context',
117 config.add_subscriber('rhodecode.subscribers.add_request_user_context',
116 'pyramid.events.ContextFound')
118 'pyramid.events.ContextFound')
117 config.add_tween('rhodecode.tweens.vcs_detection_tween_factory')
119 config.add_tween('rhodecode.tweens.vcs_detection_tween_factory')
General Comments 0
You need to be logged in to leave comments. Login now