Well, at least I found out why I'm getting an empty list
Show More
@@ -0,0 +1,44 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,17 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b'' | |||||
|
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 b' let' | |||||
201 | cp configs/production.ini $out/etc |
|
201 | cp configs/production.ini $out/etc | |
202 | echo "[DONE]: saved enterprise-ce production.ini into $out/etc" |
|
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 | # python based programs need to be wrapped |
|
207 | # python based programs need to be wrapped | |
205 | mkdir -p $out/bin |
|
208 | mkdir -p $out/bin | |
206 |
|
209 |
@@ -14,12 +14,23 b' so to clarify what is meant each time, r' | |||||
14 | between software components and can be used to trigger plugins, or their |
|
14 | between software components and can be used to trigger plugins, or their | |
15 | extensions. |
|
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 |
|
23 | * **Internal built-in hooks**: The internal |hg|, |git| or |svn| hooks are | |
20 | install-ext |
|
24 | triggered by different VCS operations, like push, pull, | |
21 | config-ext |
|
25 | or clone and are non-configurable, but you can add your own VCS hooks, | |
22 | extensions |
|
26 | see :ref:`custom-hooks`. | |
23 | hooks |
|
27 | * **Custom rcextensions hooks**: User defined hooks centre around the lifecycle of | |
24 | full-blown-example |
|
28 | certain actions such are |repo| creation, user creation etc. The actions | |
25 | int-slack |
|
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 b'' | |||||
3 | Integrations |
|
3 | Integrations | |
4 | ------------ |
|
4 | ------------ | |
5 |
|
5 | |||
6 |
|
|
6 | |RCE| supports integrations with external services for various events, | |
7 | such as commit pushes and pull requests. Multiple integrations of the same type |
|
7 | such as commit pushes and pull requests. Multiple integrations of the same type | |
8 | can be added at the same time; this is useful for posting different events to |
|
8 | can be added at the same time; this is useful for posting different events to | |
9 | different Slack channels, for example. |
|
9 | different Slack channels, for example. | |
@@ -11,18 +11,20 b' different Slack channels, for example.' | |||||
11 | Supported integrations |
|
11 | Supported integrations | |
12 | ^^^^^^^^^^^^^^^^^^^^^^ |
|
12 | ^^^^^^^^^^^^^^^^^^^^^^ | |
13 |
|
13 | |||
14 | ============================ ============ ===================================== |
|
14 | ================================ ============ ======================================== | |
15 | Type/Name |RC| Edition Description |
|
15 | Type/Name |RC| Edition Description | |
16 | ============================ ============ ===================================== |
|
16 | ================================ ============ ======================================== | |
17 |
:ref:`integrations- |
|
17 | :ref:`integrations-webhook` |RCCEshort| Trigger events as `json` to a custom url | |
18 |
:ref:`integrations- |
|
18 | :ref:`integrations-slack` |RCCEshort| Integrate with https://slack.com/ | |
19 | :ref:`integrations-webhook` |RCCEshort| POST events as `json` to a custom url |
|
19 | :ref:`integrations-hipchat` |RCCEshort| Integrate with https://www.hipchat.com/ | |
|
20 | :ref:`integrations-email` |RCCEshort| Send repo push commits by email | |||
20 | :ref:`integrations-ci` |RCCEshort| Trigger Builds for Common CI Systems |
|
21 | :ref:`integrations-ci` |RCCEshort| Trigger Builds for Common CI Systems | |
21 | :ref:`integrations-email` |RCCEshort| Send repo push commits by email |
|
22 | :ref:`integrations-rcextensions` |RCCEshort| Advanced low-level integration framework | |
|
23 | ||||
22 | :ref:`integrations-jenkins` |RCEEshort| Trigger Builds for Jenkins CI System |
|
24 | :ref:`integrations-jenkins` |RCEEshort| Trigger Builds for Jenkins CI System | |
23 | :ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference Redmine issues |
|
25 | :ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference Redmine issues | |
24 | :ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues |
|
26 | :ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues | |
25 | ============================ ============ ===================================== |
|
27 | ================================ ============ ======================================== | |
26 |
|
28 | |||
27 | .. _creating-integrations: |
|
29 | .. _creating-integrations: | |
28 |
|
30 | |||
@@ -55,3 +57,4 b' See pages specific to each type of integ' | |||||
55 |
|
57 | |||
56 | ci |
|
58 | ci | |
57 | jenkins |
|
59 | jenkins | |
|
60 | integrations-rcextensions |
@@ -273,107 +273,8 b' Use this to create or update a |RCE| con' | |||||
273 | rhodecode-extensions |
|
273 | rhodecode-extensions | |
274 | -------------------- |
|
274 | -------------------- | |
275 |
|
275 | |||
276 | |RCT| adds additional mapping for :ref:`indexing-ref`, statistics, and adds |
|
276 | The `rcextensions` since version 4.14 are now shipped together with |RCE| please check | |
277 | additional code for push/pull/create/delete |repo| hooks. These hooks can be |
|
277 | the using :ref:`integrations-rcextensions` section. | |
278 | used to send signals to build-bots such as jenkins. Options: |
|
|||
279 |
|
||||
280 | .. rst-class:: dl-horizontal |
|
|||
281 |
|
||||
282 | \-c, - -config <config_file> |
|
|||
283 | Create a configuration file. The default file is created |
|
|||
284 | in ``~/.rhoderc`` |
|
|||
285 |
|
||||
286 | \-h, - -help |
|
|||
287 | Show help messages. |
|
|||
288 |
|
||||
289 | \-F, - -format {json,pretty} |
|
|||
290 | Set the formatted representation. |
|
|||
291 |
|
||||
292 | \-I, - -install-dir <str> |
|
|||
293 | Set the location of the |RCE| installation. The default location is |
|
|||
294 | :file:`/home/{user}/.rccontrol/`. |
|
|||
295 |
|
||||
296 | \ - -ini-file <str> |
|
|||
297 | Path to the :file:`rhodecode.ini` file for that instance. |
|
|||
298 |
|
||||
299 | \ - -instance-name <instance-id> |
|
|||
300 | Set the instance name. |
|
|||
301 |
|
||||
302 | \ - -plugins |
|
|||
303 | Add plugins to your |RCE| installation. See the |
|
|||
304 | :ref:`extensions-hooks-ref` section for more details. |
|
|||
305 |
|
||||
306 | \ - -version |
|
|||
307 | Display your |RCT| version. |
|
|||
308 |
|
||||
309 |
|
||||
310 | Once installed, you will see a :file:`rcextensions` folder in the instance |
|
|||
311 | directory, for example :file:`home/{user}/.rccontrol/{instance-id}/rcextensions` |
|
|||
312 |
|
||||
313 | To install ``rcextensions``, use the following example: |
|
|||
314 |
|
||||
315 | .. code-block:: bash |
|
|||
316 |
|
||||
317 | # install extensions on the given instance |
|
|||
318 | # If using virtualenv prior to RCE 350 |
|
|||
319 | (venv)$ rhodecode-extensions --instance-name=enterprise-1 \ |
|
|||
320 | --ini-file=rhodecode.ini |
|
|||
321 | Writen new extensions file to rcextensions |
|
|||
322 |
|
||||
323 | # install extensions with additional plugins on the given instance |
|
|||
324 | (venv)$ rhodecode-extensions --instance-name=enterprise-1 \ |
|
|||
325 | --ini-file=rhodecode.ini --plugins |
|
|||
326 | Writen new extensions file to rcextensions |
|
|||
327 |
|
||||
328 | # installing extensions from 350 onwards |
|
|||
329 | # as they are packaged with RCE |
|
|||
330 | $ .rccontrol/enterprise-4/profile/bin/rhodecode-extensions --plugins \ |
|
|||
331 | --instance-name=enterprise-4 --ini-file=rhodecode.ini |
|
|||
332 |
|
||||
333 | Writen new extensions file to rcextensions |
|
|||
334 |
|
||||
335 | See the new extensions inside this directory for more details about the |
|
|||
336 | additional hooks available, for example see the ``push_post.py`` file. |
|
|||
337 |
|
||||
338 | .. code-block:: python |
|
|||
339 |
|
||||
340 | import urllib |
|
|||
341 | import urllib2 |
|
|||
342 |
|
||||
343 | def run(*args, **kwargs): |
|
|||
344 | """ |
|
|||
345 | Extra params |
|
|||
346 |
|
||||
347 | :param URL: url to send the data to |
|
|||
348 | """ |
|
|||
349 |
|
||||
350 | url = kwargs.pop('URL', None) |
|
|||
351 | if url: |
|
|||
352 | from rhodecode.lib.compat import json |
|
|||
353 | from rhodecode.model.db import Repository |
|
|||
354 |
|
||||
355 | repo = Repository.get_by_repo_name(kwargs['repository']) |
|
|||
356 | changesets = [] |
|
|||
357 | vcs_repo = repo.scm_instance_no_cache() |
|
|||
358 | for r in kwargs['pushed_revs']: |
|
|||
359 | cs = vcs_repo.get_changeset(r) |
|
|||
360 | changesets.append(json.dumps(cs)) |
|
|||
361 |
|
||||
362 | kwargs['pushed_revs'] = changesets |
|
|||
363 | headers = { |
|
|||
364 | 'User-Agent': 'RhodeCode-SCM web hook', |
|
|||
365 | 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', |
|
|||
366 | 'Accept': 'text/javascript, text/html, application/xml, ' |
|
|||
367 | 'text/xml, */*', |
|
|||
368 | 'Accept-Encoding': 'gzip,deflate,sdch', |
|
|||
369 | } |
|
|||
370 |
|
||||
371 | data = kwargs |
|
|||
372 | data = urllib.urlencode(data) |
|
|||
373 | req = urllib2.Request(url, data, headers) |
|
|||
374 | response = urllib2.urlopen(req) |
|
|||
375 | response.read() |
|
|||
376 | return 0 |
|
|||
377 |
|
278 | |||
378 |
|
279 | |||
379 | rhodecode-gist |
|
280 | rhodecode-gist |
@@ -54,23 +54,13 b' packaged with |RCE| by default.' | |||||
54 |
|
54 | |||
55 | .. code-block:: bash |
|
55 | .. code-block:: bash | |
56 |
|
56 | |||
57 | $ .rccontrol/enterprise-4/profile/bin/rhodecode-extensions --plugins \ |
|
57 | $ .rccontrol/enterprise-4/profile/bin/rhodecode-api --instance-name=enterprise-4 get_ip [11:56:57 on 05/10/2018] | |
58 | --instance-name=enterprise-4 --ini-file=rhodecode.ini |
|
|||
59 |
|
58 | |||
60 | Writen new extensions file to rcextensions |
|
59 | { | |
61 | Copied hipchat_push_notify.py plugin to rcextensions |
|
60 | "error": null, | |
62 | Copied jira_pr_flow.py plugin to rcextensions |
|
61 | "id": 1000, | |
63 | Copied default_reviewers.py plugin to rcextensions |
|
62 | "result": { | |
64 | Copied extract_commits.py plugin to rcextensions |
|
63 | "server_ip_addr": "1.2.3.4", | |
65 | Copied extract_issues.py plugin to rcextensions |
|
64 | "user_ips": [] | |
66 | Copied redmine_pr_flow.py plugin to rcextensions |
|
65 | } | |
67 | Copied extra_fields.py plugin to rcextensions |
|
66 | } | |
68 | Copied jira_smart_commits.py plugin to rcextensions |
|
|||
69 | Copied http_notify.py plugin to rcextensions |
|
|||
70 | Copied slack_push_notify.py plugin to rcextensions |
|
|||
71 | Copied slack_message.py plugin to rcextensions |
|
|||
72 | Copied extract_jira_issues.py plugin to rcextensions |
|
|||
73 | Copied extract_redmine_issues.py plugin to rcextensions |
|
|||
74 | Copied redmine_smart_commits.py plugin to rcextensions |
|
|||
75 | Copied send_mail.py plugin to rcextensions |
|
|||
76 |
|
@@ -578,11 +578,11 b' class TestPullrequestsView(object):' | |||||
578 | assert actions[-1].action_data['commit_ids'] == pr_commit_ids |
|
578 | assert actions[-1].action_data['commit_ids'] == pr_commit_ids | |
579 |
|
579 | |||
580 | # Check post_push rcextension was really executed |
|
580 | # Check post_push rcextension was really executed | |
581 |
push_calls = rhodecode.EXTENSIONS.calls[' |
|
581 | push_calls = rhodecode.EXTENSIONS.calls['_push_hook'] | |
582 | assert len(push_calls) == 1 |
|
582 | assert len(push_calls) == 1 | |
583 | unused_last_call_args, last_call_kwargs = push_calls[0] |
|
583 | unused_last_call_args, last_call_kwargs = push_calls[0] | |
584 | assert last_call_kwargs['action'] == 'push' |
|
584 | assert last_call_kwargs['action'] == 'push' | |
585 |
assert last_call_kwargs[' |
|
585 | assert last_call_kwargs['commit_ids'] == pr_commit_ids | |
586 |
|
586 | |||
587 | def test_merge_pull_request_disabled(self, pr_util, csrf_token): |
|
587 | def test_merge_pull_request_disabled(self, pr_util, csrf_token): | |
588 | pull_request = pr_util.create_pull_request(mergeable=False) |
|
588 | pull_request = pr_util.create_pull_request(mergeable=False) |
@@ -39,7 +39,21 b' from rhodecode.model.db import Repositor' | |||||
39 | log = logging.getLogger(__name__) |
|
39 | log = logging.getLogger(__name__) | |
40 |
|
40 | |||
41 |
|
41 | |||
42 | HookResponse = collections.namedtuple('HookResponse', ('status', 'output')) |
|
42 | class HookResponse(object): | |
|
43 | def __init__(self, status, output): | |||
|
44 | self.status = status | |||
|
45 | self.output = output | |||
|
46 | ||||
|
47 | def __add__(self, other): | |||
|
48 | other_status = getattr(other, 'status', 0) | |||
|
49 | new_status = max(self.status, other_status) | |||
|
50 | other_output = getattr(other, 'output', '') | |||
|
51 | new_output = self.output + other_output | |||
|
52 | ||||
|
53 | return HookResponse(new_status, new_output) | |||
|
54 | ||||
|
55 | def __bool__(self): | |||
|
56 | return self.status == 0 | |||
43 |
|
57 | |||
44 |
|
58 | |||
45 | def is_shadow_repo(extras): |
|
59 | def is_shadow_repo(extras): | |
@@ -110,6 +124,7 b' def pre_push(extras):' | |||||
110 | else: |
|
124 | else: | |
111 | raise _http_ret |
|
125 | raise _http_ret | |
112 |
|
126 | |||
|
127 | hook_response = '' | |||
113 | if not is_shadow_repo(extras): |
|
128 | if not is_shadow_repo(extras): | |
114 | if extras.commit_ids and extras.check_branch_perms: |
|
129 | if extras.commit_ids and extras.check_branch_perms: | |
115 |
|
130 | |||
@@ -152,11 +167,12 b' def pre_push(extras):' | |||||
152 |
|
167 | |||
153 | # Propagate to external components. This is done after checking the |
|
168 | # Propagate to external components. This is done after checking the | |
154 | # lock, for consistent behavior. |
|
169 | # lock, for consistent behavior. | |
155 | pre_push_extension(repo_store_path=Repository.base_path(), **extras) |
|
170 | hook_response = pre_push_extension( | |
|
171 | repo_store_path=Repository.base_path(), **extras) | |||
156 | events.trigger(events.RepoPrePushEvent( |
|
172 | events.trigger(events.RepoPrePushEvent( | |
157 | repo_name=extras.repository, extras=extras)) |
|
173 | repo_name=extras.repository, extras=extras)) | |
158 |
|
174 | |||
159 | return HookResponse(0, output) |
|
175 | return HookResponse(0, output) + hook_response | |
160 |
|
176 | |||
161 |
|
177 | |||
162 | def pre_pull(extras): |
|
178 | def pre_pull(extras): | |
@@ -182,12 +198,15 b' def pre_pull(extras):' | |||||
182 |
|
198 | |||
183 | # Propagate to external components. This is done after checking the |
|
199 | # Propagate to external components. This is done after checking the | |
184 | # lock, for consistent behavior. |
|
200 | # lock, for consistent behavior. | |
|
201 | hook_response = '' | |||
185 | if not is_shadow_repo(extras): |
|
202 | if not is_shadow_repo(extras): | |
186 | pre_pull_extension(**extras) |
|
203 | extras.hook_type = extras.hook_type or 'pre_pull' | |
|
204 | hook_response = pre_pull_extension( | |||
|
205 | repo_store_path=Repository.base_path(), **extras) | |||
187 | events.trigger(events.RepoPrePullEvent( |
|
206 | events.trigger(events.RepoPrePullEvent( | |
188 | repo_name=extras.repository, extras=extras)) |
|
207 | repo_name=extras.repository, extras=extras)) | |
189 |
|
208 | |||
190 | return HookResponse(0, output) |
|
209 | return HookResponse(0, output) + hook_response | |
191 |
|
210 | |||
192 |
|
211 | |||
193 | def post_pull(extras): |
|
212 | def post_pull(extras): | |
@@ -198,16 +217,9 b' def post_pull(extras):' | |||||
198 | ip_addr=extras.ip) |
|
217 | ip_addr=extras.ip) | |
199 | repo = audit_logger.RepoWrap(repo_name=extras.repository) |
|
218 | repo = audit_logger.RepoWrap(repo_name=extras.repository) | |
200 | audit_logger.store( |
|
219 | audit_logger.store( | |
201 | 'user.pull', action_data={ |
|
220 | 'user.pull', action_data={'user_agent': extras.user_agent}, | |
202 | 'user_agent': extras.user_agent}, |
|
|||
203 | user=audit_user, repo=repo, commit=True) |
|
221 | user=audit_user, repo=repo, commit=True) | |
204 |
|
222 | |||
205 | # Propagate to external components. |
|
|||
206 | if not is_shadow_repo(extras): |
|
|||
207 | post_pull_extension(**extras) |
|
|||
208 | events.trigger(events.RepoPullEvent( |
|
|||
209 | repo_name=extras.repository, extras=extras)) |
|
|||
210 |
|
||||
211 | output = '' |
|
223 | output = '' | |
212 | # make lock is a tri state False, True, None. We only make lock on True |
|
224 | # make lock is a tri state False, True, None. We only make lock on True | |
213 | if extras.make_lock is True and not is_shadow_repo(extras): |
|
225 | if extras.make_lock is True and not is_shadow_repo(extras): | |
@@ -227,7 +239,16 b' def post_pull(extras):' | |||||
227 | # 2xx Codes don't raise exceptions |
|
239 | # 2xx Codes don't raise exceptions | |
228 | output += _http_ret.title |
|
240 | output += _http_ret.title | |
229 |
|
241 | |||
230 | return HookResponse(0, output) |
|
242 | # Propagate to external components. | |
|
243 | hook_response = '' | |||
|
244 | if not is_shadow_repo(extras): | |||
|
245 | extras.hook_type = extras.hook_type or 'post_pull' | |||
|
246 | hook_response = post_pull_extension( | |||
|
247 | repo_store_path=Repository.base_path(), **extras) | |||
|
248 | events.trigger(events.RepoPullEvent( | |||
|
249 | repo_name=extras.repository, extras=extras)) | |||
|
250 | ||||
|
251 | return HookResponse(0, output) + hook_response | |||
231 |
|
252 | |||
232 |
|
253 | |||
233 | def post_push(extras): |
|
254 | def post_push(extras): | |
@@ -245,16 +266,6 b' def post_push(extras):' | |||||
245 | user=audit_user, repo=repo, commit=True) |
|
266 | user=audit_user, repo=repo, commit=True) | |
246 |
|
267 | |||
247 | # Propagate to external components. |
|
268 | # Propagate to external components. | |
248 | if not is_shadow_repo(extras): |
|
|||
249 | post_push_extension( |
|
|||
250 | repo_store_path=Repository.base_path(), |
|
|||
251 | pushed_revs=commit_ids, |
|
|||
252 | **extras) |
|
|||
253 | events.trigger(events.RepoPushEvent( |
|
|||
254 | repo_name=extras.repository, |
|
|||
255 | pushed_commit_ids=commit_ids, |
|
|||
256 | extras=extras)) |
|
|||
257 |
|
||||
258 | output = '' |
|
269 | output = '' | |
259 | # make lock is a tri state False, True, None. We only release lock on False |
|
270 | # make lock is a tri state False, True, None. We only release lock on False | |
260 | if extras.make_lock is False and not is_shadow_repo(extras): |
|
271 | if extras.make_lock is False and not is_shadow_repo(extras): | |
@@ -285,8 +296,16 b' def post_push(extras):' | |||||
285 | output += 'RhodeCode: open pull request link: {}\n'.format( |
|
296 | output += 'RhodeCode: open pull request link: {}\n'.format( | |
286 | tmpl.format(ref_type='bookmark', ref_name=book_name)) |
|
297 | tmpl.format(ref_type='bookmark', ref_name=book_name)) | |
287 |
|
298 | |||
|
299 | hook_response = '' | |||
|
300 | if not is_shadow_repo(extras): | |||
|
301 | hook_response = post_push_extension( | |||
|
302 | repo_store_path=Repository.base_path(), | |||
|
303 | **extras) | |||
|
304 | events.trigger(events.RepoPushEvent( | |||
|
305 | repo_name=extras.repository, pushed_commit_ids=commit_ids, extras=extras)) | |||
|
306 | ||||
288 | output += 'RhodeCode: push completed\n' |
|
307 | output += 'RhodeCode: push completed\n' | |
289 | return HookResponse(0, output) |
|
308 | return HookResponse(0, output) + hook_response | |
290 |
|
309 | |||
291 |
|
310 | |||
292 | def _locked_by_explanation(repo_name, user_name, reason): |
|
311 | def _locked_by_explanation(repo_name, user_name, reason): | |
@@ -299,8 +318,10 b' def _locked_by_explanation(repo_name, us' | |||||
299 | def check_allowed_create_user(user_dict, created_by, **kwargs): |
|
318 | def check_allowed_create_user(user_dict, created_by, **kwargs): | |
300 | # pre create hooks |
|
319 | # pre create hooks | |
301 | if pre_create_user.is_active(): |
|
320 | if pre_create_user.is_active(): | |
302 |
|
|
321 | hook_result = pre_create_user(created_by=created_by, **user_dict) | |
|
322 | allowed = hook_result.status == 0 | |||
303 | if not allowed: |
|
323 | if not allowed: | |
|
324 | reason = hook_result.output | |||
304 | raise UserCreationError(reason) |
|
325 | raise UserCreationError(reason) | |
305 |
|
326 | |||
306 |
|
327 | |||
@@ -319,8 +340,15 b' class ExtensionCallback(object):' | |||||
319 |
|
340 | |||
320 | def __call__(self, *args, **kwargs): |
|
341 | def __call__(self, *args, **kwargs): | |
321 | log.debug('Calling extension callback for %s', self._hook_name) |
|
342 | log.debug('Calling extension callback for %s', self._hook_name) | |
|
343 | kwargs_to_pass = {} | |||
|
344 | for key in self._kwargs_keys: | |||
|
345 | try: | |||
|
346 | kwargs_to_pass[key] = kwargs[key] | |||
|
347 | except KeyError: | |||
|
348 | log.error('Failed to fetch %s key. Expected keys: %s', | |||
|
349 | key, self._kwargs_keys) | |||
|
350 | raise | |||
322 |
|
351 | |||
323 | kwargs_to_pass = dict((key, kwargs[key]) for key in self._kwargs_keys) |
|
|||
324 | # backward compat for removed api_key for old hooks. THis was it works |
|
352 | # backward compat for removed api_key for old hooks. THis was it works | |
325 | # with older rcextensions that require api_key present |
|
353 | # with older rcextensions that require api_key present | |
326 | if self._hook_name in ['CREATE_USER_HOOK', 'DELETE_USER_HOOK']: |
|
354 | if self._hook_name in ['CREATE_USER_HOOK', 'DELETE_USER_HOOK']: | |
@@ -343,28 +371,28 b' pre_pull_extension = ExtensionCallback(' | |||||
343 | hook_name='PRE_PULL_HOOK', |
|
371 | hook_name='PRE_PULL_HOOK', | |
344 | kwargs_keys=( |
|
372 | kwargs_keys=( | |
345 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', |
|
373 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', | |
346 | 'repository')) |
|
374 | 'repository', 'hook_type', 'user_agent', 'repo_store_path',)) | |
347 |
|
375 | |||
348 |
|
376 | |||
349 | post_pull_extension = ExtensionCallback( |
|
377 | post_pull_extension = ExtensionCallback( | |
350 | hook_name='PULL_HOOK', |
|
378 | hook_name='PULL_HOOK', | |
351 | kwargs_keys=( |
|
379 | kwargs_keys=( | |
352 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', |
|
380 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', | |
353 | 'repository')) |
|
381 | 'repository', 'hook_type', 'user_agent', 'repo_store_path',)) | |
354 |
|
382 | |||
355 |
|
383 | |||
356 | pre_push_extension = ExtensionCallback( |
|
384 | pre_push_extension = ExtensionCallback( | |
357 | hook_name='PRE_PUSH_HOOK', |
|
385 | hook_name='PRE_PUSH_HOOK', | |
358 | kwargs_keys=( |
|
386 | kwargs_keys=( | |
359 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', |
|
387 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', | |
360 | 'repository', 'repo_store_path', 'commit_ids')) |
|
388 | 'repository', 'repo_store_path', 'commit_ids', 'hook_type', 'user_agent',)) | |
361 |
|
389 | |||
362 |
|
390 | |||
363 | post_push_extension = ExtensionCallback( |
|
391 | post_push_extension = ExtensionCallback( | |
364 | hook_name='PUSH_HOOK', |
|
392 | hook_name='PUSH_HOOK', | |
365 | kwargs_keys=( |
|
393 | kwargs_keys=( | |
366 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', |
|
394 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', | |
367 |
'repository', 'repo_store_path', ' |
|
395 | 'repository', 'repo_store_path', 'commit_ids', 'hook_type', 'user_agent',)) | |
368 |
|
396 | |||
369 |
|
397 | |||
370 | pre_create_user = ExtensionCallback( |
|
398 | pre_create_user = ExtensionCallback( |
@@ -47,7 +47,7 b' def _get_rc_scm_extras(username, repo_na' | |||||
47 |
|
47 | |||
48 |
|
48 | |||
49 | def trigger_post_push_hook( |
|
49 | def trigger_post_push_hook( | |
50 | username, action, repo_name, repo_alias, commit_ids): |
|
50 | username, action, hook_type, repo_name, repo_alias, commit_ids): | |
51 | """ |
|
51 | """ | |
52 | Triggers push action hooks |
|
52 | Triggers push action hooks | |
53 |
|
53 | |||
@@ -59,6 +59,7 b' def trigger_post_push_hook(' | |||||
59 | """ |
|
59 | """ | |
60 | extras = _get_rc_scm_extras(username, repo_name, repo_alias, action) |
|
60 | extras = _get_rc_scm_extras(username, repo_name, repo_alias, action) | |
61 | extras.commit_ids = commit_ids |
|
61 | extras.commit_ids = commit_ids | |
|
62 | extras.hook_type = hook_type | |||
62 | hooks_base.post_push(extras) |
|
63 | hooks_base.post_push(extras) | |
63 |
|
64 | |||
64 |
|
65 |
@@ -28,6 +28,7 b' import json' | |||||
28 | import logging |
|
28 | import logging | |
29 | import os |
|
29 | import os | |
30 | import re |
|
30 | import re | |
|
31 | import sys | |||
31 | import shutil |
|
32 | import shutil | |
32 | import tempfile |
|
33 | import tempfile | |
33 | import traceback |
|
34 | import traceback | |
@@ -43,7 +44,6 b' from mako import exceptions' | |||||
43 | from pyramid.threadlocal import get_current_registry |
|
44 | from pyramid.threadlocal import get_current_registry | |
44 | from rhodecode.lib.request import Request |
|
45 | from rhodecode.lib.request import Request | |
45 |
|
46 | |||
46 | from rhodecode.lib.fakemod import create_module |
|
|||
47 | from rhodecode.lib.vcs.backends.base import Config |
|
47 | from rhodecode.lib.vcs.backends.base import Config | |
48 | from rhodecode.lib.vcs.exceptions import VCSError |
|
48 | from rhodecode.lib.vcs.exceptions import VCSError | |
49 | from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend |
|
49 | from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend | |
@@ -631,21 +631,21 b' def load_rcextensions(root_path):' | |||||
631 | import rhodecode |
|
631 | import rhodecode | |
632 | from rhodecode.config import conf |
|
632 | from rhodecode.config import conf | |
633 |
|
633 | |||
634 |
path = os.path.join(root_path |
|
634 | path = os.path.join(root_path) | |
635 |
|
|
635 | sys.path.append(path) | |
636 | rcext = create_module('rc', path) |
|
636 | try: | |
637 | EXT = rhodecode.EXTENSIONS = rcext |
|
637 | rcextensions = __import__('rcextensions') | |
638 | log.debug('Found rcextensions now loading %s...', rcext) |
|
638 | except ImportError: | |
|
639 | log.warn('Unable to load rcextensions from %s', path) | |||
|
640 | rcextensions = None | |||
|
641 | ||||
|
642 | if rcextensions: | |||
|
643 | log.debug('Found rcextensions module loaded %s...', rcextensions) | |||
|
644 | rhodecode.EXTENSIONS = rcextensions | |||
639 |
|
645 | |||
640 | # Additional mappings that are not present in the pygments lexers |
|
646 | # Additional mappings that are not present in the pygments lexers | |
641 |
conf.LANGUAGES_EXTENSIONS_MAP.update( |
|
647 | conf.LANGUAGES_EXTENSIONS_MAP.update( | |
642 |
|
648 | getattr(rhodecode.EXTENSIONS, 'EXTRA_MAPPINGS', {})) | ||
643 | # auto check if the module is not missing any data, set to default if is |
|
|||
644 | # this will help autoupdate new feature of rcext module |
|
|||
645 | #from rhodecode.config import rcextensions |
|
|||
646 | #for k in dir(rcextensions): |
|
|||
647 | # if not k.startswith('_') and not hasattr(EXT, k): |
|
|||
648 | # setattr(EXT, k, getattr(rcextensions, k)) |
|
|||
649 |
|
649 | |||
650 |
|
650 | |||
651 | def get_custom_lexer(extension): |
|
651 | def get_custom_lexer(extension): |
@@ -590,6 +590,7 b' class PullRequestModel(BaseModel):' | |||||
590 |
|
590 | |||
591 | def merge_repo(self, pull_request, user, extras): |
|
591 | def merge_repo(self, pull_request, user, extras): | |
592 | log.debug("Merging pull request %s", pull_request.pull_request_id) |
|
592 | log.debug("Merging pull request %s", pull_request.pull_request_id) | |
|
593 | extras['user_agent'] = 'internal-merge' | |||
593 | merge_state = self._merge_pull_request(pull_request, user, extras) |
|
594 | merge_state = self._merge_pull_request(pull_request, user, extras) | |
594 | if merge_state.executed: |
|
595 | if merge_state.executed: | |
595 | log.debug( |
|
596 | log.debug( |
@@ -465,8 +465,8 b' class ScmModel(BaseModel):' | |||||
465 |
|
465 | |||
466 | # We trigger the post-push action |
|
466 | # We trigger the post-push action | |
467 | hooks_utils.trigger_post_push_hook( |
|
467 | hooks_utils.trigger_post_push_hook( | |
468 |
username=user.username, action='push_local', |
|
468 | username=user.username, action='push_local', hook_type='post_push', | |
469 | repo_alias=repo.alias, commit_ids=[tip.raw_id]) |
|
469 | repo_name=repo_name, repo_alias=repo.alias, commit_ids=[tip.raw_id]) | |
470 | return tip |
|
470 | return tip | |
471 |
|
471 | |||
472 | def _sanitize_path(self, f_path): |
|
472 | def _sanitize_path(self, f_path): | |
@@ -644,6 +644,7 b' class ScmModel(BaseModel):' | |||||
644 | hooks_utils.trigger_post_push_hook( |
|
644 | hooks_utils.trigger_post_push_hook( | |
645 | username=user.username, action='push_local', |
|
645 | username=user.username, action='push_local', | |
646 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, |
|
646 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, | |
|
647 | hook_type='post_push', | |||
647 | commit_ids=[tip.raw_id]) |
|
648 | commit_ids=[tip.raw_id]) | |
648 | return tip |
|
649 | return tip | |
649 |
|
650 | |||
@@ -708,7 +709,7 b' class ScmModel(BaseModel):' | |||||
708 |
|
709 | |||
709 | if trigger_push_hook: |
|
710 | if trigger_push_hook: | |
710 | hooks_utils.trigger_post_push_hook( |
|
711 | hooks_utils.trigger_post_push_hook( | |
711 | username=user.username, action='push_local', |
|
712 | username=user.username, action='push_local', hook_type='post_push', | |
712 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, |
|
713 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, | |
713 | commit_ids=[tip.raw_id]) |
|
714 | commit_ids=[tip.raw_id]) | |
714 |
|
715 | |||
@@ -768,7 +769,7 b' class ScmModel(BaseModel):' | |||||
768 | self.mark_for_invalidation(repo.repo_name) |
|
769 | self.mark_for_invalidation(repo.repo_name) | |
769 | if trigger_push_hook: |
|
770 | if trigger_push_hook: | |
770 | hooks_utils.trigger_post_push_hook( |
|
771 | hooks_utils.trigger_post_push_hook( | |
771 | username=user.username, action='push_local', |
|
772 | username=user.username, action='push_local', hook_type='post_push', | |
772 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, |
|
773 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, | |
773 | commit_ids=[tip.raw_id]) |
|
774 | commit_ids=[tip.raw_id]) | |
774 | return tip |
|
775 | return tip |
@@ -45,9 +45,10 b' def scm_extras(user_regular, repo_stub):' | |||||
45 | 'repo_store': '', |
|
45 | 'repo_store': '', | |
46 | 'server_url': 'http://example.com', |
|
46 | 'server_url': 'http://example.com', | |
47 | 'make_lock': None, |
|
47 | 'make_lock': None, | |
48 |
'user |
|
48 | 'user_agent': 'some-client', | |
49 | 'locked_by': [None], |
|
49 | 'locked_by': [None], | |
50 | 'commit_ids': ['a' * 40] * 3, |
|
50 | 'commit_ids': ['a' * 40] * 3, | |
|
51 | 'hook_type': 'scm_extras_test', | |||
51 | 'is_shadow_repo': False, |
|
52 | 'is_shadow_repo': False, | |
52 | }) |
|
53 | }) | |
53 | return extras |
|
54 | return extras |
@@ -38,6 +38,7 b' def test_post_push_truncates_commits(use' | |||||
38 | 'user_agent': 'some-client', |
|
38 | 'user_agent': 'some-client', | |
39 | 'locked_by': [None], |
|
39 | 'locked_by': [None], | |
40 | 'commit_ids': ['abcde12345' * 4] * 30000, |
|
40 | 'commit_ids': ['abcde12345' * 4] * 30000, | |
|
41 | 'hook_type': 'large_push_test_type', | |||
41 | 'is_shadow_repo': False, |
|
42 | 'is_shadow_repo': False, | |
42 | } |
|
43 | } | |
43 | extras = utils2.AttributeDict(extras) |
|
44 | extras = utils2.AttributeDict(extras) | |
@@ -76,6 +77,7 b' def hook_extras(user_regular, repo_stub)' | |||||
76 | 'user_agent': 'some-client', |
|
77 | 'user_agent': 'some-client', | |
77 | 'locked_by': [None], |
|
78 | 'locked_by': [None], | |
78 | 'commit_ids': [], |
|
79 | 'commit_ids': [], | |
|
80 | 'hook_type': 'test_type', | |||
79 | 'is_shadow_repo': False, |
|
81 | 'is_shadow_repo': False, | |
80 | }) |
|
82 | }) | |
81 | return extras |
|
83 | return extras | |
@@ -92,7 +94,12 b' def test_hooks_propagate(func, extension' | |||||
92 | Tests that our hook code propagates to rhodecode extensions and triggers |
|
94 | Tests that our hook code propagates to rhodecode extensions and triggers | |
93 | the appropriate event. |
|
95 | the appropriate event. | |
94 | """ |
|
96 | """ | |
95 |
|
|
97 | class ExtensionMock(mock.Mock): | |
|
98 | @property | |||
|
99 | def output(self): | |||
|
100 | return 'MOCK' | |||
|
101 | ||||
|
102 | extension_mock = ExtensionMock() | |||
96 | events_mock = mock.Mock() |
|
103 | events_mock = mock.Mock() | |
97 | patches = { |
|
104 | patches = { | |
98 | 'Repository': mock.Mock(), |
|
105 | 'Repository': mock.Mock(), |
@@ -393,6 +393,7 b' class TestIntegrationMerge(object):' | |||||
393 | def test_merge_triggers_push_hooks( |
|
393 | def test_merge_triggers_push_hooks( | |
394 | self, pr_util, user_admin, capture_rcextensions, merge_extras, |
|
394 | self, pr_util, user_admin, capture_rcextensions, merge_extras, | |
395 | extra_config): |
|
395 | extra_config): | |
|
396 | ||||
396 | pull_request = pr_util.create_pull_request( |
|
397 | pull_request = pr_util.create_pull_request( | |
397 | approved=True, mergeable=True) |
|
398 | approved=True, mergeable=True) | |
398 | # TODO: johbo: Needed for sqlite, try to find an automatic way for it |
|
399 | # TODO: johbo: Needed for sqlite, try to find an automatic way for it | |
@@ -404,8 +405,8 b' class TestIntegrationMerge(object):' | |||||
404 | pull_request, user_admin, extras=merge_extras) |
|
405 | pull_request, user_admin, extras=merge_extras) | |
405 |
|
406 | |||
406 | assert merge_state.executed |
|
407 | assert merge_state.executed | |
407 | assert 'pre_push' in capture_rcextensions |
|
408 | assert '_pre_push_hook' in capture_rcextensions | |
408 |
assert ' |
|
409 | assert '_push_hook' in capture_rcextensions | |
409 |
|
410 | |||
410 | def test_merge_can_be_rejected_by_pre_push_hook( |
|
411 | def test_merge_can_be_rejected_by_pre_push_hook( | |
411 | self, pr_util, user_admin, capture_rcextensions, merge_extras): |
|
412 | self, pr_util, user_admin, capture_rcextensions, merge_extras): |
@@ -154,10 +154,11 b' def activate_example_rcextensions(reques' | |||||
154 | """ |
|
154 | """ | |
155 | Patch in an example rcextensions module which verifies passed in kwargs. |
|
155 | Patch in an example rcextensions module which verifies passed in kwargs. | |
156 | """ |
|
156 | """ | |
157 |
from rhodecode. |
|
157 | from rhodecode.config import rcextensions | |
158 |
|
158 | |||
159 | old_extensions = rhodecode.EXTENSIONS |
|
159 | old_extensions = rhodecode.EXTENSIONS | |
160 |
rhodecode.EXTENSIONS = |
|
160 | rhodecode.EXTENSIONS = rcextensions | |
|
161 | rhodecode.EXTENSIONS.calls = collections.defaultdict(list) | |||
161 |
|
162 | |||
162 | @request.addfinalizer |
|
163 | @request.addfinalizer | |
163 | def cleanup(): |
|
164 | def cleanup(): |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
This diff has been collapsed as it changes many lines, (823 lines changed) Show them Hide them |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now