##// END OF EJS Templates
comments: clarify in ui whether comments are for changeset or PR
comments: clarify in ui whether comments are for changeset or PR

File last commit:

r4017:509923da default
r4049:3b5f32ae default
Show More
hooks.py
463 lines | 13.8 KiB | text/x-python | PythonLexer
filled in some docs for hooks
r913 # -*- coding: utf-8 -*-
"""
rhodecode.lib.hooks
~~~~~~~~~~~~~~~~~~~
Hooks runned by rhodecode
source code cleanup: remove trailing white space, normalize file endings
r1203
filled in some docs for hooks
r913 :created_on: Aug 6, 2010
:author: marcink
2012 copyrights
r1824 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
filled in some docs for hooks
r913 :license: GPLv3, see COPYING for more details.
"""
fixed license issue #149
r1206 # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
renamed project to rhodecode
r547 # 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.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
renamed project to rhodecode
r547 # You should have received a copy of the GNU General Public License
fixed license issue #149
r1206 # along with this program. If not, see <http://www.gnu.org/licenses/>.
filled in some docs for hooks
r913 import os
import sys
#595 add rcextension hook for repository delete
r2904 import time
save full raw id in push log data for much faster revision lookup
r2324 import binascii
Switched handling of RhodeCode extra params in consistent way...
r3577 import traceback
save full raw id in push log data for much faster revision lookup
r2324 from inspect import isfunction
renamed project to rhodecode
r547
Moved all Mercurial imports into hgcompat from vcs
r3941 from rhodecode.lib.vcs.utils.hgcompat import nullrev, revrange
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 from rhodecode.lib import helpers as h
from rhodecode.lib.utils import action_logger
Git Hooks are automatically installed in new repos...
r2404 from rhodecode.lib.vcs.backends.base import EmptyChangeset
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716 from rhodecode.lib.compat import json
raise na OSERROR if repository data sent from git hook to hook handler is somehow invalid
r2818 from rhodecode.lib.exceptions import HTTPLockedRC
Switched handling of RhodeCode extra params in consistent way...
r3577 from rhodecode.lib.utils2 import safe_str, _extract_extras
raise na OSERROR if repository data sent from git hook to hook handler is somehow invalid
r2818 from rhodecode.model.db import Repository, User
pep8ify
r1307
#595 add rcextension hook for repository delete
r2904
made repo-size hook more generic
r2196 def _get_scm_size(alias, root_path):
if not alias.startswith('.'):
alias += '.'
size_scm, size_root = 0, 0
use str() on os.walk passing unicode can lead to UnicodeDecode errors when iterating
r2963 for path, dirs, files in os.walk(safe_str(root_path)):
made repo-size hook more generic
r2196 if path.find(alias) != -1:
for f in files:
try:
size_scm += os.path.getsize(os.path.join(path, f))
except OSError:
pass
else:
for f in files:
try:
size_root += os.path.getsize(os.path.join(path, f))
except OSError:
pass
size_scm_f = h.format_byte_size(size_scm)
size_root_f = h.format_byte_size(size_root)
size_total_f = h.format_byte_size(size_root + size_scm)
return size_scm_f, size_root_f, size_total_f
renamed project to rhodecode
r547 def repo_size(ui, repo, hooktype=None, **kwargs):
#235 forking page repo group selection...
r1722 """
Presents size of repository after push
source code cleanup: remove trailing white space, normalize file endings
r1203
filled in some docs for hooks
r913 :param ui:
:param repo:
:param hooktype:
"""
renamed project to rhodecode
r547
made repo-size hook more generic
r2196 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
small change for post update hook that displays repository size
r1814
last_cs = repo[len(repo) - 1]
msg = ('Repository size .hg:%s repo:%s total:%s\n'
'Last revision is now r%s:%s\n') % (
size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
)
sys.stdout.write(msg)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
pep8ify
r1307
Implemented basic locking functionality....
r2726 def pre_push(ui, repo, **kwargs):
# pre push function, currently used to ban pushing when
# repository is locked
Switched handling of RhodeCode extra params in consistent way...
r3577 ex = _extract_extras()
Implemented basic locking functionality....
r2726
Switched handling of RhodeCode extra params in consistent way...
r3577 usr = User.get_by_username(ex.username)
if ex.locked_by[0] and usr.user_id != int(ex.locked_by[0]):
locked_by = User.get(ex.locked_by[0]).username
configurable locking codes....
r3522 # this exception is interpreted in git/hg middlewares and based
# on that proper return code is server to client
Switched handling of RhodeCode extra params in consistent way...
r3577 _http_ret = HTTPLockedRC(ex.repository, locked_by)
configurable locking codes....
r3522 if str(_http_ret.code).startswith('2'):
#2xx Codes don't raise exceptions
sys.stdout.write(_http_ret.title)
else:
raise _http_ret
Implemented basic locking functionality....
r2726
def pre_pull(ui, repo, **kwargs):
# pre push function, currently used to ban pushing when
# repository is locked
Switched handling of RhodeCode extra params in consistent way...
r3577 ex = _extract_extras()
if ex.locked_by[0]:
locked_by = User.get(ex.locked_by[0]).username
configurable locking codes....
r3522 # this exception is interpreted in git/hg middlewares and based
# on that proper return code is server to client
Switched handling of RhodeCode extra params in consistent way...
r3577 _http_ret = HTTPLockedRC(ex.repository, locked_by)
configurable locking codes....
r3522 if str(_http_ret.code).startswith('2'):
#2xx Codes don't raise exceptions
sys.stdout.write(_http_ret.title)
else:
raise _http_ret
Implemented basic locking functionality....
r2726
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 def log_pull_action(ui, repo, **kwargs):
#235 forking page repo group selection...
r1722 """
Logs user last pull action
source code cleanup: remove trailing white space, normalize file endings
r1203
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 :param ui:
:param repo:
"""
Switched handling of RhodeCode extra params in consistent way...
r3577 ex = _extract_extras()
user = User.get_by_username(ex.username)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 action = 'pull'
Switched handling of RhodeCode extra params in consistent way...
r3577 action_logger(user, action, ex.repository, ex.ip, commit=True)
added initial rc-extension module...
r2105 # extension hook call
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
r2406 from rhodecode import EXTENSIONS
added initial rc-extension module...
r2105 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
if isfunction(callback):
kw = {}
Switched handling of RhodeCode extra params in consistent way...
r3577 kw.update(ex)
added initial rc-extension module...
r2105 callback(**kw)
Implemented basic locking functionality....
r2726
Mads Kiilerich
hooks: make_lock is tristate...
r3672 if ex.make_lock is not None and ex.make_lock:
Switched handling of RhodeCode extra params in consistent way...
r3577 Repository.lock(Repository.get_by_repo_name(ex.repository), user.user_id)
Implemented basic locking functionality....
r2726 #msg = 'Made lock on repo `%s`' % repository
#sys.stdout.write(msg)
Switched handling of RhodeCode extra params in consistent way...
r3577 if ex.locked_by[0]:
locked_by = User.get(ex.locked_by[0]).username
_http_ret = HTTPLockedRC(ex.repository, locked_by)
configurable locking codes....
r3522 if str(_http_ret.code).startswith('2'):
#2xx Codes don't raise exceptions
sys.stdout.write(_http_ret.title)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 return 0
renamed project to rhodecode
r547
pep8ify
r1307
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 def log_push_action(ui, repo, **kwargs):
#235 forking page repo group selection...
r1722 """
Maps user last push action to new changeset id, from mercurial
source code cleanup: remove trailing white space, normalize file endings
r1203
fixed @repo into :repo for docs...
r604 :param ui:
fixes issue #436 git push error
r2236 :param repo: repo object containing the `ui` object
renamed project to rhodecode
r547 """
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
Switched handling of RhodeCode extra params in consistent way...
r3577 ex = _extract_extras()
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716
Switched handling of RhodeCode extra params in consistent way...
r3577 action = ex.action + ':%s'
use os.environ as a fallback for getting special info from hooks, this will allow...
r2716
Switched handling of RhodeCode extra params in consistent way...
r3577 if ex.scm == 'hg':
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 node = kwargs['node']
def get_revs(repo, rev_opt):
if rev_opt:
revs = revrange(repo, rev_opt)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 if len(revs) == 0:
return (nullrev, nullrev)
return (max(revs), min(revs))
else:
return (len(repo) - 1, 0)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added emulation of pull hook for git-backend, and dummy git-push hook
r2203 stop, start = get_revs(repo, [node + ':'])
save full raw id in push log data for much faster revision lookup
r2324 h = binascii.hexlify
Change git & hg hooks to post. They shouldn't block as they are used just for logging actions. Futhermore post hooks have access to changesets, so it's much better flexible
r2407 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
Switched handling of RhodeCode extra params in consistent way...
r3577 elif ex.scm == 'git':
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 revs = kwargs.get('_git_revs', [])
if '_git_revs' in kwargs:
kwargs.pop('_git_revs')
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 action = action % ','.join(revs)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
Switched handling of RhodeCode extra params in consistent way...
r3577 action_logger(ex.username, action, ex.repository, ex.ip, commit=True)
bugfix, repo_size crashed when broken symlinks where inside a repository.
r675
added initial rc-extension module...
r2105 # extension hook call
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
r2406 from rhodecode import EXTENSIONS
added initial rc-extension module...
r2105 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
if isfunction(callback):
kw = {'pushed_revs': revs}
Switched handling of RhodeCode extra params in consistent way...
r3577 kw.update(ex)
added initial rc-extension module...
r2105 callback(**kw)
Implemented basic locking functionality....
r2726
Mads Kiilerich
hooks: make_lock is tristate...
r3672 if ex.make_lock is not None and not ex.make_lock:
Switched handling of RhodeCode extra params in consistent way...
r3577 Repository.unlock(Repository.get_by_repo_name(ex.repository))
msg = 'Released lock on repo `%s`\n' % ex.repository
Implemented basic locking functionality....
r2726 sys.stdout.write(msg)
Switched handling of RhodeCode extra params in consistent way...
r3577 if ex.locked_by[0]:
locked_by = User.get(ex.locked_by[0]).username
_http_ret = HTTPLockedRC(ex.repository, locked_by)
configurable locking codes....
r3522 if str(_http_ret.code).startswith('2'):
#2xx Codes don't raise exceptions
sys.stdout.write(_http_ret.title)
#48 rewrite action loggers into hooks with all changesets that are inside a push
r654 return 0
#348 added post-create repository hook
r1972
def log_create_repository(repository_dict, created_by, **kwargs):
"""
Post create repository Hook. This is a dummy function for admins to re-use
utils/conf...
r2109 if needed. It's taken from rhodecode-extensions module and executed
added initial rc-extension module...
r2105 if present
#348 added post-create repository hook
r1972
#227 Initial version of repository groups permissions system...
r1982 :param repository: dict dump of repository object
#348 added post-create repository hook
r1972 :param created_by: username who created repository
available keys of repository_dict:
'repo_type',
'description',
'private',
'created_on',
'enable_downloads',
'repo_id',
'user_id',
'enable_statistics',
'clone_uri',
'fork_id',
'group_id',
'repo_name'
"""
changed scope of calling EXTENSIONS from rhodecode for githooks to be able to execute them
r2406 from rhodecode import EXTENSIONS
added initial rc-extension module...
r2105 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
if isfunction(callback):
kw = {}
kw.update(repository_dict)
kw.update({'created_by': created_by})
kw.update(kwargs)
return callback(**kw)
#348 added post-create repository hook
r1972
#227 Initial version of repository groups permissions system...
r1982 return 0
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
#595 add rcextension hook for repository delete
r2904
Jonathan Sternberg
Include the current user as a created_by/deleted_by attribute for USER_HOOK extensions.
r4017 def log_create_user(user_dict, created_by, **kwargs):
Jonathan Sternberg
User create/delete hooks for rcextensions....
r4016 """
Post create user Hook. This is a dummy function for admins to re-use
if needed. It's taken from rhodecode-extensions module and executed
if present
:param user_dict: dict dump of user object
available keys for user_dict:
'username',
'full_name_or_username',
'full_contact',
'user_id',
'name',
'firstname',
'short_contact',
'admin',
'lastname',
'ip_addresses',
'ldap_dn',
'email',
'api_key',
'last_login',
'full_name',
'active',
'password',
'emails',
'inherit_default_permissions'
"""
from rhodecode import EXTENSIONS
callback = getattr(EXTENSIONS, 'CREATE_USER_HOOK', None)
if isfunction(callback):
Jonathan Sternberg
Include the current user as a created_by/deleted_by attribute for USER_HOOK extensions.
r4017 return callback(created_by=created_by, **user_dict)
Jonathan Sternberg
User create/delete hooks for rcextensions....
r4016
return 0
#595 add rcextension hook for repository delete
r2904 def log_delete_repository(repository_dict, deleted_by, **kwargs):
"""
Post delete repository Hook. This is a dummy function for admins to re-use
if needed. It's taken from rhodecode-extensions module and executed
if present
:param repository: dict dump of repository object
:param deleted_by: username who deleted the repository
available keys of repository_dict:
'repo_type',
'description',
'private',
'created_on',
'enable_downloads',
'repo_id',
'user_id',
'enable_statistics',
'clone_uri',
'fork_id',
'group_id',
'repo_name'
"""
from rhodecode import EXTENSIONS
callback = getattr(EXTENSIONS, 'DELETE_REPO_HOOK', None)
if isfunction(callback):
kw = {}
kw.update(repository_dict)
kw.update({'deleted_by': deleted_by,
'deleted_on': time.time()})
kw.update(kwargs)
return callback(**kw)
return 0
Jonathan Sternberg
Include the current user as a created_by/deleted_by attribute for USER_HOOK extensions.
r4017 def log_delete_user(user_dict, deleted_by, **kwargs):
Jonathan Sternberg
User create/delete hooks for rcextensions....
r4016 """
Post delete user Hook. This is a dummy function for admins to re-use
if needed. It's taken from rhodecode-extensions module and executed
if present
:param user_dict: dict dump of user object
available keys for user_dict:
'username',
'full_name_or_username',
'full_contact',
'user_id',
'name',
'firstname',
'short_contact',
'admin',
'lastname',
'ip_addresses',
'ldap_dn',
'email',
'api_key',
'last_login',
'full_name',
'active',
'password',
'emails',
'inherit_default_permissions'
"""
from rhodecode import EXTENSIONS
callback = getattr(EXTENSIONS, 'DELETE_USER_HOOK', None)
if isfunction(callback):
Jonathan Sternberg
Include the current user as a created_by/deleted_by attribute for USER_HOOK extensions.
r4017 return callback(deleted_by=deleted_by, **user_dict)
Jonathan Sternberg
User create/delete hooks for rcextensions....
r4016
return 0
Implemented basic locking functionality....
r2726 handle_git_pre_receive = (lambda repo_path, revs, env:
handle_git_receive(repo_path, revs, env, hook_type='pre'))
handle_git_post_receive = (lambda repo_path, revs, env:
handle_git_receive(repo_path, revs, env, hook_type='post'))
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
Implemented basic locking functionality....
r2726
def handle_git_receive(repo_path, revs, env, hook_type='post'):
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 """
Change git & hg hooks to post. They shouldn't block as they are used just for logging actions. Futhermore post hooks have access to changesets, so it's much better flexible
r2407 A really hacky method that is runned by git post-receive hook and logs
whitespace cleanup
r2409 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.
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
:param repo_path:
:param revs:
:param 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
fix GIT env extraction
r3590 extras = _extract_extras(env)
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
There's no need to use special env variable for config file, it's already passed in in extras now
r2870 path, ini_name = os.path.split(extras['config'])
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 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')
Fixed githooks for fetching multiple tags and branches....
r2617 # fix if it's not a bare repo
Stefan Engel
Make detecting bare Git repositories more robust...
r2872 if repo_path.endswith(os.sep + '.git'):
repo_path = repo_path[:-5]
raise na OSERROR if repository data sent from git hook to hook handler is somehow invalid
r2818
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 repo = Repository.get_by_full_path(repo_path)
raise na OSERROR if repository data sent from git hook to hook handler is somehow invalid
r2818 if not repo:
raise OSError('Repository %s not found in database'
% (safe_str(repo_path)))
Added handling of git hooks, extract pushed revisions and store them inside...
r2402 _hooks = dict(baseui.configitems('hooks')) or {}
git hook handler shouldn't ever use cache instances...
r3278 if hook_type == 'pre':
repo = repo.scm_instance
else:
#post push shouldn't use the cached instance never
no_cache version of scm is now a function
r3549 repo = repo.scm_instance_no_cache()
git hook handler shouldn't ever use cache instances...
r3278
Implemented basic locking functionality....
r2726 if hook_type == 'pre':
pre_push(baseui, repo)
# if push hook is enabled via web interface
elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
Fixed githooks for fetching multiple tags and branches....
r2617
rev_data = []
for l in revs:
old_rev, new_rev, ref = l.split(' ')
_ref_data = ref.split('/')
if _ref_data[1] in ['tags', 'heads']:
rev_data.append({'old_rev': old_rev,
'new_rev': new_rev,
'ref': ref,
'type': _ref_data[1],
'name': _ref_data[2].strip()})
git_revs = []
for push_ref in rev_data:
_type = push_ref['type']
if _type == 'heads':
if push_ref['old_rev'] == EmptyChangeset().raw_id:
cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
heads = repo.run_git_command(cmd)[0]
heads = heads.replace(push_ref['ref'], '')
heads = ' '.join(map(lambda c: c.strip('\n').strip(),
heads.splitlines()))
cmd = (('log %(new_rev)s' % push_ref) +
' --reverse --pretty=format:"%H" --not ' + heads)
fixes #645 Fix git handler when doing delete remote branch...
r2998 git_revs += repo.run_git_command(cmd)[0].splitlines()
elif push_ref['new_rev'] == EmptyChangeset().raw_id:
#delete branch case
git_revs += ['delete_branch=>%s' % push_ref['name']]
Fixed githooks for fetching multiple tags and branches....
r2617 else:
cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
' --reverse --pretty=format:"%H"')
fixes #645 Fix git handler when doing delete remote branch...
r2998 git_revs += repo.run_git_command(cmd)[0].splitlines()
Fixed githooks for fetching multiple tags and branches....
r2617 elif _type == 'tags':
fixes #645 Fix git handler when doing delete remote branch...
r2998 git_revs += ['tag=>%s' % push_ref['name']]
Added handling of git hooks, extract pushed revisions and store them inside...
r2402
log_push_action(baseui, repo, _git_revs=git_revs)