##// END OF EJS Templates
core: code changes to handle branch-permissions / locking / incorrect client support
super-admin -
r1323:a1a9e846 default
parent child Browse files
Show More
@@ -53,12 +53,6 b' def ArchiveException(org_exc=None):'
53 53 return _make_exception_wrapper
54 54
55 55
56 def ClientNotSupportedException(org_exc=None):
57 def _make_exception_wrapper(*args):
58 return _make_exception('client_not_supported', org_exc, *args)
59 return _make_exception_wrapper
60
61
62 56 def LookupException(org_exc=None):
63 57 def _make_exception_wrapper(*args):
64 58 return _make_exception('lookup', org_exc, *args)
@@ -82,6 +76,10 b' def RepositoryBranchProtectedException(o'
82 76 return _make_exception('repo_branch_protected', org_exc, *args)
83 77 return _make_exception_wrapper
84 78
79 def ClientNotSupportedException(org_exc=None):
80 def _make_exception_wrapper(*args):
81 return _make_exception('client_not_supported', org_exc, *args)
82 return _make_exception_wrapper
85 83
86 84 def RequirementException(org_exc=None):
87 85 def _make_exception_wrapper(*args):
@@ -118,9 +116,18 b' class HTTPRepoLocked(HTTPLocked):'
118 116 super().__init__(**kwargs)
119 117
120 118
121 class HTTPRepoBranchProtected(HTTPForbidden):
122 def __init__(self, *args, **kwargs):
123 super(HTTPForbidden, self).__init__(*args, **kwargs)
119 class HTTPRepoBranchProtected(HTTPLocked):
120 def __init__(self, title, status_code=None, **kwargs):
121 self.code = status_code or HTTPLocked.code
122 self.title = title
123 super().__init__(**kwargs)
124
125
126 class HTTPClientNotSupported(HTTPLocked):
127 def __init__(self, title, status_code=None, **kwargs):
128 self.code = status_code or HTTPLocked.code
129 self.title = title
130 super().__init__(**kwargs)
124 131
125 132
126 133 class RefNotFoundException(KeyError):
@@ -1,5 +1,5 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2023 RhodeCode GmbH
2 # Copyright (C) 2014-2024 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
@@ -56,6 +56,9 b' class HooksCeleryClient:'
56 56 self.celery_app = celery_app
57 57
58 58 def __call__(self, method, extras):
59 # NOTE: exception handling for those tasks executed is in
60 # @adapt_for_celery decorator
61 # also see: _maybe_handle_exception which is handling exceptions
59 62 inquired_task = self.celery_app.signature(
60 63 f'rhodecode.lib.celerylib.tasks.{method}'
61 64 )
@@ -83,11 +86,8 b' class HgMessageWriter(RemoteMessageWrite'
83 86 self.ui = ui
84 87
85 88 def write(self, message: str):
86 # TODO: Check why the quiet flag is set by default.
87 old = self.ui.quiet
88 self.ui.quiet = False
89 self.ui.status(message.encode('utf-8'))
90 self.ui.quiet = old
89 args = (message.encode('utf-8'),)
90 self.ui._writemsg(self.ui._fmsgerr, type=b'status', *args)
91 91
92 92
93 93 class GitMessageWriter(RemoteMessageWriter):
@@ -97,7 +97,7 b' class GitMessageWriter(RemoteMessageWrit'
97 97 self.stdout = stdout or sys.stdout
98 98
99 99 def write(self, message: str):
100 self.stdout.write(message)
100 self.stdout.write(message + "\n" if message else "")
101 101
102 102
103 103 class SvnMessageWriter(RemoteMessageWriter):
@@ -111,28 +111,30 b' class SvnMessageWriter(RemoteMessageWrit'
111 111 self.stderr.write(message)
112 112
113 113
114 def _maybe_handle_exception(result):
115
114 def _maybe_handle_exception(writer, result):
115 """
116 adopt_for_celery defines the exception/exception_traceback
117 Ths result is a direct output from a celery task
118 """
116 119
117 120 exception_class = result.get('exception')
118 121 exception_traceback = result.get('exception_traceback')
119 if not exception_class:
120 return
121 122
122 log.debug('Handling hook-call exception: %s', exception_class)
123
124 if exception_traceback:
125 log.error('Got traceback from remote call:%s', exception_traceback)
126
127 if exception_class == 'HTTPLockedRepo':
123 match exception_class:
124 # NOTE: the underlying exceptions are setting _vcs_kind special marker
125 # which is later handled by `handle_vcs_exception` and translated into a special HTTP exception
126 # propagated later to the client
127 case 'HTTPLockedRepo':
128 128 raise exceptions.LockedRepoException()(*result['exception_args'])
129 elif exception_class == 'ClientNotSupportedError':
129 case 'ClientNotSupported':
130 130 raise exceptions.ClientNotSupportedException()(*result['exception_args'])
131 elif exception_class == 'HTTPBranchProtected':
131 case 'HTTPBranchProtected':
132 132 raise exceptions.RepositoryBranchProtectedException()(*result['exception_args'])
133 elif exception_class == 'RepositoryError':
133 case 'RepositoryError':
134 134 raise exceptions.VcsException()(*result['exception_args'])
135 elif exception_class:
135 case _:
136 if exception_class:
137 log.error('Handling hook-call exception. Got traceback from remote call:%s', exception_traceback)
136 138 raise Exception(
137 139 f"""Got remote exception "{exception_class}" with args "{result['exception_args']}" """
138 140 )
@@ -156,7 +158,7 b' def _call_hook(hook_name, extras, writer'
156 158 log.debug('Hooks, using client:%s', hooks_client)
157 159 result = hooks_client(hook_name, extras)
158 160 log.debug('Hooks got result: %s', result)
159 _maybe_handle_exception(result)
161 _maybe_handle_exception(writer, result)
160 162 writer.write(result['output'])
161 163
162 164 return result['status']
@@ -47,7 +47,7 b' from vcsserver.server import VcsServer'
47 47 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
48 48 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
49 49 from vcsserver.echo_stub.echo_app import EchoApp
50 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
50 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected, HTTPClientNotSupported
51 51 from vcsserver.lib.exc_tracking import store_exception, format_exc
52 52 from vcsserver.lib.str_utils import safe_int
53 53 from vcsserver.lib.statsd_client import StatsdClient
@@ -635,19 +635,21 b' class HTTPApplication:'
635 635 return _git_stream
636 636
637 637 def handle_vcs_exception(self, exception, request):
638 _vcs_kind = getattr(exception, '_vcs_kind', '')
639 638
640 if _vcs_kind == 'repo_locked':
639 match _vcs_kind := getattr(exception, '_vcs_kind', ''):
640 case 'repo_locked':
641 641 headers_call_context = get_headers_call_context(request.environ)
642 642 status_code = safe_int(headers_call_context['locked_status_code'])
643 643
644 644 return HTTPRepoLocked(
645 645 title=str(exception), status_code=status_code, headers=[('X-Rc-Locked', '1')])
646
647 elif _vcs_kind == 'repo_branch_protected':
646 case 'repo_branch_protected':
648 647 # Get custom repo-branch-protected status code if present.
649 648 return HTTPRepoBranchProtected(
650 649 title=str(exception), headers=[('X-Rc-Branch-Protection', '1')])
650 case 'client_not_supported':
651 return HTTPClientNotSupported(
652 title=str(exception), headers=[('X-Rc-Client-Not-Supported', '1')])
651 653
652 654 exc_info = request.exc_info
653 655 store_exception(id(exc_info), exc_info)
@@ -415,6 +415,7 b' class SubprocessIOChunker:'
415 415 return_code = _p.poll()
416 416 ret_code_ok = return_code in [None, 0]
417 417 ret_code_fail = return_code is not None and return_code != 0
418
418 419 if (
419 420 (ret_code_fail and fail_on_return_code) or
420 421 (ret_code_ok and fail_on_stderr and bg_err.length)
General Comments 0
You need to be logged in to leave comments. Login now