##// END OF EJS Templates
fix: skip process exception is there isn't one
fix: skip process exception is there isn't one

File last commit:

r1296:4ef2409a default
r1296:4ef2409a default
Show More
hooks.py
828 lines | 24.9 KiB | text/x-python | PythonLexer
initial commit
r0 # RhodeCode VCSServer provides access to different vcs backends via network.
source-code: updated copyrights to 2023
r1126 # Copyright (C) 2014-2023 RhodeCode GmbH
initial commit
r0 #
# 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.
#
# 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 General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
exception-handling: better handling of remote exception and logging....
r171 import io
hooks: added new hooks for ssh support
r276 import os
exception-handling: better handling of remote exception and logging....
r171 import sys
import logging
initial commit
r0 import collections
svn: added support for hooks management of git and subversion....
r407 import base64
python3: code change for py3 support...
r1048 import msgpack
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 import dataclasses
import pygit2
exception-handling: better handling of remote exception and logging....
r171
hooks: cleanup connection
r1110 import http.client
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 from celery import Celery
initial commit
r0
import mercurial.scmutil
import mercurial.node
fix(svn): svn events fixes
r1261 from vcsserver import exceptions, subprocessio, settings
chore(refactor): renamed rc_json to ext_json for ce compat
r1243 from vcsserver.lib.ext_json import json
core: moved str_utils and type_utils to lib so it's consistent with ce, and easier to sync up codebases
r1249 from vcsserver.lib.str_utils import ascii_str, safe_str
fix(svn): svn events fixes
r1261 from vcsserver.lib.svn_txn_utils import get_txn_id_from_store
core: renamed remote packages to prevent conflicts with builtin libraries like svn core library called same as svn remote
r1145 from vcsserver.remote.git_remote import Repository
initial commit
r0
chore(deps): bumped celery to 5.3.6 and kombu to latest version
r1205 celery_app = Celery('__vcsserver__')
exception-handling: better handling of remote exception and logging....
r171 log = logging.getLogger(__name__)
initial commit
r0
lint: auto-fixes
r1152 class HooksHttpClient:
python3: code change for py3 support...
r1048 proto = 'msgpack.v1'
initial commit
r0 connection = None
def __init__(self, hooks_uri):
self.hooks_uri = hooks_uri
hooks: cleanup connection
r1110 def __repr__(self):
return f'{self.__class__}(hook_uri={self.hooks_uri}, proto={self.proto})'
initial commit
r0 def __call__(self, method, extras):
hooks: cleanup connection
r1110 connection = http.client.HTTPConnection(self.hooks_uri)
python3: code change for py3 support...
r1048 # binary msgpack body
headers, body = self._serialize(method, extras)
hooks: cleanup connection
r1110 log.debug('Doing a new hooks call using HTTPConnection to %s', self.hooks_uri)
hooks: add extra debug/logging to help track hook errors.
r591 try:
hooks: cleanup connection
r1110 try:
connection.request('POST', '/', body, headers)
except Exception as error:
log.error('Hooks calling Connection failed on %s, org error: %s', connection.__dict__, error)
raise
response = connection.getresponse()
try:
return msgpack.load(response)
except Exception:
response_data = response.read()
log.exception('Failed to decode hook response json data. '
'response_code:%s, raw_data:%s',
response.status, response_data)
raise
finally:
connection.close()
initial commit
r0
python3: code change for py3 support...
r1048 @classmethod
def _serialize(cls, hook_name, extras):
initial commit
r0 data = {
'method': hook_name,
'extras': extras
}
python3: code change for py3 support...
r1048 headers = {
hooks: cleanup connection
r1110 "rc-hooks-protocol": cls.proto,
"Connection": "keep-alive"
python3: code change for py3 support...
r1048 }
return headers, msgpack.packb(data)
initial commit
r0
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 class HooksCeleryClient:
TASK_TIMEOUT = 60 # time in seconds
initial commit
r0
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 def __init__(self, queue, backend):
chore(deps): bumped celery to 5.3.6 and kombu to latest version
r1205 celery_app.config_from_object({
'broker_url': queue, 'result_backend': backend,
'broker_connection_retry_on_startup': True,
fix(vcsserver): make serializer consistent like in rhodecode
r1235 'task_serializer': 'json',
chore(deps): bumped celery to 5.3.6 and kombu to latest version
r1205 'accept_content': ['json', 'msgpack'],
fix(vcsserver): make serializer consistent like in rhodecode
r1235 'result_serializer': 'json',
chore(deps): bumped celery to 5.3.6 and kombu to latest version
r1205 'result_accept_content': ['json', 'msgpack']
})
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 self.celery_app = celery_app
def __call__(self, method, extras):
inquired_task = self.celery_app.signature(
f'rhodecode.lib.celerylib.tasks.{method}'
)
fix: skip process exception is there isn't one
r1296 result = inquired_task.delay(extras).get(timeout=self.TASK_TIMEOUT)
return result
initial commit
r0
lint: auto-fixes
r1152 class HooksShadowRepoClient:
hooks: added shadow repo dedicated dummy hook....
r780
def __call__(self, hook_name, extras):
return {'output': '', 'status': 0}
lint: auto-fixes
r1152 class RemoteMessageWriter:
initial commit
r0 """Writer base class."""
hooks: fixed function signature.
r222 def write(self, message):
initial commit
r0 raise NotImplementedError()
class HgMessageWriter(RemoteMessageWriter):
"""Writer that knows how to send messages to mercurial clients."""
def __init__(self, ui):
self.ui = ui
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 def write(self, message: str):
initial commit
r0 # TODO: Check why the quiet flag is set by default.
old = self.ui.quiet
self.ui.quiet = False
self.ui.status(message.encode('utf-8'))
self.ui.quiet = old
class GitMessageWriter(RemoteMessageWriter):
"""Writer that knows how to send messages to git clients."""
def __init__(self, stdout=None):
self.stdout = stdout or sys.stdout
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 def write(self, message: str):
self.stdout.write(message)
initial commit
r0
svn: added support for hooks management of git and subversion....
r407 class SvnMessageWriter(RemoteMessageWriter):
"""Writer that knows how to send messages to svn clients."""
def __init__(self, stderr=None):
# SVN needs data sent to stderr for back-to-client messaging
self.stderr = stderr or sys.stderr
def write(self, message):
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 self.stderr.write(message)
svn: added support for hooks management of git and subversion....
r407
fix: skip process exception is there isn't one
r1296 def _maybe_handle_exception(result):
initial commit
r0 exception_class = result.get('exception')
exception-handling: better handling of remote exception and logging....
r171 exception_traceback = result.get('exception_traceback')
fix: skip process exception is there isn't one
r1296 if not (exception_class and exception_traceback):
return
core: various cleanups and fixes
r1118 log.debug('Handling hook-call exception: %s', exception_class)
exception-handling: better handling of remote exception and logging....
r171
if exception_traceback:
log.error('Got traceback from remote call:%s', exception_traceback)
initial commit
r0 if exception_class == 'HTTPLockedRC':
exceptions: use new wrapper that store the org exception inside the newly generated exceptions....
r490 raise exceptions.RepositoryLockedException()(*result['exception_args'])
Added custom error.
r1283 elif exception_class == 'ClientNotSupportedError':
raise exceptions.ClientNotSupportedException()(*result['exception_args'])
hooks: adjust to handle protected branch cases, and force push.
r509 elif exception_class == 'HTTPBranchProtected':
raise exceptions.RepositoryBranchProtectedException()(*result['exception_args'])
initial commit
r0 elif exception_class == 'RepositoryError':
exceptions: use new wrapper that store the org exception inside the newly generated exceptions....
r490 raise exceptions.VcsException()(*result['exception_args'])
initial commit
r0 elif exception_class:
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 raise Exception(
f"""Got remote exception "{exception_class}" with args "{result['exception_args']}" """
)
initial commit
r0
def _get_hooks_client(extras):
hooks: added shadow repo dedicated dummy hook....
r780 hooks_uri = extras.get('hooks_uri')
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 task_queue = extras.get('task_queue')
task_backend = extras.get('task_backend')
hooks: added shadow repo dedicated dummy hook....
r780 is_shadow_repo = extras.get('is_shadow_repo')
core: various cleanups and fixes
r1118
hooks: added shadow repo dedicated dummy hook....
r780 if hooks_uri:
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 return HooksHttpClient(hooks_uri)
elif task_queue and task_backend:
return HooksCeleryClient(task_queue, task_backend)
hooks: added shadow repo dedicated dummy hook....
r780 elif is_shadow_repo:
return HooksShadowRepoClient()
initial commit
r0 else:
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
r1204 raise Exception("Hooks client not found!")
initial commit
r0
def _call_hook(hook_name, extras, writer):
svn: added support for hooks management of git and subversion....
r407 hooks_client = _get_hooks_client(extras)
log.debug('Hooks, using client:%s', hooks_client)
result = hooks_client(hook_name, extras)
hooks: added new hooks for ssh support
r276 log.debug('Hooks got result: %s', result)
fix: skip process exception is there isn't one
r1296 _maybe_handle_exception(result)
initial commit
r0 writer.write(result['output'])
return result['status']
def _extras_from_ui(ui):
py3: fixed mercurial clone
r1052 hook_data = ui.config(b'rhodecode', b'RC_SCM_DATA')
hooks: added new hooks for ssh support
r276 if not hook_data:
# maybe it's inside environ ?
hooks: use safer method of exporting the RC_SCM_DATA, prevents JSON decode errors in case of None value
r333 env_hook_data = os.environ.get('RC_SCM_DATA')
if env_hook_data:
hook_data = env_hook_data
hooks: fix case for SSH hooks executed in certain condition with errors....
r334 extras = {}
if hook_data:
extras = json.loads(hook_data)
initial commit
r0 return extras
hooks: adjust to handle protected branch cases, and force push.
r509 def _rev_range_hash(repo, node, check_heads=False):
mercurial: move imports from top-level to prevent from loading mercurial code on hook execution for svn/git
r802 from vcsserver.hgcompat import get_ctx
hooks: expose pushed refs inside hooks....
r223
commits = []
hooks: adjust to handle protected branch cases, and force push.
r509 revs = []
hg: added compat for fetching revision using new hg 4.9 code
r660 start = get_ctx(repo, node).rev()
hooks: adjust to handle protected branch cases, and force push.
r509 end = len(repo)
for rev in range(start, end):
revs.append(rev)
hg: added compat for fetching revision using new hg 4.9 code
r660 ctx = get_ctx(repo, rev)
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 commit_id = ascii_str(mercurial.node.hex(ctx.node()))
branch = safe_str(ctx.branch())
hooks: expose pushed refs inside hooks....
r223 commits.append((commit_id, branch))
hooks: adjust to handle protected branch cases, and force push.
r509 parent_heads = []
if check_heads:
parent_heads = _check_heads(repo, start, end, revs)
return commits, parent_heads
def _check_heads(repo, start, end, commits):
mercurial: move imports from top-level to prevent from loading mercurial code on hook execution for svn/git
r802 from vcsserver.hgcompat import get_ctx
hooks: adjust to handle protected branch cases, and force push.
r509 changelog = repo.changelog
parents = set()
for new_rev in commits:
for p in changelog.parentrevs(new_rev):
if p == mercurial.node.nullrev:
continue
if p < start:
parents.add(p)
for p in parents:
hg: added compat for fetching revision using new hg 4.9 code
r660 branch = get_ctx(repo, p).branch()
hooks: adjust to handle protected branch cases, and force push.
r509 # The heads descending from that parent, on the same branch
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 parent_heads = {p}
reachable = {p}
py3: drop xrange
r982 for x in range(p + 1, end):
hg: added compat for fetching revision using new hg 4.9 code
r660 if get_ctx(repo, x).branch() != branch:
hooks: adjust to handle protected branch cases, and force push.
r509 continue
for pp in changelog.parentrevs(x):
if pp in reachable:
reachable.add(x)
parent_heads.discard(pp)
parent_heads.add(x)
# More than one head? Suggest merging
if len(parent_heads) > 1:
return list(parent_heads)
return []
hooks: expose pushed refs inside hooks....
r223
hooks: expose few extra variables from hook calls
r557 def _get_git_env():
env = {}
for k, v in os.environ.items():
if k.startswith('GIT'):
env[k] = v
# serialized version
return [(k, v) for k, v in env.items()]
def _get_hg_env(old_rev, new_rev, txnid, repo_path):
env = {}
for k, v in os.environ.items():
if k.startswith('HG'):
env[k] = v
env['HG_NODE'] = old_rev
env['HG_NODE_LAST'] = new_rev
env['HG_TXNID'] = txnid
env['HG_PENDING'] = repo_path
return [(k, v) for k, v in env.items()]
fix(svn): svn events fixes
r1261 def _get_ini_settings(ini_file):
from vcsserver.http_main import sanitize_settings_and_apply_defaults
from vcsserver.lib.config_utils import get_app_config_lightweight, configure_and_store_settings
global_config = {'__file__': ini_file}
ini_settings = get_app_config_lightweight(ini_file)
sanitize_settings_and_apply_defaults(global_config, ini_settings)
configure_and_store_settings(global_config, ini_settings)
return ini_settings
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 def _fix_hooks_executables(ini_path=''):
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 """
This is a trick to set proper settings.EXECUTABLE paths for certain execution patterns
especially for subversion where hooks strip entire env, and calling just 'svn' command will most likely fail
because svn is not on PATH
"""
fix(svn): svn events fixes
r1261 # set defaults, in case we can't read from ini_file
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 core_binary_dir = settings.BINARY_DIR or '/usr/local/bin/rhodecode_bin/vcs_bin'
if ini_path:
fix(svn): svn events fixes
r1261 ini_settings = _get_ini_settings(ini_path)
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 core_binary_dir = ini_settings['core.binary_dir']
settings.BINARY_DIR = core_binary_dir
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214
hooks: added new hooks for ssh support
r276 def repo_size(ui, repo, **kwargs):
extras = _extras_from_ui(ui)
return _call_hook('repo_size', extras, HgMessageWriter(ui))
def pre_pull(ui, repo, **kwargs):
extras = _extras_from_ui(ui)
return _call_hook('pre_pull', extras, HgMessageWriter(ui))
def pre_pull_ssh(ui, repo, **kwargs):
hooks: fix case for SSH hooks executed in certain condition with errors....
r334 extras = _extras_from_ui(ui)
if extras and extras.get('SSH'):
hooks: added new hooks for ssh support
r276 return pre_pull(ui, repo, **kwargs)
return 0
def post_pull(ui, repo, **kwargs):
extras = _extras_from_ui(ui)
return _call_hook('post_pull', extras, HgMessageWriter(ui))
def post_pull_ssh(ui, repo, **kwargs):
hooks: fix case for SSH hooks executed in certain condition with errors....
r334 extras = _extras_from_ui(ui)
if extras and extras.get('SSH'):
hooks: added new hooks for ssh support
r276 return post_pull(ui, repo, **kwargs)
return 0
hooks: added changes to propagate commit metadata on pre-push....
r170 def pre_push(ui, repo, node=None, **kwargs):
hooks: adjust to handle protected branch cases, and force push.
r509 """
Mercurial pre_push hook
"""
hooks: added changes to propagate commit metadata on pre-push....
r170 extras = _extras_from_ui(ui)
hooks: adjust to handle protected branch cases, and force push.
r509 detect_force_push = extras.get('detect_force_push')
hooks: added changes to propagate commit metadata on pre-push....
r170
rev_data = []
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 hook_type: str = safe_str(kwargs.get('hooktype'))
if node and hook_type == 'pretxnchangegroup':
hooks: added changes to propagate commit metadata on pre-push....
r170 branches = collections.defaultdict(list)
hooks: adjust to handle protected branch cases, and force push.
r509 commits, _heads = _rev_range_hash(repo, node, check_heads=detect_force_push)
for commit_id, branch in commits:
hooks: added changes to propagate commit metadata on pre-push....
r170 branches[branch].append(commit_id)
hooks: adjust to handle protected branch cases, and force push.
r509 for branch, commits in branches.items():
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 old_rev = ascii_str(kwargs.get('node_last')) or commits[0]
hooks: added changes to propagate commit metadata on pre-push....
r170 rev_data.append({
hooks: expose few extra variables from hook calls
r557 'total_commits': len(commits),
hooks: added changes to propagate commit metadata on pre-push....
r170 'old_rev': old_rev,
'new_rev': commits[-1],
'ref': '',
'type': 'branch',
'name': branch,
})
hooks: adjust to handle protected branch cases, and force push.
r509 for push_ref in rev_data:
push_ref['multiple_heads'] = _heads
hooks: expose few extra variables from hook calls
r557 repo_path = os.path.join(
extras.get('repo_store', ''), extras.get('repository', ''))
push_ref['hg_env'] = _get_hg_env(
old_rev=push_ref['old_rev'],
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 new_rev=push_ref['new_rev'], txnid=ascii_str(kwargs.get('txnid')),
hooks: expose few extra variables from hook calls
r557 repo_path=repo_path)
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 extras['hook_type'] = hook_type or 'pre_push'
hooks: added changes to propagate commit metadata on pre-push....
r170 extras['commit_ids'] = rev_data
hooks: expose few extra variables from hook calls
r557
hooks: added changes to propagate commit metadata on pre-push....
r170 return _call_hook('pre_push', extras, HgMessageWriter(ui))
initial commit
r0
hooks: added new hooks for ssh support
r276 def pre_push_ssh(ui, repo, node=None, **kwargs):
git-hooks: store git-env into hooks, so we can use the sandbox storage area, and execute...
r510 extras = _extras_from_ui(ui)
if extras.get('SSH'):
hooks: added new hooks for ssh support
r276 return pre_push(ui, repo, node, **kwargs)
return 0
def pre_push_ssh_auth(ui, repo, node=None, **kwargs):
hooks: adjust to handle protected branch cases, and force push.
r509 """
Mercurial pre_push hook for SSH
"""
hooks: added new hooks for ssh support
r276 extras = _extras_from_ui(ui)
if extras.get('SSH'):
permission = extras['SSH_PERMISSIONS']
if 'repository.write' == permission or 'repository.admin' == permission:
return 0
# non-zero ret code
return 1
return 0
hooks: expose pushed refs inside hooks....
r223 def post_push(ui, repo, node, **kwargs):
hooks: adjust to handle protected branch cases, and force push.
r509 """
Mercurial post_push hook
"""
hooks: expose pushed refs inside hooks....
r223 extras = _extras_from_ui(ui)
commit_ids = []
branches = []
bookmarks = []
tags = []
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 hook_type: str = safe_str(kwargs.get('hooktype'))
initial commit
r0
hooks: adjust to handle protected branch cases, and force push.
r509 commits, _heads = _rev_range_hash(repo, node)
for commit_id, branch in commits:
hooks: expose pushed refs inside hooks....
r223 commit_ids.append(commit_id)
if branch not in branches:
branches.append(branch)
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 if hasattr(ui, '_rc_pushkey_bookmarks'):
bookmarks = ui._rc_pushkey_bookmarks
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 extras['hook_type'] = hook_type or 'post_push'
initial commit
r0 extras['commit_ids'] = commit_ids
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108
hooks: expose pushed refs inside hooks....
r223 extras['new_refs'] = {
'branches': branches,
'bookmarks': bookmarks,
'tags': tags
}
initial commit
r0
return _call_hook('post_push', extras, HgMessageWriter(ui))
hooks: added new hooks for ssh support
r276 def post_push_ssh(ui, repo, node, **kwargs):
hooks: adjust to handle protected branch cases, and force push.
r509 """
Mercurial post_push hook for SSH
"""
hooks: added new hooks for ssh support
r276 if _extras_from_ui(ui).get('SSH'):
return post_push(ui, repo, node, **kwargs)
return 0
hooks: expose post-key-push hook for Mercurial.
r221 def key_push(ui, repo, **kwargs):
mercurial: move imports from top-level to prevent from loading mercurial code on hook execution for svn/git
r802 from vcsserver.hgcompat import get_ctx
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108
if kwargs['new'] != b'0' and kwargs['namespace'] == b'bookmarks':
hooks: expose post-key-push hook for Mercurial.
r221 # store new bookmarks in our UI object propagated later to post_push
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 ui._rc_pushkey_bookmarks = get_ctx(repo, kwargs['key']).bookmarks()
hooks: expose post-key-push hook for Mercurial.
r221 return
hooks: added new hooks for ssh support
r276
initial commit
r0 # backward compat
log_pull_action = post_pull
# backward compat
log_push_action = post_push
def handle_git_pre_receive(unused_repo_path, unused_revs, unused_env):
"""
Old hook name: keep here for backward compatibility.
This is only required when the installed git hooks are not upgraded.
"""
pass
def handle_git_post_receive(unused_repo_path, unused_revs, unused_env):
"""
Old hook name: keep here for backward compatibility.
This is only required when the installed git hooks are not upgraded.
"""
pass
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 @dataclasses.dataclass
class HookResponse:
status: int
output: str
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 def git_pre_pull(extras) -> HookResponse:
initial commit
r0 """
Pre pull hook.
:param extras: dictionary containing the keys defined in simplevcs
:type extras: dict
:return: status code of the hook. 0 for success.
:rtype: int
"""
python3: code change for py3 support...
r1048
initial commit
r0 if 'pull' not in extras['hooks']:
return HookResponse(0, '')
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 stdout = io.StringIO()
initial commit
r0 try:
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 status_code = _call_hook('pre_pull', extras, GitMessageWriter(stdout))
python3: code change for py3 support...
r1048
initial commit
r0 except Exception as error:
python3: code change for py3 support...
r1048 log.exception('Failed to call pre_pull hook')
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 status_code = 128
stdout.write(f'ERROR: {error}\n')
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 return HookResponse(status_code, stdout.getvalue())
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 def git_post_pull(extras) -> HookResponse:
initial commit
r0 """
Post pull hook.
:param extras: dictionary containing the keys defined in simplevcs
:type extras: dict
:return: status code of the hook. 0 for success.
:rtype: int
"""
if 'pull' not in extras['hooks']:
return HookResponse(0, '')
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 stdout = io.StringIO()
initial commit
r0 try:
status = _call_hook('post_pull', extras, GitMessageWriter(stdout))
except Exception as error:
status = 128
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 stdout.write(f'ERROR: {error}\n')
initial commit
r0
return HookResponse(status, stdout.getvalue())
hooks: added changes to propagate commit metadata on pre-push....
r170 def _parse_git_ref_lines(revision_lines):
rev_data = []
for revision_line in revision_lines or []:
old_rev, new_rev, ref = revision_line.strip().split(' ')
ref_data = ref.split('/', 2)
if ref_data[1] in ('tags', 'heads'):
rev_data.append({
hooks: expose few extra variables from hook calls
r557 # NOTE(marcink):
# we're unable to tell total_commits for git at this point
# but we set the variable for consistency with GIT
'total_commits': -1,
hooks: added changes to propagate commit metadata on pre-push....
r170 'old_rev': old_rev,
'new_rev': new_rev,
'ref': ref,
'type': ref_data[1],
'name': ref_data[2],
})
return rev_data
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 def git_pre_receive(unused_repo_path, revision_lines, env) -> int:
initial commit
r0 """
Pre push hook.
:return: status code of the hook. 0 for success.
"""
extras = json.loads(env['RC_SCM_DATA'])
hooks: added changes to propagate commit metadata on pre-push....
r170 rev_data = _parse_git_ref_lines(revision_lines)
initial commit
r0 if 'push' not in extras['hooks']:
return 0
fix(svn): svn events fixes
r1261 _fix_hooks_executables(env.get('RC_INI_FILE'))
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230
hooks: adjust to handle protected branch cases, and force push.
r509 empty_commit_id = '0' * 40
detect_force_push = extras.get('detect_force_push')
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230
hooks: adjust to handle protected branch cases, and force push.
r509 for push_ref in rev_data:
git-hooks: store git-env into hooks, so we can use the sandbox storage area, and execute...
r510 # store our git-env which holds the temp store
hooks: expose few extra variables from hook calls
r557 push_ref['git_env'] = _get_git_env()
hooks: adjust to handle protected branch cases, and force push.
r509 push_ref['pruned_sha'] = ''
if not detect_force_push:
# don't check for forced-push when we don't need to
continue
type_ = push_ref['type']
new_branch = push_ref['old_rev'] == empty_commit_id
dan
hooks: handle delete branch permission case with branch protection
r643 delete_branch = push_ref['new_rev'] == empty_commit_id
if type_ == 'heads' and not (new_branch or delete_branch):
hooks: adjust to handle protected branch cases, and force push.
r509 old_rev = push_ref['old_rev']
new_rev = push_ref['new_rev']
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 cmd = [settings.GIT_EXECUTABLE(), 'rev-list', old_rev, f'^{new_rev}']
hooks: adjust to handle protected branch cases, and force push.
r509 stdout, stderr = subprocessio.run_command(
cmd, env=os.environ.copy())
dan
hooks: handle delete branch permission case with branch protection
r643 # means we're having some non-reachable objects, this forced push was used
hooks: adjust to handle protected branch cases, and force push.
r509 if stdout:
push_ref['pruned_sha'] = stdout.splitlines()
hooks: store hook type for extensions.
r555 extras['hook_type'] = 'pre_receive'
hooks: added changes to propagate commit metadata on pre-push....
r170 extras['commit_ids'] = rev_data
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108
stdout = sys.stdout
status_code = _call_hook('pre_push', extras, GitMessageWriter(stdout))
return status_code
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 def git_post_receive(unused_repo_path, revision_lines, env) -> int:
initial commit
r0 """
Post push hook.
:return: status code of the hook. 0 for success.
"""
extras = json.loads(env['RC_SCM_DATA'])
if 'push' not in extras['hooks']:
return 0
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230
fix(svn): svn events fixes
r1261 _fix_hooks_executables(env.get('RC_INI_FILE'))
initial commit
r0
hooks: added changes to propagate commit metadata on pre-push....
r170 rev_data = _parse_git_ref_lines(revision_lines)
initial commit
r0
git_revs = []
# N.B.(skreft): it is ok to just call git, as git before calling a
# subcommand sets the PATH environment variable so that it point to the
# correct version of the git executable.
empty_commit_id = '0' * 40
hooks: expose pushed refs inside hooks....
r223 branches = []
tags = []
initial commit
r0 for push_ref in rev_data:
type_ = push_ref['type']
hooks: expose pushed refs inside hooks....
r223
initial commit
r0 if type_ == 'heads':
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 # starting new branch case
initial commit
r0 if push_ref['old_rev'] == empty_commit_id:
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 push_ref_name = push_ref['name']
if push_ref_name not in branches:
branches.append(push_ref_name)
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 need_head_set = ''
with Repository(os.getcwd()) as repo:
try:
repo.head
except pygit2.GitError:
need_head_set = f'refs/heads/{push_ref_name}'
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 if need_head_set:
repo.set_head(need_head_set)
print(f"Setting default branch to {push_ref_name}")
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 cmd = [settings.GIT_EXECUTABLE(), 'for-each-ref', '--format=%(refname)', 'refs/heads/*']
subprocess: use subprocessio helper to run various subprocess commands.
r370 stdout, stderr = subprocessio.run_command(
cmd, env=os.environ.copy())
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 heads = safe_str(stdout)
initial commit
r0 heads = heads.replace(push_ref['ref'], '')
git: fixed code after version upgrade
r434 heads = ' '.join(head for head
in heads.splitlines() if head) or '.'
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 cmd = [settings.GIT_EXECUTABLE(), 'log', '--reverse',
subprocess: use subprocessio helper to run various subprocess commands.
r370 '--pretty=format:%H', '--', push_ref['new_rev'],
'--not', heads]
stdout, stderr = subprocessio.run_command(
cmd, env=os.environ.copy())
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 git_revs.extend(list(map(ascii_str, stdout.splitlines())))
# delete branch case
initial commit
r0 elif push_ref['new_rev'] == empty_commit_id:
lint: auto-fixes
r1152 git_revs.append(f'delete_branch=>{push_ref["name"]}')
initial commit
r0 else:
hooks: expose pushed refs inside hooks....
r223 if push_ref['name'] not in branches:
branches.append(push_ref['name'])
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230 cmd = [settings.GIT_EXECUTABLE(), 'log',
strings: fix formatting
r1154 f'{push_ref["old_rev"]}..{push_ref["new_rev"]}',
initial commit
r0 '--reverse', '--pretty=format:%H']
subprocess: use subprocessio helper to run various subprocess commands.
r370 stdout, stderr = subprocessio.run_command(
cmd, env=os.environ.copy())
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 # we get bytes from stdout, we need str to be consistent
log_revs = list(map(ascii_str, stdout.splitlines()))
git_revs.extend(log_revs)
# Pure pygit2 impl. but still 2-3x slower :/
# results = []
#
# with Repository(os.getcwd()) as repo:
# repo_new_rev = repo[push_ref['new_rev']]
# repo_old_rev = repo[push_ref['old_rev']]
# walker = repo.walk(repo_new_rev.id, pygit2.GIT_SORT_TOPOLOGICAL)
#
# for commit in walker:
# if commit.id == repo_old_rev.id:
# break
# results.append(commit.id.hex)
# # reverse the order, can't use GIT_SORT_REVERSE
# log_revs = results[::-1]
initial commit
r0 elif type_ == 'tags':
hooks: expose pushed refs inside hooks....
r223 if push_ref['name'] not in tags:
tags.append(push_ref['name'])
lint: auto-fixes
r1152 git_revs.append(f'tag=>{push_ref["name"]}')
initial commit
r0
hooks: store hook type for extensions.
r555 extras['hook_type'] = 'post_receive'
initial commit
r0 extras['commit_ids'] = git_revs
hooks: expose pushed refs inside hooks....
r223 extras['new_refs'] = {
'branches': branches,
'bookmarks': [],
'tags': tags,
}
initial commit
r0
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 stdout = sys.stdout
initial commit
r0 if 'repo_size' in extras['hooks']:
try:
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 _call_hook('repo_size', extras, GitMessageWriter(stdout))
linting
r1095 except Exception:
initial commit
r0 pass
hooks: added few python3 related fixes to handle bytes vs str on Mercurial hooks
r1108 status_code = _call_hook('post_push', extras, GitMessageWriter(stdout))
return status_code
svn: added support for hooks management of git and subversion....
r407
fix(svn): svn events fixes
r1261 def get_extras_from_txn_id(repo_path, txn_id):
extras = get_txn_id_from_store(repo_path, txn_id)
hooks: expose few extra variables from hook calls
r557 return extras
svn: added support for hooks management of git and subversion....
r407 def svn_pre_commit(repo_path, commit_data, env):
fix(svn): fixed problems with svn hooks binary dir not beeing propagates in mod_dav_svn
r1230
svn: added support for hooks management of git and subversion....
r407 path, txn_id = commit_data
branches = []
tags = []
svn: make hooks safe and fully backward compatible....
r436 if env.get('RC_SCM_DATA'):
extras = json.loads(env['RC_SCM_DATA'])
else:
fix(svn): svn events fixes
r1261 ini_path = env.get('RC_INI_FILE')
if ini_path:
_get_ini_settings(ini_path)
svn: make hooks safe and fully backward compatible....
r436 # fallback method to read from TXN-ID stored data
fix(svn): svn events fixes
r1261 extras = get_extras_from_txn_id(path, txn_id)
feat: svn hooks are mandatory and blocking from now on
r1231
if not extras:
fix(svn): svn events fixes
r1261 raise ValueError('SVN-PRE-COMMIT: Failed to extract context data in called extras for hook execution')
if extras.get('rc_internal_commit'):
# special marker for internal commit, we don't call hooks client
fix: svn, remove accidentally merged strict svn checks.
r1234 return 0
svn: added support for hooks management of git and subversion....
r407
hooks: fixed SVN hook problem
r575 extras['hook_type'] = 'pre_commit'
svn: expose txn_id in pre-commit hooks so we can analyze it in pre transaction hooks.
r670 extras['commit_ids'] = [txn_id]
svn: added support for hooks management of git and subversion....
r407 extras['txn_id'] = txn_id
extras['new_refs'] = {
hooks: expose few extra variables from hook calls
r557 'total_commits': 1,
svn: added support for hooks management of git and subversion....
r407 'branches': branches,
'bookmarks': [],
'tags': tags,
}
svn: make hooks safe and fully backward compatible....
r436
svn: added support for hooks management of git and subversion....
r407 return _call_hook('pre_push', extras, SvnMessageWriter())
def svn_post_commit(repo_path, commit_data, env):
"""
commit_data is path, rev, txn_id
"""
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214
svn: allow legacy (pre SVN 1.7) extraction of post commit data....
r824 if len(commit_data) == 3:
path, commit_id, txn_id = commit_data
elif len(commit_data) == 2:
log.error('Failed to extract txn_id from commit_data using legacy method. '
'Some functionality might be limited')
path, commit_id = commit_data
txn_id = None
fix(svn-hooks): fixed problem with svn subprocess execution fixes RCCE-62
r1214 else:
return 0
svn: allow legacy (pre SVN 1.7) extraction of post commit data....
r824
svn: added support for hooks management of git and subversion....
r407 branches = []
tags = []
svn: make hooks safe and fully backward compatible....
r436 if env.get('RC_SCM_DATA'):
extras = json.loads(env['RC_SCM_DATA'])
else:
fix(svn): svn events fixes
r1261 ini_path = env.get('RC_INI_FILE')
if ini_path:
_get_ini_settings(ini_path)
svn: make hooks safe and fully backward compatible....
r436 # fallback method to read from TXN-ID stored data
fix(svn): svn events fixes
r1261 extras = get_extras_from_txn_id(path, txn_id)
feat: svn hooks are mandatory and blocking from now on
r1231
fix(svn): svn events fixes
r1261 if not extras and txn_id:
raise ValueError('SVN-POST-COMMIT: Failed to extract context data in called extras for hook execution')
if extras.get('rc_internal_commit'):
# special marker for internal commit, we don't call hooks client
fix: svn, remove accidentally merged strict svn checks.
r1234 return 0
svn: added support for hooks management of git and subversion....
r407
hooks: fixed SVN hook problem
r575 extras['hook_type'] = 'post_commit'
svn: added support for hooks management of git and subversion....
r407 extras['commit_ids'] = [commit_id]
extras['txn_id'] = txn_id
extras['new_refs'] = {
'branches': branches,
'bookmarks': [],
'tags': tags,
hooks: expose few extra variables from hook calls
r557 'total_commits': 1,
svn: added support for hooks management of git and subversion....
r407 }
if 'repo_size' in extras['hooks']:
try:
_call_hook('repo_size', extras, SvnMessageWriter())
svn: make hooks safe and fully backward compatible....
r436 except Exception:
svn: added support for hooks management of git and subversion....
r407 pass
return _call_hook('post_push', extras, SvnMessageWriter())