hook_module.py
104 lines
| 3.7 KiB
| text/x-python
|
PythonLexer
r5325 | # Copyright (C) 2010-2023 RhodeCode GmbH | |||
# | ||||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU Affero General Public License, version 3 | ||||
# (only), as published by the Free Software Foundation. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU Affero General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
# | ||||
# This program is dual-licensed. If you wish to learn more about the | ||||
# RhodeCode Enterprise Edition, including its added features, Support services, | ||||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
import logging | ||||
import traceback | ||||
from rhodecode.model import meta | ||||
from rhodecode.lib import hooks_base | ||||
from rhodecode.lib.exceptions import HTTPLockedRC, HTTPBranchProtected | ||||
from rhodecode.lib.utils2 import AttributeDict | ||||
log = logging.getLogger(__name__) | ||||
class Hooks(object): | ||||
""" | ||||
Exposes the hooks for remote callbacks | ||||
""" | ||||
def __init__(self, request=None, log_prefix=''): | ||||
self.log_prefix = log_prefix | ||||
self.request = request | ||||
def repo_size(self, extras): | ||||
log.debug("%sCalled repo_size of %s object", self.log_prefix, self) | ||||
return self._call_hook(hooks_base.repo_size, extras) | ||||
def pre_pull(self, extras): | ||||
log.debug("%sCalled pre_pull of %s object", self.log_prefix, self) | ||||
return self._call_hook(hooks_base.pre_pull, extras) | ||||
def post_pull(self, extras): | ||||
log.debug("%sCalled post_pull of %s object", self.log_prefix, self) | ||||
return self._call_hook(hooks_base.post_pull, extras) | ||||
def pre_push(self, extras): | ||||
log.debug("%sCalled pre_push of %s object", self.log_prefix, self) | ||||
return self._call_hook(hooks_base.pre_push, extras) | ||||
def post_push(self, extras): | ||||
log.debug("%sCalled post_push of %s object", self.log_prefix, self) | ||||
return self._call_hook(hooks_base.post_push, extras) | ||||
def _call_hook(self, hook, extras): | ||||
extras = AttributeDict(extras) | ||||
_server_url = extras['server_url'] | ||||
extras.request = self.request | ||||
try: | ||||
result = hook(extras) | ||||
if result is None: | ||||
raise Exception(f'Failed to obtain hook result from func: {hook}') | ||||
except HTTPBranchProtected as handled_error: | ||||
# Those special cases don't need error reporting. It's a case of | ||||
# locked repo or protected branch | ||||
result = AttributeDict({ | ||||
'status': handled_error.code, | ||||
'output': handled_error.explanation | ||||
}) | ||||
except (HTTPLockedRC, Exception) as error: | ||||
# locked needs different handling since we need to also | ||||
# handle PULL operations | ||||
exc_tb = '' | ||||
if not isinstance(error, HTTPLockedRC): | ||||
exc_tb = traceback.format_exc() | ||||
log.exception('%sException when handling hook %s', self.log_prefix, hook) | ||||
error_args = error.args | ||||
return { | ||||
'status': 128, | ||||
'output': '', | ||||
'exception': type(error).__name__, | ||||
'exception_traceback': exc_tb, | ||||
'exception_args': error_args, | ||||
} | ||||
finally: | ||||
meta.Session.remove() | ||||
log.debug('%sGot hook call response %s', self.log_prefix, result) | ||||
return { | ||||
'status': result.status, | ||||
'output': result.output, | ||||
} | ||||
def __enter__(self): | ||||
return self | ||||
def __exit__(self, exc_type, exc_val, exc_tb): | ||||
pass | ||||