##// END OF EJS Templates
code: unified coverage notes to # pragma: no cover
marcink -
r3282:5c2818aa default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,106 +1,106 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Single source for redirection links.
23 23
24 24 Goal of this module is to provide a single source of truth regarding external
25 25 links. The data inside this module is used to configure the routing
26 26 system of Enterprise and it is used also as a base to check if this data
27 27 and our server configuration are in sync.
28 28
29 29 .. py:data:: link_config
30 30
31 31 Contains the configuration for external links. Each item is supposed to be
32 32 a `dict` like this example::
33 33
34 34 {"name": "url_name",
35 35 "target": "https://rhodecode.com/r1/enterprise/keyword/",
36 36 "external_target": "https://example.com/some-page.html",
37 37 }
38 38
39 39 then you can retrieve the url by simply calling the URL function:
40 40
41 41 `h.route_path('url_name')`
42 42
43 43 The redirection must be first implemented in our servers before
44 44 you can see it working.
45 45 """
46 # flake8: noqa
46 # pragma: no cover
47 47 from __future__ import unicode_literals
48 48
49 49 link_config = [
50 50 {
51 51 "name": "enterprise_docs",
52 52 "target": "https://rhodecode.com/r1/enterprise/docs/",
53 53 "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/",
54 54 },
55 55 {
56 56 "name": "enterprise_log_file_locations",
57 57 "target": "https://rhodecode.com/r1/enterprise/docs/admin-system-overview/",
58 58 "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/admin/system-overview.html#log-files",
59 59 },
60 60 {
61 61 "name": "enterprise_issue_tracker_settings",
62 62 "target": "https://rhodecode.com/r1/enterprise/docs/issue-trackers-overview/",
63 63 "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/issue-trackers/issue-trackers.html",
64 64 },
65 65 {
66 66 "name": "enterprise_svn_setup",
67 67 "target": "https://rhodecode.com/r1/enterprise/docs/svn-setup/",
68 68 "external_target": "https://docs.rhodecode.com/RhodeCode-Enterprise/admin/svn-http.html",
69 69 },
70 70 {
71 71 "name": "enterprise_license_convert_from_old",
72 72 "target": "https://rhodecode.com/r1/enterprise/convert-license/",
73 73 "external_target": "https://rhodecode.com/u/license-upgrade",
74 74 },
75 75 {
76 76 "name": "rst_help",
77 77 "target": "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
78 78 "external_target": "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
79 79 },
80 80 {
81 81 "name": "markdown_help",
82 82 "target": "https://daringfireball.net/projects/markdown/syntax",
83 83 "external_target": "https://daringfireball.net/projects/markdown/syntax",
84 84 },
85 85 {
86 86 "name": "rhodecode_official",
87 87 "target": "https://rhodecode.com",
88 88 "external_target": "https://rhodecode.com/",
89 89 },
90 90 {
91 91 "name": "rhodecode_support",
92 92 "target": "https://rhodecode.com/help/",
93 93 "external_target": "https://rhodecode.com/support",
94 94 },
95 95 {
96 96 "name": "rhodecode_translations",
97 97 "target": "https://rhodecode.com/translate/enterprise",
98 98 "external_target": "https://www.transifex.com/rhodecode/RhodeCode/",
99 99 },
100 100
101 101 ]
102 102
103 103
104 104 def connect_redirection_links(config):
105 105 for link in link_config:
106 106 config.add_route(link['name'], link['target'], static=True)
@@ -1,78 +1,78 b''
1 1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 2 #
3 3 # This program is free software: you can redistribute it and/or modify
4 4 # it under the terms of the GNU Affero General Public License, version 3
5 5 # (only), as published by the Free Software Foundation.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU Affero General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 #
15 15 # This program is dual-licensed. If you wish to learn more about the
16 16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 19 import logging
20 20 from pyramid.threadlocal import get_current_registry
21 21 from rhodecode.events.base import RhodeCodeIntegrationEvent
22 22
23 23
24 24 log = logging.getLogger(__name__)
25 25
26 26
27 27 def trigger(event, registry=None):
28 28 """
29 29 Helper method to send an event. This wraps the pyramid logic to send an
30 30 event.
31 31 """
32 32 # For the first step we are using pyramids thread locals here. If the
33 33 # event mechanism works out as a good solution we should think about
34 34 # passing the registry as an argument to get rid of it.
35 35 event_name = event.__class__
36 36 log.debug('event %s sent for execution', event_name)
37 37 registry = registry or get_current_registry()
38 38 registry.notify(event)
39 39 log.debug('event %s triggered using registry %s', event_name, registry)
40 40
41 41 # Send the events to integrations directly
42 42 from rhodecode.integrations import integrations_event_handler
43 43 if isinstance(event, RhodeCodeIntegrationEvent):
44 44 integrations_event_handler(event)
45 45
46 46
47 from rhodecode.events.user import ( # noqa
47 from rhodecode.events.user import ( # pragma: no cover
48 48 UserPreCreate,
49 49 UserPostCreate,
50 50 UserPreUpdate,
51 51 UserRegistered,
52 52 UserPermissionsChange,
53 53 )
54 54
55 from rhodecode.events.repo import ( # noqa
55 from rhodecode.events.repo import ( # pragma: no cover
56 56 RepoEvent,
57 57 RepoPreCreateEvent, RepoCreateEvent,
58 58 RepoPreDeleteEvent, RepoDeleteEvent,
59 59 RepoPrePushEvent, RepoPushEvent,
60 60 RepoPrePullEvent, RepoPullEvent,
61 61 )
62 62
63 from rhodecode.events.repo_group import ( # noqa
63 from rhodecode.events.repo_group import ( # pragma: no cover
64 64 RepoGroupEvent,
65 65 RepoGroupCreateEvent,
66 66 RepoGroupUpdateEvent,
67 67 RepoGroupDeleteEvent,
68 68 )
69 69
70 from rhodecode.events.pullrequest import ( # noqa
70 from rhodecode.events.pullrequest import ( # pragma: no cover
71 71 PullRequestEvent,
72 72 PullRequestCreateEvent,
73 73 PullRequestUpdateEvent,
74 74 PullRequestCommentEvent,
75 75 PullRequestReviewEvent,
76 76 PullRequestMergeEvent,
77 77 PullRequestCloseEvent,
78 78 )
@@ -1,302 +1,302 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 """
21 21 Celery loader, run with::
22 22
23 23 celery worker \
24 24 --beat \
25 25 --app rhodecode.lib.celerylib.loader \
26 26 --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \
27 27 --loglevel DEBUG --ini=._dev/dev.ini
28 28 """
29 29 import os
30 30 import logging
31 31 import importlib
32 32
33 33 from celery import Celery
34 34 from celery import signals
35 35 from celery import Task
36 from celery import exceptions # noqa
36 from celery import exceptions # pragma: no cover
37 37 from kombu.serialization import register
38 38 from pyramid.threadlocal import get_current_request
39 39
40 40 import rhodecode
41 41
42 42 from rhodecode.lib.auth import AuthUser
43 43 from rhodecode.lib.celerylib.utils import get_ini_config, parse_ini_vars
44 44 from rhodecode.lib.ext_json import json
45 45 from rhodecode.lib.pyramid_utils import bootstrap, setup_logging, prepare_request
46 46 from rhodecode.lib.utils2 import str2bool
47 47 from rhodecode.model import meta
48 48
49 49
50 50 register('json_ext', json.dumps, json.loads,
51 51 content_type='application/x-json-ext',
52 52 content_encoding='utf-8')
53 53
54 54 log = logging.getLogger('celery.rhodecode.loader')
55 55
56 56
57 57 def add_preload_arguments(parser):
58 58 parser.add_argument(
59 59 '--ini', default=None,
60 60 help='Path to ini configuration file.'
61 61 )
62 62 parser.add_argument(
63 63 '--ini-var', default=None,
64 64 help='Comma separated list of key=value to pass to ini.'
65 65 )
66 66
67 67
68 68 def get_logger(obj):
69 69 custom_log = logging.getLogger(
70 70 'rhodecode.task.{}'.format(obj.__class__.__name__))
71 71
72 72 if rhodecode.CELERY_ENABLED:
73 73 try:
74 74 custom_log = obj.get_logger()
75 75 except Exception:
76 76 pass
77 77
78 78 return custom_log
79 79
80 80
81 81 imports = ['rhodecode.lib.celerylib.tasks']
82 82
83 83 try:
84 84 # try if we have EE tasks available
85 85 importlib.import_module('rc_ee')
86 86 imports.append('rc_ee.lib.celerylib.tasks')
87 87 except ImportError:
88 88 pass
89 89
90 90
91 91 base_celery_config = {
92 92 'result_backend': 'rpc://',
93 93 'result_expires': 60 * 60 * 24,
94 94 'result_persistent': True,
95 95 'imports': imports,
96 96 'worker_max_tasks_per_child': 100,
97 97 'accept_content': ['json_ext'],
98 98 'task_serializer': 'json_ext',
99 99 'result_serializer': 'json_ext',
100 100 'worker_hijack_root_logger': False,
101 101 'database_table_names': {
102 102 'task': 'beat_taskmeta',
103 103 'group': 'beat_groupmeta',
104 104 }
105 105 }
106 106 # init main celery app
107 107 celery_app = Celery()
108 108 celery_app.user_options['preload'].add(add_preload_arguments)
109 109 ini_file_glob = None
110 110
111 111
112 112 @signals.setup_logging.connect
113 113 def setup_logging_callback(**kwargs):
114 114 setup_logging(ini_file_glob)
115 115
116 116
117 117 @signals.user_preload_options.connect
118 118 def on_preload_parsed(options, **kwargs):
119 119 ini_location = options['ini']
120 120 ini_vars = options['ini_var']
121 121 celery_app.conf['INI_PYRAMID'] = options['ini']
122 122
123 123 if ini_location is None:
124 124 print('You must provide the paste --ini argument')
125 125 exit(-1)
126 126
127 127 options = None
128 128 if ini_vars is not None:
129 129 options = parse_ini_vars(ini_vars)
130 130
131 131 global ini_file_glob
132 132 ini_file_glob = ini_location
133 133
134 134 log.debug('Bootstrapping RhodeCode application...')
135 135 env = bootstrap(ini_location, options=options)
136 136
137 137 setup_celery_app(
138 138 app=env['app'], root=env['root'], request=env['request'],
139 139 registry=env['registry'], closer=env['closer'],
140 140 ini_location=ini_location)
141 141
142 142 # fix the global flag even if it's disabled via .ini file because this
143 143 # is a worker code that doesn't need this to be disabled.
144 144 rhodecode.CELERY_ENABLED = True
145 145
146 146
147 147 @signals.task_success.connect
148 148 def task_success_signal(result, **kwargs):
149 149 meta.Session.commit()
150 150 closer = celery_app.conf['PYRAMID_CLOSER']
151 151 if closer:
152 152 closer()
153 153
154 154
155 155 @signals.task_retry.connect
156 156 def task_retry_signal(
157 157 request, reason, einfo, **kwargs):
158 158 meta.Session.remove()
159 159 closer = celery_app.conf['PYRAMID_CLOSER']
160 160 if closer:
161 161 closer()
162 162
163 163
164 164 @signals.task_failure.connect
165 165 def task_failure_signal(
166 166 task_id, exception, args, kwargs, traceback, einfo, **kargs):
167 167 from rhodecode.lib.exc_tracking import store_exception
168 168
169 169 meta.Session.remove()
170 170
171 171 # simulate sys.exc_info()
172 172 exc_info = (einfo.type, einfo.exception, einfo.tb)
173 173 store_exception(id(exc_info), exc_info, prefix='celery_rhodecode')
174 174
175 175 closer = celery_app.conf['PYRAMID_CLOSER']
176 176 if closer:
177 177 closer()
178 178
179 179
180 180 @signals.task_revoked.connect
181 181 def task_revoked_signal(
182 182 request, terminated, signum, expired, **kwargs):
183 183 closer = celery_app.conf['PYRAMID_CLOSER']
184 184 if closer:
185 185 closer()
186 186
187 187
188 188 def setup_celery_app(app, root, request, registry, closer, ini_location):
189 189 ini_dir = os.path.dirname(os.path.abspath(ini_location))
190 190 celery_config = base_celery_config
191 191 celery_config.update({
192 192 # store celerybeat scheduler db where the .ini file is
193 193 'beat_schedule_filename': os.path.join(ini_dir, 'celerybeat-schedule'),
194 194 })
195 195 ini_settings = get_ini_config(ini_location)
196 196 log.debug('Got custom celery conf: %s', ini_settings)
197 197
198 198 celery_config.update(ini_settings)
199 199 celery_app.config_from_object(celery_config)
200 200
201 201 celery_app.conf.update({'PYRAMID_APP': app})
202 202 celery_app.conf.update({'PYRAMID_ROOT': root})
203 203 celery_app.conf.update({'PYRAMID_REQUEST': request})
204 204 celery_app.conf.update({'PYRAMID_REGISTRY': registry})
205 205 celery_app.conf.update({'PYRAMID_CLOSER': closer})
206 206
207 207
208 208 def configure_celery(config, ini_location):
209 209 """
210 210 Helper that is called from our application creation logic. It gives
211 211 connection info into running webapp and allows execution of tasks from
212 212 RhodeCode itself
213 213 """
214 214 # store some globals into rhodecode
215 215 rhodecode.CELERY_ENABLED = str2bool(
216 216 config.registry.settings.get('use_celery'))
217 217 if rhodecode.CELERY_ENABLED:
218 218 log.info('Configuring celery based on `%s` file', ini_location)
219 219 setup_celery_app(
220 220 app=None, root=None, request=None, registry=config.registry,
221 221 closer=None, ini_location=ini_location)
222 222
223 223
224 224 def maybe_prepare_env(req):
225 225 environ = {}
226 226 try:
227 227 environ.update({
228 228 'PATH_INFO': req.environ['PATH_INFO'],
229 229 'SCRIPT_NAME': req.environ['SCRIPT_NAME'],
230 230 'HTTP_HOST':
231 231 req.environ.get('HTTP_HOST', req.environ['SERVER_NAME']),
232 232 'SERVER_NAME': req.environ['SERVER_NAME'],
233 233 'SERVER_PORT': req.environ['SERVER_PORT'],
234 234 'wsgi.url_scheme': req.environ['wsgi.url_scheme'],
235 235 })
236 236 except Exception:
237 237 pass
238 238
239 239 return environ
240 240
241 241
242 242 class RequestContextTask(Task):
243 243 """
244 244 This is a celery task which will create a rhodecode app instance context
245 245 for the task, patch pyramid with the original request
246 246 that created the task and also add the user to the context.
247 247 """
248 248
249 249 def apply_async(self, args=None, kwargs=None, task_id=None, producer=None,
250 250 link=None, link_error=None, shadow=None, **options):
251 251 """ queue the job to run (we are in web request context here) """
252 252
253 253 req = get_current_request()
254 254
255 255 # web case
256 256 if hasattr(req, 'user'):
257 257 ip_addr = req.user.ip_addr
258 258 user_id = req.user.user_id
259 259
260 260 # api case
261 261 elif hasattr(req, 'rpc_user'):
262 262 ip_addr = req.rpc_user.ip_addr
263 263 user_id = req.rpc_user.user_id
264 264 else:
265 265 raise Exception(
266 266 'Unable to fetch required data from request: {}. \n'
267 267 'This task is required to be executed from context of '
268 268 'request in a webapp'.format(repr(req)))
269 269
270 270 if req:
271 271 # we hook into kwargs since it is the only way to pass our data to
272 272 # the celery worker
273 273 environ = maybe_prepare_env(req)
274 274 options['headers'] = options.get('headers', {})
275 275 options['headers'].update({
276 276 'rhodecode_proxy_data': {
277 277 'environ': environ,
278 278 'auth_user': {
279 279 'ip_addr': ip_addr,
280 280 'user_id': user_id
281 281 },
282 282 }
283 283 })
284 284
285 285 return super(RequestContextTask, self).apply_async(
286 286 args, kwargs, task_id, producer, link, link_error, shadow, **options)
287 287
288 288 def __call__(self, *args, **kwargs):
289 289 """ rebuild the context and then run task on celery worker """
290 290
291 291 proxy_data = getattr(self.request, 'rhodecode_proxy_data', None)
292 292 if not proxy_data:
293 293 return super(RequestContextTask, self).__call__(*args, **kwargs)
294 294
295 295 log.debug('using celery proxy data to run task: %r', proxy_data)
296 296 # re-inject and register threadlocals for proper routing support
297 297 request = prepare_request(proxy_data['environ'])
298 298 request.user = AuthUser(user_id=proxy_data['auth_user']['user_id'],
299 299 ip_addr=proxy_data['auth_user']['ip_addr'])
300 300
301 301 return super(RequestContextTask, self).__call__(*args, **kwargs)
302 302
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now