##// END OF EJS Templates
hooks: added new hooks for comments on pull requests and commits....
dan -
r4305:de8db8da default
parent child Browse files
Show More
@@ -0,0 +1,60 b''
1 # Example to trigger a CI call action on specific comment text, e.g chatops and ci
2 # rebuild on mention of ci bot
3
4 @has_kwargs({
5 'repo_name': '',
6 'repo_type': '',
7 'description': '',
8 'private': '',
9 'created_on': '',
10 'enable_downloads': '',
11 'repo_id': '',
12 'user_id': '',
13 'enable_statistics': '',
14 'clone_uri': '',
15 'fork_id': '',
16 'group_id': '',
17 'created_by': '',
18 'repository': '',
19 'comment': '',
20 'commit': ''
21 })
22 def _comment_commit_repo_hook(*args, **kwargs):
23 """
24 POST CREATE REPOSITORY COMMENT ON COMMIT HOOK. This function will be executed after
25 a comment is made on this repository commit.
26
27 """
28 from .helpers import http_call, extra_fields
29 from .utils import UrlTemplate
30 # returns list of dicts with key-val fetched from extra fields
31 repo_extra_fields = extra_fields.run(**kwargs)
32
33 import rhodecode
34 from rc_integrations.jenkins_ci import csrf_call, get_auth, requests_retry_call
35
36 endpoint_url = extra_fields.get_field(
37 repo_extra_fields, key='ci_endpoint_url',
38 default='http://ci.rc.com/job/rc-ce-commits/build?COMMIT_ID=${commit}')
39 mention_text = extra_fields.get_field(
40 repo_extra_fields, key='ci_mention_text',
41 default='@jenkins build')
42
43 endpoint_url = UrlTemplate(endpoint_url).safe_substitute(
44 commit=kwargs['commit']['raw_id'])
45
46 trigger_ci = False
47 comment = kwargs['comment']['comment_text']
48 if mention_text in comment:
49 trigger_ci = True
50
51 if trigger_ci is False:
52 return HookResponse(0, '')
53
54 # call some CI based on the special coment mention marker
55 data = {
56 'project': kwargs['repository'],
57 }
58 response = http_call.run(url=endpoint_url, params=data)
59
60 return HookResponse(0, '') No newline at end of file
@@ -1599,7 +1599,8 b' def comment_commit('
1599 validate_repo_permissions(apiuser, repoid, repo, _perms)
1599 validate_repo_permissions(apiuser, repoid, repo, _perms)
1600
1600
1601 try:
1601 try:
1602 commit_id = repo.scm_instance().get_commit(commit_id=commit_id).raw_id
1602 commit = repo.scm_instance().get_commit(commit_id=commit_id)
1603 commit_id = commit.raw_id
1603 except Exception as e:
1604 except Exception as e:
1604 log.exception('Failed to fetch commit')
1605 log.exception('Failed to fetch commit')
1605 raise JSONRPCError(safe_str(e))
1606 raise JSONRPCError(safe_str(e))
@@ -1659,6 +1660,10 b' def comment_commit('
1659 'a closed pull request is not allowed')
1660 'a closed pull request is not allowed')
1660 raise JSONRPCError(msg)
1661 raise JSONRPCError(msg)
1661
1662
1663 CommentsModel().trigger_commit_comment_hook(
1664 repo, apiuser, 'create',
1665 data={'comment': comment, 'commit': commit})
1666
1662 Session().commit()
1667 Session().commit()
1663 return {
1668 return {
1664 'msg': (
1669 'msg': (
@@ -380,6 +380,11 b' class RepoCommitsView(RepoAppView):'
380 'repo_commit', repo_name=self.db_repo_name,
380 'repo_commit', repo_name=self.db_repo_name,
381 commit_id=current_id))
381 commit_id=current_id))
382
382
383 commit = self.db_repo.get_commit(current_id)
384 CommentsModel().trigger_commit_comment_hook(
385 self.db_repo, self._rhodecode_user, 'create',
386 data={'comment': comment, 'commit': commit})
387
383 # finalize, commit and redirect
388 # finalize, commit and redirect
384 Session().commit()
389 Session().commit()
385
390
@@ -25,6 +25,7 b' from .hooks import ('
25 _create_repo_group_hook,
25 _create_repo_group_hook,
26 _pre_create_user_hook,
26 _pre_create_user_hook,
27 _create_user_hook,
27 _create_user_hook,
28 _comment_commit_repo_hook,
28 _delete_repo_hook,
29 _delete_repo_hook,
29 _delete_user_hook,
30 _delete_user_hook,
30 _pre_push_hook,
31 _pre_push_hook,
@@ -33,6 +34,7 b' from .hooks import ('
33 _pull_hook,
34 _pull_hook,
34 _create_pull_request_hook,
35 _create_pull_request_hook,
35 _review_pull_request_hook,
36 _review_pull_request_hook,
37 _comment_pull_request_hook,
36 _update_pull_request_hook,
38 _update_pull_request_hook,
37 _merge_pull_request_hook,
39 _merge_pull_request_hook,
38 _close_pull_request_hook,
40 _close_pull_request_hook,
@@ -40,6 +42,7 b' from .hooks import ('
40
42
41 # set as module attributes, we use those to call hooks. *do not change this*
43 # set as module attributes, we use those to call hooks. *do not change this*
42 CREATE_REPO_HOOK = _create_repo_hook
44 CREATE_REPO_HOOK = _create_repo_hook
45 COMMENT_COMMIT_REPO_HOOK = _comment_commit_repo_hook
43 CREATE_REPO_GROUP_HOOK = _create_repo_group_hook
46 CREATE_REPO_GROUP_HOOK = _create_repo_group_hook
44 PRE_CREATE_USER_HOOK = _pre_create_user_hook
47 PRE_CREATE_USER_HOOK = _pre_create_user_hook
45 CREATE_USER_HOOK = _create_user_hook
48 CREATE_USER_HOOK = _create_user_hook
@@ -51,6 +54,7 b' PRE_PULL_HOOK = _pre_pull_hook'
51 PULL_HOOK = _pull_hook
54 PULL_HOOK = _pull_hook
52 CREATE_PULL_REQUEST = _create_pull_request_hook
55 CREATE_PULL_REQUEST = _create_pull_request_hook
53 REVIEW_PULL_REQUEST = _review_pull_request_hook
56 REVIEW_PULL_REQUEST = _review_pull_request_hook
57 COMMENT_PULL_REQUEST = _comment_pull_request_hook
54 UPDATE_PULL_REQUEST = _update_pull_request_hook
58 UPDATE_PULL_REQUEST = _update_pull_request_hook
55 MERGE_PULL_REQUEST = _merge_pull_request_hook
59 MERGE_PULL_REQUEST = _merge_pull_request_hook
56 CLOSE_PULL_REQUEST = _close_pull_request_hook
60 CLOSE_PULL_REQUEST = _close_pull_request_hook
@@ -24,14 +24,13 b' def _push_hook(*args, **kwargs):'
24 # returns list of dicts with key-val fetched from extra fields
24 # returns list of dicts with key-val fetched from extra fields
25 repo_extra_fields = extra_fields.run(**kwargs)
25 repo_extra_fields = extra_fields.run(**kwargs)
26
26
27 if repo_extra_fields.get('endpoint_url'):
27 endpoint_url = extra_fields.get_field(repo_extra_fields, key='endpoint_url', default='')
28 field_metadata = repo_extra_fields['endpoint_url']
28
29 endpoint = field_metadata['field_value']
29 if endpoint_url:
30 if endpoint:
30 data = {
31 data = {
31 'project': kwargs['repository'],
32 'project': kwargs['repository'],
32 }
33 }
33 response = http_call.run(url=endpoint_url, params=data)
34 response = http_call.run(url=endpoint, params=data)
34 return HookResponse(0, 'Called endpoint {}, with response {}\n'.format(endpoint_url, response))
35 return HookResponse(0, 'Called endpoint {}, with response {}\n'.format(endpoint, response))
36
35
37 return HookResponse(0, '')
36 return HookResponse(0, '')
@@ -24,14 +24,12 b' def _push_hook(*args, **kwargs):'
24 # returns list of dicts with key-val fetched from extra fields
24 # returns list of dicts with key-val fetched from extra fields
25 repo_extra_fields = extra_fields.run(**kwargs)
25 repo_extra_fields = extra_fields.run(**kwargs)
26
26
27 if repo_extra_fields.get('endpoint_url'):
27 endpoint_url = extra_fields.get_field(repo_extra_fields, key='endpoint_url', default='')
28 field_metadata = repo_extra_fields['endpoint_url']
28 if endpoint_url:
29 endpoint = field_metadata['field_value']
29 data = {
30 if endpoint:
30 'some_key': 'val'
31 data = {
31 }
32 'some_key': 'val'
32 response = http_call.run(url=endpoint_url, json_data=data)
33 }
33 return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint_url, response))
34 response = http_call.run(url=endpoint, json_data=data)
35 return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint, response))
36
34
37 return HookResponse(0, '')
35 return HookResponse(0, '')
@@ -41,11 +41,13 b' def _pre_push_hook(*args, **kwargs):'
41 repo_extra_fields = extra_fields.run(**kwargs)
41 repo_extra_fields = extra_fields.run(**kwargs)
42
42
43 # optionally use 'extra fields' to control the logic per repo
43 # optionally use 'extra fields' to control the logic per repo
44 validate_author = repo_extra_fields.get('validate_author', {}).get('field_value')
44 validate_author = extra_fields.get_field(
45 repo_extra_fields, key='validate_author', default=False)
45 should_validate = str2bool(validate_author)
46 should_validate = str2bool(validate_author)
46
47
47 # optionally store validation regex into extra fields
48 # optionally store validation regex into extra fields
48 validation_regex = repo_extra_fields.get('validation_regex', {}).get('field_value')
49 validation_regex = extra_fields.get_field(
50 repo_extra_fields, key='validation_regex', default='')
49
51
50 def validate_commit_message(commit_message, message_regex=None):
52 def validate_commit_message(commit_message, message_regex=None):
51 """
53 """
@@ -44,13 +44,16 b' def _pre_push_hook(*args, **kwargs):'
44
44
45 # optionally use 'extra fields' to control the logic per repo
45 # optionally use 'extra fields' to control the logic per repo
46 # e.g store a list of patterns to be forbidden e.g `*.exe, *.dump`
46 # e.g store a list of patterns to be forbidden e.g `*.exe, *.dump`
47 forbid_files = repo_extra_fields.get('forbid_files_glob', {}).get('field_value')
47 forbid_files = extra_fields.get_field(repo_extra_fields, key='forbid_files_glob',
48 convert_type=False, default=[])
48 forbid_files = aslist(forbid_files)
49 forbid_files = aslist(forbid_files)
49
50
50 # forbid_files = ['*'] # example pattern
51 # forbid_files = ['*'] # example pattern
51
52
52 # optionally get bytes limit for a single file, e.g 1024 for 1KB
53 # optionally get bytes limit for a single file, e.g 1024 for 1KB
53 forbid_size_over = repo_extra_fields.get('forbid_size_over', {}).get('field_value')
54 forbid_size_over = extra_fields.get_field(repo_extra_fields, key='forbid_size_over',
55 convert_type=False, default=0)
56
54 forbid_size_over = int(forbid_size_over or 0)
57 forbid_size_over = int(forbid_size_over or 0)
55
58
56 # forbid_size_over = 1024 # example 1024
59 # forbid_size_over = 1024 # example 1024
@@ -53,3 +53,36 b' def run(*args, **kwargs):'
53 fields[field.field_key] = field.get_dict()
53 fields[field.field_key] = field.get_dict()
54
54
55 return fields
55 return fields
56
57
58 class _Undefined(object):
59 pass
60
61
62 def get_field(extra_fields_data, key, default=_Undefined(), convert_type=True):
63 """
64 field_value = get_field(extra_fields, key='ci_endpoint_url', default='')
65 """
66 from ..utils import str2bool, aslist
67
68 if key not in extra_fields_data:
69 if isinstance(default, _Undefined):
70 raise ValueError('key {} not present in extra_fields'.format(key))
71 return default
72
73 # NOTE(dan): from metadata we get field_label, field_value, field_desc, field_type
74 field_metadata = extra_fields_data[key]
75
76 field_value = field_metadata['field_value']
77
78 # NOTE(dan): empty value, use default
79 if not field_value and not isinstance(default, _Undefined):
80 return default
81
82 if convert_type:
83 # 'str', 'unicode', 'list', 'tuple'
84 _type = field_metadata['field_type']
85 if _type in ['list', 'tuple']:
86 field_value = aslist(field_value)
87
88 return field_value
@@ -15,11 +15,12 b''
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18 import logging
19 import logging
19 from .utils import DotDict, HookResponse, has_kwargs
20 from .utils import DotDict, HookResponse, has_kwargs
21
20 log = logging.getLogger('rhodecode.' + __name__)
22 log = logging.getLogger('rhodecode.' + __name__)
21
23
22
23 # Config shortcut to keep, all configuration in one place
24 # Config shortcut to keep, all configuration in one place
24 # Example: api_key = CONFIG.my_config.api_key
25 # Example: api_key = CONFIG.my_config.api_key
25 CONFIG = DotDict(
26 CONFIG = DotDict(
@@ -55,13 +56,40 b' def _create_repo_hook(*args, **kwargs):'
55
56
56
57
57 @has_kwargs({
58 @has_kwargs({
58 'group_name': '',
59 'repo_name': '',
59 'group_parent_id': '',
60 'repo_type': '',
61 'description': '',
62 'private': '',
63 'created_on': '',
64 'enable_downloads': '',
65 'repo_id': '',
66 'user_id': '',
67 'enable_statistics': '',
68 'clone_uri': '',
69 'fork_id': '',
70 'group_id': '',
71 'created_by': '',
72 'repository': '',
73 'comment': '',
74 'commit': ''
75 })
76 def _comment_commit_repo_hook(*args, **kwargs):
77 """
78 POST CREATE REPOSITORY COMMENT ON COMMIT HOOK. This function will be executed after
79 a comment is made on this repository commit.
80
81 """
82 return HookResponse(0, '')
83
84
85 @has_kwargs({
86 'group_name': '',
87 'group_parent_id': '',
60 'group_description': '',
88 'group_description': '',
61 'group_id': '',
89 'group_id': '',
62 'user_id': '',
90 'user_id': '',
63 'created_by': '',
91 'created_by': '',
64 'created_on': '',
92 'created_on': '',
65 'enable_locking': ''
93 'enable_locking': ''
66 })
94 })
67 def _create_repo_group_hook(*args, **kwargs):
95 def _create_repo_group_hook(*args, **kwargs):
@@ -73,13 +101,13 b' def _create_repo_group_hook(*args, **kwa'
73
101
74
102
75 @has_kwargs({
103 @has_kwargs({
76 'username': '',
104 'username': '',
77 'password': '',
105 'password': '',
78 'email': '',
106 'email': '',
79 'firstname': '',
107 'firstname': '',
80 'lastname': '',
108 'lastname': '',
81 'active': '',
109 'active': '',
82 'admin': '',
110 'admin': '',
83 'created_by': '',
111 'created_by': '',
84 })
112 })
85 def _pre_create_user_hook(*args, **kwargs):
113 def _pre_create_user_hook(*args, **kwargs):
@@ -173,7 +201,7 b' def _delete_repo_hook(*args, **kwargs):'
173 'emails': '',
201 'emails': '',
174 'inherit_default_permissions': '',
202 'inherit_default_permissions': '',
175 'deleted_by': '',
203 'deleted_by': '',
176 })
204 })
177 def _delete_user_hook(*args, **kwargs):
205 def _delete_user_hook(*args, **kwargs):
178 """
206 """
179 POST DELETE USER HOOK, this function will be executed after each
207 POST DELETE USER HOOK, this function will be executed after each
@@ -348,6 +376,38 b' def _review_pull_request_hook(*args, **k'
348 'scm': 'type of version control "git", "hg", "svn"',
376 'scm': 'type of version control "git", "hg", "svn"',
349 'username': 'username of actor who triggered this event',
377 'username': 'username of actor who triggered this event',
350 'ip': 'ip address of actor who triggered this hook',
378 'ip': 'ip address of actor who triggered this hook',
379
380 'action': '',
381 'repository': 'repository name',
382 'pull_request_id': '',
383 'url': '',
384 'title': '',
385 'description': '',
386 'status': '',
387 'comment': '',
388 'created_on': '',
389 'updated_on': '',
390 'commit_ids': '',
391 'review_status': '',
392 'mergeable': '',
393 'source': '',
394 'target': '',
395 'author': '',
396 'reviewers': '',
397 })
398 def _comment_pull_request_hook(*args, **kwargs):
399 """
400 This hook will be executed after comment is made on a pull request
401 """
402 return HookResponse(0, '')
403
404
405 @has_kwargs({
406 'server_url': 'url of instance that triggered this hook',
407 'config': 'path to .ini config used',
408 'scm': 'type of version control "git", "hg", "svn"',
409 'username': 'username of actor who triggered this event',
410 'ip': 'ip address of actor who triggered this hook',
351 'action': '',
411 'action': '',
352 'repository': 'repository name',
412 'repository': 'repository name',
353 'pull_request_id': '',
413 'pull_request_id': '',
@@ -18,8 +18,10 b''
18
18
19 import logging
19 import logging
20 import os
20 import os
21 import string
21 import functools
22 import functools
22 import collections
23 import collections
24 import urllib
23
25
24 log = logging.getLogger('rhodecode.' + __name__)
26 log = logging.getLogger('rhodecode.' + __name__)
25
27
@@ -186,4 +188,12 b' def aslist(obj, sep=None, strip=True):'
186 elif obj is None:
188 elif obj is None:
187 return []
189 return []
188 else:
190 else:
189 return [obj] No newline at end of file
191 return [obj]
192
193
194 class UrlTemplate(string.Template):
195
196 def safe_substitute(self, **kws):
197 # url encode the kw for usage in url
198 kws = {k: urllib.quote(str(v)) for k, v in kws.items()}
199 return super(UrlTemplate, self).safe_substitute(**kws)
@@ -53,7 +53,7 b' from rhodecode.events.user import ( # p'
53 )
53 )
54
54
55 from rhodecode.events.repo import ( # pragma: no cover
55 from rhodecode.events.repo import ( # pragma: no cover
56 RepoEvent,
56 RepoEvent, RepoCommitCommentEvent,
57 RepoPreCreateEvent, RepoCreateEvent,
57 RepoPreCreateEvent, RepoCreateEvent,
58 RepoPreDeleteEvent, RepoDeleteEvent,
58 RepoPreDeleteEvent, RepoDeleteEvent,
59 RepoPrePushEvent, RepoPushEvent,
59 RepoPrePushEvent, RepoPushEvent,
@@ -181,6 +181,20 b' class RepoEvent(RhodeCodeIntegrationEven'
181 return data
181 return data
182
182
183
183
184 class RepoCommitCommentEvent(RepoEvent):
185 """
186 An instance of this class is emitted as an :term:`event` after a comment is made
187 on repository commit.
188 """
189 def __init__(self, repo, commit, comment):
190 super(RepoCommitCommentEvent, self).__init__(repo)
191 self.commit = commit
192 self.comment = comment
193
194 name = 'repo-commit-comment'
195 display_name = lazy_ugettext('repository commit comment')
196
197
184 class RepoPreCreateEvent(RepoEvent):
198 class RepoPreCreateEvent(RepoEvent):
185 """
199 """
186 An instance of this class is emitted as an :term:`event` before a repo is
200 An instance of this class is emitted as an :term:`event` before a repo is
@@ -24,7 +24,6 b' Set of hooks run by RhodeCode Enterprise'
24 """
24 """
25
25
26 import os
26 import os
27 import collections
28 import logging
27 import logging
29
28
30 import rhodecode
29 import rhodecode
@@ -349,8 +348,8 b' class ExtensionCallback(object):'
349 try:
348 try:
350 kwargs_to_pass[key] = kwargs[key]
349 kwargs_to_pass[key] = kwargs[key]
351 except KeyError:
350 except KeyError:
352 log.error('Failed to fetch %s key. Expected keys: %s',
351 log.error('Failed to fetch %s key from given kwargs. '
353 key, self._kwargs_keys)
352 'Expected keys: %s', key, self._kwargs_keys)
354 raise
353 raise
355
354
356 # backward compat for removed api_key for old hooks. This was it works
355 # backward compat for removed api_key for old hooks. This was it works
@@ -437,6 +436,15 b' log_review_pull_request = ExtensionCallb'
437 'mergeable', 'source', 'target', 'author', 'reviewers'))
436 'mergeable', 'source', 'target', 'author', 'reviewers'))
438
437
439
438
439 log_comment_pull_request = ExtensionCallback(
440 hook_name='COMMENT_PULL_REQUEST',
441 kwargs_keys=(
442 'server_url', 'config', 'scm', 'username', 'ip', 'action',
443 'repository', 'pull_request_id', 'url', 'title', 'description',
444 'status', 'comment', 'created_on', 'updated_on', 'commit_ids', 'review_status',
445 'mergeable', 'source', 'target', 'author', 'reviewers'))
446
447
440 log_update_pull_request = ExtensionCallback(
448 log_update_pull_request = ExtensionCallback(
441 hook_name='UPDATE_PULL_REQUEST',
449 hook_name='UPDATE_PULL_REQUEST',
442 kwargs_keys=(
450 kwargs_keys=(
@@ -484,6 +492,15 b' log_delete_repository = ExtensionCallbac'
484 'clone_uri', 'fork_id', 'group_id', 'deleted_by', 'deleted_on'))
492 'clone_uri', 'fork_id', 'group_id', 'deleted_by', 'deleted_on'))
485
493
486
494
495 log_comment_commit_repository = ExtensionCallback(
496 hook_name='COMMENT_COMMIT_REPO_HOOK',
497 kwargs_keys=(
498 'repo_name', 'repo_type', 'description', 'private', 'created_on',
499 'enable_downloads', 'repo_id', 'user_id', 'enable_statistics',
500 'clone_uri', 'fork_id', 'group_id',
501 'repository', 'created_by', 'comment', 'commit'))
502
503
487 log_create_repository_group = ExtensionCallback(
504 log_create_repository_group = ExtensionCallback(
488 hook_name='CREATE_REPO_GROUP_HOOK',
505 hook_name='CREATE_REPO_GROUP_HOOK',
489 kwargs_keys=(
506 kwargs_keys=(
@@ -26,144 +26,190 b' from rhodecode.lib import hooks_base'
26 from rhodecode.lib import utils2
26 from rhodecode.lib import utils2
27
27
28
28
29 def _get_rc_scm_extras(username, repo_name, repo_alias, action):
29 def _supports_repo_type(repo_type):
30 # TODO: johbo: Replace by vcs_operation_context and remove fully
30 if repo_type in ('hg', 'git'):
31 return True
32 return False
33
34
35 def _get_vcs_operation_context(username, repo_name, repo_type, action):
36 # NOTE(dan): import loop
31 from rhodecode.lib.base import vcs_operation_context
37 from rhodecode.lib.base import vcs_operation_context
38
32 check_locking = action in ('pull', 'push')
39 check_locking = action in ('pull', 'push')
33
40
34 request = get_current_request()
41 request = get_current_request()
35
42
36 # default
37 dummy_environ = webob.Request.blank('').environ
38 try:
43 try:
39 environ = request.environ or dummy_environ
44 environ = request.environ
40 except TypeError:
45 except TypeError:
41 # we might use this outside of request context
46 # we might use this outside of request context
42 environ = dummy_environ
47 environ = {}
43
48
44 extras = vcs_operation_context(
49 if not environ:
45 environ, repo_name, username, action, repo_alias, check_locking)
50 environ = webob.Request.blank('').environ
51
52 extras = vcs_operation_context(environ, repo_name, username, action, repo_type, check_locking)
46 return utils2.AttributeDict(extras)
53 return utils2.AttributeDict(extras)
47
54
48
55
49 def trigger_post_push_hook(
56 def trigger_post_push_hook(username, action, hook_type, repo_name, repo_type, commit_ids):
50 username, action, hook_type, repo_name, repo_alias, commit_ids):
51 """
57 """
52 Triggers push action hooks
58 Triggers push action hooks
53
59
54 :param username: username who pushes
60 :param username: username who pushes
55 :param action: push/push_local/push_remote
61 :param action: push/push_local/push_remote
62 :param hook_type: type of hook executed
56 :param repo_name: name of repo
63 :param repo_name: name of repo
57 :param repo_alias: the type of SCM repo
64 :param repo_type: the type of SCM repo
58 :param commit_ids: list of commit ids that we pushed
65 :param commit_ids: list of commit ids that we pushed
59 """
66 """
60 extras = _get_rc_scm_extras(username, repo_name, repo_alias, action)
67 extras = _get_vcs_operation_context(username, repo_name, repo_type, action)
61 extras.commit_ids = commit_ids
68 extras.commit_ids = commit_ids
62 extras.hook_type = hook_type
69 extras.hook_type = hook_type
63 hooks_base.post_push(extras)
70 hooks_base.post_push(extras)
64
71
65
72
66 def trigger_log_create_pull_request_hook(username, repo_name, repo_alias,
73 def trigger_comment_commit_hooks(username, repo_name, repo_type, repo, data=None):
67 pull_request, data=None):
74 """
75 Triggers when a comment is made on a commit
76
77 :param username: username who creates the comment
78 :param repo_name: name of target repo
79 :param repo_type: the type of SCM target repo
80 :param repo: the repo object we trigger the event for
81 :param data: extra data for specific events e.g {'comment': comment_obj, 'commit': commit_obj}
82 """
83 if not _supports_repo_type(repo_type):
84 return
85
86 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'comment_commit')
87
88 comment = data['comment']
89 commit = data['commit']
90
91 events.trigger(events.RepoCommitCommentEvent(repo, commit, comment))
92 extras.update(repo.get_dict())
93
94 extras.commit = commit.serialize()
95 extras.comment = comment.get_api_data()
96 extras.created_by = username
97 hooks_base.log_comment_commit_repository(**extras)
98
99
100 def trigger_create_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
68 """
101 """
69 Triggers create pull request action hooks
102 Triggers create pull request action hooks
70
103
71 :param username: username who creates the pull request
104 :param username: username who creates the pull request
72 :param repo_name: name of target repo
105 :param repo_name: name of target repo
73 :param repo_alias: the type of SCM target repo
106 :param repo_type: the type of SCM target repo
74 :param pull_request: the pull request that was created
107 :param pull_request: the pull request that was created
75 :param data: extra data for specific events e.g {'comment': comment_obj}
108 :param data: extra data for specific events e.g {'comment': comment_obj}
76 """
109 """
77 if repo_alias not in ('hg', 'git'):
110 if not _supports_repo_type(repo_type):
78 return
111 return
79
112
80 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
113 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'create_pull_request')
81 'create_pull_request')
82 events.trigger(events.PullRequestCreateEvent(pull_request))
114 events.trigger(events.PullRequestCreateEvent(pull_request))
83 extras.update(pull_request.get_api_data(with_merge_state=False))
115 extras.update(pull_request.get_api_data(with_merge_state=False))
84 hooks_base.log_create_pull_request(**extras)
116 hooks_base.log_create_pull_request(**extras)
85
117
86
118
87 def trigger_log_merge_pull_request_hook(username, repo_name, repo_alias,
119 def trigger_merge_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
88 pull_request, data=None):
89 """
120 """
90 Triggers merge pull request action hooks
121 Triggers merge pull request action hooks
91
122
92 :param username: username who creates the pull request
123 :param username: username who creates the pull request
93 :param repo_name: name of target repo
124 :param repo_name: name of target repo
94 :param repo_alias: the type of SCM target repo
125 :param repo_type: the type of SCM target repo
95 :param pull_request: the pull request that was merged
126 :param pull_request: the pull request that was merged
96 :param data: extra data for specific events e.g {'comment': comment_obj}
127 :param data: extra data for specific events e.g {'comment': comment_obj}
97 """
128 """
98 if repo_alias not in ('hg', 'git'):
129 if not _supports_repo_type(repo_type):
99 return
130 return
100
131
101 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
132 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'merge_pull_request')
102 'merge_pull_request')
103 events.trigger(events.PullRequestMergeEvent(pull_request))
133 events.trigger(events.PullRequestMergeEvent(pull_request))
104 extras.update(pull_request.get_api_data())
134 extras.update(pull_request.get_api_data())
105 hooks_base.log_merge_pull_request(**extras)
135 hooks_base.log_merge_pull_request(**extras)
106
136
107
137
108 def trigger_log_close_pull_request_hook(username, repo_name, repo_alias,
138 def trigger_close_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
109 pull_request, data=None):
110 """
139 """
111 Triggers close pull request action hooks
140 Triggers close pull request action hooks
112
141
113 :param username: username who creates the pull request
142 :param username: username who creates the pull request
114 :param repo_name: name of target repo
143 :param repo_name: name of target repo
115 :param repo_alias: the type of SCM target repo
144 :param repo_type: the type of SCM target repo
116 :param pull_request: the pull request that was closed
145 :param pull_request: the pull request that was closed
117 :param data: extra data for specific events e.g {'comment': comment_obj}
146 :param data: extra data for specific events e.g {'comment': comment_obj}
118 """
147 """
119 if repo_alias not in ('hg', 'git'):
148 if not _supports_repo_type(repo_type):
120 return
149 return
121
150
122 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
151 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'close_pull_request')
123 'close_pull_request')
124 events.trigger(events.PullRequestCloseEvent(pull_request))
152 events.trigger(events.PullRequestCloseEvent(pull_request))
125 extras.update(pull_request.get_api_data())
153 extras.update(pull_request.get_api_data())
126 hooks_base.log_close_pull_request(**extras)
154 hooks_base.log_close_pull_request(**extras)
127
155
128
156
129 def trigger_log_review_pull_request_hook(username, repo_name, repo_alias,
157 def trigger_review_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
130 pull_request, data=None):
131 """
158 """
132 Triggers review status change pull request action hooks
159 Triggers review status change pull request action hooks
133
160
134 :param username: username who creates the pull request
161 :param username: username who creates the pull request
135 :param repo_name: name of target repo
162 :param repo_name: name of target repo
136 :param repo_alias: the type of SCM target repo
163 :param repo_type: the type of SCM target repo
137 :param pull_request: the pull request that review status changed
164 :param pull_request: the pull request that review status changed
138 :param data: extra data for specific events e.g {'comment': comment_obj}
165 :param data: extra data for specific events e.g {'comment': comment_obj}
139 """
166 """
140 if repo_alias not in ('hg', 'git'):
167 if not _supports_repo_type(repo_type):
141 return
168 return
142
169
143 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
170 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'review_pull_request')
144 'review_pull_request')
145 status = data.get('status')
171 status = data.get('status')
146 events.trigger(events.PullRequestReviewEvent(pull_request, status))
172 events.trigger(events.PullRequestReviewEvent(pull_request, status))
147 extras.update(pull_request.get_api_data())
173 extras.update(pull_request.get_api_data())
148 hooks_base.log_review_pull_request(**extras)
174 hooks_base.log_review_pull_request(**extras)
149
175
150
176
151 def trigger_log_update_pull_request_hook(username, repo_name, repo_alias,
177 def trigger_comment_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
152 pull_request, data=None):
178 """
179 Triggers when a comment is made on a pull request
180
181 :param username: username who creates the pull request
182 :param repo_name: name of target repo
183 :param repo_type: the type of SCM target repo
184 :param pull_request: the pull request that comment was made on
185 :param data: extra data for specific events e.g {'comment': comment_obj}
186 """
187 if not _supports_repo_type(repo_type):
188 return
189
190 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'comment_pull_request')
191
192 comment = data['comment']
193 events.trigger(events.PullRequestCommentEvent(pull_request, comment))
194 extras.update(pull_request.get_api_data())
195 extras.comment = comment.get_api_data()
196 hooks_base.log_comment_pull_request(**extras)
197
198
199 def trigger_update_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
153 """
200 """
154 Triggers update pull request action hooks
201 Triggers update pull request action hooks
155
202
156 :param username: username who creates the pull request
203 :param username: username who creates the pull request
157 :param repo_name: name of target repo
204 :param repo_name: name of target repo
158 :param repo_alias: the type of SCM target repo
205 :param repo_type: the type of SCM target repo
159 :param pull_request: the pull request that was updated
206 :param pull_request: the pull request that was updated
160 :param data: extra data for specific events e.g {'comment': comment_obj}
207 :param data: extra data for specific events e.g {'comment': comment_obj}
161 """
208 """
162 if repo_alias not in ('hg', 'git'):
209 if not _supports_repo_type(repo_type):
163 return
210 return
164
211
165 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
212 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'update_pull_request')
166 'update_pull_request')
167 events.trigger(events.PullRequestUpdateEvent(pull_request))
213 events.trigger(events.PullRequestUpdateEvent(pull_request))
168 extras.update(pull_request.get_api_data())
214 extras.update(pull_request.get_api_data())
169 hooks_base.log_update_pull_request(**extras)
215 hooks_base.log_update_pull_request(**extras)
@@ -925,6 +925,9 b' class BaseCommit(object):'
925 d.pop('repository', None)
925 d.pop('repository', None)
926 return d
926 return d
927
927
928 def serialize(self):
929 return self.__json__()
930
928 def _get_refs(self):
931 def _get_refs(self):
929 return {
932 return {
930 'branches': [self.branch] if self.branch else [],
933 'branches': [self.branch] if self.branch else [],
@@ -30,7 +30,7 b' from pyramid.threadlocal import get_curr'
30 from sqlalchemy.sql.expression import null
30 from sqlalchemy.sql.expression import null
31 from sqlalchemy.sql.functions import coalesce
31 from sqlalchemy.sql.functions import coalesce
32
32
33 from rhodecode.lib import helpers as h, diffs, channelstream
33 from rhodecode.lib import helpers as h, diffs, channelstream, hooks_utils
34 from rhodecode.lib import audit_logger
34 from rhodecode.lib import audit_logger
35 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str
35 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str
36 from rhodecode.model import BaseModel
36 from rhodecode.model import BaseModel
@@ -720,6 +720,26 b' class CommentsModel(BaseModel):'
720 settings = settings_model.get_general_settings()
720 settings = settings_model.get_general_settings()
721 return settings.get('rhodecode_use_outdated_comments', False)
721 return settings.get('rhodecode_use_outdated_comments', False)
722
722
723 def trigger_commit_comment_hook(self, repo, user, action, data=None):
724 repo = self._get_repo(repo)
725 target_scm = repo.scm_instance()
726 if action == 'create':
727 trigger_hook = hooks_utils.trigger_comment_commit_hooks
728 elif action == 'edit':
729 # TODO(dan): when this is supported we trigger edit hook too
730 return
731 else:
732 return
733
734 log.debug('Handling repo %s trigger_commit_comment_hook with action %s: %s',
735 repo, action, trigger_hook)
736 trigger_hook(
737 username=user.username,
738 repo_name=repo.repo_name,
739 repo_type=target_scm.alias,
740 repo=repo,
741 data=data)
742
723
743
724 def _parse_comment_line_number(line_no):
744 def _parse_comment_line_number(line_no):
725 """
745 """
@@ -542,8 +542,7 b' class PullRequestModel(BaseModel):'
542 pull_request, auth_user=auth_user, translator=translator)
542 pull_request, auth_user=auth_user, translator=translator)
543
543
544 self.notify_reviewers(pull_request, reviewer_ids)
544 self.notify_reviewers(pull_request, reviewer_ids)
545 self.trigger_pull_request_hook(
545 self.trigger_pull_request_hook(pull_request, created_by_user, 'create')
546 pull_request, created_by_user, 'create')
547
546
548 creation_data = pull_request.get_api_data(with_merge_state=False)
547 creation_data = pull_request.get_api_data(with_merge_state=False)
549 self._log_audit_action(
548 self._log_audit_action(
@@ -556,28 +555,26 b' class PullRequestModel(BaseModel):'
556 pull_request = self.__get_pull_request(pull_request)
555 pull_request = self.__get_pull_request(pull_request)
557 target_scm = pull_request.target_repo.scm_instance()
556 target_scm = pull_request.target_repo.scm_instance()
558 if action == 'create':
557 if action == 'create':
559 trigger_hook = hooks_utils.trigger_log_create_pull_request_hook
558 trigger_hook = hooks_utils.trigger_create_pull_request_hook
560 elif action == 'merge':
559 elif action == 'merge':
561 trigger_hook = hooks_utils.trigger_log_merge_pull_request_hook
560 trigger_hook = hooks_utils.trigger_merge_pull_request_hook
562 elif action == 'close':
561 elif action == 'close':
563 trigger_hook = hooks_utils.trigger_log_close_pull_request_hook
562 trigger_hook = hooks_utils.trigger_close_pull_request_hook
564 elif action == 'review_status_change':
563 elif action == 'review_status_change':
565 trigger_hook = hooks_utils.trigger_log_review_pull_request_hook
564 trigger_hook = hooks_utils.trigger_review_pull_request_hook
566 elif action == 'update':
565 elif action == 'update':
567 trigger_hook = hooks_utils.trigger_log_update_pull_request_hook
566 trigger_hook = hooks_utils.trigger_update_pull_request_hook
568 elif action == 'comment':
567 elif action == 'comment':
569 # dummy hook ! for comment. We want this function to handle all cases
568 trigger_hook = hooks_utils.trigger_comment_pull_request_hook
570 def trigger_hook(*args, **kwargs):
571 pass
572 comment = data['comment']
573 events.trigger(events.PullRequestCommentEvent(pull_request, comment))
574 else:
569 else:
575 return
570 return
576
571
572 log.debug('Handling pull_request %s trigger_pull_request_hook with action %s and hook: %s',
573 pull_request, action, trigger_hook)
577 trigger_hook(
574 trigger_hook(
578 username=user.username,
575 username=user.username,
579 repo_name=pull_request.target_repo.repo_name,
576 repo_name=pull_request.target_repo.repo_name,
580 repo_alias=target_scm.alias,
577 repo_type=target_scm.alias,
581 pull_request=pull_request,
578 pull_request=pull_request,
582 data=data)
579 data=data)
583
580
@@ -1286,8 +1283,7 b' class PullRequestModel(BaseModel):'
1286 pull_request.status = PullRequest.STATUS_CLOSED
1283 pull_request.status = PullRequest.STATUS_CLOSED
1287 pull_request.updated_on = datetime.datetime.now()
1284 pull_request.updated_on = datetime.datetime.now()
1288 Session().add(pull_request)
1285 Session().add(pull_request)
1289 self.trigger_pull_request_hook(
1286 self.trigger_pull_request_hook(pull_request, pull_request.author, 'close')
1290 pull_request, pull_request.author, 'close')
1291
1287
1292 pr_data = pull_request.get_api_data(with_merge_state=False)
1288 pr_data = pull_request.get_api_data(with_merge_state=False)
1293 self._log_audit_action(
1289 self._log_audit_action(
@@ -1333,20 +1329,21 b' class PullRequestModel(BaseModel):'
1333 )
1329 )
1334
1330
1335 Session().flush()
1331 Session().flush()
1336 events.trigger(events.PullRequestCommentEvent(pull_request, comment))
1332
1333 self.trigger_pull_request_hook(pull_request, user, 'comment',
1334 data={'comment': comment})
1335
1337 # we now calculate the status of pull request again, and based on that
1336 # we now calculate the status of pull request again, and based on that
1338 # calculation trigger status change. This might happen in cases
1337 # calculation trigger status change. This might happen in cases
1339 # that non-reviewer admin closes a pr, which means his vote doesn't
1338 # that non-reviewer admin closes a pr, which means his vote doesn't
1340 # change the status, while if he's a reviewer this might change it.
1339 # change the status, while if he's a reviewer this might change it.
1341 calculated_status = pull_request.calculated_review_status()
1340 calculated_status = pull_request.calculated_review_status()
1342 if old_calculated_status != calculated_status:
1341 if old_calculated_status != calculated_status:
1343 self.trigger_pull_request_hook(
1342 self.trigger_pull_request_hook(pull_request, user, 'review_status_change',
1344 pull_request, user, 'review_status_change',
1343 data={'status': calculated_status})
1345 data={'status': calculated_status})
1346
1344
1347 # finally close the PR
1345 # finally close the PR
1348 PullRequestModel().close_pull_request(
1346 PullRequestModel().close_pull_request(pull_request.pull_request_id, user)
1349 pull_request.pull_request_id, user)
1350
1347
1351 return comment, status
1348 return comment, status
1352
1349
@@ -473,7 +473,7 b' class ScmModel(BaseModel):'
473 # We trigger the post-push action
473 # We trigger the post-push action
474 hooks_utils.trigger_post_push_hook(
474 hooks_utils.trigger_post_push_hook(
475 username=user.username, action='push_local', hook_type='post_push',
475 username=user.username, action='push_local', hook_type='post_push',
476 repo_name=repo_name, repo_alias=repo.alias, commit_ids=[tip.raw_id])
476 repo_name=repo_name, repo_type=repo.alias, commit_ids=[tip.raw_id])
477 return tip
477 return tip
478
478
479 def _sanitize_path(self, f_path):
479 def _sanitize_path(self, f_path):
@@ -799,7 +799,7 b' class ScmModel(BaseModel):'
799 if trigger_push_hook:
799 if trigger_push_hook:
800 hooks_utils.trigger_post_push_hook(
800 hooks_utils.trigger_post_push_hook(
801 username=user.username, action='push_local',
801 username=user.username, action='push_local',
802 repo_name=repo.repo_name, repo_alias=scm_instance.alias,
802 repo_name=repo.repo_name, repo_type=scm_instance.alias,
803 hook_type='post_push',
803 hook_type='post_push',
804 commit_ids=[tip.raw_id])
804 commit_ids=[tip.raw_id])
805 return tip
805 return tip
@@ -864,7 +864,7 b' class ScmModel(BaseModel):'
864 if trigger_push_hook:
864 if trigger_push_hook:
865 hooks_utils.trigger_post_push_hook(
865 hooks_utils.trigger_post_push_hook(
866 username=user.username, action='push_local', hook_type='post_push',
866 username=user.username, action='push_local', hook_type='post_push',
867 repo_name=repo.repo_name, repo_alias=scm_instance.alias,
867 repo_name=repo.repo_name, repo_type=scm_instance.alias,
868 commit_ids=[tip.raw_id])
868 commit_ids=[tip.raw_id])
869
869
870 return tip
870 return tip
@@ -926,7 +926,7 b' class ScmModel(BaseModel):'
926 if trigger_push_hook:
926 if trigger_push_hook:
927 hooks_utils.trigger_post_push_hook(
927 hooks_utils.trigger_post_push_hook(
928 username=user.username, action='push_local', hook_type='post_push',
928 username=user.username, action='push_local', hook_type='post_push',
929 repo_name=repo.repo_name, repo_alias=scm_instance.alias,
929 repo_name=repo.repo_name, repo_type=scm_instance.alias,
930 commit_ids=[tip.raw_id])
930 commit_ids=[tip.raw_id])
931 return tip
931 return tip
932
932
General Comments 0
You need to be logged in to leave comments. Login now