##// END OF EJS Templates
rcextensions: new builtin rcextensions....
marcink -
r3133:6afdd8e7 default
parent child
Show More
@@ -0,0 +1,44
1 .. _integrations-rcextensions:
2
3
4 rcextensions integrations
5 =========================
6
7
8 Since RhodeCode 4.14 release rcextensions aren't part of rhodecode-tools, and instead
9 they are shipped with the new or upgraded installations.
10
11 The rcextensions template `rcextensions.tmpl` is created in the `etc/` directory
12 of enterprise or community installation. It's always re-created and updated on upgrades.
13
14
15 Activating rcextensions
16 +++++++++++++++++++++++
17
18 To activate rcextensions simply copy or rename the created template rcextensions
19 into the path where the rhodecode.ini file is located::
20
21 pushd ~/rccontrol/enterprise-1/
22 or
23 pushd ~/rccontrol/community-1/
24
25 mv etc/rcextensions.tmpl rcextensions
26
27
28 rcextensions are loaded when |RCE| starts. So a restart is required after activation or
29 change of code in rcextensions.
30
31 Simply restart only the enterprise/community instance::
32
33 rccontrol restart enterprise-1
34 or
35 rccontrol restart community-1
36
37
38 Example usage
39 +++++++++++++
40
41
42 To see examples of usage please check the examples directory under:
43
44 https://code.rhodecode.com/rhodecode-enterprise-ce/files/stable/rhodecode/config/rcextensions/examples
@@ -0,0 +1,56
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 """
20 rcextensions module, please edit `hooks.py` to over write hooks logic
21 """
22
23 from .hooks import (
24 _create_repo_hook,
25 _create_repo_group_hook,
26 _pre_create_user_hook,
27 _create_user_hook,
28 _delete_repo_hook,
29 _delete_user_hook,
30 _pre_push_hook,
31 _push_hook,
32 _pre_pull_hook,
33 _pull_hook,
34 _create_pull_request_hook,
35 _review_pull_request_hook,
36 _update_pull_request_hook,
37 _merge_pull_request_hook,
38 _close_pull_request_hook,
39 )
40
41 # set as module attributes, we use those to call hooks. *do not change this*
42 CREATE_REPO_HOOK = _create_repo_hook
43 CREATE_REPO_GROUP_HOOK = _create_repo_group_hook
44 PRE_CREATE_USER_HOOK = _pre_create_user_hook
45 CREATE_USER_HOOK = _create_user_hook
46 DELETE_REPO_HOOK = _delete_repo_hook
47 DELETE_USER_HOOK = _delete_user_hook
48 PRE_PUSH_HOOK = _pre_push_hook
49 PUSH_HOOK = _push_hook
50 PRE_PULL_HOOK = _pre_pull_hook
51 PULL_HOOK = _pull_hook
52 CREATE_PULL_REQUEST = _create_pull_request_hook
53 REVIEW_PULL_REQUEST = _review_pull_request_hook
54 UPDATE_PULL_REQUEST = _update_pull_request_hook
55 MERGE_PULL_REQUEST = _merge_pull_request_hook
56 CLOSE_PULL_REQUEST = _close_pull_request_hook
@@ -0,0 +1,36
1 # Example to trigger a HTTP call via an HTTP helper via post_push hook
2
3
4 @has_kwargs({
5 'server_url': 'url of instance that triggered this hook',
6 'config': 'path to .ini config used',
7 'scm': 'type of version control "git", "hg", "svn"',
8 'username': 'username of actor who triggered this event',
9 'ip': 'ip address of actor who triggered this hook',
10 'action': '',
11 'repository': 'repository name',
12 'repo_store_path': 'full path to where repositories are stored',
13 'commit_ids': '',
14 'hook_type': '',
15 'user_agent': '',
16 })
17 def _push_hook(*args, **kwargs):
18 """
19 POST PUSH HOOK, this function will be executed after each push it's
20 executed after the build-in hook that RhodeCode uses for logging pushes
21 """
22
23 from .helpers import http_call, extra_fields
24 # returns list of dicts with key-val fetched from extra fields
25 repo_extra_fields = extra_fields.run(**kwargs)
26
27 if repo_extra_fields.get('endpoint_url'):
28 endpoint = repo_extra_fields['endpoint_url']
29 if endpoint:
30 data = {
31 'some_key': 'val'
32 }
33 response = http_call.run(url=endpoint, json_data=data)
34 return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint, response))
35
36 return HookResponse(0, '')
@@ -0,0 +1,36
1 # Example to trigger a CI call via an HTTP helper via post_push hook
2
3
4 @has_kwargs({
5 'server_url': 'url of instance that triggered this hook',
6 'config': 'path to .ini config used',
7 'scm': 'type of version control "git", "hg", "svn"',
8 'username': 'username of actor who triggered this event',
9 'ip': 'ip address of actor who triggered this hook',
10 'action': '',
11 'repository': 'repository name',
12 'repo_store_path': 'full path to where repositories are stored',
13 'commit_ids': '',
14 'hook_type': '',
15 'user_agent': '',
16 })
17 def _push_hook(*args, **kwargs):
18 """
19 POST PUSH HOOK, this function will be executed after each push it's
20 executed after the build-in hook that RhodeCode uses for logging pushes
21 """
22
23 from .helpers import http_call, extra_fields
24 # returns list of dicts with key-val fetched from extra fields
25 repo_extra_fields = extra_fields.run(**kwargs)
26
27 if repo_extra_fields.get('endpoint_url'):
28 endpoint = repo_extra_fields['endpoint_url']
29 if endpoint:
30 data = {
31 'some_key': 'val'
32 }
33 response = http_call.run(url=endpoint, json_data=data)
34 return HookResponse(0, 'Called endpoint {}, with response {}'.format(endpoint, response))
35
36 return HookResponse(0, '')
1 NO CONTENT: new file 100644
1 NO CONTENT: new file 100644
@@ -0,0 +1,17
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
@@ -0,0 +1,40
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2018 RhodeCode GmbH
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
20 """
21 us in hooks::
22
23 from .helpers import extra_fields
24 # returns list of dicts with key-val fetched from extra fields
25 repo_extra_fields = extra_fields.run(**kwargs)
26
27 """
28
29
30 def run(*args, **kwargs):
31 from rhodecode.model.db import Repository
32 # use temp name then the main one propagated
33 repo_name = kwargs.pop('REPOSITORY', None) or kwargs['repository']
34 repo = Repository.get_by_repo_name(repo_name)
35
36 fields = {}
37 for field in repo.extra_fields:
38 fields[field.field_key] = field.get_dict()
39
40 return fields
@@ -0,0 +1,61
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2018 RhodeCode GmbH
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
20 """
21 Extract and serialize commits taken from a list of commit_ids. This should
22 be used in post_push hook
23
24 us in hooks::
25
26 from .helpers import extract_post_commits
27 # returns list of dicts with key-val fetched from extra fields
28 commit_list = extract_post_commits.run(**kwargs)
29 """
30 import traceback
31
32
33 def run(*args, **kwargs):
34 from rhodecode.lib.utils2 import extract_mentioned_users
35 from rhodecode.model.db import Repository
36
37 commit_ids = kwargs.get('commit_ids')
38 if not commit_ids:
39 return 0
40
41 # use temp name then the main one propagated
42 repo_name = kwargs.pop('REPOSITORY', None) or kwargs['repository']
43
44 repo = Repository.get_by_repo_name(repo_name)
45 commits = []
46
47 vcs_repo = repo.scm_instance(cache=False)
48 try:
49 for commit_id in commit_ids:
50 cs = vcs_repo.get_changeset(commit_id)
51 cs_data = cs.__json__()
52 cs_data['mentions'] = extract_mentioned_users(cs_data['message'])
53 # optionally add more logic to parse the commits, like reading extra
54 # fields of repository to read managers of reviewers ?
55 commits.append(cs_data)
56 except Exception:
57 print(traceback.format_exc())
58 # we don't send any commits when crash happens, only full list matters
59 # we short circuit then.
60 return []
61 return commits
@@ -0,0 +1,63
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2018 RhodeCode GmbH
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
20 """
21 us in hooks::
22
23 from .helpers import extract_pre_commits
24 # returns list of dicts with key-val fetched from extra fields
25 commit_list = extract_pre_commits.run(**kwargs)
26
27 """
28 import re
29 import collections
30
31
32 def get_hg_commits(repo, refs):
33 commits = []
34 return commits
35
36
37 def get_git_commits(repo, refs):
38 commits = []
39 return commits
40
41
42 def run(*args, **kwargs):
43 from rhodecode.model.db import Repository
44
45 vcs_type = kwargs['scm']
46 # use temp name then the main one propagated
47 repo_name = kwargs.pop('REPOSITORY', None) or kwargs['repository']
48
49 repo = Repository.get_by_repo_name(repo_name)
50 vcs_repo = repo.scm_instance(cache=False)
51
52 commits = []
53
54 for rev_data in kwargs['commit_ids']:
55 new_environ = dict((k, v) for k, v in rev_data['hg_env'])
56
57 if vcs_type == 'git':
58 commits = get_git_commits(vcs_repo, kwargs['commit_ids'])
59
60 if vcs_type == 'hg':
61 commits = get_hg_commits(vcs_repo, kwargs['commit_ids'])
62
63 return commits
@@ -0,0 +1,36
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2018 RhodeCode GmbH
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
20 """
21 us in hooks::
22
23 from .helpers import http_call
24 # returns response after making a POST call
25 response = http_call.run(url=url, json_data=data)
26
27 """
28
29 from rhodecode.integrations.types.base import requests_retry_call
30
31
32 def run(url, json_data, method='post'):
33 requests_session = requests_retry_call()
34 requests_session.verify = True # Verify SSL
35 resp = requests_session.post(url, json=json_data, timeout=60)
36 return resp.raise_for_status() # raise exception on a failed request
@@ -0,0 +1,431
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 from .utils import DotDict, HookResponse, has_kwargs
20
21
22 # Config shortcut to keep, all configuration in one place
23 # Example: api_key = CONFIG.my_config.api_key
24 CONFIG = DotDict(
25 my_config=DotDict(
26 api_key='<secret>',
27 ),
28
29 )
30
31
32 @has_kwargs({
33 'repo_name': '',
34 'repo_type': '',
35 'description': '',
36 'private': '',
37 'created_on': '',
38 'enable_downloads': '',
39 'repo_id': '',
40 'user_id': '',
41 'enable_statistics': '',
42 'clone_uri': '',
43 'fork_id': '',
44 'group_id': '',
45 'created_by': ''
46 })
47 def _create_repo_hook(*args, **kwargs):
48 """
49 POST CREATE REPOSITORY HOOK. This function will be executed after
50 each repository is created. kwargs available:
51
52 """
53 return HookResponse(0, '')
54
55
56 @has_kwargs({
57 'group_name': '',
58 'group_parent_id': '',
59 'group_description': '',
60 'group_id': '',
61 'user_id': '',
62 'created_by': '',
63 'created_on': '',
64 'enable_locking': ''
65 })
66 def _create_repo_group_hook(*args, **kwargs):
67 """
68 POST CREATE REPOSITORY GROUP HOOK, this function will be
69 executed after each repository group is created. kwargs available:
70 """
71 return HookResponse(0, '')
72
73
74 @has_kwargs({
75 'username': '',
76 'password': '',
77 'email': '',
78 'firstname': '',
79 'lastname': '',
80 'active': '',
81 'admin': '',
82 'created_by': '',
83 })
84 def _pre_create_user_hook(*args, **kwargs):
85 """
86 PRE CREATE USER HOOK, this function will be executed before each
87 user is created, it returns a tuple of bool, reason.
88 If bool is False the user creation will be stopped and reason
89 will be displayed to the user.
90
91 Return HookResponse(1, reason) to block user creation
92
93 """
94
95 reason = 'allowed'
96 return HookResponse(0, reason)
97
98
99 @has_kwargs({
100 'username': '',
101 'full_name_or_username': '',
102 'full_contact': '',
103 'user_id': '',
104 'name': '',
105 'firstname': '',
106 'short_contact': '',
107 'admin': '',
108 'lastname': '',
109 'ip_addresses': '',
110 'extern_type': '',
111 'extern_name': '',
112 'email': '',
113 'api_key': '',
114 'api_keys': '',
115 'last_login': '',
116 'full_name': '',
117 'active': '',
118 'password': '',
119 'emails': '',
120 'inherit_default_permissions': '',
121 'created_by': '',
122 'created_on': '',
123 })
124 def _create_user_hook(*args, **kwargs):
125 """
126 POST CREATE USER HOOK, this function will be executed after each user is created
127 """
128 return HookResponse(0, '')
129
130
131 @has_kwargs({
132 'repo_name': '',
133 'repo_type': '',
134 'description': '',
135 'private': '',
136 'created_on': '',
137 'enable_downloads': '',
138 'repo_id': '',
139 'user_id': '',
140 'enable_statistics': '',
141 'clone_uri': '',
142 'fork_id': '',
143 'group_id': '',
144 'deleted_by': '',
145 'deleted_on': '',
146 })
147 def _delete_repo_hook(*args, **kwargs):
148 """
149 POST DELETE REPOSITORY HOOK, this function will be executed after
150 each repository deletion
151 """
152 return HookResponse(0, '')
153
154
155 @has_kwargs({
156 'username': '',
157 'full_name_or_username': '',
158 'full_contact': '',
159 'user_id': '',
160 'name': '',
161 'short_contact': '',
162 'admin': '',
163 'firstname': '',
164 'lastname': '',
165 'ip_addresses': '',
166 'email': '',
167 'api_key': '',
168 'last_login': '',
169 'full_name': '',
170 'active': '',
171 'password': '',
172 'emails': '',
173 'inherit_default_permissions': '',
174 'deleted_by': '',
175 })
176 def _delete_user_hook(*args, **kwargs):
177 """
178 POST DELETE USER HOOK, this function will be executed after each
179 user is deleted kwargs available:
180 """
181 return HookResponse(0, '')
182
183
184 # =============================================================================
185 # PUSH/PULL RELATED HOOKS
186 # =============================================================================
187 @has_kwargs({
188 'server_url': 'url of instance that triggered this hook',
189 'config': 'path to .ini config used',
190 'scm': 'type of version control "git", "hg", "svn"',
191 'username': 'username of actor who triggered this event',
192 'ip': 'ip address of actor who triggered this hook',
193 'action': '',
194 'repository': 'repository name',
195 'repo_store_path': 'full path to where repositories are stored',
196 'commit_ids': 'pre transaction metadata for commit ids',
197 'hook_type': '',
198 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
199 })
200 def _pre_push_hook(*args, **kwargs):
201 """
202 Post push hook
203 To stop version control from storing the transaction and send a message to user
204 use non-zero HookResponse with a message, e.g return HookResponse(1, 'Not allowed')
205
206 This message will be shown back to client during PUSH operation
207
208 Commit ids might look like that::
209
210 [{u'hg_env|git_env': ...,
211 u'multiple_heads': [],
212 u'name': u'default',
213 u'new_rev': u'd0befe0692e722e01d5677f27a104631cf798b69',
214 u'old_rev': u'd0befe0692e722e01d5677f27a104631cf798b69',
215 u'ref': u'',
216 u'total_commits': 2,
217 u'type': u'branch'}]
218 """
219 return HookResponse(0, '')
220
221
222 @has_kwargs({
223 'server_url': 'url of instance that triggered this hook',
224 'config': 'path to .ini config used',
225 'scm': 'type of version control "git", "hg", "svn"',
226 'username': 'username of actor who triggered this event',
227 'ip': 'ip address of actor who triggered this hook',
228 'action': '',
229 'repository': 'repository name',
230 'repo_store_path': 'full path to where repositories are stored',
231 'commit_ids': 'list of pushed commit_ids (sha1)',
232 'hook_type': '',
233 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
234 })
235 def _push_hook(*args, **kwargs):
236 """
237 POST PUSH HOOK, this function will be executed after each push it's
238 executed after the build-in hook that RhodeCode uses for logging pushes
239 """
240 return HookResponse(0, '')
241
242
243 @has_kwargs({
244 'server_url': 'url of instance that triggered this hook',
245 'repo_store_path': 'full path to where repositories are stored',
246 'config': 'path to .ini config used',
247 'scm': 'type of version control "git", "hg", "svn"',
248 'username': 'username of actor who triggered this event',
249 'ip': 'ip address of actor who triggered this hook',
250 'action': '',
251 'repository': 'repository name',
252 'hook_type': '',
253 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
254 })
255 def _pre_pull_hook(*args, **kwargs):
256 """
257 Post pull hook
258 """
259 return HookResponse(0, '')
260
261
262 @has_kwargs({
263 'server_url': 'url of instance that triggered this hook',
264 'repo_store_path': 'full path to where repositories are stored',
265 'config': 'path to .ini config used',
266 'scm': 'type of version control "git", "hg", "svn"',
267 'username': 'username of actor who triggered this event',
268 'ip': 'ip address of actor who triggered this hook',
269 'action': '',
270 'repository': 'repository name',
271 'hook_type': '',
272 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
273 })
274 def _pull_hook(*args, **kwargs):
275 """
276 This hook will be executed after each code pull.
277 """
278 return HookResponse(0, '')
279
280
281 # =============================================================================
282 # PULL REQUEST RELATED HOOKS
283 # =============================================================================
284 @has_kwargs({
285 'server_url': 'url of instance that triggered this hook',
286 'config': 'path to .ini config used',
287 'scm': 'type of version control "git", "hg", "svn"',
288 'username': 'username of actor who triggered this event',
289 'ip': 'ip address of actor who triggered this hook',
290 'action': '',
291 'repository': 'repository name',
292 'pull_request_id': '',
293 'url': '',
294 'title': '',
295 'description': '',
296 'status': '',
297 'created_on': '',
298 'updated_on': '',
299 'commit_ids': '',
300 'review_status': '',
301 'mergeable': '',
302 'source': '',
303 'target': '',
304 'author': '',
305 'reviewers': '',
306 })
307 def _create_pull_request_hook(*args, **kwargs):
308 """
309 This hook will be executed after creation of a pull request.
310 """
311 return HookResponse(0, '')
312
313
314 @has_kwargs({
315 'server_url': 'url of instance that triggered this hook',
316 'config': 'path to .ini config used',
317 'scm': 'type of version control "git", "hg", "svn"',
318 'username': 'username of actor who triggered this event',
319 'ip': 'ip address of actor who triggered this hook',
320 'action': '',
321 'repository': 'repository name',
322 'pull_request_id': '',
323 'url': '',
324 'title': '',
325 'description': '',
326 'status': '',
327 'created_on': '',
328 'updated_on': '',
329 'commit_ids': '',
330 'review_status': '',
331 'mergeable': '',
332 'source': '',
333 'target': '',
334 'author': '',
335 'reviewers': '',
336 })
337 def _review_pull_request_hook(*args, **kwargs):
338 """
339 This hook will be executed after review action was made on a pull request.
340 """
341 return HookResponse(0, '')
342
343
344 @has_kwargs({
345 'server_url': 'url of instance that triggered this hook',
346 'config': 'path to .ini config used',
347 'scm': 'type of version control "git", "hg", "svn"',
348 'username': 'username of actor who triggered this event',
349 'ip': 'ip address of actor who triggered this hook',
350 'action': '',
351 'repository': 'repository name',
352 'pull_request_id': '',
353 'url': '',
354 'title': '',
355 'description': '',
356 'status': '',
357 'created_on': '',
358 'updated_on': '',
359 'commit_ids': '',
360 'review_status': '',
361 'mergeable': '',
362 'source': '',
363 'target': '',
364 'author': '',
365 'reviewers': '',
366 })
367 def _update_pull_request_hook(*args, **kwargs):
368 """
369 This hook will be executed after pull requests has been updated with new commits.
370 """
371 return HookResponse(0, '')
372
373
374 @has_kwargs({
375 'server_url': 'url of instance that triggered this hook',
376 'config': 'path to .ini config used',
377 'scm': 'type of version control "git", "hg", "svn"',
378 'username': 'username of actor who triggered this event',
379 'ip': 'ip address of actor who triggered this hook',
380 'action': '',
381 'repository': 'repository name',
382 'pull_request_id': '',
383 'url': '',
384 'title': '',
385 'description': '',
386 'status': '',
387 'created_on': '',
388 'updated_on': '',
389 'commit_ids': '',
390 'review_status': '',
391 'mergeable': '',
392 'source': '',
393 'target': '',
394 'author': '',
395 'reviewers': '',
396 })
397 def _merge_pull_request_hook(*args, **kwargs):
398 """
399 This hook will be executed after merge of a pull request.
400 """
401 return HookResponse(0, '')
402
403
404 @has_kwargs({
405 'server_url': 'url of instance that triggered this hook',
406 'config': 'path to .ini config used',
407 'scm': 'type of version control "git", "hg", "svn"',
408 'username': 'username of actor who triggered this event',
409 'ip': 'ip address of actor who triggered this hook',
410 'action': '',
411 'repository': 'repository name',
412 'pull_request_id': '',
413 'url': '',
414 'title': '',
415 'description': '',
416 'status': '',
417 'created_on': '',
418 'updated_on': '',
419 'commit_ids': '',
420 'review_status': '',
421 'mergeable': '',
422 'source': '',
423 'target': '',
424 'author': '',
425 'reviewers': '',
426 })
427 def _close_pull_request_hook(*args, **kwargs):
428 """
429 This hook will be executed after close of a pull request.
430 """
431 return HookResponse(0, '')
@@ -0,0 +1,21
1 # =============================================================================
2 # END OF UTILITY FUNCTIONS HERE
3 # =============================================================================
4
5 # Additional mappings that are not present in the pygments lexers
6 # used for building stats
7 # format is {'ext':['Names']} eg. {'py':['Python']} note: there can be
8 # more than one name for extension
9 # NOTE: that this will override any mappings in LANGUAGES_EXTENSIONS_MAP
10 # build by pygments
11 EXTRA_MAPPINGS = {'html': ['Text']}
12
13 # additional lexer definitions for custom files it's overrides pygments lexers,
14 # and uses defined name of lexer to colorize the files. Format is {'ext':
15 # 'lexer_name'} List of lexers can be printed running:
16 # >> python -c "import pprint;from pygments import lexers;
17 # pprint.pprint([(x[0], x[1]) for x in lexers.get_all_lexers()]);"
18
19 EXTRA_LEXERS = {
20 'tt': 'vbnet'
21 }
@@ -0,0 +1,147
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 import os
20 import functools
21 import collections
22
23
24 class HookResponse(object):
25 def __init__(self, status, output):
26 self.status = status
27 self.output = output
28
29 def __add__(self, other):
30 other_status = getattr(other, 'status', 0)
31 new_status = max(self.status, other_status)
32 other_output = getattr(other, 'output', '')
33 new_output = self.output + other_output
34
35 return HookResponse(new_status, new_output)
36
37 def __bool__(self):
38 return self.status == 0
39
40
41 class DotDict(dict):
42
43 def __contains__(self, k):
44 try:
45 return dict.__contains__(self, k) or hasattr(self, k)
46 except:
47 return False
48
49 # only called if k not found in normal places
50 def __getattr__(self, k):
51 try:
52 return object.__getattribute__(self, k)
53 except AttributeError:
54 try:
55 return self[k]
56 except KeyError:
57 raise AttributeError(k)
58
59 def __setattr__(self, k, v):
60 try:
61 object.__getattribute__(self, k)
62 except AttributeError:
63 try:
64 self[k] = v
65 except:
66 raise AttributeError(k)
67 else:
68 object.__setattr__(self, k, v)
69
70 def __delattr__(self, k):
71 try:
72 object.__getattribute__(self, k)
73 except AttributeError:
74 try:
75 del self[k]
76 except KeyError:
77 raise AttributeError(k)
78 else:
79 object.__delattr__(self, k)
80
81 def toDict(self):
82 return unserialize(self)
83
84 def __repr__(self):
85 keys = list(self.keys())
86 keys.sort()
87 args = ', '.join(['%s=%r' % (key, self[key]) for key in keys])
88 return '%s(%s)' % (self.__class__.__name__, args)
89
90 @staticmethod
91 def fromDict(d):
92 return serialize(d)
93
94
95 def serialize(x):
96 if isinstance(x, dict):
97 return DotDict((k, serialize(v)) for k, v in x.items())
98 elif isinstance(x, (list, tuple)):
99 return type(x)(serialize(v) for v in x)
100 else:
101 return x
102
103
104 def unserialize(x):
105 if isinstance(x, dict):
106 return dict((k, unserialize(v)) for k, v in x.items())
107 elif isinstance(x, (list, tuple)):
108 return type(x)(unserialize(v) for v in x)
109 else:
110 return x
111
112
113 def _verify_kwargs(func_name, expected_parameters, kwargs):
114 """
115 Verify that exactly `expected_parameters` are passed in as `kwargs`.
116 """
117 expected_parameters = set(expected_parameters)
118 kwargs_keys = set(kwargs.keys())
119 if kwargs_keys != expected_parameters:
120 missing_kwargs = expected_parameters - kwargs_keys
121 unexpected_kwargs = kwargs_keys - expected_parameters
122 raise AssertionError(
123 "func:%s: missing parameters: %r, unexpected parameters: %s" %
124 (func_name, missing_kwargs, unexpected_kwargs))
125
126
127 def has_kwargs(required_args):
128 """
129 decorator to verify extension calls arguments.
130
131 :param required_args:
132 """
133 def wrap(func):
134 def wrapper(*args, **kwargs):
135 _verify_kwargs(func.func_name, required_args.keys(), kwargs)
136 # in case there's `calls` defined on module we store the data
137 maybe_log_call(func.func_name, args, kwargs)
138 return func(*args, **kwargs)
139 return wrapper
140 return wrap
141
142
143 def maybe_log_call(name, args, kwargs):
144 from rhodecode.config import rcextensions
145 if hasattr(rcextensions, 'calls'):
146 calls = rcextensions.calls
147 calls[name].append((args, kwargs))
@@ -201,6 +201,9 let
201 201 cp configs/production.ini $out/etc
202 202 echo "[DONE]: saved enterprise-ce production.ini into $out/etc"
203 203
204 cp -r rhodecode/config/rcextensions $out/etc/rcextensions.tmpl
205 echo "[DONE]: saved enterprise-ce rcextensions into $out/etc/rcextensions.tmpl"
206
204 207 # python based programs need to be wrapped
205 208 mkdir -p $out/bin
206 209
@@ -14,12 +14,23 so to clarify what is meant each time, r
14 14 between software components and can be used to trigger plugins, or their
15 15 extensions.
16 16
17 .. toctree::
17
18 Hooks
19 -----
20
21 Within |RCM| there are two types of supported hooks.
18 22
19 rcx
20 install-ext
21 config-ext
22 extensions
23 hooks
24 full-blown-example
25 int-slack
23 * **Internal built-in hooks**: The internal |hg|, |git| or |svn| hooks are
24 triggered by different VCS operations, like push, pull,
25 or clone and are non-configurable, but you can add your own VCS hooks,
26 see :ref:`custom-hooks`.
27 * **Custom rcextensions hooks**: User defined hooks centre around the lifecycle of
28 certain actions such are |repo| creation, user creation etc. The actions
29 these hooks trigger can be rejected based on the API permissions of the
30 user calling them.
31
32 On instructions how to use the custom `rcextensions`
33 see :ref:`integrations-rcextensions` section.
34
35
36
@@ -3,7 +3,7
3 3 Integrations
4 4 ------------
5 5
6 Rhodecode supports integrations with external services for various events,
6 |RCE| supports integrations with external services for various events,
7 7 such as commit pushes and pull requests. Multiple integrations of the same type
8 8 can be added at the same time; this is useful for posting different events to