##// 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 1599 validate_repo_permissions(apiuser, repoid, repo, _perms)
1600 1600
1601 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 1604 except Exception as e:
1604 1605 log.exception('Failed to fetch commit')
1605 1606 raise JSONRPCError(safe_str(e))
@@ -1659,6 +1660,10 b' def comment_commit('
1659 1660 'a closed pull request is not allowed')
1660 1661 raise JSONRPCError(msg)
1661 1662
1663 CommentsModel().trigger_commit_comment_hook(
1664 repo, apiuser, 'create',
1665 data={'comment': comment, 'commit': commit})
1666
1662 1667 Session().commit()
1663 1668 return {
1664 1669 'msg': (
@@ -380,6 +380,11 b' class RepoCommitsView(RepoAppView):'
380 380 'repo_commit', repo_name=self.db_repo_name,
381 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 388 # finalize, commit and redirect
384 389 Session().commit()
385 390
@@ -25,6 +25,7 b' from .hooks import ('
25 25 _create_repo_group_hook,
26 26 _pre_create_user_hook,
27 27 _create_user_hook,
28 _comment_commit_repo_hook,
28 29 _delete_repo_hook,
29 30 _delete_user_hook,
30 31 _pre_push_hook,
@@ -33,6 +34,7 b' from .hooks import ('
33 34 _pull_hook,
34 35 _create_pull_request_hook,
35 36 _review_pull_request_hook,
37 _comment_pull_request_hook,
36 38 _update_pull_request_hook,
37 39 _merge_pull_request_hook,
38 40 _close_pull_request_hook,
@@ -40,6 +42,7 b' from .hooks import ('
40 42
41 43 # set as module attributes, we use those to call hooks. *do not change this*
42 44 CREATE_REPO_HOOK = _create_repo_hook
45 COMMENT_COMMIT_REPO_HOOK = _comment_commit_repo_hook
43 46 CREATE_REPO_GROUP_HOOK = _create_repo_group_hook
44 47 PRE_CREATE_USER_HOOK = _pre_create_user_hook
45 48 CREATE_USER_HOOK = _create_user_hook
@@ -51,6 +54,7 b' PRE_PULL_HOOK = _pre_pull_hook'
51 54 PULL_HOOK = _pull_hook
52 55 CREATE_PULL_REQUEST = _create_pull_request_hook
53 56 REVIEW_PULL_REQUEST = _review_pull_request_hook
57 COMMENT_PULL_REQUEST = _comment_pull_request_hook
54 58 UPDATE_PULL_REQUEST = _update_pull_request_hook
55 59 MERGE_PULL_REQUEST = _merge_pull_request_hook
56 60 CLOSE_PULL_REQUEST = _close_pull_request_hook
@@ -24,14 +24,13 b' def _push_hook(*args, **kwargs):'
24 24 # returns list of dicts with key-val fetched from extra fields
25 25 repo_extra_fields = extra_fields.run(**kwargs)
26 26
27 if repo_extra_fields.get('endpoint_url'):
28 field_metadata = repo_extra_fields['endpoint_url']
29 endpoint = field_metadata['field_value']
30 if endpoint:
27 endpoint_url = extra_fields.get_field(repo_extra_fields, key='endpoint_url', default='')
28
29 if endpoint_url:
31 30 data = {
32 31 'project': kwargs['repository'],
33 32 }
34 response = http_call.run(url=endpoint, params=data)
35 return HookResponse(0, 'Called endpoint {}, with response {}\n'.format(endpoint, response))
33 response = http_call.run(url=endpoint_url, params=data)
34 return HookResponse(0, 'Called endpoint {}, with response {}\n'.format(endpoint_url, response))
36 35
37 36 return HookResponse(0, '')
@@ -24,14 +24,12 b' def _push_hook(*args, **kwargs):'
24 24 # returns list of dicts with key-val fetched from extra fields
25 25 repo_extra_fields = extra_fields.run(**kwargs)
26 26
27 if repo_extra_fields.get('endpoint_url'):
28 field_metadata = repo_extra_fields['endpoint_url']
29 endpoint = field_metadata['field_value']
30 if endpoint:
27 endpoint_url = extra_fields.get_field(repo_extra_fields, key='endpoint_url', default='')
28 if endpoint_url:
31 29 data = {
32 30 'some_key': 'val'
33 31 }
34 response = http_call.run(url=endpoint, json_data=data)
35 return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint, response))
32 response = http_call.run(url=endpoint_url, json_data=data)
33 return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint_url, response))
36 34
37 35 return HookResponse(0, '')
@@ -41,11 +41,13 b' def _pre_push_hook(*args, **kwargs):'
41 41 repo_extra_fields = extra_fields.run(**kwargs)
42 42
43 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 46 should_validate = str2bool(validate_author)
46 47
47 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 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 45 # optionally use 'extra fields' to control the logic per repo
46 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 49 forbid_files = aslist(forbid_files)
49 50
50 51 # forbid_files = ['*'] # example pattern
51 52
52 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 57 forbid_size_over = int(forbid_size_over or 0)
55 58
56 59 # forbid_size_over = 1024 # example 1024
@@ -53,3 +53,36 b' def run(*args, **kwargs):'
53 53 fields[field.field_key] = field.get_dict()
54 54
55 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 15 # This program is dual-licensed. If you wish to learn more about the
16 16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18 19 import logging
19 20 from .utils import DotDict, HookResponse, has_kwargs
21
20 22 log = logging.getLogger('rhodecode.' + __name__)
21 23
22
23 24 # Config shortcut to keep, all configuration in one place
24 25 # Example: api_key = CONFIG.my_config.api_key
25 26 CONFIG = DotDict(
@@ -55,6 +56,33 b' def _create_repo_hook(*args, **kwargs):'
55 56
56 57
57 58 @has_kwargs({
59 'repo_name': '',
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({
58 86 'group_name': '',
59 87 'group_parent_id': '',
60 88 'group_description': '',
@@ -348,6 +376,38 b' def _review_pull_request_hook(*args, **k'
348 376 'scm': 'type of version control "git", "hg", "svn"',
349 377 'username': 'username of actor who triggered this event',
350 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 411 'action': '',
352 412 'repository': 'repository name',
353 413 'pull_request_id': '',
@@ -18,8 +18,10 b''
18 18
19 19 import logging
20 20 import os
21 import string
21 22 import functools
22 23 import collections
24 import urllib
23 25
24 26 log = logging.getLogger('rhodecode.' + __name__)
25 27
@@ -186,4 +188,12 b' def aslist(obj, sep=None, strip=True):'
186 188 elif obj is None:
187 189 return []
188 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 55 from rhodecode.events.repo import ( # pragma: no cover
56 RepoEvent,
56 RepoEvent, RepoCommitCommentEvent,
57 57 RepoPreCreateEvent, RepoCreateEvent,
58 58 RepoPreDeleteEvent, RepoDeleteEvent,
59 59 RepoPrePushEvent, RepoPushEvent,
@@ -181,6 +181,20 b' class RepoEvent(RhodeCodeIntegrationEven'
181 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 198 class RepoPreCreateEvent(RepoEvent):
185 199 """
186 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 26 import os
27 import collections
28 27 import logging
29 28
30 29 import rhodecode
@@ -349,8 +348,8 b' class ExtensionCallback(object):'
349 348 try:
350 349 kwargs_to_pass[key] = kwargs[key]
351 350 except KeyError:
352 log.error('Failed to fetch %s key. Expected keys: %s',
353 key, self._kwargs_keys)
351 log.error('Failed to fetch %s key from given kwargs. '
352 'Expected keys: %s', key, self._kwargs_keys)
354 353 raise
355 354
356 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 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 448 log_update_pull_request = ExtensionCallback(
441 449 hook_name='UPDATE_PULL_REQUEST',
442 450 kwargs_keys=(
@@ -484,6 +492,15 b' log_delete_repository = ExtensionCallbac'
484 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 504 log_create_repository_group = ExtensionCallback(
488 505 hook_name='CREATE_REPO_GROUP_HOOK',
489 506 kwargs_keys=(
@@ -26,144 +26,190 b' from rhodecode.lib import hooks_base'
26 26 from rhodecode.lib import utils2
27 27
28 28
29 def _get_rc_scm_extras(username, repo_name, repo_alias, action):
30 # TODO: johbo: Replace by vcs_operation_context and remove fully
29 def _supports_repo_type(repo_type):
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 37 from rhodecode.lib.base import vcs_operation_context
38
32 39 check_locking = action in ('pull', 'push')
33 40
34 41 request = get_current_request()
35 42
36 # default
37 dummy_environ = webob.Request.blank('').environ
38 43 try:
39 environ = request.environ or dummy_environ
44 environ = request.environ
40 45 except TypeError:
41 46 # we might use this outside of request context
42 environ = dummy_environ
47 environ = {}
43 48
44 extras = vcs_operation_context(
45 environ, repo_name, username, action, repo_alias, check_locking)
49 if not environ:
50 environ = webob.Request.blank('').environ
51
52 extras = vcs_operation_context(environ, repo_name, username, action, repo_type, check_locking)
46 53 return utils2.AttributeDict(extras)
47 54
48 55
49 def trigger_post_push_hook(
50 username, action, hook_type, repo_name, repo_alias, commit_ids):
56 def trigger_post_push_hook(username, action, hook_type, repo_name, repo_type, commit_ids):
51 57 """
52 58 Triggers push action hooks
53 59
54 60 :param username: username who pushes
55 61 :param action: push/push_local/push_remote
62 :param hook_type: type of hook executed
56 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 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 68 extras.commit_ids = commit_ids
62 69 extras.hook_type = hook_type
63 70 hooks_base.post_push(extras)
64 71
65 72
66 def trigger_log_create_pull_request_hook(username, repo_name, repo_alias,
67 pull_request, data=None):
73 def trigger_comment_commit_hooks(username, repo_name, repo_type, repo, 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 102 Triggers create pull request action hooks
70 103
71 104 :param username: username who creates the pull request
72 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 107 :param pull_request: the pull request that was created
75 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 111 return
79 112
80 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
81 'create_pull_request')
113 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'create_pull_request')
82 114 events.trigger(events.PullRequestCreateEvent(pull_request))
83 115 extras.update(pull_request.get_api_data(with_merge_state=False))
84 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,
88 pull_request, data=None):
119 def trigger_merge_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
89 120 """
90 121 Triggers merge pull request action hooks
91 122
92 123 :param username: username who creates the pull request
93 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 126 :param pull_request: the pull request that was merged
96 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 130 return
100 131
101 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
102 'merge_pull_request')
132 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'merge_pull_request')
103 133 events.trigger(events.PullRequestMergeEvent(pull_request))
104 134 extras.update(pull_request.get_api_data())
105 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,
109 pull_request, data=None):
138 def trigger_close_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
110 139 """
111 140 Triggers close pull request action hooks
112 141
113 142 :param username: username who creates the pull request
114 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 145 :param pull_request: the pull request that was closed
117 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 149 return
121 150
122 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
123 'close_pull_request')
151 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'close_pull_request')
124 152 events.trigger(events.PullRequestCloseEvent(pull_request))
125 153 extras.update(pull_request.get_api_data())
126 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,
130 pull_request, data=None):
157 def trigger_review_pull_request_hook(username, repo_name, repo_type, pull_request, data=None):
131 158 """
132 159 Triggers review status change pull request action hooks
133 160
134 161 :param username: username who creates the pull request
135 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 164 :param pull_request: the pull request that review status changed
138 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 168 return
142 169
143 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
144 'review_pull_request')
170 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'review_pull_request')
145 171 status = data.get('status')
146 172 events.trigger(events.PullRequestReviewEvent(pull_request, status))
147 173 extras.update(pull_request.get_api_data())
148 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,
152 pull_request, data=None):
177 def trigger_comment_pull_request_hook(username, repo_name, repo_type, 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 201 Triggers update pull request action hooks
155 202
156 203 :param username: username who creates the pull request
157 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 206 :param pull_request: the pull request that was updated
160 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 210 return
164 211
165 extras = _get_rc_scm_extras(username, repo_name, repo_alias,
166 'update_pull_request')
212 extras = _get_vcs_operation_context(username, repo_name, repo_type, 'update_pull_request')
167 213 events.trigger(events.PullRequestUpdateEvent(pull_request))
168 214 extras.update(pull_request.get_api_data())
169 215 hooks_base.log_update_pull_request(**extras)
@@ -925,6 +925,9 b' class BaseCommit(object):'
925 925 d.pop('repository', None)
926 926 return d
927 927
928 def serialize(self):
929 return self.__json__()
930
928 931 def _get_refs(self):
929 932 return {
930 933 'branches': [self.branch] if self.branch else [],
@@ -30,7 +30,7 b' from pyramid.threadlocal import get_curr'
30 30 from sqlalchemy.sql.expression import null
31 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 34 from rhodecode.lib import audit_logger
35 35 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str
36 36 from rhodecode.model import BaseModel
@@ -720,6 +720,26 b' class CommentsModel(BaseModel):'
720 720 settings = settings_model.get_general_settings()
721 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 744 def _parse_comment_line_number(line_no):
725 745 """
@@ -542,8 +542,7 b' class PullRequestModel(BaseModel):'
542 542 pull_request, auth_user=auth_user, translator=translator)
543 543
544 544 self.notify_reviewers(pull_request, reviewer_ids)
545 self.trigger_pull_request_hook(
546 pull_request, created_by_user, 'create')
545 self.trigger_pull_request_hook(pull_request, created_by_user, 'create')
547 546
548 547 creation_data = pull_request.get_api_data(with_merge_state=False)
549 548 self._log_audit_action(
@@ -556,28 +555,26 b' class PullRequestModel(BaseModel):'
556 555 pull_request = self.__get_pull_request(pull_request)
557 556 target_scm = pull_request.target_repo.scm_instance()
558 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 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 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 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 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 567 elif action == 'comment':
569 # dummy hook ! for comment. We want this function to handle all cases
570 def trigger_hook(*args, **kwargs):
571 pass
572 comment = data['comment']
573 events.trigger(events.PullRequestCommentEvent(pull_request, comment))
568 trigger_hook = hooks_utils.trigger_comment_pull_request_hook
574 569 else:
575 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 574 trigger_hook(
578 575 username=user.username,
579 576 repo_name=pull_request.target_repo.repo_name,
580 repo_alias=target_scm.alias,
577 repo_type=target_scm.alias,
581 578 pull_request=pull_request,
582 579 data=data)
583 580
@@ -1286,8 +1283,7 b' class PullRequestModel(BaseModel):'
1286 1283 pull_request.status = PullRequest.STATUS_CLOSED
1287 1284 pull_request.updated_on = datetime.datetime.now()
1288 1285 Session().add(pull_request)
1289 self.trigger_pull_request_hook(
1290 pull_request, pull_request.author, 'close')
1286 self.trigger_pull_request_hook(pull_request, pull_request.author, 'close')
1291 1287
1292 1288 pr_data = pull_request.get_api_data(with_merge_state=False)
1293 1289 self._log_audit_action(
@@ -1333,20 +1329,21 b' class PullRequestModel(BaseModel):'
1333 1329 )
1334 1330
1335 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 1336 # we now calculate the status of pull request again, and based on that
1338 1337 # calculation trigger status change. This might happen in cases
1339 1338 # that non-reviewer admin closes a pr, which means his vote doesn't
1340 1339 # change the status, while if he's a reviewer this might change it.
1341 1340 calculated_status = pull_request.calculated_review_status()
1342 1341 if old_calculated_status != calculated_status:
1343 self.trigger_pull_request_hook(
1344 pull_request, user, 'review_status_change',
1342 self.trigger_pull_request_hook(pull_request, user, 'review_status_change',
1345 1343 data={'status': calculated_status})
1346 1344
1347 1345 # finally close the PR
1348 PullRequestModel().close_pull_request(
1349 pull_request.pull_request_id, user)
1346 PullRequestModel().close_pull_request(pull_request.pull_request_id, user)
1350 1347
1351 1348 return comment, status
1352 1349
@@ -473,7 +473,7 b' class ScmModel(BaseModel):'
473 473 # We trigger the post-push action
474 474 hooks_utils.trigger_post_push_hook(
475 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 477 return tip
478 478
479 479 def _sanitize_path(self, f_path):
@@ -799,7 +799,7 b' class ScmModel(BaseModel):'
799 799 if trigger_push_hook:
800 800 hooks_utils.trigger_post_push_hook(
801 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 803 hook_type='post_push',
804 804 commit_ids=[tip.raw_id])
805 805 return tip
@@ -864,7 +864,7 b' class ScmModel(BaseModel):'
864 864 if trigger_push_hook:
865 865 hooks_utils.trigger_post_push_hook(
866 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 868 commit_ids=[tip.raw_id])
869 869
870 870 return tip
@@ -926,7 +926,7 b' class ScmModel(BaseModel):'
926 926 if trigger_push_hook:
927 927 hooks_utils.trigger_post_push_hook(
928 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 930 commit_ids=[tip.raw_id])
931 931 return tip
932 932
General Comments 0
You need to be logged in to leave comments. Login now