Show More
@@ -1,431 +1,432 b'' | |||||
1 | # Copyright (C) 2016-2019 RhodeCode GmbH |
|
1 | # Copyright (C) 2016-2019 RhodeCode GmbH | |
2 | # |
|
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify |
|
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 |
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |
5 | # (only), as published by the Free Software Foundation. |
|
5 | # (only), as published by the Free Software Foundation. | |
6 | # |
|
6 | # | |
7 | # This program is distributed in the hope that it will be useful, |
|
7 | # This program is distributed in the hope that it will be useful, | |
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | # GNU General Public License for more details. |
|
10 | # GNU General Public License for more details. | |
11 | # |
|
11 | # | |
12 | # You should have received a copy of the GNU Affero General Public License |
|
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/>. |
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | # |
|
14 | # | |
15 | # This program is dual-licensed. If you wish to learn more about the |
|
15 | # This program is dual-licensed. If you wish to learn more about the | |
16 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 |
|
18 | import logging | ||
19 | from .utils import DotDict, HookResponse, has_kwargs |
|
19 | from .utils import DotDict, HookResponse, has_kwargs | |
|
20 | log = logging.getLogger('rhodecode.' + __name__) | |||
20 |
|
21 | |||
21 |
|
22 | |||
22 | # Config shortcut to keep, all configuration in one place |
|
23 | # Config shortcut to keep, all configuration in one place | |
23 | # Example: api_key = CONFIG.my_config.api_key |
|
24 | # Example: api_key = CONFIG.my_config.api_key | |
24 | CONFIG = DotDict( |
|
25 | CONFIG = DotDict( | |
25 | my_config=DotDict( |
|
26 | my_config=DotDict( | |
26 | api_key='<secret>', |
|
27 | api_key='<secret>', | |
27 | ), |
|
28 | ), | |
28 |
|
29 | |||
29 | ) |
|
30 | ) | |
30 |
|
31 | |||
31 |
|
32 | |||
32 | @has_kwargs({ |
|
33 | @has_kwargs({ | |
33 | 'repo_name': '', |
|
34 | 'repo_name': '', | |
34 | 'repo_type': '', |
|
35 | 'repo_type': '', | |
35 | 'description': '', |
|
36 | 'description': '', | |
36 | 'private': '', |
|
37 | 'private': '', | |
37 | 'created_on': '', |
|
38 | 'created_on': '', | |
38 | 'enable_downloads': '', |
|
39 | 'enable_downloads': '', | |
39 | 'repo_id': '', |
|
40 | 'repo_id': '', | |
40 | 'user_id': '', |
|
41 | 'user_id': '', | |
41 | 'enable_statistics': '', |
|
42 | 'enable_statistics': '', | |
42 | 'clone_uri': '', |
|
43 | 'clone_uri': '', | |
43 | 'fork_id': '', |
|
44 | 'fork_id': '', | |
44 | 'group_id': '', |
|
45 | 'group_id': '', | |
45 | 'created_by': '' |
|
46 | 'created_by': '' | |
46 | }) |
|
47 | }) | |
47 | def _create_repo_hook(*args, **kwargs): |
|
48 | def _create_repo_hook(*args, **kwargs): | |
48 | """ |
|
49 | """ | |
49 | POST CREATE REPOSITORY HOOK. This function will be executed after |
|
50 | POST CREATE REPOSITORY HOOK. This function will be executed after | |
50 | each repository is created. kwargs available: |
|
51 | each repository is created. kwargs available: | |
51 |
|
52 | |||
52 | """ |
|
53 | """ | |
53 | return HookResponse(0, '') |
|
54 | return HookResponse(0, '') | |
54 |
|
55 | |||
55 |
|
56 | |||
56 | @has_kwargs({ |
|
57 | @has_kwargs({ | |
57 | 'group_name': '', |
|
58 | 'group_name': '', | |
58 | 'group_parent_id': '', |
|
59 | 'group_parent_id': '', | |
59 | 'group_description': '', |
|
60 | 'group_description': '', | |
60 | 'group_id': '', |
|
61 | 'group_id': '', | |
61 | 'user_id': '', |
|
62 | 'user_id': '', | |
62 | 'created_by': '', |
|
63 | 'created_by': '', | |
63 | 'created_on': '', |
|
64 | 'created_on': '', | |
64 | 'enable_locking': '' |
|
65 | 'enable_locking': '' | |
65 | }) |
|
66 | }) | |
66 | def _create_repo_group_hook(*args, **kwargs): |
|
67 | def _create_repo_group_hook(*args, **kwargs): | |
67 | """ |
|
68 | """ | |
68 | POST CREATE REPOSITORY GROUP HOOK, this function will be |
|
69 | POST CREATE REPOSITORY GROUP HOOK, this function will be | |
69 | executed after each repository group is created. kwargs available: |
|
70 | executed after each repository group is created. kwargs available: | |
70 | """ |
|
71 | """ | |
71 | return HookResponse(0, '') |
|
72 | return HookResponse(0, '') | |
72 |
|
73 | |||
73 |
|
74 | |||
74 | @has_kwargs({ |
|
75 | @has_kwargs({ | |
75 | 'username': '', |
|
76 | 'username': '', | |
76 | 'password': '', |
|
77 | 'password': '', | |
77 | 'email': '', |
|
78 | 'email': '', | |
78 | 'firstname': '', |
|
79 | 'firstname': '', | |
79 | 'lastname': '', |
|
80 | 'lastname': '', | |
80 | 'active': '', |
|
81 | 'active': '', | |
81 | 'admin': '', |
|
82 | 'admin': '', | |
82 | 'created_by': '', |
|
83 | 'created_by': '', | |
83 | }) |
|
84 | }) | |
84 | def _pre_create_user_hook(*args, **kwargs): |
|
85 | def _pre_create_user_hook(*args, **kwargs): | |
85 | """ |
|
86 | """ | |
86 | PRE CREATE USER HOOK, this function will be executed before each |
|
87 | PRE CREATE USER HOOK, this function will be executed before each | |
87 | user is created, it returns a tuple of bool, reason. |
|
88 | user is created, it returns a tuple of bool, reason. | |
88 | If bool is False the user creation will be stopped and reason |
|
89 | If bool is False the user creation will be stopped and reason | |
89 | will be displayed to the user. |
|
90 | will be displayed to the user. | |
90 |
|
91 | |||
91 | Return HookResponse(1, reason) to block user creation |
|
92 | Return HookResponse(1, reason) to block user creation | |
92 |
|
93 | |||
93 | """ |
|
94 | """ | |
94 |
|
95 | |||
95 | reason = 'allowed' |
|
96 | reason = 'allowed' | |
96 | return HookResponse(0, reason) |
|
97 | return HookResponse(0, reason) | |
97 |
|
98 | |||
98 |
|
99 | |||
99 | @has_kwargs({ |
|
100 | @has_kwargs({ | |
100 | 'username': '', |
|
101 | 'username': '', | |
101 | 'full_name_or_username': '', |
|
102 | 'full_name_or_username': '', | |
102 | 'full_contact': '', |
|
103 | 'full_contact': '', | |
103 | 'user_id': '', |
|
104 | 'user_id': '', | |
104 | 'name': '', |
|
105 | 'name': '', | |
105 | 'firstname': '', |
|
106 | 'firstname': '', | |
106 | 'short_contact': '', |
|
107 | 'short_contact': '', | |
107 | 'admin': '', |
|
108 | 'admin': '', | |
108 | 'lastname': '', |
|
109 | 'lastname': '', | |
109 | 'ip_addresses': '', |
|
110 | 'ip_addresses': '', | |
110 | 'extern_type': '', |
|
111 | 'extern_type': '', | |
111 | 'extern_name': '', |
|
112 | 'extern_name': '', | |
112 | 'email': '', |
|
113 | 'email': '', | |
113 | 'api_key': '', |
|
114 | 'api_key': '', | |
114 | 'api_keys': '', |
|
115 | 'api_keys': '', | |
115 | 'last_login': '', |
|
116 | 'last_login': '', | |
116 | 'full_name': '', |
|
117 | 'full_name': '', | |
117 | 'active': '', |
|
118 | 'active': '', | |
118 | 'password': '', |
|
119 | 'password': '', | |
119 | 'emails': '', |
|
120 | 'emails': '', | |
120 | 'inherit_default_permissions': '', |
|
121 | 'inherit_default_permissions': '', | |
121 | 'created_by': '', |
|
122 | 'created_by': '', | |
122 | 'created_on': '', |
|
123 | 'created_on': '', | |
123 | }) |
|
124 | }) | |
124 | def _create_user_hook(*args, **kwargs): |
|
125 | def _create_user_hook(*args, **kwargs): | |
125 | """ |
|
126 | """ | |
126 | POST CREATE USER HOOK, this function will be executed after each user is created |
|
127 | POST CREATE USER HOOK, this function will be executed after each user is created | |
127 | """ |
|
128 | """ | |
128 | return HookResponse(0, '') |
|
129 | return HookResponse(0, '') | |
129 |
|
130 | |||
130 |
|
131 | |||
131 | @has_kwargs({ |
|
132 | @has_kwargs({ | |
132 | 'repo_name': '', |
|
133 | 'repo_name': '', | |
133 | 'repo_type': '', |
|
134 | 'repo_type': '', | |
134 | 'description': '', |
|
135 | 'description': '', | |
135 | 'private': '', |
|
136 | 'private': '', | |
136 | 'created_on': '', |
|
137 | 'created_on': '', | |
137 | 'enable_downloads': '', |
|
138 | 'enable_downloads': '', | |
138 | 'repo_id': '', |
|
139 | 'repo_id': '', | |
139 | 'user_id': '', |
|
140 | 'user_id': '', | |
140 | 'enable_statistics': '', |
|
141 | 'enable_statistics': '', | |
141 | 'clone_uri': '', |
|
142 | 'clone_uri': '', | |
142 | 'fork_id': '', |
|
143 | 'fork_id': '', | |
143 | 'group_id': '', |
|
144 | 'group_id': '', | |
144 | 'deleted_by': '', |
|
145 | 'deleted_by': '', | |
145 | 'deleted_on': '', |
|
146 | 'deleted_on': '', | |
146 | }) |
|
147 | }) | |
147 | def _delete_repo_hook(*args, **kwargs): |
|
148 | def _delete_repo_hook(*args, **kwargs): | |
148 | """ |
|
149 | """ | |
149 | POST DELETE REPOSITORY HOOK, this function will be executed after |
|
150 | POST DELETE REPOSITORY HOOK, this function will be executed after | |
150 | each repository deletion |
|
151 | each repository deletion | |
151 | """ |
|
152 | """ | |
152 | return HookResponse(0, '') |
|
153 | return HookResponse(0, '') | |
153 |
|
154 | |||
154 |
|
155 | |||
155 | @has_kwargs({ |
|
156 | @has_kwargs({ | |
156 | 'username': '', |
|
157 | 'username': '', | |
157 | 'full_name_or_username': '', |
|
158 | 'full_name_or_username': '', | |
158 | 'full_contact': '', |
|
159 | 'full_contact': '', | |
159 | 'user_id': '', |
|
160 | 'user_id': '', | |
160 | 'name': '', |
|
161 | 'name': '', | |
161 | 'short_contact': '', |
|
162 | 'short_contact': '', | |
162 | 'admin': '', |
|
163 | 'admin': '', | |
163 | 'firstname': '', |
|
164 | 'firstname': '', | |
164 | 'lastname': '', |
|
165 | 'lastname': '', | |
165 | 'ip_addresses': '', |
|
166 | 'ip_addresses': '', | |
166 | 'email': '', |
|
167 | 'email': '', | |
167 | 'api_key': '', |
|
168 | 'api_key': '', | |
168 | 'last_login': '', |
|
169 | 'last_login': '', | |
169 | 'full_name': '', |
|
170 | 'full_name': '', | |
170 | 'active': '', |
|
171 | 'active': '', | |
171 | 'password': '', |
|
172 | 'password': '', | |
172 | 'emails': '', |
|
173 | 'emails': '', | |
173 | 'inherit_default_permissions': '', |
|
174 | 'inherit_default_permissions': '', | |
174 | 'deleted_by': '', |
|
175 | 'deleted_by': '', | |
175 | }) |
|
176 | }) | |
176 | def _delete_user_hook(*args, **kwargs): |
|
177 | def _delete_user_hook(*args, **kwargs): | |
177 | """ |
|
178 | """ | |
178 | POST DELETE USER HOOK, this function will be executed after each |
|
179 | POST DELETE USER HOOK, this function will be executed after each | |
179 | user is deleted kwargs available: |
|
180 | user is deleted kwargs available: | |
180 | """ |
|
181 | """ | |
181 | return HookResponse(0, '') |
|
182 | return HookResponse(0, '') | |
182 |
|
183 | |||
183 |
|
184 | |||
184 | # ============================================================================= |
|
185 | # ============================================================================= | |
185 | # PUSH/PULL RELATED HOOKS |
|
186 | # PUSH/PULL RELATED HOOKS | |
186 | # ============================================================================= |
|
187 | # ============================================================================= | |
187 | @has_kwargs({ |
|
188 | @has_kwargs({ | |
188 | 'server_url': 'url of instance that triggered this hook', |
|
189 | 'server_url': 'url of instance that triggered this hook', | |
189 | 'config': 'path to .ini config used', |
|
190 | 'config': 'path to .ini config used', | |
190 | 'scm': 'type of version control "git", "hg", "svn"', |
|
191 | 'scm': 'type of version control "git", "hg", "svn"', | |
191 | 'username': 'username of actor who triggered this event', |
|
192 | 'username': 'username of actor who triggered this event', | |
192 | 'ip': 'ip address of actor who triggered this hook', |
|
193 | 'ip': 'ip address of actor who triggered this hook', | |
193 | 'action': '', |
|
194 | 'action': '', | |
194 | 'repository': 'repository name', |
|
195 | 'repository': 'repository name', | |
195 | 'repo_store_path': 'full path to where repositories are stored', |
|
196 | 'repo_store_path': 'full path to where repositories are stored', | |
196 | 'commit_ids': 'pre transaction metadata for commit ids', |
|
197 | 'commit_ids': 'pre transaction metadata for commit ids', | |
197 | 'hook_type': '', |
|
198 | 'hook_type': '', | |
198 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', |
|
199 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', | |
199 | }) |
|
200 | }) | |
200 | def _pre_push_hook(*args, **kwargs): |
|
201 | def _pre_push_hook(*args, **kwargs): | |
201 | """ |
|
202 | """ | |
202 | Post push hook |
|
203 | Post push hook | |
203 | To stop version control from storing the transaction and send a message to user |
|
204 | 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 | use non-zero HookResponse with a message, e.g return HookResponse(1, 'Not allowed') | |
205 |
|
206 | |||
206 | This message will be shown back to client during PUSH operation |
|
207 | This message will be shown back to client during PUSH operation | |
207 |
|
208 | |||
208 | Commit ids might look like that:: |
|
209 | Commit ids might look like that:: | |
209 |
|
210 | |||
210 | [{u'hg_env|git_env': ..., |
|
211 | [{u'hg_env|git_env': ..., | |
211 | u'multiple_heads': [], |
|
212 | u'multiple_heads': [], | |
212 | u'name': u'default', |
|
213 | u'name': u'default', | |
213 | u'new_rev': u'd0befe0692e722e01d5677f27a104631cf798b69', |
|
214 | u'new_rev': u'd0befe0692e722e01d5677f27a104631cf798b69', | |
214 | u'old_rev': u'd0befe0692e722e01d5677f27a104631cf798b69', |
|
215 | u'old_rev': u'd0befe0692e722e01d5677f27a104631cf798b69', | |
215 | u'ref': u'', |
|
216 | u'ref': u'', | |
216 | u'total_commits': 2, |
|
217 | u'total_commits': 2, | |
217 | u'type': u'branch'}] |
|
218 | u'type': u'branch'}] | |
218 | """ |
|
219 | """ | |
219 | return HookResponse(0, '') |
|
220 | return HookResponse(0, '') | |
220 |
|
221 | |||
221 |
|
222 | |||
222 | @has_kwargs({ |
|
223 | @has_kwargs({ | |
223 | 'server_url': 'url of instance that triggered this hook', |
|
224 | 'server_url': 'url of instance that triggered this hook', | |
224 | 'config': 'path to .ini config used', |
|
225 | 'config': 'path to .ini config used', | |
225 | 'scm': 'type of version control "git", "hg", "svn"', |
|
226 | 'scm': 'type of version control "git", "hg", "svn"', | |
226 | 'username': 'username of actor who triggered this event', |
|
227 | 'username': 'username of actor who triggered this event', | |
227 | 'ip': 'ip address of actor who triggered this hook', |
|
228 | 'ip': 'ip address of actor who triggered this hook', | |
228 | 'action': '', |
|
229 | 'action': '', | |
229 | 'repository': 'repository name', |
|
230 | 'repository': 'repository name', | |
230 | 'repo_store_path': 'full path to where repositories are stored', |
|
231 | 'repo_store_path': 'full path to where repositories are stored', | |
231 | 'commit_ids': 'list of pushed commit_ids (sha1)', |
|
232 | 'commit_ids': 'list of pushed commit_ids (sha1)', | |
232 | 'hook_type': '', |
|
233 | 'hook_type': '', | |
233 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', |
|
234 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', | |
234 | }) |
|
235 | }) | |
235 | def _push_hook(*args, **kwargs): |
|
236 | def _push_hook(*args, **kwargs): | |
236 | """ |
|
237 | """ | |
237 | POST PUSH HOOK, this function will be executed after each push it's |
|
238 | 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 | executed after the build-in hook that RhodeCode uses for logging pushes | |
239 | """ |
|
240 | """ | |
240 | return HookResponse(0, '') |
|
241 | return HookResponse(0, '') | |
241 |
|
242 | |||
242 |
|
243 | |||
243 | @has_kwargs({ |
|
244 | @has_kwargs({ | |
244 | 'server_url': 'url of instance that triggered this hook', |
|
245 | 'server_url': 'url of instance that triggered this hook', | |
245 | 'repo_store_path': 'full path to where repositories are stored', |
|
246 | 'repo_store_path': 'full path to where repositories are stored', | |
246 | 'config': 'path to .ini config used', |
|
247 | 'config': 'path to .ini config used', | |
247 | 'scm': 'type of version control "git", "hg", "svn"', |
|
248 | 'scm': 'type of version control "git", "hg", "svn"', | |
248 | 'username': 'username of actor who triggered this event', |
|
249 | 'username': 'username of actor who triggered this event', | |
249 | 'ip': 'ip address of actor who triggered this hook', |
|
250 | 'ip': 'ip address of actor who triggered this hook', | |
250 | 'action': '', |
|
251 | 'action': '', | |
251 | 'repository': 'repository name', |
|
252 | 'repository': 'repository name', | |
252 | 'hook_type': '', |
|
253 | 'hook_type': '', | |
253 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', |
|
254 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', | |
254 | }) |
|
255 | }) | |
255 | def _pre_pull_hook(*args, **kwargs): |
|
256 | def _pre_pull_hook(*args, **kwargs): | |
256 | """ |
|
257 | """ | |
257 | Post pull hook |
|
258 | Post pull hook | |
258 | """ |
|
259 | """ | |
259 | return HookResponse(0, '') |
|
260 | return HookResponse(0, '') | |
260 |
|
261 | |||
261 |
|
262 | |||
262 | @has_kwargs({ |
|
263 | @has_kwargs({ | |
263 | 'server_url': 'url of instance that triggered this hook', |
|
264 | 'server_url': 'url of instance that triggered this hook', | |
264 | 'repo_store_path': 'full path to where repositories are stored', |
|
265 | 'repo_store_path': 'full path to where repositories are stored', | |
265 | 'config': 'path to .ini config used', |
|
266 | 'config': 'path to .ini config used', | |
266 | 'scm': 'type of version control "git", "hg", "svn"', |
|
267 | 'scm': 'type of version control "git", "hg", "svn"', | |
267 | 'username': 'username of actor who triggered this event', |
|
268 | 'username': 'username of actor who triggered this event', | |
268 | 'ip': 'ip address of actor who triggered this hook', |
|
269 | 'ip': 'ip address of actor who triggered this hook', | |
269 | 'action': '', |
|
270 | 'action': '', | |
270 | 'repository': 'repository name', |
|
271 | 'repository': 'repository name', | |
271 | 'hook_type': '', |
|
272 | 'hook_type': '', | |
272 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', |
|
273 | 'user_agent': 'Client user agent, e.g git or mercurial CLI version', | |
273 | }) |
|
274 | }) | |
274 | def _pull_hook(*args, **kwargs): |
|
275 | def _pull_hook(*args, **kwargs): | |
275 | """ |
|
276 | """ | |
276 | This hook will be executed after each code pull. |
|
277 | This hook will be executed after each code pull. | |
277 | """ |
|
278 | """ | |
278 | return HookResponse(0, '') |
|
279 | return HookResponse(0, '') | |
279 |
|
280 | |||
280 |
|
281 | |||
281 | # ============================================================================= |
|
282 | # ============================================================================= | |
282 | # PULL REQUEST RELATED HOOKS |
|
283 | # PULL REQUEST RELATED HOOKS | |
283 | # ============================================================================= |
|
284 | # ============================================================================= | |
284 | @has_kwargs({ |
|
285 | @has_kwargs({ | |
285 | 'server_url': 'url of instance that triggered this hook', |
|
286 | 'server_url': 'url of instance that triggered this hook', | |
286 | 'config': 'path to .ini config used', |
|
287 | 'config': 'path to .ini config used', | |
287 | 'scm': 'type of version control "git", "hg", "svn"', |
|
288 | 'scm': 'type of version control "git", "hg", "svn"', | |
288 | 'username': 'username of actor who triggered this event', |
|
289 | 'username': 'username of actor who triggered this event', | |
289 | 'ip': 'ip address of actor who triggered this hook', |
|
290 | 'ip': 'ip address of actor who triggered this hook', | |
290 | 'action': '', |
|
291 | 'action': '', | |
291 | 'repository': 'repository name', |
|
292 | 'repository': 'repository name', | |
292 | 'pull_request_id': '', |
|
293 | 'pull_request_id': '', | |
293 | 'url': '', |
|
294 | 'url': '', | |
294 | 'title': '', |
|
295 | 'title': '', | |
295 | 'description': '', |
|
296 | 'description': '', | |
296 | 'status': '', |
|
297 | 'status': '', | |
297 | 'created_on': '', |
|
298 | 'created_on': '', | |
298 | 'updated_on': '', |
|
299 | 'updated_on': '', | |
299 | 'commit_ids': '', |
|
300 | 'commit_ids': '', | |
300 | 'review_status': '', |
|
301 | 'review_status': '', | |
301 | 'mergeable': '', |
|
302 | 'mergeable': '', | |
302 | 'source': '', |
|
303 | 'source': '', | |
303 | 'target': '', |
|
304 | 'target': '', | |
304 | 'author': '', |
|
305 | 'author': '', | |
305 | 'reviewers': '', |
|
306 | 'reviewers': '', | |
306 | }) |
|
307 | }) | |
307 | def _create_pull_request_hook(*args, **kwargs): |
|
308 | def _create_pull_request_hook(*args, **kwargs): | |
308 | """ |
|
309 | """ | |
309 | This hook will be executed after creation of a pull request. |
|
310 | This hook will be executed after creation of a pull request. | |
310 | """ |
|
311 | """ | |
311 | return HookResponse(0, '') |
|
312 | return HookResponse(0, '') | |
312 |
|
313 | |||
313 |
|
314 | |||
314 | @has_kwargs({ |
|
315 | @has_kwargs({ | |
315 | 'server_url': 'url of instance that triggered this hook', |
|
316 | 'server_url': 'url of instance that triggered this hook', | |
316 | 'config': 'path to .ini config used', |
|
317 | 'config': 'path to .ini config used', | |
317 | 'scm': 'type of version control "git", "hg", "svn"', |
|
318 | 'scm': 'type of version control "git", "hg", "svn"', | |
318 | 'username': 'username of actor who triggered this event', |
|
319 | 'username': 'username of actor who triggered this event', | |
319 | 'ip': 'ip address of actor who triggered this hook', |
|
320 | 'ip': 'ip address of actor who triggered this hook', | |
320 | 'action': '', |
|
321 | 'action': '', | |
321 | 'repository': 'repository name', |
|
322 | 'repository': 'repository name', | |
322 | 'pull_request_id': '', |
|
323 | 'pull_request_id': '', | |
323 | 'url': '', |
|
324 | 'url': '', | |
324 | 'title': '', |
|
325 | 'title': '', | |
325 | 'description': '', |
|
326 | 'description': '', | |
326 | 'status': '', |
|
327 | 'status': '', | |
327 | 'created_on': '', |
|
328 | 'created_on': '', | |
328 | 'updated_on': '', |
|
329 | 'updated_on': '', | |
329 | 'commit_ids': '', |
|
330 | 'commit_ids': '', | |
330 | 'review_status': '', |
|
331 | 'review_status': '', | |
331 | 'mergeable': '', |
|
332 | 'mergeable': '', | |
332 | 'source': '', |
|
333 | 'source': '', | |
333 | 'target': '', |
|
334 | 'target': '', | |
334 | 'author': '', |
|
335 | 'author': '', | |
335 | 'reviewers': '', |
|
336 | 'reviewers': '', | |
336 | }) |
|
337 | }) | |
337 | def _review_pull_request_hook(*args, **kwargs): |
|
338 | def _review_pull_request_hook(*args, **kwargs): | |
338 | """ |
|
339 | """ | |
339 | This hook will be executed after review action was made on a pull request. |
|
340 | This hook will be executed after review action was made on a pull request. | |
340 | """ |
|
341 | """ | |
341 | return HookResponse(0, '') |
|
342 | return HookResponse(0, '') | |
342 |
|
343 | |||
343 |
|
344 | |||
344 | @has_kwargs({ |
|
345 | @has_kwargs({ | |
345 | 'server_url': 'url of instance that triggered this hook', |
|
346 | 'server_url': 'url of instance that triggered this hook', | |
346 | 'config': 'path to .ini config used', |
|
347 | 'config': 'path to .ini config used', | |
347 | 'scm': 'type of version control "git", "hg", "svn"', |
|
348 | 'scm': 'type of version control "git", "hg", "svn"', | |
348 | 'username': 'username of actor who triggered this event', |
|
349 | 'username': 'username of actor who triggered this event', | |
349 | 'ip': 'ip address of actor who triggered this hook', |
|
350 | 'ip': 'ip address of actor who triggered this hook', | |
350 | 'action': '', |
|
351 | 'action': '', | |
351 | 'repository': 'repository name', |
|
352 | 'repository': 'repository name', | |
352 | 'pull_request_id': '', |
|
353 | 'pull_request_id': '', | |
353 | 'url': '', |
|
354 | 'url': '', | |
354 | 'title': '', |
|
355 | 'title': '', | |
355 | 'description': '', |
|
356 | 'description': '', | |
356 | 'status': '', |
|
357 | 'status': '', | |
357 | 'created_on': '', |
|
358 | 'created_on': '', | |
358 | 'updated_on': '', |
|
359 | 'updated_on': '', | |
359 | 'commit_ids': '', |
|
360 | 'commit_ids': '', | |
360 | 'review_status': '', |
|
361 | 'review_status': '', | |
361 | 'mergeable': '', |
|
362 | 'mergeable': '', | |
362 | 'source': '', |
|
363 | 'source': '', | |
363 | 'target': '', |
|
364 | 'target': '', | |
364 | 'author': '', |
|
365 | 'author': '', | |
365 | 'reviewers': '', |
|
366 | 'reviewers': '', | |
366 | }) |
|
367 | }) | |
367 | def _update_pull_request_hook(*args, **kwargs): |
|
368 | def _update_pull_request_hook(*args, **kwargs): | |
368 | """ |
|
369 | """ | |
369 | This hook will be executed after pull requests has been updated with new commits. |
|
370 | This hook will be executed after pull requests has been updated with new commits. | |
370 | """ |
|
371 | """ | |
371 | return HookResponse(0, '') |
|
372 | return HookResponse(0, '') | |
372 |
|
373 | |||
373 |
|
374 | |||
374 | @has_kwargs({ |
|
375 | @has_kwargs({ | |
375 | 'server_url': 'url of instance that triggered this hook', |
|
376 | 'server_url': 'url of instance that triggered this hook', | |
376 | 'config': 'path to .ini config used', |
|
377 | 'config': 'path to .ini config used', | |
377 | 'scm': 'type of version control "git", "hg", "svn"', |
|
378 | 'scm': 'type of version control "git", "hg", "svn"', | |
378 | 'username': 'username of actor who triggered this event', |
|
379 | 'username': 'username of actor who triggered this event', | |
379 | 'ip': 'ip address of actor who triggered this hook', |
|
380 | 'ip': 'ip address of actor who triggered this hook', | |
380 | 'action': '', |
|
381 | 'action': '', | |
381 | 'repository': 'repository name', |
|
382 | 'repository': 'repository name', | |
382 | 'pull_request_id': '', |
|
383 | 'pull_request_id': '', | |
383 | 'url': '', |
|
384 | 'url': '', | |
384 | 'title': '', |
|
385 | 'title': '', | |
385 | 'description': '', |
|
386 | 'description': '', | |
386 | 'status': '', |
|
387 | 'status': '', | |
387 | 'created_on': '', |
|
388 | 'created_on': '', | |
388 | 'updated_on': '', |
|
389 | 'updated_on': '', | |
389 | 'commit_ids': '', |
|
390 | 'commit_ids': '', | |
390 | 'review_status': '', |
|
391 | 'review_status': '', | |
391 | 'mergeable': '', |
|
392 | 'mergeable': '', | |
392 | 'source': '', |
|
393 | 'source': '', | |
393 | 'target': '', |
|
394 | 'target': '', | |
394 | 'author': '', |
|
395 | 'author': '', | |
395 | 'reviewers': '', |
|
396 | 'reviewers': '', | |
396 | }) |
|
397 | }) | |
397 | def _merge_pull_request_hook(*args, **kwargs): |
|
398 | def _merge_pull_request_hook(*args, **kwargs): | |
398 | """ |
|
399 | """ | |
399 | This hook will be executed after merge of a pull request. |
|
400 | This hook will be executed after merge of a pull request. | |
400 | """ |
|
401 | """ | |
401 | return HookResponse(0, '') |
|
402 | return HookResponse(0, '') | |
402 |
|
403 | |||
403 |
|
404 | |||
404 | @has_kwargs({ |
|
405 | @has_kwargs({ | |
405 | 'server_url': 'url of instance that triggered this hook', |
|
406 | 'server_url': 'url of instance that triggered this hook', | |
406 | 'config': 'path to .ini config used', |
|
407 | 'config': 'path to .ini config used', | |
407 | 'scm': 'type of version control "git", "hg", "svn"', |
|
408 | 'scm': 'type of version control "git", "hg", "svn"', | |
408 | 'username': 'username of actor who triggered this event', |
|
409 | 'username': 'username of actor who triggered this event', | |
409 | 'ip': 'ip address of actor who triggered this hook', |
|
410 | 'ip': 'ip address of actor who triggered this hook', | |
410 | 'action': '', |
|
411 | 'action': '', | |
411 | 'repository': 'repository name', |
|
412 | 'repository': 'repository name', | |
412 | 'pull_request_id': '', |
|
413 | 'pull_request_id': '', | |
413 | 'url': '', |
|
414 | 'url': '', | |
414 | 'title': '', |
|
415 | 'title': '', | |
415 | 'description': '', |
|
416 | 'description': '', | |
416 | 'status': '', |
|
417 | 'status': '', | |
417 | 'created_on': '', |
|
418 | 'created_on': '', | |
418 | 'updated_on': '', |
|
419 | 'updated_on': '', | |
419 | 'commit_ids': '', |
|
420 | 'commit_ids': '', | |
420 | 'review_status': '', |
|
421 | 'review_status': '', | |
421 | 'mergeable': '', |
|
422 | 'mergeable': '', | |
422 | 'source': '', |
|
423 | 'source': '', | |
423 | 'target': '', |
|
424 | 'target': '', | |
424 | 'author': '', |
|
425 | 'author': '', | |
425 | 'reviewers': '', |
|
426 | 'reviewers': '', | |
426 | }) |
|
427 | }) | |
427 | def _close_pull_request_hook(*args, **kwargs): |
|
428 | def _close_pull_request_hook(*args, **kwargs): | |
428 | """ |
|
429 | """ | |
429 | This hook will be executed after close of a pull request. |
|
430 | This hook will be executed after close of a pull request. | |
430 | """ |
|
431 | """ | |
431 | return HookResponse(0, '') |
|
432 | return HookResponse(0, '') |
@@ -1,185 +1,189 b'' | |||||
1 | # Copyright (C) 2016-2019 RhodeCode GmbH |
|
1 | # Copyright (C) 2016-2019 RhodeCode GmbH | |
2 | # |
|
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify |
|
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 |
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |
5 | # (only), as published by the Free Software Foundation. |
|
5 | # (only), as published by the Free Software Foundation. | |
6 | # |
|
6 | # | |
7 | # This program is distributed in the hope that it will be useful, |
|
7 | # This program is distributed in the hope that it will be useful, | |
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | # GNU General Public License for more details. |
|
10 | # GNU General Public License for more details. | |
11 | # |
|
11 | # | |
12 | # You should have received a copy of the GNU Affero General Public License |
|
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/>. |
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | # |
|
14 | # | |
15 | # This program is dual-licensed. If you wish to learn more about the |
|
15 | # This program is dual-licensed. If you wish to learn more about the | |
16 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
18 |
|
18 | |||
|
19 | import logging | |||
19 | import os |
|
20 | import os | |
20 | import functools |
|
21 | import functools | |
21 | import collections |
|
22 | import collections | |
22 |
|
23 | |||
|
24 | log = logging.getLogger('rhodecode.' + __name__) | |||
|
25 | ||||
23 |
|
26 | |||
24 | class HookResponse(object): |
|
27 | class HookResponse(object): | |
25 | def __init__(self, status, output): |
|
28 | def __init__(self, status, output): | |
26 | self.status = status |
|
29 | self.status = status | |
27 | self.output = output |
|
30 | self.output = output | |
28 |
|
31 | |||
29 | def __add__(self, other): |
|
32 | def __add__(self, other): | |
30 | other_status = getattr(other, 'status', 0) |
|
33 | other_status = getattr(other, 'status', 0) | |
31 | new_status = max(self.status, other_status) |
|
34 | new_status = max(self.status, other_status) | |
32 | other_output = getattr(other, 'output', '') |
|
35 | other_output = getattr(other, 'output', '') | |
33 | new_output = self.output + other_output |
|
36 | new_output = self.output + other_output | |
34 |
|
37 | |||
35 | return HookResponse(new_status, new_output) |
|
38 | return HookResponse(new_status, new_output) | |
36 |
|
39 | |||
37 | def __bool__(self): |
|
40 | def __bool__(self): | |
38 | return self.status == 0 |
|
41 | return self.status == 0 | |
39 |
|
42 | |||
40 |
|
43 | |||
41 | class DotDict(dict): |
|
44 | class DotDict(dict): | |
42 |
|
45 | |||
43 | def __contains__(self, k): |
|
46 | def __contains__(self, k): | |
44 | try: |
|
47 | try: | |
45 | return dict.__contains__(self, k) or hasattr(self, k) |
|
48 | return dict.__contains__(self, k) or hasattr(self, k) | |
46 | except: |
|
49 | except: | |
47 | return False |
|
50 | return False | |
48 |
|
51 | |||
49 | # only called if k not found in normal places |
|
52 | # only called if k not found in normal places | |
50 | def __getattr__(self, k): |
|
53 | def __getattr__(self, k): | |
51 | try: |
|
54 | try: | |
52 | return object.__getattribute__(self, k) |
|
55 | return object.__getattribute__(self, k) | |
53 | except AttributeError: |
|
56 | except AttributeError: | |
54 | try: |
|
57 | try: | |
55 | return self[k] |
|
58 | return self[k] | |
56 | except KeyError: |
|
59 | except KeyError: | |
57 | raise AttributeError(k) |
|
60 | raise AttributeError(k) | |
58 |
|
61 | |||
59 | def __setattr__(self, k, v): |
|
62 | def __setattr__(self, k, v): | |
60 | try: |
|
63 | try: | |
61 | object.__getattribute__(self, k) |
|
64 | object.__getattribute__(self, k) | |
62 | except AttributeError: |
|
65 | except AttributeError: | |
63 | try: |
|
66 | try: | |
64 | self[k] = v |
|
67 | self[k] = v | |
65 | except: |
|
68 | except: | |
66 | raise AttributeError(k) |
|
69 | raise AttributeError(k) | |
67 | else: |
|
70 | else: | |
68 | object.__setattr__(self, k, v) |
|
71 | object.__setattr__(self, k, v) | |
69 |
|
72 | |||
70 | def __delattr__(self, k): |
|
73 | def __delattr__(self, k): | |
71 | try: |
|
74 | try: | |
72 | object.__getattribute__(self, k) |
|
75 | object.__getattribute__(self, k) | |
73 | except AttributeError: |
|
76 | except AttributeError: | |
74 | try: |
|
77 | try: | |
75 | del self[k] |
|
78 | del self[k] | |
76 | except KeyError: |
|
79 | except KeyError: | |
77 | raise AttributeError(k) |
|
80 | raise AttributeError(k) | |
78 | else: |
|
81 | else: | |
79 | object.__delattr__(self, k) |
|
82 | object.__delattr__(self, k) | |
80 |
|
83 | |||
81 | def toDict(self): |
|
84 | def toDict(self): | |
82 | return unserialize(self) |
|
85 | return unserialize(self) | |
83 |
|
86 | |||
84 | def __repr__(self): |
|
87 | def __repr__(self): | |
85 | keys = list(self.keys()) |
|
88 | keys = list(self.keys()) | |
86 | keys.sort() |
|
89 | keys.sort() | |
87 | args = ', '.join(['%s=%r' % (key, self[key]) for key in keys]) |
|
90 | args = ', '.join(['%s=%r' % (key, self[key]) for key in keys]) | |
88 | return '%s(%s)' % (self.__class__.__name__, args) |
|
91 | return '%s(%s)' % (self.__class__.__name__, args) | |
89 |
|
92 | |||
90 | @staticmethod |
|
93 | @staticmethod | |
91 | def fromDict(d): |
|
94 | def fromDict(d): | |
92 | return serialize(d) |
|
95 | return serialize(d) | |
93 |
|
96 | |||
94 |
|
97 | |||
95 | def serialize(x): |
|
98 | def serialize(x): | |
96 | if isinstance(x, dict): |
|
99 | if isinstance(x, dict): | |
97 | return DotDict((k, serialize(v)) for k, v in x.items()) |
|
100 | return DotDict((k, serialize(v)) for k, v in x.items()) | |
98 | elif isinstance(x, (list, tuple)): |
|
101 | elif isinstance(x, (list, tuple)): | |
99 | return type(x)(serialize(v) for v in x) |
|
102 | return type(x)(serialize(v) for v in x) | |
100 | else: |
|
103 | else: | |
101 | return x |
|
104 | return x | |
102 |
|
105 | |||
103 |
|
106 | |||
104 | def unserialize(x): |
|
107 | def unserialize(x): | |
105 | if isinstance(x, dict): |
|
108 | if isinstance(x, dict): | |
106 | return dict((k, unserialize(v)) for k, v in x.items()) |
|
109 | return dict((k, unserialize(v)) for k, v in x.items()) | |
107 | elif isinstance(x, (list, tuple)): |
|
110 | elif isinstance(x, (list, tuple)): | |
108 | return type(x)(unserialize(v) for v in x) |
|
111 | return type(x)(unserialize(v) for v in x) | |
109 | else: |
|
112 | else: | |
110 | return x |
|
113 | return x | |
111 |
|
114 | |||
112 |
|
115 | |||
113 | def _verify_kwargs(func_name, expected_parameters, kwargs): |
|
116 | def _verify_kwargs(func_name, expected_parameters, kwargs): | |
114 | """ |
|
117 | """ | |
115 | Verify that exactly `expected_parameters` are passed in as `kwargs`. |
|
118 | Verify that exactly `expected_parameters` are passed in as `kwargs`. | |
116 | """ |
|
119 | """ | |
117 | expected_parameters = set(expected_parameters) |
|
120 | expected_parameters = set(expected_parameters) | |
118 | kwargs_keys = set(kwargs.keys()) |
|
121 | kwargs_keys = set(kwargs.keys()) | |
119 | if kwargs_keys != expected_parameters: |
|
122 | if kwargs_keys != expected_parameters: | |
120 | missing_kwargs = expected_parameters - kwargs_keys |
|
123 | missing_kwargs = expected_parameters - kwargs_keys | |
121 | unexpected_kwargs = kwargs_keys - expected_parameters |
|
124 | unexpected_kwargs = kwargs_keys - expected_parameters | |
122 | raise AssertionError( |
|
125 | raise AssertionError( | |
123 | "func:%s: missing parameters: %r, unexpected parameters: %s" % |
|
126 | "func:%s: missing parameters: %r, unexpected parameters: %s" % | |
124 | (func_name, missing_kwargs, unexpected_kwargs)) |
|
127 | (func_name, missing_kwargs, unexpected_kwargs)) | |
125 |
|
128 | |||
126 |
|
129 | |||
127 | def has_kwargs(required_args): |
|
130 | def has_kwargs(required_args): | |
128 | """ |
|
131 | """ | |
129 | decorator to verify extension calls arguments. |
|
132 | decorator to verify extension calls arguments. | |
130 |
|
133 | |||
131 | :param required_args: |
|
134 | :param required_args: | |
132 | """ |
|
135 | """ | |
133 | def wrap(func): |
|
136 | def wrap(func): | |
134 | def wrapper(*args, **kwargs): |
|
137 | def wrapper(*args, **kwargs): | |
135 | _verify_kwargs(func.func_name, required_args.keys(), kwargs) |
|
138 | _verify_kwargs(func.func_name, required_args.keys(), kwargs) | |
136 | # in case there's `calls` defined on module we store the data |
|
139 | # in case there's `calls` defined on module we store the data | |
137 | maybe_log_call(func.func_name, args, kwargs) |
|
140 | maybe_log_call(func.func_name, args, kwargs) | |
|
141 | log.debug('Calling rcextensions function %s', func.func_name) | |||
138 | return func(*args, **kwargs) |
|
142 | return func(*args, **kwargs) | |
139 | return wrapper |
|
143 | return wrapper | |
140 | return wrap |
|
144 | return wrap | |
141 |
|
145 | |||
142 |
|
146 | |||
143 | def maybe_log_call(name, args, kwargs): |
|
147 | def maybe_log_call(name, args, kwargs): | |
144 | from rhodecode.config import rcextensions |
|
148 | from rhodecode.config import rcextensions | |
145 | if hasattr(rcextensions, 'calls'): |
|
149 | if hasattr(rcextensions, 'calls'): | |
146 | calls = rcextensions.calls |
|
150 | calls = rcextensions.calls | |
147 | calls[name].append((args, kwargs)) |
|
151 | calls[name].append((args, kwargs)) | |
148 |
|
152 | |||
149 |
|
153 | |||
150 | def str2bool(_str): |
|
154 | def str2bool(_str): | |
151 | """ |
|
155 | """ | |
152 | returns True/False value from given string, it tries to translate the |
|
156 | returns True/False value from given string, it tries to translate the | |
153 | string into boolean |
|
157 | string into boolean | |
154 |
|
158 | |||
155 | :param _str: string value to translate into boolean |
|
159 | :param _str: string value to translate into boolean | |
156 | :rtype: boolean |
|
160 | :rtype: boolean | |
157 | :returns: boolean from given string |
|
161 | :returns: boolean from given string | |
158 | """ |
|
162 | """ | |
159 | if _str is None: |
|
163 | if _str is None: | |
160 | return False |
|
164 | return False | |
161 | if _str in (True, False): |
|
165 | if _str in (True, False): | |
162 | return _str |
|
166 | return _str | |
163 | _str = str(_str).strip().lower() |
|
167 | _str = str(_str).strip().lower() | |
164 | return _str in ('t', 'true', 'y', 'yes', 'on', '1') |
|
168 | return _str in ('t', 'true', 'y', 'yes', 'on', '1') | |
165 |
|
169 | |||
166 |
|
170 | |||
167 | def aslist(obj, sep=None, strip=True): |
|
171 | def aslist(obj, sep=None, strip=True): | |
168 | """ |
|
172 | """ | |
169 | Returns given string separated by sep as list |
|
173 | Returns given string separated by sep as list | |
170 |
|
174 | |||
171 | :param obj: |
|
175 | :param obj: | |
172 | :param sep: |
|
176 | :param sep: | |
173 | :param strip: |
|
177 | :param strip: | |
174 | """ |
|
178 | """ | |
175 | if isinstance(obj, (basestring,)): |
|
179 | if isinstance(obj, (basestring,)): | |
176 | lst = obj.split(sep) |
|
180 | lst = obj.split(sep) | |
177 | if strip: |
|
181 | if strip: | |
178 | lst = [v.strip() for v in lst] |
|
182 | lst = [v.strip() for v in lst] | |
179 | return lst |
|
183 | return lst | |
180 | elif isinstance(obj, (list, tuple)): |
|
184 | elif isinstance(obj, (list, tuple)): | |
181 | return obj |
|
185 | return obj | |
182 | elif obj is None: |
|
186 | elif obj is None: | |
183 | return [] |
|
187 | return [] | |
184 | else: |
|
188 | else: | |
185 | return [obj] No newline at end of file |
|
189 | return [obj] |
General Comments 0
You need to be logged in to leave comments.
Login now