# 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 . # # 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