diff --git a/rhodecode/lib/hooks.py b/rhodecode/lib/hooks.py --- a/rhodecode/lib/hooks.py +++ b/rhodecode/lib/hooks.py @@ -30,9 +30,9 @@ from inspect import isfunction from mercurial.scmutil import revrange from mercurial.node import nullrev -from rhodecode import EXTENSIONS from rhodecode.lib import helpers as h from rhodecode.lib.utils import action_logger +from rhodecode.lib.vcs.backends.base import EmptyChangeset def _get_scm_size(alias, root_path): @@ -99,6 +99,7 @@ def log_pull_action(ui, repo, **kwargs): action_logger(username, action, repository, extras['ip'], commit=True) # extension hook call + from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'PULL_HOOK', None) if isfunction(callback): @@ -137,15 +138,18 @@ def log_push_action(ui, repo, **kwargs): stop, start = get_revs(repo, [node + ':']) h = binascii.hexlify - revs = (h(repo[r].node()) for r in xrange(start, stop + 1)) + revs = [h(repo[r].node()) for r in xrange(start, stop + 1)] elif scm == 'git': - revs = [] + revs = kwargs.get('_git_revs', []) + if '_git_revs' in kwargs: + kwargs.pop('_git_revs') action = action % ','.join(revs) action_logger(username, action, repository, extras['ip'], commit=True) # extension hook call + from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'PUSH_HOOK', None) if isfunction(callback): kw = {'pushed_revs': revs} @@ -180,7 +184,7 @@ def log_create_repository(repository_dic 'repo_name' """ - + from rhodecode import EXTENSIONS callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None) if isfunction(callback): kw = {} @@ -190,3 +194,67 @@ def log_create_repository(repository_dic return callback(**kw) return 0 + + +def handle_git_post_receive(repo_path, revs, env): + """ + A really hacky method that is runned by git post-receive hook and logs + an push action together with pushed revisions. It's executed by subprocess + thus needs all info to be able to create a on the fly pylons enviroment, + connect to database and run the logging code. Hacky as sh*t but works. + + :param repo_path: + :type repo_path: + :param revs: + :type revs: + :param env: + :type env: + """ + from paste.deploy import appconfig + from sqlalchemy import engine_from_config + from rhodecode.config.environment import load_environment + from rhodecode.model import init_model + from rhodecode.model.db import RhodeCodeUi + from rhodecode.lib.utils import make_ui + from rhodecode.model.db import Repository + + path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE']) + conf = appconfig('config:%s' % ini_name, relative_to=path) + load_environment(conf.global_conf, conf.local_conf) + + engine = engine_from_config(conf, 'sqlalchemy.db1.') + init_model(engine) + + baseui = make_ui('db') + repo = Repository.get_by_full_path(repo_path) + + _hooks = dict(baseui.configitems('hooks')) or {} + # if push hook is enabled via web interface + if _hooks.get(RhodeCodeUi.HOOK_PUSH): + + extras = { + 'username': env['RHODECODE_USER'], + 'repository': repo.repo_name, + 'scm': 'git', + 'action': 'push', + 'ip': env['RHODECODE_CONFIG_IP'], + } + for k, v in extras.items(): + baseui.setconfig('rhodecode_extras', k, v) + repo = repo.scm_instance + repo.ui = baseui + old_rev, new_rev, ref = revs + if old_rev == EmptyChangeset().raw_id: + cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'" + heads = repo.run_git_command(cmd)[0] + heads = heads.replace(ref, '') + heads = ' '.join(map(lambda c: c.strip('\n').strip(), + heads.splitlines())) + cmd = ('log ' + new_rev + + ' --reverse --pretty=format:"%H" --not ' + heads) + else: + cmd = ('log ' + old_rev + '..' + new_rev + + ' --reverse --pretty=format:"%H"') + git_revs = repo.run_git_command(cmd)[0].splitlines() + + log_push_action(baseui, repo, _git_revs=git_revs)