hooks: added new hooks for comments on pull requests and commits.
- allows writing custom actions on top of comments - new rcextension hooks - organized and renamed some hooks - new helpers for rcextensions - fixes #5583
This commit is contained in:
parent
1e8d393f02
commit
466826a84a
19 changed files with 386 additions and 110 deletions
|
|
@ -1599,7 +1599,8 @@ def comment_commit(
|
|||
validate_repo_permissions(apiuser, repoid, repo, _perms)
|
||||
|
||||
try:
|
||||
commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
|
||||
commit = repo.scm_instance().get_commit(commit_id=commit_id)
|
||||
commit_id = commit.raw_id
|
||||
except Exception as e:
|
||||
log.exception('Failed to fetch commit')
|
||||
raise JSONRPCError(safe_str(e))
|
||||
|
|
@ -1659,6 +1660,10 @@ def comment_commit(
|
|||
'a closed pull request is not allowed')
|
||||
raise JSONRPCError(msg)
|
||||
|
||||
CommentsModel().trigger_commit_comment_hook(
|
||||
repo, apiuser, 'create',
|
||||
data={'comment': comment, 'commit': commit})
|
||||
|
||||
Session().commit()
|
||||
return {
|
||||
'msg': (
|
||||
|
|
|
|||
|
|
@ -380,6 +380,11 @@ class RepoCommitsView(RepoAppView):
|
|||
'repo_commit', repo_name=self.db_repo_name,
|
||||
commit_id=current_id))
|
||||
|
||||
commit = self.db_repo.get_commit(current_id)
|
||||
CommentsModel().trigger_commit_comment_hook(
|
||||
self.db_repo, self._rhodecode_user, 'create',
|
||||
data={'comment': comment, 'commit': commit})
|
||||
|
||||
# finalize, commit and redirect
|
||||
Session().commit()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from .hooks import (
|
|||
_create_repo_group_hook,
|
||||
_pre_create_user_hook,
|
||||
_create_user_hook,
|
||||
_comment_commit_repo_hook,
|
||||
_delete_repo_hook,
|
||||
_delete_user_hook,
|
||||
_pre_push_hook,
|
||||
|
|
@ -33,6 +34,7 @@ from .hooks import (
|
|||
_pull_hook,
|
||||
_create_pull_request_hook,
|
||||
_review_pull_request_hook,
|
||||
_comment_pull_request_hook,
|
||||
_update_pull_request_hook,
|
||||
_merge_pull_request_hook,
|
||||
_close_pull_request_hook,
|
||||
|
|
@ -40,6 +42,7 @@ from .hooks import (
|
|||
|
||||
# set as module attributes, we use those to call hooks. *do not change this*
|
||||
CREATE_REPO_HOOK = _create_repo_hook
|
||||
COMMENT_COMMIT_REPO_HOOK = _comment_commit_repo_hook
|
||||
CREATE_REPO_GROUP_HOOK = _create_repo_group_hook
|
||||
PRE_CREATE_USER_HOOK = _pre_create_user_hook
|
||||
CREATE_USER_HOOK = _create_user_hook
|
||||
|
|
@ -51,6 +54,7 @@ PRE_PULL_HOOK = _pre_pull_hook
|
|||
PULL_HOOK = _pull_hook
|
||||
CREATE_PULL_REQUEST = _create_pull_request_hook
|
||||
REVIEW_PULL_REQUEST = _review_pull_request_hook
|
||||
COMMENT_PULL_REQUEST = _comment_pull_request_hook
|
||||
UPDATE_PULL_REQUEST = _update_pull_request_hook
|
||||
MERGE_PULL_REQUEST = _merge_pull_request_hook
|
||||
CLOSE_PULL_REQUEST = _close_pull_request_hook
|
||||
|
|
|
|||
|
|
@ -24,14 +24,13 @@ def _push_hook(*args, **kwargs):
|
|||
# returns list of dicts with key-val fetched from extra fields
|
||||
repo_extra_fields = extra_fields.run(**kwargs)
|
||||
|
||||
if repo_extra_fields.get('endpoint_url'):
|
||||
field_metadata = repo_extra_fields['endpoint_url']
|
||||
endpoint = field_metadata['field_value']
|
||||
if endpoint:
|
||||
data = {
|
||||
'project': kwargs['repository'],
|
||||
}
|
||||
response = http_call.run(url=endpoint, params=data)
|
||||
return HookResponse(0, 'Called endpoint {}, with response {}\n'.format(endpoint, response))
|
||||
endpoint_url = extra_fields.get_field(repo_extra_fields, key='endpoint_url', default='')
|
||||
|
||||
if endpoint_url:
|
||||
data = {
|
||||
'project': kwargs['repository'],
|
||||
}
|
||||
response = http_call.run(url=endpoint_url, params=data)
|
||||
return HookResponse(0, 'Called endpoint {}, with response {}\n'.format(endpoint_url, response))
|
||||
|
||||
return HookResponse(0, '')
|
||||
|
|
|
|||
|
|
@ -24,14 +24,12 @@ def _push_hook(*args, **kwargs):
|
|||
# returns list of dicts with key-val fetched from extra fields
|
||||
repo_extra_fields = extra_fields.run(**kwargs)
|
||||
|
||||
if repo_extra_fields.get('endpoint_url'):
|
||||
field_metadata = repo_extra_fields['endpoint_url']
|
||||
endpoint = field_metadata['field_value']
|
||||
if endpoint:
|
||||
data = {
|
||||
'some_key': 'val'
|
||||
}
|
||||
response = http_call.run(url=endpoint, json_data=data)
|
||||
return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint, response))
|
||||
endpoint_url = extra_fields.get_field(repo_extra_fields, key='endpoint_url', default='')
|
||||
if endpoint_url:
|
||||
data = {
|
||||
'some_key': 'val'
|
||||
}
|
||||
response = http_call.run(url=endpoint_url, json_data=data)
|
||||
return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint_url, response))
|
||||
|
||||
return HookResponse(0, '')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
# Example to trigger a CI call action on specific comment text, e.g chatops and ci
|
||||
# rebuild on mention of ci bot
|
||||
|
||||
@has_kwargs({
|
||||
'repo_name': '',
|
||||
'repo_type': '',
|
||||
'description': '',
|
||||
'private': '',
|
||||
'created_on': '',
|
||||
'enable_downloads': '',
|
||||
'repo_id': '',
|
||||
'user_id': '',
|
||||
'enable_statistics': '',
|
||||
'clone_uri': '',
|
||||
'fork_id': '',
|
||||
'group_id': '',
|
||||
'created_by': '',
|
||||
'repository': '',
|
||||
'comment': '',
|
||||
'commit': ''
|
||||
})
|
||||
def _comment_commit_repo_hook(*args, **kwargs):
|
||||
"""
|
||||
POST CREATE REPOSITORY COMMENT ON COMMIT HOOK. This function will be executed after
|
||||
a comment is made on this repository commit.
|
||||
|
||||
"""
|
||||
from .helpers import http_call, extra_fields
|
||||
from .utils import UrlTemplate
|
||||
# returns list of dicts with key-val fetched from extra fields
|
||||
repo_extra_fields = extra_fields.run(**kwargs)
|
||||
|
||||
import rhodecode
|
||||
from rc_integrations.jenkins_ci import csrf_call, get_auth, requests_retry_call
|
||||
|
||||
endpoint_url = extra_fields.get_field(
|
||||
repo_extra_fields, key='ci_endpoint_url',
|
||||
default='http://ci.rc.com/job/rc-ce-commits/build?COMMIT_ID=${commit}')
|
||||
mention_text = extra_fields.get_field(
|
||||
repo_extra_fields, key='ci_mention_text',
|
||||
default='@jenkins build')
|
||||
|
||||
endpoint_url = UrlTemplate(endpoint_url).safe_substitute(
|
||||
commit=kwargs['commit']['raw_id'])
|
||||
|
||||
trigger_ci = False
|
||||
comment = kwargs['comment']['comment_text']
|
||||
if mention_text in comment:
|
||||
trigger_ci = True
|
||||
|
||||
if trigger_ci is False:
|
||||
return HookResponse(0, '')
|
||||
|
||||
# call some CI based on the special coment mention marker
|
||||
data = {
|
||||
'project': kwargs['repository'],
|
||||
}
|
||||
response = http_call.run(url=endpoint_url, params=data)
|
||||
|
||||
return HookResponse(0, '')
|
||||
|
|
@ -41,11 +41,13 @@ def _pre_push_hook(*args, **kwargs):
|
|||
repo_extra_fields = extra_fields.run(**kwargs)
|
||||
|
||||
# optionally use 'extra fields' to control the logic per repo
|
||||
validate_author = repo_extra_fields.get('validate_author', {}).get('field_value')
|
||||
validate_author = extra_fields.get_field(
|
||||
repo_extra_fields, key='validate_author', default=False)
|
||||
should_validate = str2bool(validate_author)
|
||||
|
||||
# optionally store validation regex into extra fields
|
||||
validation_regex = repo_extra_fields.get('validation_regex', {}).get('field_value')
|
||||
validation_regex = extra_fields.get_field(
|
||||
repo_extra_fields, key='validation_regex', default='')
|
||||
|
||||
def validate_commit_message(commit_message, message_regex=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -44,13 +44,16 @@ def _pre_push_hook(*args, **kwargs):
|
|||
|
||||
# optionally use 'extra fields' to control the logic per repo
|
||||
# e.g store a list of patterns to be forbidden e.g `*.exe, *.dump`
|
||||
forbid_files = repo_extra_fields.get('forbid_files_glob', {}).get('field_value')
|
||||
forbid_files = extra_fields.get_field(repo_extra_fields, key='forbid_files_glob',
|
||||
convert_type=False, default=[])
|
||||
forbid_files = aslist(forbid_files)
|
||||
|
||||
# forbid_files = ['*'] # example pattern
|
||||
|
||||
# optionally get bytes limit for a single file, e.g 1024 for 1KB
|
||||
forbid_size_over = repo_extra_fields.get('forbid_size_over', {}).get('field_value')
|
||||
forbid_size_over = extra_fields.get_field(repo_extra_fields, key='forbid_size_over',
|
||||
convert_type=False, default=0)
|
||||
|
||||
forbid_size_over = int(forbid_size_over or 0)
|
||||
|
||||
# forbid_size_over = 1024 # example 1024
|
||||
|
|
|
|||
|
|
@ -53,3 +53,36 @@ def run(*args, **kwargs):
|
|||
fields[field.field_key] = field.get_dict()
|
||||
|
||||
return fields
|
||||
|
||||
|
||||
class _Undefined(object):
|
||||
pass
|
||||
|
||||
|
||||
def get_field(extra_fields_data, key, default=_Undefined(), convert_type=True):
|
||||
"""
|
||||
field_value = get_field(extra_fields, key='ci_endpoint_url', default='')
|
||||
"""
|
||||
from ..utils import str2bool, aslist
|
||||
|
||||
if key not in extra_fields_data:
|
||||
if isinstance(default, _Undefined):
|
||||
raise ValueError('key {} not present in extra_fields'.format(key))
|
||||
return default
|
||||
|
||||
# NOTE(dan): from metadata we get field_label, field_value, field_desc, field_type
|
||||
field_metadata = extra_fields_data[key]
|
||||
|
||||
field_value = field_metadata['field_value']
|
||||
|
||||
# NOTE(dan): empty value, use default
|
||||
if not field_value and not isinstance(default, _Undefined):
|
||||
return default
|
||||
|
||||
if convert_type:
|
||||
# 'str', 'unicode', 'list', 'tuple'
|
||||
_type = field_metadata['field_type']
|
||||
if _type in ['list', 'tuple']:
|
||||
field_value = aslist(field_value)
|
||||
|
||||
return field_value
|
||||
|
|
|
|||
|
|
@ -15,10 +15,11 @@
|
|||
# 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
|
||||
from .utils import DotDict, HookResponse, has_kwargs
|
||||
log = logging.getLogger('rhodecode.' + __name__)
|
||||
|
||||
log = logging.getLogger('rhodecode.' + __name__)
|
||||
|
||||
# Config shortcut to keep, all configuration in one place
|
||||
# Example: api_key = CONFIG.my_config.api_key
|
||||
|
|
@ -55,13 +56,40 @@ def _create_repo_hook(*args, **kwargs):
|
|||
|
||||
|
||||
@has_kwargs({
|
||||
'group_name': '',
|
||||
'group_parent_id': '',
|
||||
'repo_name': '',
|
||||
'repo_type': '',
|
||||
'description': '',
|
||||
'private': '',
|
||||
'created_on': '',
|
||||
'enable_downloads': '',
|
||||
'repo_id': '',
|
||||
'user_id': '',
|
||||
'enable_statistics': '',
|
||||
'clone_uri': '',
|
||||
'fork_id': '',
|
||||
'group_id': '',
|
||||
'created_by': '',
|
||||
'repository': '',
|
||||
'comment': '',
|
||||
'commit': ''
|
||||
})
|
||||
def _comment_commit_repo_hook(*args, **kwargs):
|
||||
"""
|
||||
POST CREATE REPOSITORY COMMENT ON COMMIT HOOK. This function will be executed after
|
||||
a comment is made on this repository commit.
|
||||
|
||||
"""
|
||||
return HookResponse(0, '')
|
||||
|
||||
|
||||
@has_kwargs({
|
||||
'group_name': '',
|
||||
'group_parent_id': '',
|
||||
'group_description': '',
|
||||
'group_id': '',
|
||||
'user_id': '',
|
||||
'created_by': '',
|
||||
'created_on': '',
|
||||
'group_id': '',
|
||||
'user_id': '',
|
||||
'created_by': '',
|
||||
'created_on': '',
|
||||
'enable_locking': ''
|
||||
})
|
||||
def _create_repo_group_hook(*args, **kwargs):
|
||||
|
|
@ -73,13 +101,13 @@ def _create_repo_group_hook(*args, **kwargs):
|
|||
|
||||
|
||||
@has_kwargs({
|
||||
'username': '',
|
||||
'password': '',
|
||||
'email': '',
|
||||
'username': '',
|
||||
'password': '',
|
||||
'email': '',
|
||||
'firstname': '',
|
||||
'lastname': '',
|
||||
'active': '',
|
||||
'admin': '',
|
||||
'lastname': '',
|
||||
'active': '',
|
||||
'admin': '',
|
||||
'created_by': '',
|
||||
})
|
||||
def _pre_create_user_hook(*args, **kwargs):
|
||||
|
|
@ -173,7 +201,7 @@ def _delete_repo_hook(*args, **kwargs):
|
|||
'emails': '',
|
||||
'inherit_default_permissions': '',
|
||||
'deleted_by': '',
|
||||
})
|
||||
})
|
||||
def _delete_user_hook(*args, **kwargs):
|
||||
"""
|
||||
POST DELETE USER HOOK, this function will be executed after each
|
||||
|
|
@ -342,6 +370,38 @@ def _review_pull_request_hook(*args, **kwargs):
|
|||
return HookResponse(0, '')
|
||||
|
||||
|
||||
@has_kwargs({
|
||||
'server_url': 'url of instance that triggered this hook',
|
||||
'config': 'path to .ini config used',
|
||||
'scm': 'type of version control "git", "hg", "svn"',
|
||||
'username': 'username of actor who triggered this event',
|
||||
'ip': 'ip address of actor who triggered this hook',
|
||||
|
||||
'action': '',
|
||||
'repository': 'repository name',
|
||||
'pull_request_id': '',
|
||||
'url': '',
|
||||
'title': '',
|
||||
'description': '',
|
||||
'status': '',
|
||||
'comment': '',
|
||||
'created_on': '',
|
||||
'updated_on': '',
|
||||
'commit_ids': '',
|
||||
'review_status': '',
|
||||
'mergeable': '',
|
||||
'source': '',
|
||||
'target': '',
|
||||
'author': '',
|
||||
'reviewers': '',
|
||||
})
|
||||
def _comment_pull_request_hook(*args, **kwargs):
|
||||
"""
|
||||
This hook will be executed after comment is made on a pull request
|
||||
"""
|
||||
return HookResponse(0, '')
|
||||
|
||||
|
||||
@has_kwargs({
|
||||
'server_url': 'url of instance that triggered this hook',
|
||||
'config': 'path to .ini config used',
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import logging
|
||||
import os
|
||||
import string
|
||||
import functools
|
||||
import collections
|
||||
import urllib
|
||||
|
||||
log = logging.getLogger('rhodecode.' + __name__)
|
||||
|
||||
|
|
@ -186,4 +188,12 @@ def aslist(obj, sep=None, strip=True):
|
|||
elif obj is None:
|
||||
return []
|
||||
else:
|
||||
return [obj]
|
||||
return [obj]
|
||||
|
||||
|
||||
class UrlTemplate(string.Template):
|
||||
|
||||
def safe_substitute(self, **kws):
|
||||
# url encode the kw for usage in url
|
||||
kws = {k: urllib.quote(str(v)) for k, v in kws.items()}
|
||||
return super(UrlTemplate, self).safe_substitute(**kws)
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ from rhodecode.events.user import ( # pragma: no cover
|
|||
)
|
||||
|
||||
from rhodecode.events.repo import ( # pragma: no cover
|
||||
RepoEvent,
|
||||
RepoEvent, RepoCommitCommentEvent,
|
||||
RepoPreCreateEvent, RepoCreateEvent,
|
||||
RepoPreDeleteEvent, RepoDeleteEvent,
|
||||
RepoPrePushEvent, RepoPushEvent,
|
||||
|
|
|
|||
|
|
@ -181,6 +181,20 @@ class RepoEvent(RhodeCodeIntegrationEvent):
|
|||
return data
|
||||
|
||||
|
||||
class RepoCommitCommentEvent(RepoEvent):
|
||||
"""
|
||||
An instance of this class is emitted as an :term:`event` after a comment is made
|
||||
on repository commit.
|
||||
"""
|
||||
def __init__(self, repo, commit, comment):
|
||||
super(RepoCommitCommentEvent, self).__init__(repo)
|
||||
self.commit = commit
|
||||
self.comment = comment
|
||||
|
||||
name = 'repo-commit-comment'
|
||||
display_name = lazy_ugettext('repository commit comment')
|
||||
|
||||
|
||||
class RepoPreCreateEvent(RepoEvent):
|
||||
"""
|
||||
An instance of this class is emitted as an :term:`event` before a repo is
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ Set of hooks run by RhodeCode Enterprise
|
|||
"""
|
||||
|
||||
import os
|
||||
import collections
|
||||
import logging
|
||||
|
||||
import rhodecode
|
||||
|
|
@ -349,8 +348,8 @@ class ExtensionCallback(object):
|
|||
try:
|
||||
kwargs_to_pass[key] = kwargs[key]
|
||||
except KeyError:
|
||||
log.error('Failed to fetch %s key. Expected keys: %s',
|
||||
key, self._kwargs_keys)
|
||||
log.error('Failed to fetch %s key from given kwargs. '
|
||||
'Expected keys: %s', key, self._kwargs_keys)
|
||||
raise
|
||||
|
||||
# backward compat for removed api_key for old hooks. This was it works
|
||||
|
|
@ -437,6 +436,15 @@ log_review_pull_request = ExtensionCallback(
|
|||
'mergeable', 'source', 'target', 'author', 'reviewers'))
|
||||
|
||||
|
||||
log_comment_pull_request = ExtensionCallback(
|
||||
hook_name='COMMENT_PULL_REQUEST',
|
||||
kwargs_keys=(
|
||||
'server_url', 'config', 'scm', 'username', 'ip', 'action',
|
||||
'repository', 'pull_request_id', 'url', 'title', 'description',
|
||||
'status', 'comment', 'created_on', 'updated_on', 'commit_ids', 'review_status',
|
||||
'mergeable', 'source', 'target', 'author', 'reviewers'))
|
||||
|
||||
|
||||
log_update_pull_request = ExtensionCallback(
|
||||
hook_name='UPDATE_PULL_REQUEST',
|
||||
kwargs_keys=(
|
||||
|
|
@ -484,6 +492,15 @@ log_delete_repository = ExtensionCallback(
|
|||
'clone_uri', 'fork_id', 'group_id', 'deleted_by', 'deleted_on'))
|
||||
|
||||
|
||||
log_comment_commit_repository = ExtensionCallback(
|
||||
hook_name='COMMENT_COMMIT_REPO_HOOK',
|
||||
kwargs_keys=(
|
||||
'repo_name', 'repo_type', 'description', 'private', 'created_on',
|
||||
'enable_downloads', 'repo_id', 'user_id', 'enable_statistics',
|
||||
'clone_uri', 'fork_id', 'group_id',
|
||||
'repository', 'created_by', 'comment', 'commit'))
|
||||
|
||||
|
||||
log_create_repository_group = ExtensionCallback(
|
||||
hook_name='CREATE_REPO_GROUP_HOOK',
|
||||
kwargs_keys=(
|
||||
|
|
|
|||
|
|
@ -26,144 +26,190 @@ from rhodecode.lib import hooks_base
|
|||
from rhodecode.lib import utils2
|
||||
|
||||
|
||||
def _get_rc_scm_extras(username, repo_name, repo_alias, action):
|
||||
# TODO: johbo: Replace by vcs_operation_context and remove fully
|
||||
def _supports_repo_type(repo_type):
|
||||
if repo_type in ('hg', 'git'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _get_vcs_operation_context(username, repo_name, repo_type, action):
|
||||
# NOTE(dan): import loop
|
||||
from rhodecode.lib.base import vcs_operation_context
|
||||
|
||||
check_locking = action in ('pull', 'push')
|
||||
|
||||
request = get_current_request()
|
||||
|
||||
# default
|
||||
dummy_environ = webob.Request.blank('').environ
|
||||
try:
|
||||
environ = request.environ or dummy_environ
|
||||
environ = request.environ
|
||||
except TypeError:
|
||||
# we might use this outside of request context
|
||||
environ = dummy_environ
|
||||
environ = {}
|
||||
|
||||
extras = vcs_operation_context(
|
||||
environ, repo_name, username, action, repo_alias, check_locking)
|
||||
if not environ:
|
||||
environ = webob.Request.blank('').environ
|
||||
|
||||
extras = vcs_operation_context(environ, repo_name, username, action, repo_type, check_locking)
|
||||
return utils2.AttributeDict(extras)
|
||||
|
||||
|
||||
def trigger_post_push_hook(
|
||||
username, action, hook_type, repo_name, repo_alias, commit_ids):
|
||||
def trigger_post_push_hook(username, action, hook_type, repo_name, repo_type, commit_ids):
|
||||
"""
|
||||
Triggers push action hooks
|
||||
|
||||
:param username: username who pushes
|
||||
:param action: push/push_local/push_remote
|
||||
:param hook_type: type of hook executed
|
||||
:param repo_name: name of repo
|
||||
:param repo_alias: the type of SCM repo
|
||||
:param repo_type: the type of SCM repo
|
||||
:param commit_ids: list of commit ids that we pushed
|
||||
"""
|
||||
extras = _get_rc_scm_extras(username, repo_name, repo_alias, action)
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, action)
|
||||
extras.commit_ids = commit_ids
|
||||
extras.hook_type = hook_type
|
||||
hooks_base.post_push(extras)
|
||||
|
||||
|
||||
def trigger_log_create_pull_request_hook(username, repo_name, repo_alias,
|
||||
pull_request, data=None):
|
||||
def trigger_comment_commit_hooks(username, repo_name, repo_type, repo, data=None):
|
||||
"""
|
||||
Triggers when a comment is made on a commit
|
||||
|
||||
:param username: username who creates the comment
|
||||
:param repo_name: name of target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param repo: the repo object we trigger the event for
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj, 'commit': commit_obj}
|
||||
"""
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'comment_commit')
|
||||
|
||||
comment = data['comment']
|
||||
commit = data['commit']
|
||||
|
||||
events.trigger(events.RepoCommitCommentEvent(repo, commit, comment))
|
||||
extras.update(repo.get_dict())
|
||||
|
||||
extras.commit = commit.serialize()
|
||||
extras.comment = comment.get_api_data()
|
||||
extras.created_by = username
|
||||
hooks_base.log_comment_commit_repository(**extras)
|
||||
|
||||
|
||||
def trigger_create_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
|
||||
"""
|
||||
Triggers create pull request action hooks
|
||||
|
||||
:param username: username who creates the pull request
|
||||
:param repo_name: name of target repo
|
||||
:param repo_alias: the type of SCM target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param pull_request: the pull request that was created
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj}
|
||||
"""
|
||||
if repo_alias not in ('hg', 'git'):
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_rc_scm_extras(username, repo_name, repo_alias,
|
||||
'create_pull_request')
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'create_pull_request')
|
||||
events.trigger(events.PullRequestCreateEvent(pull_request))
|
||||
extras.update(pull_request.get_api_data(with_merge_state=False))
|
||||
hooks_base.log_create_pull_request(**extras)
|
||||
|
||||
|
||||
def trigger_log_merge_pull_request_hook(username, repo_name, repo_alias,
|
||||
pull_request, data=None):
|
||||
def trigger_merge_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
|
||||
"""
|
||||
Triggers merge pull request action hooks
|
||||
|
||||
:param username: username who creates the pull request
|
||||
:param repo_name: name of target repo
|
||||
:param repo_alias: the type of SCM target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param pull_request: the pull request that was merged
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj}
|
||||
"""
|
||||
if repo_alias not in ('hg', 'git'):
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_rc_scm_extras(username, repo_name, repo_alias,
|
||||
'merge_pull_request')
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'merge_pull_request')
|
||||
events.trigger(events.PullRequestMergeEvent(pull_request))
|
||||
extras.update(pull_request.get_api_data())
|
||||
hooks_base.log_merge_pull_request(**extras)
|
||||
|
||||
|
||||
def trigger_log_close_pull_request_hook(username, repo_name, repo_alias,
|
||||
pull_request, data=None):
|
||||
def trigger_close_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
|
||||
"""
|
||||
Triggers close pull request action hooks
|
||||
|
||||
:param username: username who creates the pull request
|
||||
:param repo_name: name of target repo
|
||||
:param repo_alias: the type of SCM target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param pull_request: the pull request that was closed
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj}
|
||||
"""
|
||||
if repo_alias not in ('hg', 'git'):
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_rc_scm_extras(username, repo_name, repo_alias,
|
||||
'close_pull_request')
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'close_pull_request')
|
||||
events.trigger(events.PullRequestCloseEvent(pull_request))
|
||||
extras.update(pull_request.get_api_data())
|
||||
hooks_base.log_close_pull_request(**extras)
|
||||
|
||||
|
||||
def trigger_log_review_pull_request_hook(username, repo_name, repo_alias,
|
||||
pull_request, data=None):
|
||||
def trigger_review_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
|
||||
"""
|
||||
Triggers review status change pull request action hooks
|
||||
|
||||
:param username: username who creates the pull request
|
||||
:param repo_name: name of target repo
|
||||
:param repo_alias: the type of SCM target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param pull_request: the pull request that review status changed
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj}
|
||||
"""
|
||||
if repo_alias not in ('hg', 'git'):
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_rc_scm_extras(username, repo_name, repo_alias,
|
||||
'review_pull_request')
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'review_pull_request')
|
||||
status = data.get('status')
|
||||
events.trigger(events.PullRequestReviewEvent(pull_request, status))
|
||||
extras.update(pull_request.get_api_data())
|
||||
hooks_base.log_review_pull_request(**extras)
|
||||
|
||||
|
||||
def trigger_log_update_pull_request_hook(username, repo_name, repo_alias,
|
||||
pull_request, data=None):
|
||||
def trigger_comment_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
|
||||
"""
|
||||
Triggers when a comment is made on a pull request
|
||||
|
||||
:param username: username who creates the pull request
|
||||
:param repo_name: name of target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param pull_request: the pull request that comment was made on
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj}
|
||||
"""
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'comment_pull_request')
|
||||
|
||||
comment = data['comment']
|
||||
events.trigger(events.PullRequestCommentEvent(pull_request, comment))
|
||||
extras.update(pull_request.get_api_data())
|
||||
extras.comment = comment.get_api_data()
|
||||
hooks_base.log_comment_pull_request(**extras)
|
||||
|
||||
|
||||
def trigger_update_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
|
||||
"""
|
||||
Triggers update pull request action hooks
|
||||
|
||||
:param username: username who creates the pull request
|
||||
:param repo_name: name of target repo
|
||||
:param repo_alias: the type of SCM target repo
|
||||
:param repo_type: the type of SCM target repo
|
||||
:param pull_request: the pull request that was updated
|
||||
:param data: extra data for specific events e.g {'comment': comment_obj}
|
||||
"""
|
||||
if repo_alias not in ('hg', 'git'):
|
||||
if not _supports_repo_type(repo_type):
|
||||
return
|
||||
|
||||
extras = _get_rc_scm_extras(username, repo_name, repo_alias,
|
||||
'update_pull_request')
|
||||
extras = _get_vcs_operation_context(username, repo_name, repo_type, 'update_pull_request')
|
||||
events.trigger(events.PullRequestUpdateEvent(pull_request))
|
||||
extras.update(pull_request.get_api_data())
|
||||
hooks_base.log_update_pull_request(**extras)
|
||||
|
|
|
|||
|
|
@ -925,6 +925,9 @@ class BaseCommit(object):
|
|||
d.pop('repository', None)
|
||||
return d
|
||||
|
||||
def serialize(self):
|
||||
return self.__json__()
|
||||
|
||||
def _get_refs(self):
|
||||
return {
|
||||
'branches': [self.branch] if self.branch else [],
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from pyramid.threadlocal import get_current_registry, get_current_request
|
|||
from sqlalchemy.sql.expression import null
|
||||
from sqlalchemy.sql.functions import coalesce
|
||||
|
||||
from rhodecode.lib import helpers as h, diffs, channelstream
|
||||
from rhodecode.lib import helpers as h, diffs, channelstream, hooks_utils
|
||||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.utils2 import extract_mentioned_users, safe_str
|
||||
from rhodecode.model import BaseModel
|
||||
|
|
@ -720,6 +720,26 @@ class CommentsModel(BaseModel):
|
|||
settings = settings_model.get_general_settings()
|
||||
return settings.get('rhodecode_use_outdated_comments', False)
|
||||
|
||||
def trigger_commit_comment_hook(self, repo, user, action, data=None):
|
||||
repo = self._get_repo(repo)
|
||||
target_scm = repo.scm_instance()
|
||||
if action == 'create':
|
||||
trigger_hook = hooks_utils.trigger_comment_commit_hooks
|
||||
elif action == 'edit':
|
||||
# TODO(dan): when this is supported we trigger edit hook too
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
log.debug('Handling repo %s trigger_commit_comment_hook with action %s: %s',
|
||||
repo, action, trigger_hook)
|
||||
trigger_hook(
|
||||
username=user.username,
|
||||
repo_name=repo.repo_name,
|
||||
repo_type=target_scm.alias,
|
||||
repo=repo,
|
||||
data=data)
|
||||
|
||||
|
||||
def _parse_comment_line_number(line_no):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -542,8 +542,7 @@ class PullRequestModel(BaseModel):
|
|||
pull_request, auth_user=auth_user, translator=translator)
|
||||
|
||||
self.notify_reviewers(pull_request, reviewer_ids)
|
||||
self.trigger_pull_request_hook(
|
||||
pull_request, created_by_user, 'create')
|
||||
self.trigger_pull_request_hook(pull_request, created_by_user, 'create')
|
||||
|
||||
creation_data = pull_request.get_api_data(with_merge_state=False)
|
||||
self._log_audit_action(
|
||||
|
|
@ -556,28 +555,26 @@ class PullRequestModel(BaseModel):
|
|||
pull_request = self.__get_pull_request(pull_request)
|
||||
target_scm = pull_request.target_repo.scm_instance()
|
||||
if action == 'create':
|
||||
trigger_hook = hooks_utils.trigger_log_create_pull_request_hook
|
||||
trigger_hook = hooks_utils.trigger_create_pull_request_hook
|
||||
elif action == 'merge':
|
||||
trigger_hook = hooks_utils.trigger_log_merge_pull_request_hook
|
||||
trigger_hook = hooks_utils.trigger_merge_pull_request_hook
|
||||
elif action == 'close':
|
||||
trigger_hook = hooks_utils.trigger_log_close_pull_request_hook
|
||||
trigger_hook = hooks_utils.trigger_close_pull_request_hook
|
||||
elif action == 'review_status_change':
|
||||
trigger_hook = hooks_utils.trigger_log_review_pull_request_hook
|
||||
trigger_hook = hooks_utils.trigger_review_pull_request_hook
|
||||
elif action == 'update':
|
||||
trigger_hook = hooks_utils.trigger_log_update_pull_request_hook
|
||||
trigger_hook = hooks_utils.trigger_update_pull_request_hook
|
||||
elif action == 'comment':
|
||||
# dummy hook ! for comment. We want this function to handle all cases
|
||||
def trigger_hook(*args, **kwargs):
|
||||
pass
|
||||
comment = data['comment']
|
||||
events.trigger(events.PullRequestCommentEvent(pull_request, comment))
|
||||
trigger_hook = hooks_utils.trigger_comment_pull_request_hook
|
||||
else:
|
||||
return
|
||||
|
||||
log.debug('Handling pull_request %s trigger_pull_request_hook with action %s and hook: %s',
|
||||
pull_request, action, trigger_hook)
|
||||
trigger_hook(
|
||||
username=user.username,
|
||||
repo_name=pull_request.target_repo.repo_name,
|
||||
repo_alias=target_scm.alias,
|
||||
repo_type=target_scm.alias,
|
||||
pull_request=pull_request,
|
||||
data=data)
|
||||
|
||||
|
|
@ -1286,8 +1283,7 @@ class PullRequestModel(BaseModel):
|
|||
pull_request.status = PullRequest.STATUS_CLOSED
|
||||
pull_request.updated_on = datetime.datetime.now()
|
||||
Session().add(pull_request)
|
||||
self.trigger_pull_request_hook(
|
||||
pull_request, pull_request.author, 'close')
|
||||
self.trigger_pull_request_hook(pull_request, pull_request.author, 'close')
|
||||
|
||||
pr_data = pull_request.get_api_data(with_merge_state=False)
|
||||
self._log_audit_action(
|
||||
|
|
@ -1333,20 +1329,21 @@ class PullRequestModel(BaseModel):
|
|||
)
|
||||
|
||||
Session().flush()
|
||||
events.trigger(events.PullRequestCommentEvent(pull_request, comment))
|
||||
|
||||
self.trigger_pull_request_hook(pull_request, user, 'comment',
|
||||
data={'comment': comment})
|
||||
|
||||
# we now calculate the status of pull request again, and based on that
|
||||
# calculation trigger status change. This might happen in cases
|
||||
# that non-reviewer admin closes a pr, which means his vote doesn't
|
||||
# change the status, while if he's a reviewer this might change it.
|
||||
calculated_status = pull_request.calculated_review_status()
|
||||
if old_calculated_status != calculated_status:
|
||||
self.trigger_pull_request_hook(
|
||||
pull_request, user, 'review_status_change',
|
||||
data={'status': calculated_status})
|
||||
self.trigger_pull_request_hook(pull_request, user, 'review_status_change',
|
||||
data={'status': calculated_status})
|
||||
|
||||
# finally close the PR
|
||||
PullRequestModel().close_pull_request(
|
||||
pull_request.pull_request_id, user)
|
||||
PullRequestModel().close_pull_request(pull_request.pull_request_id, user)
|
||||
|
||||
return comment, status
|
||||
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ class ScmModel(BaseModel):
|
|||
# We trigger the post-push action
|
||||
hooks_utils.trigger_post_push_hook(
|
||||
username=user.username, action='push_local', hook_type='post_push',
|
||||
repo_name=repo_name, repo_alias=repo.alias, commit_ids=[tip.raw_id])
|
||||
repo_name=repo_name, repo_type=repo.alias, commit_ids=[tip.raw_id])
|
||||
return tip
|
||||
|
||||
def _sanitize_path(self, f_path):
|
||||
|
|
@ -799,7 +799,7 @@ class ScmModel(BaseModel):
|
|||
if trigger_push_hook:
|
||||
hooks_utils.trigger_post_push_hook(
|
||||
username=user.username, action='push_local',
|
||||
repo_name=repo.repo_name, repo_alias=scm_instance.alias,
|
||||
repo_name=repo.repo_name, repo_type=scm_instance.alias,
|
||||
hook_type='post_push',
|
||||
commit_ids=[tip.raw_id])
|
||||
return tip
|
||||
|
|
@ -864,7 +864,7 @@ class ScmModel(BaseModel):
|
|||
if trigger_push_hook:
|
||||
hooks_utils.trigger_post_push_hook(
|
||||
username=user.username, action='push_local', hook_type='post_push',
|
||||
repo_name=repo.repo_name, repo_alias=scm_instance.alias,
|
||||
repo_name=repo.repo_name, repo_type=scm_instance.alias,
|
||||
commit_ids=[tip.raw_id])
|
||||
|
||||
return tip
|
||||
|
|
@ -926,7 +926,7 @@ class ScmModel(BaseModel):
|
|||
if trigger_push_hook:
|
||||
hooks_utils.trigger_post_push_hook(
|
||||
username=user.username, action='push_local', hook_type='post_push',
|
||||
repo_name=repo.repo_name, repo_alias=scm_instance.alias,
|
||||
repo_name=repo.repo_name, repo_type=scm_instance.alias,
|
||||
commit_ids=[tip.raw_id])
|
||||
return tip
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue