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 |
|
1 | 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 | 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 b' 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 b'' | |||
|
3 | 3 | Integrations |
|
4 | 4 | ------------ |
|
5 | 5 | |
|
6 |
|
|
|
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 |
|
9 | 9 | different Slack channels, for example. |
@@ -11,18 +11,20 b' different Slack channels, for example.' | |||
|
11 | 11 | Supported integrations |
|
12 | 12 | ^^^^^^^^^^^^^^^^^^^^^^ |
|
13 | 13 | |
|
14 | ============================ ============ ===================================== | |
|
15 | Type/Name |RC| Edition Description | |
|
16 | ============================ ============ ===================================== | |
|
17 |
:ref:`integrations- |
|
|
18 |
:ref:`integrations- |
|
|
19 | :ref:`integrations-webhook` |RCCEshort| POST events as `json` to a custom url | |
|
20 |
:ref:`integrations- |
|
|
21 |
:ref:`integrations- |
|
|
22 | :ref:`integrations-jenkins` |RCEEshort| Trigger Builds for Jenkins CI System | |
|
23 | :ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference Redmine issues | |
|
24 | :ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues | |
|
25 | ============================ ============ ===================================== | |
|
14 | ================================ ============ ======================================== | |
|
15 | Type/Name |RC| Edition Description | |
|
16 | ================================ ============ ======================================== | |
|
17 | :ref:`integrations-webhook` |RCCEshort| Trigger events as `json` to a custom url | |
|
18 | :ref:`integrations-slack` |RCCEshort| Integrate with https://slack.com/ | |
|
19 | :ref:`integrations-hipchat` |RCCEshort| Integrate with https://www.hipchat.com/ | |
|
20 | :ref:`integrations-email` |RCCEshort| Send repo push commits by email | |
|
21 | :ref:`integrations-ci` |RCCEshort| Trigger Builds for Common CI Systems | |
|
22 | :ref:`integrations-rcextensions` |RCCEshort| Advanced low-level integration framework | |
|
23 | ||
|
24 | :ref:`integrations-jenkins` |RCEEshort| Trigger Builds for Jenkins CI System | |
|
25 | :ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference Redmine issues | |
|
26 | :ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues | |
|
27 | ================================ ============ ======================================== | |
|
26 | 28 | |
|
27 | 29 | .. _creating-integrations: |
|
28 | 30 | |
@@ -55,3 +57,4 b' See pages specific to each type of integ' | |||
|
55 | 57 | |
|
56 | 58 | ci |
|
57 | 59 | jenkins |
|
60 | integrations-rcextensions |
@@ -273,107 +273,8 b' Use this to create or update a |RCE| con' | |||
|
273 | 273 | rhodecode-extensions |
|
274 | 274 | -------------------- |
|
275 | 275 | |
|
276 | |RCT| adds additional mapping for :ref:`indexing-ref`, statistics, and adds | |
|
277 | additional code for push/pull/create/delete |repo| hooks. These hooks can be | |
|
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 | |
|
276 | The `rcextensions` since version 4.14 are now shipped together with |RCE| please check | |
|
277 | the using :ref:`integrations-rcextensions` section. | |
|
377 | 278 | |
|
378 | 279 | |
|
379 | 280 | rhodecode-gist |
@@ -54,23 +54,13 b' packaged with |RCE| by default.' | |||
|
54 | 54 | |
|
55 | 55 | .. code-block:: bash |
|
56 | 56 | |
|
57 | $ .rccontrol/enterprise-4/profile/bin/rhodecode-extensions --plugins \ | |
|
58 | --instance-name=enterprise-4 --ini-file=rhodecode.ini | |
|
57 | $ .rccontrol/enterprise-4/profile/bin/rhodecode-api --instance-name=enterprise-4 get_ip [11:56:57 on 05/10/2018] | |
|
59 | 58 | |
|
60 | Writen new extensions file to rcextensions | |
|
61 | Copied hipchat_push_notify.py plugin to rcextensions | |
|
62 | Copied jira_pr_flow.py plugin to rcextensions | |
|
63 | Copied default_reviewers.py plugin to rcextensions | |
|
64 | Copied extract_commits.py plugin to rcextensions | |
|
65 | Copied extract_issues.py plugin to rcextensions | |
|
66 | Copied redmine_pr_flow.py plugin to rcextensions | |
|
67 | Copied extra_fields.py plugin to rcextensions | |
|
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 | ||
|
59 | { | |
|
60 | "error": null, | |
|
61 | "id": 1000, | |
|
62 | "result": { | |
|
63 | "server_ip_addr": "1.2.3.4", | |
|
64 | "user_ips": [] | |
|
65 | } | |
|
66 | } |
@@ -578,11 +578,11 b' class TestPullrequestsView(object):' | |||
|
578 | 578 | assert actions[-1].action_data['commit_ids'] == pr_commit_ids |
|
579 | 579 | |
|
580 | 580 | # Check post_push rcextension was really executed |
|
581 |
push_calls = rhodecode.EXTENSIONS.calls[' |
|
|
581 | push_calls = rhodecode.EXTENSIONS.calls['_push_hook'] | |
|
582 | 582 | assert len(push_calls) == 1 |
|
583 | 583 | unused_last_call_args, last_call_kwargs = push_calls[0] |
|
584 | 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 | 587 | def test_merge_pull_request_disabled(self, pr_util, csrf_token): |
|
588 | 588 | pull_request = pr_util.create_pull_request(mergeable=False) |
@@ -39,7 +39,21 b' from rhodecode.model.db import Repositor' | |||
|
39 | 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 | 59 | def is_shadow_repo(extras): |
@@ -110,6 +124,7 b' def pre_push(extras):' | |||
|
110 | 124 | else: |
|
111 | 125 | raise _http_ret |
|
112 | 126 | |
|
127 | hook_response = '' | |
|
113 | 128 | if not is_shadow_repo(extras): |
|
114 | 129 | if extras.commit_ids and extras.check_branch_perms: |
|
115 | 130 | |
@@ -152,11 +167,12 b' def pre_push(extras):' | |||
|
152 | 167 | |
|
153 | 168 | # Propagate to external components. This is done after checking the |
|
154 | 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 | 172 | events.trigger(events.RepoPrePushEvent( |
|
157 | 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 | 178 | def pre_pull(extras): |
@@ -182,12 +198,15 b' def pre_pull(extras):' | |||
|
182 | 198 | |
|
183 | 199 | # Propagate to external components. This is done after checking the |
|
184 | 200 | # lock, for consistent behavior. |
|
201 | hook_response = '' | |
|
185 | 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 | 206 | events.trigger(events.RepoPrePullEvent( |
|
188 | 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 | 212 | def post_pull(extras): |
@@ -198,16 +217,9 b' def post_pull(extras):' | |||
|
198 | 217 | ip_addr=extras.ip) |
|
199 | 218 | repo = audit_logger.RepoWrap(repo_name=extras.repository) |
|
200 | 219 | audit_logger.store( |
|
201 | 'user.pull', action_data={ | |
|
202 | 'user_agent': extras.user_agent}, | |
|
220 | 'user.pull', action_data={'user_agent': extras.user_agent}, | |
|
203 | 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 | 223 | output = '' |
|
212 | 224 | # make lock is a tri state False, True, None. We only make lock on True |
|
213 | 225 | if extras.make_lock is True and not is_shadow_repo(extras): |
@@ -227,7 +239,16 b' def post_pull(extras):' | |||
|
227 | 239 | # 2xx Codes don't raise exceptions |
|
228 | 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 | 254 | def post_push(extras): |
@@ -245,16 +266,6 b' def post_push(extras):' | |||
|
245 | 266 | user=audit_user, repo=repo, commit=True) |
|
246 | 267 | |
|
247 | 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 | 269 | output = '' |
|
259 | 270 | # make lock is a tri state False, True, None. We only release lock on False |
|
260 | 271 | if extras.make_lock is False and not is_shadow_repo(extras): |
@@ -285,8 +296,16 b' def post_push(extras):' | |||
|
285 | 296 | output += 'RhodeCode: open pull request link: {}\n'.format( |
|
286 | 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 | 307 | output += 'RhodeCode: push completed\n' |
|
289 | return HookResponse(0, output) | |
|
308 | return HookResponse(0, output) + hook_response | |
|
290 | 309 | |
|
291 | 310 | |
|
292 | 311 | def _locked_by_explanation(repo_name, user_name, reason): |
@@ -299,8 +318,10 b' def _locked_by_explanation(repo_name, us' | |||
|
299 | 318 | def check_allowed_create_user(user_dict, created_by, **kwargs): |
|
300 | 319 | # pre create hooks |
|
301 | 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 | 323 | if not allowed: |
|
324 | reason = hook_result.output | |
|
304 | 325 | raise UserCreationError(reason) |
|
305 | 326 | |
|
306 | 327 | |
@@ -319,8 +340,15 b' class ExtensionCallback(object):' | |||
|
319 | 340 | |
|
320 | 341 | def __call__(self, *args, **kwargs): |
|
321 | 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 | 352 | # backward compat for removed api_key for old hooks. THis was it works |
|
325 | 353 | # with older rcextensions that require api_key present |
|
326 | 354 | if self._hook_name in ['CREATE_USER_HOOK', 'DELETE_USER_HOOK']: |
@@ -343,28 +371,28 b' pre_pull_extension = ExtensionCallback(' | |||
|
343 | 371 | hook_name='PRE_PULL_HOOK', |
|
344 | 372 | kwargs_keys=( |
|
345 | 373 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', |
|
346 | 'repository')) | |
|
374 | 'repository', 'hook_type', 'user_agent', 'repo_store_path',)) | |
|
347 | 375 | |
|
348 | 376 | |
|
349 | 377 | post_pull_extension = ExtensionCallback( |
|
350 | 378 | hook_name='PULL_HOOK', |
|
351 | 379 | kwargs_keys=( |
|
352 | 380 | 'server_url', 'config', 'scm', 'username', 'ip', 'action', |
|
353 | 'repository')) | |
|
381 | 'repository', 'hook_type', 'user_agent', 'repo_store_path',)) | |
|
354 | 382 | |
|
355 | 383 | |
|
356 | 384 | pre_push_extension = ExtensionCallback( |
|
357 | 385 | hook_name='PRE_PUSH_HOOK', |
|
358 | 386 | kwargs_keys=( |
|
359 | 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 | 391 | post_push_extension = ExtensionCallback( |
|
364 | 392 | hook_name='PUSH_HOOK', |
|
365 | 393 | kwargs_keys=( |
|
366 | 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 | 398 | pre_create_user = ExtensionCallback( |
@@ -47,7 +47,7 b' def _get_rc_scm_extras(username, repo_na' | |||
|
47 | 47 | |
|
48 | 48 | |
|
49 | 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 | 52 | Triggers push action hooks |
|
53 | 53 | |
@@ -59,6 +59,7 b' def trigger_post_push_hook(' | |||
|
59 | 59 | """ |
|
60 | 60 | extras = _get_rc_scm_extras(username, repo_name, repo_alias, action) |
|
61 | 61 | extras.commit_ids = commit_ids |
|
62 | extras.hook_type = hook_type | |
|
62 | 63 | hooks_base.post_push(extras) |
|
63 | 64 | |
|
64 | 65 |
@@ -28,6 +28,7 b' import json' | |||
|
28 | 28 | import logging |
|
29 | 29 | import os |
|
30 | 30 | import re |
|
31 | import sys | |
|
31 | 32 | import shutil |
|
32 | 33 | import tempfile |
|
33 | 34 | import traceback |
@@ -43,7 +44,6 b' from mako import exceptions' | |||
|
43 | 44 | from pyramid.threadlocal import get_current_registry |
|
44 | 45 | from rhodecode.lib.request import Request |
|
45 | 46 | |
|
46 | from rhodecode.lib.fakemod import create_module | |
|
47 | 47 | from rhodecode.lib.vcs.backends.base import Config |
|
48 | 48 | from rhodecode.lib.vcs.exceptions import VCSError |
|
49 | 49 | from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend |
@@ -631,21 +631,21 b' def load_rcextensions(root_path):' | |||
|
631 | 631 | import rhodecode |
|
632 | 632 | from rhodecode.config import conf |
|
633 | 633 | |
|
634 |
path = os.path.join(root_path |
|
|
635 |
|
|
|
636 | rcext = create_module('rc', path) | |
|
637 | EXT = rhodecode.EXTENSIONS = rcext | |
|
638 | log.debug('Found rcextensions now loading %s...', rcext) | |
|
634 | path = os.path.join(root_path) | |
|
635 | sys.path.append(path) | |
|
636 | try: | |
|
637 | rcextensions = __import__('rcextensions') | |
|
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 | 646 | # Additional mappings that are not present in the pygments lexers |
|
641 |
conf.LANGUAGES_EXTENSIONS_MAP.update( |
|
|
642 | ||
|
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)) | |
|
647 | conf.LANGUAGES_EXTENSIONS_MAP.update( | |
|
648 | getattr(rhodecode.EXTENSIONS, 'EXTRA_MAPPINGS', {})) | |
|
649 | 649 | |
|
650 | 650 | |
|
651 | 651 | def get_custom_lexer(extension): |
@@ -590,6 +590,7 b' class PullRequestModel(BaseModel):' | |||
|
590 | 590 | |
|
591 | 591 | def merge_repo(self, pull_request, user, extras): |
|
592 | 592 | log.debug("Merging pull request %s", pull_request.pull_request_id) |
|
593 | extras['user_agent'] = 'internal-merge' | |
|
593 | 594 | merge_state = self._merge_pull_request(pull_request, user, extras) |
|
594 | 595 | if merge_state.executed: |
|
595 | 596 | log.debug( |
@@ -465,8 +465,8 b' class ScmModel(BaseModel):' | |||
|
465 | 465 | |
|
466 | 466 | # We trigger the post-push action |
|
467 | 467 | hooks_utils.trigger_post_push_hook( |
|
468 |
username=user.username, action='push_local', |
|
|
469 | repo_alias=repo.alias, commit_ids=[tip.raw_id]) | |
|
468 | username=user.username, action='push_local', hook_type='post_push', | |
|
469 | repo_name=repo_name, repo_alias=repo.alias, commit_ids=[tip.raw_id]) | |
|
470 | 470 | return tip |
|
471 | 471 | |
|
472 | 472 | def _sanitize_path(self, f_path): |
@@ -644,6 +644,7 b' class ScmModel(BaseModel):' | |||
|
644 | 644 | hooks_utils.trigger_post_push_hook( |
|
645 | 645 | username=user.username, action='push_local', |
|
646 | 646 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, |
|
647 | hook_type='post_push', | |
|
647 | 648 | commit_ids=[tip.raw_id]) |
|
648 | 649 | return tip |
|
649 | 650 | |
@@ -708,7 +709,7 b' class ScmModel(BaseModel):' | |||
|
708 | 709 | |
|
709 | 710 | if trigger_push_hook: |
|
710 | 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 | 713 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, |
|
713 | 714 | commit_ids=[tip.raw_id]) |
|
714 | 715 | |
@@ -768,7 +769,7 b' class ScmModel(BaseModel):' | |||
|
768 | 769 | self.mark_for_invalidation(repo.repo_name) |
|
769 | 770 | if trigger_push_hook: |
|
770 | 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 | 773 | repo_name=repo.repo_name, repo_alias=scm_instance.alias, |
|
773 | 774 | commit_ids=[tip.raw_id]) |
|
774 | 775 | return tip |
@@ -45,9 +45,10 b' def scm_extras(user_regular, repo_stub):' | |||
|
45 | 45 | 'repo_store': '', |
|
46 | 46 | 'server_url': 'http://example.com', |
|
47 | 47 | 'make_lock': None, |
|
48 |
'user |
|
|
48 | 'user_agent': 'some-client', | |
|
49 | 49 | 'locked_by': [None], |
|
50 | 50 | 'commit_ids': ['a' * 40] * 3, |
|
51 | 'hook_type': 'scm_extras_test', | |
|
51 | 52 | 'is_shadow_repo': False, |
|
52 | 53 | }) |
|
53 | 54 | return extras |
@@ -38,6 +38,7 b' def test_post_push_truncates_commits(use' | |||
|
38 | 38 | 'user_agent': 'some-client', |
|
39 | 39 | 'locked_by': [None], |
|
40 | 40 | 'commit_ids': ['abcde12345' * 4] * 30000, |
|
41 | 'hook_type': 'large_push_test_type', | |
|
41 | 42 | 'is_shadow_repo': False, |
|
42 | 43 | } |
|
43 | 44 | extras = utils2.AttributeDict(extras) |
@@ -76,6 +77,7 b' def hook_extras(user_regular, repo_stub)' | |||
|
76 | 77 | 'user_agent': 'some-client', |
|
77 | 78 | 'locked_by': [None], |
|
78 | 79 | 'commit_ids': [], |
|
80 | 'hook_type': 'test_type', | |
|
79 | 81 | 'is_shadow_repo': False, |
|
80 | 82 | }) |
|
81 | 83 | return extras |
@@ -92,7 +94,12 b' def test_hooks_propagate(func, extension' | |||
|
92 | 94 | Tests that our hook code propagates to rhodecode extensions and triggers |
|
93 | 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 | 103 | events_mock = mock.Mock() |
|
97 | 104 | patches = { |
|
98 | 105 | 'Repository': mock.Mock(), |
@@ -393,6 +393,7 b' class TestIntegrationMerge(object):' | |||
|
393 | 393 | def test_merge_triggers_push_hooks( |
|
394 | 394 | self, pr_util, user_admin, capture_rcextensions, merge_extras, |
|
395 | 395 | extra_config): |
|
396 | ||
|
396 | 397 | pull_request = pr_util.create_pull_request( |
|
397 | 398 | approved=True, mergeable=True) |
|
398 | 399 | # TODO: johbo: Needed for sqlite, try to find an automatic way for it |
@@ -404,8 +405,8 b' class TestIntegrationMerge(object):' | |||
|
404 | 405 | pull_request, user_admin, extras=merge_extras) |
|
405 | 406 | |
|
406 | 407 | assert merge_state.executed |
|
407 | assert 'pre_push' in capture_rcextensions | |
|
408 |
assert ' |
|
|
408 | assert '_pre_push_hook' in capture_rcextensions | |
|
409 | assert '_push_hook' in capture_rcextensions | |
|
409 | 410 | |
|
410 | 411 | def test_merge_can_be_rejected_by_pre_push_hook( |
|
411 | 412 | self, pr_util, user_admin, capture_rcextensions, merge_extras): |
@@ -154,10 +154,11 b' def activate_example_rcextensions(reques' | |||
|
154 | 154 | """ |
|
155 | 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 | 159 | old_extensions = rhodecode.EXTENSIONS |
|
160 |
rhodecode.EXTENSIONS = |
|
|
160 | rhodecode.EXTENSIONS = rcextensions | |
|
161 | rhodecode.EXTENSIONS.calls = collections.defaultdict(list) | |
|
161 | 162 | |
|
162 | 163 | @request.addfinalizer |
|
163 | 164 | def cleanup(): |
|
1 | NO CONTENT: file was removed |
|
1 | 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 |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now