##// END OF EJS Templates
vcs: expose SSL certificate path over the wire to the vcsserver....
ergo -
r3337:32bd6215 default
parent child Browse files
Show More
@@ -1,770 +1,776 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2018 RhodeCode GmbH
3 # Copyright (C) 2017-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import os
22 import os
23 import sys
23 import sys
24 import time
24 import time
25 import platform
25 import platform
26 import collections
26 import collections
27 import pkg_resources
27 import pkg_resources
28 import logging
28 import logging
29 import resource
29 import resource
30
30
31 from pyramid.compat import configparser
31 from pyramid.compat import configparser
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35
35
36 psutil = None
36 psutil = None
37
37
38 try:
38 try:
39 # cygwin cannot have yet psutil support.
39 # cygwin cannot have yet psutil support.
40 import psutil as psutil
40 import psutil as psutil
41 except ImportError:
41 except ImportError:
42 pass
42 pass
43
43
44
44
45 _NA = 'NOT AVAILABLE'
45 _NA = 'NOT AVAILABLE'
46
46
47 STATE_OK = 'ok'
47 STATE_OK = 'ok'
48 STATE_ERR = 'error'
48 STATE_ERR = 'error'
49 STATE_WARN = 'warning'
49 STATE_WARN = 'warning'
50
50
51 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
51 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
52
52
53
53
54 # HELPERS
54 # HELPERS
55 def percentage(part, whole):
55 def percentage(part, whole):
56 whole = float(whole)
56 whole = float(whole)
57 if whole > 0:
57 if whole > 0:
58 return round(100 * float(part) / whole, 1)
58 return round(100 * float(part) / whole, 1)
59 return 0.0
59 return 0.0
60
60
61
61
62 def get_storage_size(storage_path):
62 def get_storage_size(storage_path):
63 sizes = []
63 sizes = []
64 for file_ in os.listdir(storage_path):
64 for file_ in os.listdir(storage_path):
65 storage_file = os.path.join(storage_path, file_)
65 storage_file = os.path.join(storage_path, file_)
66 if os.path.isfile(storage_file):
66 if os.path.isfile(storage_file):
67 try:
67 try:
68 sizes.append(os.path.getsize(storage_file))
68 sizes.append(os.path.getsize(storage_file))
69 except OSError:
69 except OSError:
70 log.exception('Failed to get size of storage file %s',
70 log.exception('Failed to get size of storage file %s', storage_file)
71 storage_file)
72 pass
71 pass
73
72
74 return sum(sizes)
73 return sum(sizes)
75
74
76
75
77 def get_resource(resource_type):
76 def get_resource(resource_type):
78 try:
77 try:
79 return resource.getrlimit(resource_type)
78 return resource.getrlimit(resource_type)
80 except Exception:
79 except Exception:
81 return 'NOT_SUPPORTED'
80 return 'NOT_SUPPORTED'
82
81
83
82
83 def get_cert_path(ini_path):
84 default = '/etc/ssl/certs/ca-certificates.crt'
85 control_ca_bundle = os.path.join(
86 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(ini_path)))),
87 '.rccontrol-profile/etc/ca-bundle.crt')
88 if os.path.isfile(control_ca_bundle):
89 default = control_ca_bundle
90
91 return default
92
84 class SysInfoRes(object):
93 class SysInfoRes(object):
85 def __init__(self, value, state=None, human_value=None):
94 def __init__(self, value, state=None, human_value=None):
86 self.value = value
95 self.value = value
87 self.state = state or STATE_OK_DEFAULT
96 self.state = state or STATE_OK_DEFAULT
88 self.human_value = human_value or value
97 self.human_value = human_value or value
89
98
90 def __json__(self):
99 def __json__(self):
91 return {
100 return {
92 'value': self.value,
101 'value': self.value,
93 'state': self.state,
102 'state': self.state,
94 'human_value': self.human_value,
103 'human_value': self.human_value,
95 }
104 }
96
105
97 def get_value(self):
106 def get_value(self):
98 return self.__json__()
107 return self.__json__()
99
108
100 def __str__(self):
109 def __str__(self):
101 return '<SysInfoRes({})>'.format(self.__json__())
110 return '<SysInfoRes({})>'.format(self.__json__())
102
111
103
112
104 class SysInfo(object):
113 class SysInfo(object):
105
114
106 def __init__(self, func_name, **kwargs):
115 def __init__(self, func_name, **kwargs):
107 self.func_name = func_name
116 self.func_name = func_name
108 self.value = _NA
117 self.value = _NA
109 self.state = None
118 self.state = None
110 self.kwargs = kwargs or {}
119 self.kwargs = kwargs or {}
111
120
112 def __call__(self):
121 def __call__(self):
113 computed = self.compute(**self.kwargs)
122 computed = self.compute(**self.kwargs)
114 if not isinstance(computed, SysInfoRes):
123 if not isinstance(computed, SysInfoRes):
115 raise ValueError(
124 raise ValueError(
116 'computed value for {} is not instance of '
125 'computed value for {} is not instance of '
117 '{}, got {} instead'.format(
126 '{}, got {} instead'.format(
118 self.func_name, SysInfoRes, type(computed)))
127 self.func_name, SysInfoRes, type(computed)))
119 return computed.__json__()
128 return computed.__json__()
120
129
121 def __str__(self):
130 def __str__(self):
122 return '<SysInfo({})>'.format(self.func_name)
131 return '<SysInfo({})>'.format(self.func_name)
123
132
124 def compute(self, **kwargs):
133 def compute(self, **kwargs):
125 return self.func_name(**kwargs)
134 return self.func_name(**kwargs)
126
135
127
136
128 # SysInfo functions
137 # SysInfo functions
129 def python_info():
138 def python_info():
130 value = dict(version=' '.join(platform._sys_version()),
139 value = dict(version=' '.join(platform._sys_version()),
131 executable=sys.executable)
140 executable=sys.executable)
132 return SysInfoRes(value=value)
141 return SysInfoRes(value=value)
133
142
134
143
135 def py_modules():
144 def py_modules():
136 mods = dict([(p.project_name, p.version)
145 mods = dict([(p.project_name, p.version)
137 for p in pkg_resources.working_set])
146 for p in pkg_resources.working_set])
138 value = sorted(mods.items(), key=lambda k: k[0].lower())
147 value = sorted(mods.items(), key=lambda k: k[0].lower())
139 return SysInfoRes(value=value)
148 return SysInfoRes(value=value)
140
149
141
150
142 def platform_type():
151 def platform_type():
143 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
152 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
144
153
145 value = dict(
154 value = dict(
146 name=safe_unicode(platform.platform()),
155 name=safe_unicode(platform.platform()),
147 uuid=generate_platform_uuid()
156 uuid=generate_platform_uuid()
148 )
157 )
149 return SysInfoRes(value=value)
158 return SysInfoRes(value=value)
150
159
151
160
152 def locale_info():
161 def locale_info():
153 import locale
162 import locale
154
163
155 value = dict(
164 value = dict(
156 locale_default=locale.getdefaultlocale(),
165 locale_default=locale.getdefaultlocale(),
157 locale_lc_all=locale.getlocale(locale.LC_ALL),
166 locale_lc_all=locale.getlocale(locale.LC_ALL),
158 lang_env=os.environ.get('LANG'),
167 lang_env=os.environ.get('LANG'),
159 lc_all_env=os.environ.get('LC_ALL'),
168 lc_all_env=os.environ.get('LC_ALL'),
160 local_archive_env=os.environ.get('LOCALE_ARCHIVE'),
169 local_archive_env=os.environ.get('LOCALE_ARCHIVE'),
161 )
170 )
162 human_value = 'LANG: {}, locale LC_ALL: {}, Default locales: {}'.format(
171 human_value = 'LANG: {}, locale LC_ALL: {}, Default locales: {}'.format(
163 value['lang_env'], value['locale_lc_all'], value['locale_default'])
172 value['lang_env'], value['locale_lc_all'], value['locale_default'])
164 return SysInfoRes(value=value, human_value=human_value)
173 return SysInfoRes(value=value, human_value=human_value)
165
174
166
175
167 def ulimit_info():
176 def ulimit_info():
168 data = collections.OrderedDict([
177 data = collections.OrderedDict([
169 ('cpu time (seconds)', get_resource(resource.RLIMIT_CPU)),
178 ('cpu time (seconds)', get_resource(resource.RLIMIT_CPU)),
170 ('file size', get_resource(resource.RLIMIT_FSIZE)),
179 ('file size', get_resource(resource.RLIMIT_FSIZE)),
171 ('stack size', get_resource(resource.RLIMIT_STACK)),
180 ('stack size', get_resource(resource.RLIMIT_STACK)),
172 ('core file size', get_resource(resource.RLIMIT_CORE)),
181 ('core file size', get_resource(resource.RLIMIT_CORE)),
173 ('address space size', get_resource(resource.RLIMIT_AS)),
182 ('address space size', get_resource(resource.RLIMIT_AS)),
174 ('locked in mem size', get_resource(resource.RLIMIT_MEMLOCK)),
183 ('locked in mem size', get_resource(resource.RLIMIT_MEMLOCK)),
175 ('heap size', get_resource(resource.RLIMIT_DATA)),
184 ('heap size', get_resource(resource.RLIMIT_DATA)),
176 ('rss size', get_resource(resource.RLIMIT_RSS)),
185 ('rss size', get_resource(resource.RLIMIT_RSS)),
177 ('number of processes', get_resource(resource.RLIMIT_NPROC)),
186 ('number of processes', get_resource(resource.RLIMIT_NPROC)),
178 ('open files', get_resource(resource.RLIMIT_NOFILE)),
187 ('open files', get_resource(resource.RLIMIT_NOFILE)),
179 ])
188 ])
180
189
181 text = ', '.join('{}:{}'.format(k,v) for k,v in data.items())
190 text = ', '.join('{}:{}'.format(k,v) for k,v in data.items())
182
191
183 value = {
192 value = {
184 'limits': data,
193 'limits': data,
185 'text': text,
194 'text': text,
186 }
195 }
187 return SysInfoRes(value=value)
196 return SysInfoRes(value=value)
188
197
189
198
190 def uptime():
199 def uptime():
191 from rhodecode.lib.helpers import age, time_to_datetime
200 from rhodecode.lib.helpers import age, time_to_datetime
192 from rhodecode.translation import TranslationString
201 from rhodecode.translation import TranslationString
193
202
194 value = dict(boot_time=0, uptime=0, text='')
203 value = dict(boot_time=0, uptime=0, text='')
195 state = STATE_OK_DEFAULT
204 state = STATE_OK_DEFAULT
196 if not psutil:
205 if not psutil:
197 return SysInfoRes(value=value, state=state)
206 return SysInfoRes(value=value, state=state)
198
207
199 boot_time = psutil.boot_time()
208 boot_time = psutil.boot_time()
200 value['boot_time'] = boot_time
209 value['boot_time'] = boot_time
201 value['uptime'] = time.time() - boot_time
210 value['uptime'] = time.time() - boot_time
202
211
203 date_or_age = age(time_to_datetime(boot_time))
212 date_or_age = age(time_to_datetime(boot_time))
204 if isinstance(date_or_age, TranslationString):
213 if isinstance(date_or_age, TranslationString):
205 date_or_age = date_or_age.interpolate()
214 date_or_age = date_or_age.interpolate()
206
215
207 human_value = value.copy()
216 human_value = value.copy()
208 human_value['boot_time'] = time_to_datetime(boot_time)
217 human_value['boot_time'] = time_to_datetime(boot_time)
209 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
218 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
210
219
211 human_value['text'] = u'Server started {}'.format(date_or_age)
220 human_value['text'] = u'Server started {}'.format(date_or_age)
212 return SysInfoRes(value=value, human_value=human_value)
221 return SysInfoRes(value=value, human_value=human_value)
213
222
214
223
215 def memory():
224 def memory():
216 from rhodecode.lib.helpers import format_byte_size_binary
225 from rhodecode.lib.helpers import format_byte_size_binary
217 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
226 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
218 percent_used=0, free=0, inactive=0, active=0, shared=0,
227 percent_used=0, free=0, inactive=0, active=0, shared=0,
219 total=0, buffers=0, text='')
228 total=0, buffers=0, text='')
220
229
221 state = STATE_OK_DEFAULT
230 state = STATE_OK_DEFAULT
222 if not psutil:
231 if not psutil:
223 return SysInfoRes(value=value, state=state)
232 return SysInfoRes(value=value, state=state)
224
233
225 value.update(dict(psutil.virtual_memory()._asdict()))
234 value.update(dict(psutil.virtual_memory()._asdict()))
226 value['used_real'] = value['total'] - value['available']
235 value['used_real'] = value['total'] - value['available']
227 value['percent_used'] = psutil._common.usage_percent(
236 value['percent_used'] = psutil._common.usage_percent(
228 value['used_real'], value['total'], 1)
237 value['used_real'], value['total'], 1)
229
238
230 human_value = value.copy()
239 human_value = value.copy()
231 human_value['text'] = '%s/%s, %s%% used' % (
240 human_value['text'] = '%s/%s, %s%% used' % (
232 format_byte_size_binary(value['used_real']),
241 format_byte_size_binary(value['used_real']),
233 format_byte_size_binary(value['total']),
242 format_byte_size_binary(value['total']),
234 value['percent_used'],)
243 value['percent_used'],)
235
244
236 keys = value.keys()[::]
245 keys = value.keys()[::]
237 keys.pop(keys.index('percent'))
246 keys.pop(keys.index('percent'))
238 keys.pop(keys.index('percent_used'))
247 keys.pop(keys.index('percent_used'))
239 keys.pop(keys.index('text'))
248 keys.pop(keys.index('text'))
240 for k in keys:
249 for k in keys:
241 human_value[k] = format_byte_size_binary(value[k])
250 human_value[k] = format_byte_size_binary(value[k])
242
251
243 if state['type'] == STATE_OK and value['percent_used'] > 90:
252 if state['type'] == STATE_OK and value['percent_used'] > 90:
244 msg = 'Critical: your available RAM memory is very low.'
253 msg = 'Critical: your available RAM memory is very low.'
245 state = {'message': msg, 'type': STATE_ERR}
254 state = {'message': msg, 'type': STATE_ERR}
246
255
247 elif state['type'] == STATE_OK and value['percent_used'] > 70:
256 elif state['type'] == STATE_OK and value['percent_used'] > 70:
248 msg = 'Warning: your available RAM memory is running low.'
257 msg = 'Warning: your available RAM memory is running low.'
249 state = {'message': msg, 'type': STATE_WARN}
258 state = {'message': msg, 'type': STATE_WARN}
250
259
251 return SysInfoRes(value=value, state=state, human_value=human_value)
260 return SysInfoRes(value=value, state=state, human_value=human_value)
252
261
253
262
254 def machine_load():
263 def machine_load():
255 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
264 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
256 state = STATE_OK_DEFAULT
265 state = STATE_OK_DEFAULT
257 if not psutil:
266 if not psutil:
258 return SysInfoRes(value=value, state=state)
267 return SysInfoRes(value=value, state=state)
259
268
260 # load averages
269 # load averages
261 if hasattr(psutil.os, 'getloadavg'):
270 if hasattr(psutil.os, 'getloadavg'):
262 value.update(dict(
271 value.update(dict(
263 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
272 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
264
273
265 human_value = value.copy()
274 human_value = value.copy()
266 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
275 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
267 value['1_min'], value['5_min'], value['15_min'])
276 value['1_min'], value['5_min'], value['15_min'])
268
277
269 if state['type'] == STATE_OK and value['15_min'] > 5:
278 if state['type'] == STATE_OK and value['15_min'] > 5:
270 msg = 'Warning: your machine load is very high.'
279 msg = 'Warning: your machine load is very high.'
271 state = {'message': msg, 'type': STATE_WARN}
280 state = {'message': msg, 'type': STATE_WARN}
272
281
273 return SysInfoRes(value=value, state=state, human_value=human_value)
282 return SysInfoRes(value=value, state=state, human_value=human_value)
274
283
275
284
276 def cpu():
285 def cpu():
277 value = {'cpu': 0, 'cpu_count': 0, 'cpu_usage': []}
286 value = {'cpu': 0, 'cpu_count': 0, 'cpu_usage': []}
278 state = STATE_OK_DEFAULT
287 state = STATE_OK_DEFAULT
279
288
280 if not psutil:
289 if not psutil:
281 return SysInfoRes(value=value, state=state)
290 return SysInfoRes(value=value, state=state)
282
291
283 value['cpu'] = psutil.cpu_percent(0.5)
292 value['cpu'] = psutil.cpu_percent(0.5)
284 value['cpu_usage'] = psutil.cpu_percent(0.5, percpu=True)
293 value['cpu_usage'] = psutil.cpu_percent(0.5, percpu=True)
285 value['cpu_count'] = psutil.cpu_count()
294 value['cpu_count'] = psutil.cpu_count()
286
295
287 human_value = value.copy()
296 human_value = value.copy()
288 human_value['text'] = '{} cores at {} %'.format(
297 human_value['text'] = '{} cores at {} %'.format(
289 value['cpu_count'], value['cpu'])
298 value['cpu_count'], value['cpu'])
290
299
291 return SysInfoRes(value=value, state=state, human_value=human_value)
300 return SysInfoRes(value=value, state=state, human_value=human_value)
292
301
293
302
294 def storage():
303 def storage():
295 from rhodecode.lib.helpers import format_byte_size_binary
304 from rhodecode.lib.helpers import format_byte_size_binary
296 from rhodecode.model.settings import VcsSettingsModel
305 from rhodecode.model.settings import VcsSettingsModel
297 path = VcsSettingsModel().get_repos_location()
306 path = VcsSettingsModel().get_repos_location()
298
307
299 value = dict(percent=0, used=0, total=0, path=path, text='')
308 value = dict(percent=0, used=0, total=0, path=path, text='')
300 state = STATE_OK_DEFAULT
309 state = STATE_OK_DEFAULT
301 if not psutil:
310 if not psutil:
302 return SysInfoRes(value=value, state=state)
311 return SysInfoRes(value=value, state=state)
303
312
304 try:
313 try:
305 value.update(dict(psutil.disk_usage(path)._asdict()))
314 value.update(dict(psutil.disk_usage(path)._asdict()))
306 except Exception as e:
315 except Exception as e:
307 log.exception('Failed to fetch disk info')
316 log.exception('Failed to fetch disk info')
308 state = {'message': str(e), 'type': STATE_ERR}
317 state = {'message': str(e), 'type': STATE_ERR}
309
318
310 human_value = value.copy()
319 human_value = value.copy()
311 human_value['used'] = format_byte_size_binary(value['used'])
320 human_value['used'] = format_byte_size_binary(value['used'])
312 human_value['total'] = format_byte_size_binary(value['total'])
321 human_value['total'] = format_byte_size_binary(value['total'])
313 human_value['text'] = "{}/{}, {}% used".format(
322 human_value['text'] = "{}/{}, {}% used".format(
314 format_byte_size_binary(value['used']),
323 format_byte_size_binary(value['used']),
315 format_byte_size_binary(value['total']),
324 format_byte_size_binary(value['total']),
316 value['percent'])
325 value['percent'])
317
326
318 if state['type'] == STATE_OK and value['percent'] > 90:
327 if state['type'] == STATE_OK and value['percent'] > 90:
319 msg = 'Critical: your disk space is very low.'
328 msg = 'Critical: your disk space is very low.'
320 state = {'message': msg, 'type': STATE_ERR}
329 state = {'message': msg, 'type': STATE_ERR}
321
330
322 elif state['type'] == STATE_OK and value['percent'] > 70:
331 elif state['type'] == STATE_OK and value['percent'] > 70:
323 msg = 'Warning: your disk space is running low.'
332 msg = 'Warning: your disk space is running low.'
324 state = {'message': msg, 'type': STATE_WARN}
333 state = {'message': msg, 'type': STATE_WARN}
325
334
326 return SysInfoRes(value=value, state=state, human_value=human_value)
335 return SysInfoRes(value=value, state=state, human_value=human_value)
327
336
328
337
329 def storage_inodes():
338 def storage_inodes():
330 from rhodecode.model.settings import VcsSettingsModel
339 from rhodecode.model.settings import VcsSettingsModel
331 path = VcsSettingsModel().get_repos_location()
340 path = VcsSettingsModel().get_repos_location()
332
341
333 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
342 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
334 state = STATE_OK_DEFAULT
343 state = STATE_OK_DEFAULT
335 if not psutil:
344 if not psutil:
336 return SysInfoRes(value=value, state=state)
345 return SysInfoRes(value=value, state=state)
337
346
338 try:
347 try:
339 i_stat = os.statvfs(path)
348 i_stat = os.statvfs(path)
340 value['free'] = i_stat.f_ffree
349 value['free'] = i_stat.f_ffree
341 value['used'] = i_stat.f_files-i_stat.f_favail
350 value['used'] = i_stat.f_files-i_stat.f_favail
342 value['total'] = i_stat.f_files
351 value['total'] = i_stat.f_files
343 value['percent'] = percentage(value['used'], value['total'])
352 value['percent'] = percentage(value['used'], value['total'])
344 except Exception as e:
353 except Exception as e:
345 log.exception('Failed to fetch disk inodes info')
354 log.exception('Failed to fetch disk inodes info')
346 state = {'message': str(e), 'type': STATE_ERR}
355 state = {'message': str(e), 'type': STATE_ERR}
347
356
348 human_value = value.copy()
357 human_value = value.copy()
349 human_value['text'] = "{}/{}, {}% used".format(
358 human_value['text'] = "{}/{}, {}% used".format(
350 value['used'], value['total'], value['percent'])
359 value['used'], value['total'], value['percent'])
351
360
352 if state['type'] == STATE_OK and value['percent'] > 90:
361 if state['type'] == STATE_OK and value['percent'] > 90:
353 msg = 'Critical: your disk free inodes are very low.'
362 msg = 'Critical: your disk free inodes are very low.'
354 state = {'message': msg, 'type': STATE_ERR}
363 state = {'message': msg, 'type': STATE_ERR}
355
364
356 elif state['type'] == STATE_OK and value['percent'] > 70:
365 elif state['type'] == STATE_OK and value['percent'] > 70:
357 msg = 'Warning: your disk free inodes are running low.'
366 msg = 'Warning: your disk free inodes are running low.'
358 state = {'message': msg, 'type': STATE_WARN}
367 state = {'message': msg, 'type': STATE_WARN}
359
368
360 return SysInfoRes(value=value, state=state, human_value=human_value)
369 return SysInfoRes(value=value, state=state, human_value=human_value)
361
370
362
371
363 def storage_archives():
372 def storage_archives():
364 import rhodecode
373 import rhodecode
365 from rhodecode.lib.utils import safe_str
374 from rhodecode.lib.utils import safe_str
366 from rhodecode.lib.helpers import format_byte_size_binary
375 from rhodecode.lib.helpers import format_byte_size_binary
367
376
368 msg = 'Enable this by setting ' \
377 msg = 'Enable this by setting ' \
369 'archive_cache_dir=/path/to/cache option in the .ini file'
378 'archive_cache_dir=/path/to/cache option in the .ini file'
370 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
379 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
371
380
372 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
381 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
373 state = STATE_OK_DEFAULT
382 state = STATE_OK_DEFAULT
374 try:
383 try:
375 items_count = 0
384 items_count = 0
376 used = 0
385 used = 0
377 for root, dirs, files in os.walk(path):
386 for root, dirs, files in os.walk(path):
378 if root == path:
387 if root == path:
379 items_count = len(files)
388 items_count = len(files)
380
389
381 for f in files:
390 for f in files:
382 try:
391 try:
383 used += os.path.getsize(os.path.join(root, f))
392 used += os.path.getsize(os.path.join(root, f))
384 except OSError:
393 except OSError:
385 pass
394 pass
386 value.update({
395 value.update({
387 'percent': 100,
396 'percent': 100,
388 'used': used,
397 'used': used,
389 'total': used,
398 'total': used,
390 'items': items_count
399 'items': items_count
391 })
400 })
392
401
393 except Exception as e:
402 except Exception as e:
394 log.exception('failed to fetch archive cache storage')
403 log.exception('failed to fetch archive cache storage')
395 state = {'message': str(e), 'type': STATE_ERR}
404 state = {'message': str(e), 'type': STATE_ERR}
396
405
397 human_value = value.copy()
406 human_value = value.copy()
398 human_value['used'] = format_byte_size_binary(value['used'])
407 human_value['used'] = format_byte_size_binary(value['used'])
399 human_value['total'] = format_byte_size_binary(value['total'])
408 human_value['total'] = format_byte_size_binary(value['total'])
400 human_value['text'] = "{} ({} items)".format(
409 human_value['text'] = "{} ({} items)".format(
401 human_value['used'], value['items'])
410 human_value['used'], value['items'])
402
411
403 return SysInfoRes(value=value, state=state, human_value=human_value)
412 return SysInfoRes(value=value, state=state, human_value=human_value)
404
413
405
414
406 def storage_gist():
415 def storage_gist():
407 from rhodecode.model.gist import GIST_STORE_LOC
416 from rhodecode.model.gist import GIST_STORE_LOC
408 from rhodecode.model.settings import VcsSettingsModel
417 from rhodecode.model.settings import VcsSettingsModel
409 from rhodecode.lib.utils import safe_str
418 from rhodecode.lib.utils import safe_str
410 from rhodecode.lib.helpers import format_byte_size_binary
419 from rhodecode.lib.helpers import format_byte_size_binary
411 path = safe_str(os.path.join(
420 path = safe_str(os.path.join(
412 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
421 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
413
422
414 # gist storage
423 # gist storage
415 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
424 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
416 state = STATE_OK_DEFAULT
425 state = STATE_OK_DEFAULT
417
426
418 try:
427 try:
419 items_count = 0
428 items_count = 0
420 used = 0
429 used = 0
421 for root, dirs, files in os.walk(path):
430 for root, dirs, files in os.walk(path):
422 if root == path:
431 if root == path:
423 items_count = len(dirs)
432 items_count = len(dirs)
424
433
425 for f in files:
434 for f in files:
426 try:
435 try:
427 used += os.path.getsize(os.path.join(root, f))
436 used += os.path.getsize(os.path.join(root, f))
428 except OSError:
437 except OSError:
429 pass
438 pass
430 value.update({
439 value.update({
431 'percent': 100,
440 'percent': 100,
432 'used': used,
441 'used': used,
433 'total': used,
442 'total': used,
434 'items': items_count
443 'items': items_count
435 })
444 })
436 except Exception as e:
445 except Exception as e:
437 log.exception('failed to fetch gist storage items')
446 log.exception('failed to fetch gist storage items')
438 state = {'message': str(e), 'type': STATE_ERR}
447 state = {'message': str(e), 'type': STATE_ERR}
439
448
440 human_value = value.copy()
449 human_value = value.copy()
441 human_value['used'] = format_byte_size_binary(value['used'])
450 human_value['used'] = format_byte_size_binary(value['used'])
442 human_value['total'] = format_byte_size_binary(value['total'])
451 human_value['total'] = format_byte_size_binary(value['total'])
443 human_value['text'] = "{} ({} items)".format(
452 human_value['text'] = "{} ({} items)".format(
444 human_value['used'], value['items'])
453 human_value['used'], value['items'])
445
454
446 return SysInfoRes(value=value, state=state, human_value=human_value)
455 return SysInfoRes(value=value, state=state, human_value=human_value)
447
456
448
457
449 def storage_temp():
458 def storage_temp():
450 import tempfile
459 import tempfile
451 from rhodecode.lib.helpers import format_byte_size_binary
460 from rhodecode.lib.helpers import format_byte_size_binary
452
461
453 path = tempfile.gettempdir()
462 path = tempfile.gettempdir()
454 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
463 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
455 state = STATE_OK_DEFAULT
464 state = STATE_OK_DEFAULT
456
465
457 if not psutil:
466 if not psutil:
458 return SysInfoRes(value=value, state=state)
467 return SysInfoRes(value=value, state=state)
459
468
460 try:
469 try:
461 value.update(dict(psutil.disk_usage(path)._asdict()))
470 value.update(dict(psutil.disk_usage(path)._asdict()))
462 except Exception as e:
471 except Exception as e:
463 log.exception('Failed to fetch temp dir info')
472 log.exception('Failed to fetch temp dir info')
464 state = {'message': str(e), 'type': STATE_ERR}
473 state = {'message': str(e), 'type': STATE_ERR}
465
474
466 human_value = value.copy()
475 human_value = value.copy()
467 human_value['used'] = format_byte_size_binary(value['used'])
476 human_value['used'] = format_byte_size_binary(value['used'])
468 human_value['total'] = format_byte_size_binary(value['total'])
477 human_value['total'] = format_byte_size_binary(value['total'])
469 human_value['text'] = "{}/{}, {}% used".format(
478 human_value['text'] = "{}/{}, {}% used".format(
470 format_byte_size_binary(value['used']),
479 format_byte_size_binary(value['used']),
471 format_byte_size_binary(value['total']),
480 format_byte_size_binary(value['total']),
472 value['percent'])
481 value['percent'])
473
482
474 return SysInfoRes(value=value, state=state, human_value=human_value)
483 return SysInfoRes(value=value, state=state, human_value=human_value)
475
484
476
485
477 def search_info():
486 def search_info():
478 import rhodecode
487 import rhodecode
479 from rhodecode.lib.index import searcher_from_config
488 from rhodecode.lib.index import searcher_from_config
480
489
481 backend = rhodecode.CONFIG.get('search.module', '')
490 backend = rhodecode.CONFIG.get('search.module', '')
482 location = rhodecode.CONFIG.get('search.location', '')
491 location = rhodecode.CONFIG.get('search.location', '')
483
492
484 try:
493 try:
485 searcher = searcher_from_config(rhodecode.CONFIG)
494 searcher = searcher_from_config(rhodecode.CONFIG)
486 searcher = searcher.__class__.__name__
495 searcher = searcher.__class__.__name__
487 except Exception:
496 except Exception:
488 searcher = None
497 searcher = None
489
498
490 value = dict(
499 value = dict(
491 backend=backend, searcher=searcher, location=location, text='')
500 backend=backend, searcher=searcher, location=location, text='')
492 state = STATE_OK_DEFAULT
501 state = STATE_OK_DEFAULT
493
502
494 human_value = value.copy()
503 human_value = value.copy()
495 human_value['text'] = "backend:`{}`".format(human_value['backend'])
504 human_value['text'] = "backend:`{}`".format(human_value['backend'])
496
505
497 return SysInfoRes(value=value, state=state, human_value=human_value)
506 return SysInfoRes(value=value, state=state, human_value=human_value)
498
507
499
508
500 def git_info():
509 def git_info():
501 from rhodecode.lib.vcs.backends import git
510 from rhodecode.lib.vcs.backends import git
502 state = STATE_OK_DEFAULT
511 state = STATE_OK_DEFAULT
503 value = human_value = ''
512 value = human_value = ''
504 try:
513 try:
505 value = git.discover_git_version(raise_on_exc=True)
514 value = git.discover_git_version(raise_on_exc=True)
506 human_value = 'version reported from VCSServer: {}'.format(value)
515 human_value = 'version reported from VCSServer: {}'.format(value)
507 except Exception as e:
516 except Exception as e:
508 state = {'message': str(e), 'type': STATE_ERR}
517 state = {'message': str(e), 'type': STATE_ERR}
509
518
510 return SysInfoRes(value=value, state=state, human_value=human_value)
519 return SysInfoRes(value=value, state=state, human_value=human_value)
511
520
512
521
513 def hg_info():
522 def hg_info():
514 from rhodecode.lib.vcs.backends import hg
523 from rhodecode.lib.vcs.backends import hg
515 state = STATE_OK_DEFAULT
524 state = STATE_OK_DEFAULT
516 value = human_value = ''
525 value = human_value = ''
517 try:
526 try:
518 value = hg.discover_hg_version(raise_on_exc=True)
527 value = hg.discover_hg_version(raise_on_exc=True)
519 human_value = 'version reported from VCSServer: {}'.format(value)
528 human_value = 'version reported from VCSServer: {}'.format(value)
520 except Exception as e:
529 except Exception as e:
521 state = {'message': str(e), 'type': STATE_ERR}
530 state = {'message': str(e), 'type': STATE_ERR}
522 return SysInfoRes(value=value, state=state, human_value=human_value)
531 return SysInfoRes(value=value, state=state, human_value=human_value)
523
532
524
533
525 def svn_info():
534 def svn_info():
526 from rhodecode.lib.vcs.backends import svn
535 from rhodecode.lib.vcs.backends import svn
527 state = STATE_OK_DEFAULT
536 state = STATE_OK_DEFAULT
528 value = human_value = ''
537 value = human_value = ''
529 try:
538 try:
530 value = svn.discover_svn_version(raise_on_exc=True)
539 value = svn.discover_svn_version(raise_on_exc=True)
531 human_value = 'version reported from VCSServer: {}'.format(value)
540 human_value = 'version reported from VCSServer: {}'.format(value)
532 except Exception as e:
541 except Exception as e:
533 state = {'message': str(e), 'type': STATE_ERR}
542 state = {'message': str(e), 'type': STATE_ERR}
534 return SysInfoRes(value=value, state=state, human_value=human_value)
543 return SysInfoRes(value=value, state=state, human_value=human_value)
535
544
536
545
537 def vcs_backends():
546 def vcs_backends():
538 import rhodecode
547 import rhodecode
539 value = rhodecode.CONFIG.get('vcs.backends')
548 value = rhodecode.CONFIG.get('vcs.backends')
540 human_value = 'Enabled backends in order: {}'.format(','.join(value))
549 human_value = 'Enabled backends in order: {}'.format(','.join(value))
541 return SysInfoRes(value=value, human_value=human_value)
550 return SysInfoRes(value=value, human_value=human_value)
542
551
543
552
544 def vcs_server():
553 def vcs_server():
545 import rhodecode
554 import rhodecode
546 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
555 from rhodecode.lib.vcs.backends import get_vcsserver_service_data
547
556
548 server_url = rhodecode.CONFIG.get('vcs.server')
557 server_url = rhodecode.CONFIG.get('vcs.server')
549 enabled = rhodecode.CONFIG.get('vcs.server.enable')
558 enabled = rhodecode.CONFIG.get('vcs.server.enable')
550 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
559 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
551 state = STATE_OK_DEFAULT
560 state = STATE_OK_DEFAULT
552 version = None
561 version = None
553 workers = 0
562 workers = 0
554
563
555 try:
564 try:
556 data = get_vcsserver_service_data()
565 data = get_vcsserver_service_data()
557 if data and 'version' in data:
566 if data and 'version' in data:
558 version = data['version']
567 version = data['version']
559
568
560 if data and 'config' in data:
569 if data and 'config' in data:
561 conf = data['config']
570 conf = data['config']
562 workers = conf.get('workers', 'NOT AVAILABLE')
571 workers = conf.get('workers', 'NOT AVAILABLE')
563
572
564 connection = 'connected'
573 connection = 'connected'
565 except Exception as e:
574 except Exception as e:
566 connection = 'failed'
575 connection = 'failed'
567 state = {'message': str(e), 'type': STATE_ERR}
576 state = {'message': str(e), 'type': STATE_ERR}
568
577
569 value = dict(
578 value = dict(
570 url=server_url,
579 url=server_url,
571 enabled=enabled,
580 enabled=enabled,
572 protocol=protocol,
581 protocol=protocol,
573 connection=connection,
582 connection=connection,
574 version=version,
583 version=version,
575 text='',
584 text='',
576 )
585 )
577
586
578 human_value = value.copy()
587 human_value = value.copy()
579 human_value['text'] = \
588 human_value['text'] = \
580 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
589 '{url}@ver:{ver} via {mode} mode[workers:{workers}], connection:{conn}'.format(
581 url=server_url, ver=version, workers=workers, mode=protocol,
590 url=server_url, ver=version, workers=workers, mode=protocol,
582 conn=connection)
591 conn=connection)
583
592
584 return SysInfoRes(value=value, state=state, human_value=human_value)
593 return SysInfoRes(value=value, state=state, human_value=human_value)
585
594
586
595
587 def rhodecode_app_info():
596 def rhodecode_app_info():
588 import rhodecode
597 import rhodecode
589 edition = rhodecode.CONFIG.get('rhodecode.edition')
598 edition = rhodecode.CONFIG.get('rhodecode.edition')
590
599
591 value = dict(
600 value = dict(
592 rhodecode_version=rhodecode.__version__,
601 rhodecode_version=rhodecode.__version__,
593 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
602 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
594 text=''
603 text=''
595 )
604 )
596 human_value = value.copy()
605 human_value = value.copy()
597 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
606 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
598 edition=edition, ver=value['rhodecode_version']
607 edition=edition, ver=value['rhodecode_version']
599 )
608 )
600 return SysInfoRes(value=value, human_value=human_value)
609 return SysInfoRes(value=value, human_value=human_value)
601
610
602
611
603 def rhodecode_config():
612 def rhodecode_config():
604 import rhodecode
613 import rhodecode
605 path = rhodecode.CONFIG.get('__file__')
614 path = rhodecode.CONFIG.get('__file__')
606 rhodecode_ini_safe = rhodecode.CONFIG.copy()
615 rhodecode_ini_safe = rhodecode.CONFIG.copy()
616 cert_path = get_cert_path(path)
607
617
608 try:
618 try:
609 config = configparser.ConfigParser()
619 config = configparser.ConfigParser()
610 config.read(path)
620 config.read(path)
611 parsed_ini = config
621 parsed_ini = config
612 if parsed_ini.has_section('server:main'):
622 if parsed_ini.has_section('server:main'):
613 parsed_ini = dict(parsed_ini.items('server:main'))
623 parsed_ini = dict(parsed_ini.items('server:main'))
614 except Exception:
624 except Exception:
615 log.exception('Failed to read .ini file for display')
625 log.exception('Failed to read .ini file for display')
616 parsed_ini = {}
626 parsed_ini = {}
617
627
618 cert_path = os.path.join(
619 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(path)))),
620 '.rccontrol-profile/etc/ca-bundle.crt')
621
622 rhodecode_ini_safe['server:main'] = parsed_ini
628 rhodecode_ini_safe['server:main'] = parsed_ini
623
629
624 blacklist = [
630 blacklist = [
625 'rhodecode_license_key',
631 'rhodecode_license_key',
626 'routes.map',
632 'routes.map',
627 'sqlalchemy.db1.url',
633 'sqlalchemy.db1.url',
628 'channelstream.secret',
634 'channelstream.secret',
629 'beaker.session.secret',
635 'beaker.session.secret',
630 'rhodecode.encrypted_values.secret',
636 'rhodecode.encrypted_values.secret',
631 'rhodecode_auth_github_consumer_key',
637 'rhodecode_auth_github_consumer_key',
632 'rhodecode_auth_github_consumer_secret',
638 'rhodecode_auth_github_consumer_secret',
633 'rhodecode_auth_google_consumer_key',
639 'rhodecode_auth_google_consumer_key',
634 'rhodecode_auth_google_consumer_secret',
640 'rhodecode_auth_google_consumer_secret',
635 'rhodecode_auth_bitbucket_consumer_secret',
641 'rhodecode_auth_bitbucket_consumer_secret',
636 'rhodecode_auth_bitbucket_consumer_key',
642 'rhodecode_auth_bitbucket_consumer_key',
637 'rhodecode_auth_twitter_consumer_secret',
643 'rhodecode_auth_twitter_consumer_secret',
638 'rhodecode_auth_twitter_consumer_key',
644 'rhodecode_auth_twitter_consumer_key',
639
645
640 'rhodecode_auth_twitter_secret',
646 'rhodecode_auth_twitter_secret',
641 'rhodecode_auth_github_secret',
647 'rhodecode_auth_github_secret',
642 'rhodecode_auth_google_secret',
648 'rhodecode_auth_google_secret',
643 'rhodecode_auth_bitbucket_secret',
649 'rhodecode_auth_bitbucket_secret',
644
650
645 'appenlight.api_key',
651 'appenlight.api_key',
646 ('app_conf', 'sqlalchemy.db1.url')
652 ('app_conf', 'sqlalchemy.db1.url')
647 ]
653 ]
648 for k in blacklist:
654 for k in blacklist:
649 if isinstance(k, tuple):
655 if isinstance(k, tuple):
650 section, key = k
656 section, key = k
651 if section in rhodecode_ini_safe:
657 if section in rhodecode_ini_safe:
652 rhodecode_ini_safe[section] = '**OBFUSCATED**'
658 rhodecode_ini_safe[section] = '**OBFUSCATED**'
653 else:
659 else:
654 rhodecode_ini_safe.pop(k, None)
660 rhodecode_ini_safe.pop(k, None)
655
661
656 # TODO: maybe put some CONFIG checks here ?
662 # TODO: maybe put some CONFIG checks here ?
657 return SysInfoRes(value={'config': rhodecode_ini_safe,
663 return SysInfoRes(value={'config': rhodecode_ini_safe,
658 'path': path, 'cert_path': cert_path})
664 'path': path, 'cert_path': cert_path})
659
665
660
666
661 def database_info():
667 def database_info():
662 import rhodecode
668 import rhodecode
663 from sqlalchemy.engine import url as engine_url
669 from sqlalchemy.engine import url as engine_url
664 from rhodecode.model.meta import Base as sql_base, Session
670 from rhodecode.model.meta import Base as sql_base, Session
665 from rhodecode.model.db import DbMigrateVersion
671 from rhodecode.model.db import DbMigrateVersion
666
672
667 state = STATE_OK_DEFAULT
673 state = STATE_OK_DEFAULT
668
674
669 db_migrate = DbMigrateVersion.query().filter(
675 db_migrate = DbMigrateVersion.query().filter(
670 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
676 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
671
677
672 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
678 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
673
679
674 try:
680 try:
675 engine = sql_base.metadata.bind
681 engine = sql_base.metadata.bind
676 db_server_info = engine.dialect._get_server_version_info(
682 db_server_info = engine.dialect._get_server_version_info(
677 Session.connection(bind=engine))
683 Session.connection(bind=engine))
678 db_version = '.'.join(map(str, db_server_info))
684 db_version = '.'.join(map(str, db_server_info))
679 except Exception:
685 except Exception:
680 log.exception('failed to fetch db version')
686 log.exception('failed to fetch db version')
681 db_version = 'UNKNOWN'
687 db_version = 'UNKNOWN'
682
688
683 db_info = dict(
689 db_info = dict(
684 migrate_version=db_migrate.version,
690 migrate_version=db_migrate.version,
685 type=db_url_obj.get_backend_name(),
691 type=db_url_obj.get_backend_name(),
686 version=db_version,
692 version=db_version,
687 url=repr(db_url_obj)
693 url=repr(db_url_obj)
688 )
694 )
689 current_version = db_migrate.version
695 current_version = db_migrate.version
690 expected_version = rhodecode.__dbversion__
696 expected_version = rhodecode.__dbversion__
691 if state['type'] == STATE_OK and current_version != expected_version:
697 if state['type'] == STATE_OK and current_version != expected_version:
692 msg = 'Critical: database schema mismatch, ' \
698 msg = 'Critical: database schema mismatch, ' \
693 'expected version {}, got {}. ' \
699 'expected version {}, got {}. ' \
694 'Please run migrations on your database.'.format(
700 'Please run migrations on your database.'.format(
695 expected_version, current_version)
701 expected_version, current_version)
696 state = {'message': msg, 'type': STATE_ERR}
702 state = {'message': msg, 'type': STATE_ERR}
697
703
698 human_value = db_info.copy()
704 human_value = db_info.copy()
699 human_value['url'] = "{} @ migration version: {}".format(
705 human_value['url'] = "{} @ migration version: {}".format(
700 db_info['url'], db_info['migrate_version'])
706 db_info['url'], db_info['migrate_version'])
701 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
707 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
702 return SysInfoRes(value=db_info, state=state, human_value=human_value)
708 return SysInfoRes(value=db_info, state=state, human_value=human_value)
703
709
704
710
705 def server_info(environ):
711 def server_info(environ):
706 import rhodecode
712 import rhodecode
707 from rhodecode.lib.base import get_server_ip_addr, get_server_port
713 from rhodecode.lib.base import get_server_ip_addr, get_server_port
708
714
709 value = {
715 value = {
710 'server_ip': '%s:%s' % (
716 'server_ip': '%s:%s' % (
711 get_server_ip_addr(environ, log_errors=False),
717 get_server_ip_addr(environ, log_errors=False),
712 get_server_port(environ)
718 get_server_port(environ)
713 ),
719 ),
714 'server_id': rhodecode.CONFIG.get('instance_id'),
720 'server_id': rhodecode.CONFIG.get('instance_id'),
715 }
721 }
716 return SysInfoRes(value=value)
722 return SysInfoRes(value=value)
717
723
718
724
719 def usage_info():
725 def usage_info():
720 from rhodecode.model.db import User, Repository
726 from rhodecode.model.db import User, Repository
721 value = {
727 value = {
722 'users': User.query().count(),
728 'users': User.query().count(),
723 'users_active': User.query().filter(User.active == True).count(),
729 'users_active': User.query().filter(User.active == True).count(),
724 'repositories': Repository.query().count(),
730 'repositories': Repository.query().count(),
725 'repository_types': {
731 'repository_types': {
726 'hg': Repository.query().filter(
732 'hg': Repository.query().filter(
727 Repository.repo_type == 'hg').count(),
733 Repository.repo_type == 'hg').count(),
728 'git': Repository.query().filter(
734 'git': Repository.query().filter(
729 Repository.repo_type == 'git').count(),
735 Repository.repo_type == 'git').count(),
730 'svn': Repository.query().filter(
736 'svn': Repository.query().filter(
731 Repository.repo_type == 'svn').count(),
737 Repository.repo_type == 'svn').count(),
732 },
738 },
733 }
739 }
734 return SysInfoRes(value=value)
740 return SysInfoRes(value=value)
735
741
736
742
737 def get_system_info(environ):
743 def get_system_info(environ):
738 environ = environ or {}
744 environ = environ or {}
739 return {
745 return {
740 'rhodecode_app': SysInfo(rhodecode_app_info)(),
746 'rhodecode_app': SysInfo(rhodecode_app_info)(),
741 'rhodecode_config': SysInfo(rhodecode_config)(),
747 'rhodecode_config': SysInfo(rhodecode_config)(),
742 'rhodecode_usage': SysInfo(usage_info)(),
748 'rhodecode_usage': SysInfo(usage_info)(),
743 'python': SysInfo(python_info)(),
749 'python': SysInfo(python_info)(),
744 'py_modules': SysInfo(py_modules)(),
750 'py_modules': SysInfo(py_modules)(),
745
751
746 'platform': SysInfo(platform_type)(),
752 'platform': SysInfo(platform_type)(),
747 'locale': SysInfo(locale_info)(),
753 'locale': SysInfo(locale_info)(),
748 'server': SysInfo(server_info, environ=environ)(),
754 'server': SysInfo(server_info, environ=environ)(),
749 'database': SysInfo(database_info)(),
755 'database': SysInfo(database_info)(),
750 'ulimit': SysInfo(ulimit_info)(),
756 'ulimit': SysInfo(ulimit_info)(),
751 'storage': SysInfo(storage)(),
757 'storage': SysInfo(storage)(),
752 'storage_inodes': SysInfo(storage_inodes)(),
758 'storage_inodes': SysInfo(storage_inodes)(),
753 'storage_archive': SysInfo(storage_archives)(),
759 'storage_archive': SysInfo(storage_archives)(),
754 'storage_gist': SysInfo(storage_gist)(),
760 'storage_gist': SysInfo(storage_gist)(),
755 'storage_temp': SysInfo(storage_temp)(),
761 'storage_temp': SysInfo(storage_temp)(),
756
762
757 'search': SysInfo(search_info)(),
763 'search': SysInfo(search_info)(),
758
764
759 'uptime': SysInfo(uptime)(),
765 'uptime': SysInfo(uptime)(),
760 'load': SysInfo(machine_load)(),
766 'load': SysInfo(machine_load)(),
761 'cpu': SysInfo(cpu)(),
767 'cpu': SysInfo(cpu)(),
762 'memory': SysInfo(memory)(),
768 'memory': SysInfo(memory)(),
763
769
764 'vcs_backends': SysInfo(vcs_backends)(),
770 'vcs_backends': SysInfo(vcs_backends)(),
765 'vcs_server': SysInfo(vcs_server)(),
771 'vcs_server': SysInfo(vcs_server)(),
766
772
767 'git': SysInfo(git_info)(),
773 'git': SysInfo(git_info)(),
768 'hg': SysInfo(hg_info)(),
774 'hg': SysInfo(hg_info)(),
769 'svn': SysInfo(svn_info)(),
775 'svn': SysInfo(svn_info)(),
770 }
776 }
@@ -1,305 +1,311 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Client for the VCSServer implemented based on HTTP.
22 Client for the VCSServer implemented based on HTTP.
23 """
23 """
24
24
25 import copy
25 import copy
26 import logging
26 import logging
27 import threading
27 import threading
28 import urllib2
28 import urllib2
29 import urlparse
29 import urlparse
30 import uuid
30 import uuid
31 import traceback
31 import traceback
32
32
33 import pycurl
33 import pycurl
34 import msgpack
34 import msgpack
35 import requests
35 import requests
36 from requests.packages.urllib3.util.retry import Retry
36 from requests.packages.urllib3.util.retry import Retry
37
37
38 from . import exceptions, CurlSession
38 import rhodecode
39 from rhodecode.lib.system_info import get_cert_path
40 from rhodecode.lib.vcs import exceptions, CurlSession
39
41
40
42
41 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
42
44
43
45
44 # TODO: mikhail: Keep it in sync with vcsserver's
46 # TODO: mikhail: Keep it in sync with vcsserver's
45 # HTTPApplication.ALLOWED_EXCEPTIONS
47 # HTTPApplication.ALLOWED_EXCEPTIONS
46 EXCEPTIONS_MAP = {
48 EXCEPTIONS_MAP = {
47 'KeyError': KeyError,
49 'KeyError': KeyError,
48 'URLError': urllib2.URLError,
50 'URLError': urllib2.URLError,
49 }
51 }
50
52
51
53
52 class RepoMaker(object):
54 class RepoMaker(object):
53
55
54 def __init__(self, server_and_port, backend_endpoint, backend_type, session_factory):
56 def __init__(self, server_and_port, backend_endpoint, backend_type, session_factory):
55 self.url = urlparse.urljoin(
57 self.url = urlparse.urljoin(
56 'http://%s' % server_and_port, backend_endpoint)
58 'http://%s' % server_and_port, backend_endpoint)
57 self._session_factory = session_factory
59 self._session_factory = session_factory
58 self.backend_type = backend_type
60 self.backend_type = backend_type
59
61
60 def __call__(self, path, config, with_wire=None):
62 def __call__(self, path, config, with_wire=None):
61 log.debug('RepoMaker call on %s', path)
63 log.debug('RepoMaker call on %s', path)
62 return RemoteRepo(
64 return RemoteRepo(
63 path, config, self.url, self._session_factory(),
65 path, config, self.url, self._session_factory(),
64 with_wire=with_wire)
66 with_wire=with_wire)
65
67
66 def __getattr__(self, name):
68 def __getattr__(self, name):
67 def f(*args, **kwargs):
69 def f(*args, **kwargs):
68 return self._call(name, *args, **kwargs)
70 return self._call(name, *args, **kwargs)
69 return f
71 return f
70
72
71 @exceptions.map_vcs_exceptions
73 @exceptions.map_vcs_exceptions
72 def _call(self, name, *args, **kwargs):
74 def _call(self, name, *args, **kwargs):
73 payload = {
75 payload = {
74 'id': str(uuid.uuid4()),
76 'id': str(uuid.uuid4()),
75 'method': name,
77 'method': name,
76 'backend': self.backend_type,
78 'backend': self.backend_type,
77 'params': {'args': args, 'kwargs': kwargs}
79 'params': {'args': args, 'kwargs': kwargs}
78 }
80 }
79 return _remote_call(
81 return _remote_call(
80 self.url, payload, EXCEPTIONS_MAP, self._session_factory())
82 self.url, payload, EXCEPTIONS_MAP, self._session_factory())
81
83
82
84
83 class ServiceConnection(object):
85 class ServiceConnection(object):
84 def __init__(self, server_and_port, backend_endpoint, session_factory):
86 def __init__(self, server_and_port, backend_endpoint, session_factory):
85 self.url = urlparse.urljoin(
87 self.url = urlparse.urljoin(
86 'http://%s' % server_and_port, backend_endpoint)
88 'http://%s' % server_and_port, backend_endpoint)
87 self._session_factory = session_factory
89 self._session_factory = session_factory
88
90
89 def __getattr__(self, name):
91 def __getattr__(self, name):
90 def f(*args, **kwargs):
92 def f(*args, **kwargs):
91 return self._call(name, *args, **kwargs)
93 return self._call(name, *args, **kwargs)
92
94
93 return f
95 return f
94
96
95 @exceptions.map_vcs_exceptions
97 @exceptions.map_vcs_exceptions
96 def _call(self, name, *args, **kwargs):
98 def _call(self, name, *args, **kwargs):
97 payload = {
99 payload = {
98 'id': str(uuid.uuid4()),
100 'id': str(uuid.uuid4()),
99 'method': name,
101 'method': name,
100 'params': {'args': args, 'kwargs': kwargs}
102 'params': {'args': args, 'kwargs': kwargs}
101 }
103 }
102 return _remote_call(
104 return _remote_call(
103 self.url, payload, EXCEPTIONS_MAP, self._session_factory())
105 self.url, payload, EXCEPTIONS_MAP, self._session_factory())
104
106
105
107
106 class RemoteRepo(object):
108 class RemoteRepo(object):
107
109
108 def __init__(self, path, config, url, session, with_wire=None):
110 def __init__(self, path, config, url, session, with_wire=None):
109 self.url = url
111 self.url = url
110 self._session = session
112 self._session = session
111 self._wire = {
113 self._wire = {
112 "path": path,
114 "path": path,
113 "config": config,
115 "config": config,
114 "context": self._create_vcs_cache_context(),
116 "context": self._create_vcs_cache_context(),
115 }
117 }
116 if with_wire:
118 if with_wire:
117 self._wire.update(with_wire)
119 self._wire.update(with_wire)
118
120
119 # johbo: Trading complexity for performance. Avoiding the call to
121 # johbo: Trading complexity for performance. Avoiding the call to
120 # log.debug brings a few percent gain even if is is not active.
122 # log.debug brings a few percent gain even if is is not active.
121 if log.isEnabledFor(logging.DEBUG):
123 if log.isEnabledFor(logging.DEBUG):
122 self._call = self._call_with_logging
124 self._call = self._call_with_logging
123
125
126 self.cert_dir = get_cert_path(rhodecode.CONFIG.get('__file__'))
127
124 def __getattr__(self, name):
128 def __getattr__(self, name):
125 def f(*args, **kwargs):
129 def f(*args, **kwargs):
126 return self._call(name, *args, **kwargs)
130 return self._call(name, *args, **kwargs)
127 return f
131 return f
128
132
129 @exceptions.map_vcs_exceptions
133 @exceptions.map_vcs_exceptions
130 def _call(self, name, *args, **kwargs):
134 def _call(self, name, *args, **kwargs):
131 # TODO: oliver: This is currently necessary pre-call since the
135 # TODO: oliver: This is currently necessary pre-call since the
132 # config object is being changed for hooking scenarios
136 # config object is being changed for hooking scenarios
133 wire = copy.deepcopy(self._wire)
137 wire = copy.deepcopy(self._wire)
134 wire["config"] = wire["config"].serialize()
138 wire["config"] = wire["config"].serialize()
139
140 wire["config"].append(('vcs', 'ssl_dir', self.cert_dir))
135 payload = {
141 payload = {
136 'id': str(uuid.uuid4()),
142 'id': str(uuid.uuid4()),
137 'method': name,
143 'method': name,
138 'params': {'wire': wire, 'args': args, 'kwargs': kwargs}
144 'params': {'wire': wire, 'args': args, 'kwargs': kwargs}
139 }
145 }
140 return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session)
146 return _remote_call(self.url, payload, EXCEPTIONS_MAP, self._session)
141
147
142 def _call_with_logging(self, name, *args, **kwargs):
148 def _call_with_logging(self, name, *args, **kwargs):
143 context_uid = self._wire.get('context')
149 context_uid = self._wire.get('context')
144 log.debug('Calling %s@%s with args:%r. wire_context: %s',
150 log.debug('Calling %s@%s with args:%r. wire_context: %s',
145 self.url, name, args, context_uid)
151 self.url, name, args, context_uid)
146 return RemoteRepo._call(self, name, *args, **kwargs)
152 return RemoteRepo._call(self, name, *args, **kwargs)
147
153
148 def __getitem__(self, key):
154 def __getitem__(self, key):
149 return self.revision(key)
155 return self.revision(key)
150
156
151 def _create_vcs_cache_context(self):
157 def _create_vcs_cache_context(self):
152 """
158 """
153 Creates a unique string which is passed to the VCSServer on every
159 Creates a unique string which is passed to the VCSServer on every
154 remote call. It is used as cache key in the VCSServer.
160 remote call. It is used as cache key in the VCSServer.
155 """
161 """
156 return str(uuid.uuid4())
162 return str(uuid.uuid4())
157
163
158 def invalidate_vcs_cache(self):
164 def invalidate_vcs_cache(self):
159 """
165 """
160 This invalidates the context which is sent to the VCSServer on every
166 This invalidates the context which is sent to the VCSServer on every
161 call to a remote method. It forces the VCSServer to create a fresh
167 call to a remote method. It forces the VCSServer to create a fresh
162 repository instance on the next call to a remote method.
168 repository instance on the next call to a remote method.
163 """
169 """
164 self._wire['context'] = self._create_vcs_cache_context()
170 self._wire['context'] = self._create_vcs_cache_context()
165
171
166
172
167 class RemoteObject(object):
173 class RemoteObject(object):
168
174
169 def __init__(self, url, session):
175 def __init__(self, url, session):
170 self._url = url
176 self._url = url
171 self._session = session
177 self._session = session
172
178
173 # johbo: Trading complexity for performance. Avoiding the call to
179 # johbo: Trading complexity for performance. Avoiding the call to
174 # log.debug brings a few percent gain even if is is not active.
180 # log.debug brings a few percent gain even if is is not active.
175 if log.isEnabledFor(logging.DEBUG):
181 if log.isEnabledFor(logging.DEBUG):
176 self._call = self._call_with_logging
182 self._call = self._call_with_logging
177
183
178 def __getattr__(self, name):
184 def __getattr__(self, name):
179 def f(*args, **kwargs):
185 def f(*args, **kwargs):
180 return self._call(name, *args, **kwargs)
186 return self._call(name, *args, **kwargs)
181 return f
187 return f
182
188
183 @exceptions.map_vcs_exceptions
189 @exceptions.map_vcs_exceptions
184 def _call(self, name, *args, **kwargs):
190 def _call(self, name, *args, **kwargs):
185 payload = {
191 payload = {
186 'id': str(uuid.uuid4()),
192 'id': str(uuid.uuid4()),
187 'method': name,
193 'method': name,
188 'params': {'args': args, 'kwargs': kwargs}
194 'params': {'args': args, 'kwargs': kwargs}
189 }
195 }
190 return _remote_call(self._url, payload, EXCEPTIONS_MAP, self._session)
196 return _remote_call(self._url, payload, EXCEPTIONS_MAP, self._session)
191
197
192 def _call_with_logging(self, name, *args, **kwargs):
198 def _call_with_logging(self, name, *args, **kwargs):
193 log.debug('Calling %s@%s', self._url, name)
199 log.debug('Calling %s@%s', self._url, name)
194 return RemoteObject._call(self, name, *args, **kwargs)
200 return RemoteObject._call(self, name, *args, **kwargs)
195
201
196
202
197 def _remote_call(url, payload, exceptions_map, session):
203 def _remote_call(url, payload, exceptions_map, session):
198 try:
204 try:
199 response = session.post(url, data=msgpack.packb(payload))
205 response = session.post(url, data=msgpack.packb(payload))
200 except pycurl.error as e:
206 except pycurl.error as e:
201 msg = '{}. \npycurl traceback: {}'.format(e, traceback.format_exc())
207 msg = '{}. \npycurl traceback: {}'.format(e, traceback.format_exc())
202 raise exceptions.HttpVCSCommunicationError(msg)
208 raise exceptions.HttpVCSCommunicationError(msg)
203 except Exception as e:
209 except Exception as e:
204 message = getattr(e, 'message', '')
210 message = getattr(e, 'message', '')
205 if 'Failed to connect' in message:
211 if 'Failed to connect' in message:
206 # gevent doesn't return proper pycurl errors
212 # gevent doesn't return proper pycurl errors
207 raise exceptions.HttpVCSCommunicationError(e)
213 raise exceptions.HttpVCSCommunicationError(e)
208 else:
214 else:
209 raise
215 raise
210
216
211 if response.status_code >= 400:
217 if response.status_code >= 400:
212 log.error('Call to %s returned non 200 HTTP code: %s',
218 log.error('Call to %s returned non 200 HTTP code: %s',
213 url, response.status_code)
219 url, response.status_code)
214 raise exceptions.HttpVCSCommunicationError(repr(response.content))
220 raise exceptions.HttpVCSCommunicationError(repr(response.content))
215
221
216 try:
222 try:
217 response = msgpack.unpackb(response.content)
223 response = msgpack.unpackb(response.content)
218 except Exception:
224 except Exception:
219 log.exception('Failed to decode response %r', response.content)
225 log.exception('Failed to decode response %r', response.content)
220 raise
226 raise
221
227
222 error = response.get('error')
228 error = response.get('error')
223 if error:
229 if error:
224 type_ = error.get('type', 'Exception')
230 type_ = error.get('type', 'Exception')
225 exc = exceptions_map.get(type_, Exception)
231 exc = exceptions_map.get(type_, Exception)
226 exc = exc(error.get('message'))
232 exc = exc(error.get('message'))
227 try:
233 try:
228 exc._vcs_kind = error['_vcs_kind']
234 exc._vcs_kind = error['_vcs_kind']
229 except KeyError:
235 except KeyError:
230 pass
236 pass
231
237
232 try:
238 try:
233 exc._vcs_server_traceback = error['traceback']
239 exc._vcs_server_traceback = error['traceback']
234 except KeyError:
240 except KeyError:
235 pass
241 pass
236
242
237 raise exc
243 raise exc
238 return response.get('result')
244 return response.get('result')
239
245
240
246
241 class VcsHttpProxy(object):
247 class VcsHttpProxy(object):
242
248
243 CHUNK_SIZE = 16384
249 CHUNK_SIZE = 16384
244
250
245 def __init__(self, server_and_port, backend_endpoint):
251 def __init__(self, server_and_port, backend_endpoint):
246
252
247
253
248 retries = Retry(total=5, connect=None, read=None, redirect=None)
254 retries = Retry(total=5, connect=None, read=None, redirect=None)
249
255
250 adapter = requests.adapters.HTTPAdapter(max_retries=retries)
256 adapter = requests.adapters.HTTPAdapter(max_retries=retries)
251 self.base_url = urlparse.urljoin(
257 self.base_url = urlparse.urljoin(
252 'http://%s' % server_and_port, backend_endpoint)
258 'http://%s' % server_and_port, backend_endpoint)
253 self.session = requests.Session()
259 self.session = requests.Session()
254 self.session.mount('http://', adapter)
260 self.session.mount('http://', adapter)
255
261
256 def handle(self, environment, input_data, *args, **kwargs):
262 def handle(self, environment, input_data, *args, **kwargs):
257 data = {
263 data = {
258 'environment': environment,
264 'environment': environment,
259 'input_data': input_data,
265 'input_data': input_data,
260 'args': args,
266 'args': args,
261 'kwargs': kwargs
267 'kwargs': kwargs
262 }
268 }
263 result = self.session.post(
269 result = self.session.post(
264 self.base_url, msgpack.packb(data), stream=True)
270 self.base_url, msgpack.packb(data), stream=True)
265 return self._get_result(result)
271 return self._get_result(result)
266
272
267 def _deserialize_and_raise(self, error):
273 def _deserialize_and_raise(self, error):
268 exception = Exception(error['message'])
274 exception = Exception(error['message'])
269 try:
275 try:
270 exception._vcs_kind = error['_vcs_kind']
276 exception._vcs_kind = error['_vcs_kind']
271 except KeyError:
277 except KeyError:
272 pass
278 pass
273 raise exception
279 raise exception
274
280
275 def _iterate(self, result):
281 def _iterate(self, result):
276 unpacker = msgpack.Unpacker()
282 unpacker = msgpack.Unpacker()
277 for line in result.iter_content(chunk_size=self.CHUNK_SIZE):
283 for line in result.iter_content(chunk_size=self.CHUNK_SIZE):
278 unpacker.feed(line)
284 unpacker.feed(line)
279 for chunk in unpacker:
285 for chunk in unpacker:
280 yield chunk
286 yield chunk
281
287
282 def _get_result(self, result):
288 def _get_result(self, result):
283 iterator = self._iterate(result)
289 iterator = self._iterate(result)
284 error = iterator.next()
290 error = iterator.next()
285 if error:
291 if error:
286 self._deserialize_and_raise(error)
292 self._deserialize_and_raise(error)
287
293
288 status = iterator.next()
294 status = iterator.next()
289 headers = iterator.next()
295 headers = iterator.next()
290
296
291 return iterator, status, headers
297 return iterator, status, headers
292
298
293
299
294 class ThreadlocalSessionFactory(object):
300 class ThreadlocalSessionFactory(object):
295 """
301 """
296 Creates one CurlSession per thread on demand.
302 Creates one CurlSession per thread on demand.
297 """
303 """
298
304
299 def __init__(self):
305 def __init__(self):
300 self._thread_local = threading.local()
306 self._thread_local = threading.local()
301
307
302 def __call__(self):
308 def __call__(self):
303 if not hasattr(self._thread_local, 'curl_session'):
309 if not hasattr(self._thread_local, 'curl_session'):
304 self._thread_local.curl_session = CurlSession()
310 self._thread_local.curl_session = CurlSession()
305 return self._thread_local.curl_session
311 return self._thread_local.curl_session
@@ -1,336 +1,355 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('favicon', '/favicon.ico', []);
15 pyroutes.register('favicon', '/favicon.ico', []);
16 pyroutes.register('robots', '/robots.txt', []);
16 pyroutes.register('robots', '/robots.txt', []);
17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
38 pyroutes.register('admin_home', '/_admin', []);
38 pyroutes.register('admin_home', '/_admin', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
83 pyroutes.register('admin_settings_automation', '/_admin/_admin/settings/automation', []);
84 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
85 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
86 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
87 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
88 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
89 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
90 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
91 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
92 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
93 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
94 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
95 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
96 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
97 pyroutes.register('users', '/_admin/users', []);
95 pyroutes.register('users', '/_admin/users', []);
98 pyroutes.register('users_data', '/_admin/users_data', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
99 pyroutes.register('users_create', '/_admin/users/create', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
100 pyroutes.register('users_new', '/_admin/users/new', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
101 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
102 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
103 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
104 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
105 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
106 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
107 pyroutes.register('user_force_password_reset', '/_admin/users/%(user_id)s/password_reset', ['user_id']);
105 pyroutes.register('user_force_password_reset', '/_admin/users/%(user_id)s/password_reset', ['user_id']);
108 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
106 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
109 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
110 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
111 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
107 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
112 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
108 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
113 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
114 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
115 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
116 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
112 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
117 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
113 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
118 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
114 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
119 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
115 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
120 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
116 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
121 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
117 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
122 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
118 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
123 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
119 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
124 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
120 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
125 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
121 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
126 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
122 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
127 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
123 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
128 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
124 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
129 pyroutes.register('user_groups', '/_admin/user_groups', []);
125 pyroutes.register('user_groups', '/_admin/user_groups', []);
130 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
126 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
131 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
127 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
132 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
128 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
133 pyroutes.register('repos', '/_admin/repos', []);
129 pyroutes.register('repos', '/_admin/repos', []);
134 pyroutes.register('repo_new', '/_admin/repos/new', []);
130 pyroutes.register('repo_new', '/_admin/repos/new', []);
135 pyroutes.register('repo_create', '/_admin/repos/create', []);
131 pyroutes.register('repo_create', '/_admin/repos/create', []);
136 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
132 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
137 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
133 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
138 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
134 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
139 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
135 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
140 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
136 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
141 pyroutes.register('channelstream_proxy', '/_channelstream', []);
137 pyroutes.register('channelstream_proxy', '/_channelstream', []);
142 pyroutes.register('login', '/_admin/login', []);
143 pyroutes.register('logout', '/_admin/logout', []);
138 pyroutes.register('logout', '/_admin/logout', []);
144 pyroutes.register('register', '/_admin/register', []);
145 pyroutes.register('reset_password', '/_admin/password_reset', []);
139 pyroutes.register('reset_password', '/_admin/password_reset', []);
146 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
140 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
147 pyroutes.register('home', '/', []);
141 pyroutes.register('home', '/', []);
148 pyroutes.register('user_autocomplete_data', '/_users', []);
142 pyroutes.register('user_autocomplete_data', '/_users', []);
149 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
143 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
150 pyroutes.register('repo_list_data', '/_repos', []);
144 pyroutes.register('repo_list_data', '/_repos', []);
151 pyroutes.register('goto_switcher_data', '/_goto_data', []);
145 pyroutes.register('goto_switcher_data', '/_goto_data', []);
152 pyroutes.register('markup_preview', '/_markup_preview', []);
146 pyroutes.register('markup_preview', '/_markup_preview', []);
153 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
147 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
154 pyroutes.register('journal', '/_admin/journal', []);
148 pyroutes.register('journal', '/_admin/journal', []);
155 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
149 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
156 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
150 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
157 pyroutes.register('journal_public', '/_admin/public_journal', []);
151 pyroutes.register('journal_public', '/_admin/public_journal', []);
158 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
152 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
159 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
153 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
160 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
154 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
161 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
155 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
162 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
156 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
163 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
157 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
164 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
158 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
165 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
159 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
166 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
160 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
167 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
161 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
168 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
162 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
163 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
164 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
171 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
165 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
166 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
173 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
167 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
174 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
168 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
175 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
176 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
170 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
177 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
171 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
178 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
172 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
179 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
173 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
180 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
174 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
181 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
175 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
182 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
176 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
183 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
177 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
184 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
178 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
185 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
179 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
186 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
180 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
181 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
182 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
189 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
183 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
185 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
186 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
195 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
202 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
196 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
203 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
197 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
204 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
198 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
205 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
206 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
200 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
207 pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
208 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
202 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
209 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
203 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
210 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
204 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
211 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
205 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
212 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
206 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
213 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
207 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
214 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
208 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
215 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
209 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
216 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
210 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
217 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
211 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
218 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
212 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
219 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
213 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
220 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
214 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
221 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
215 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
222 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
216 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
223 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
217 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
224 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
218 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
225 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
219 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
226 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
220 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
227 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
221 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
228 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
222 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
229 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
223 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
230 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
224 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
231 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
225 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
232 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
226 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
233 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
227 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
234 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
228 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
235 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
229 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
236 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
230 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
237 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
231 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
238 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
232 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
239 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
240 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
241 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
233 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
242 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
234 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
243 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
235 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
244 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
236 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
245 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
237 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
246 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
238 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
247 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
239 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
248 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
240 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
249 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
250 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
241 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
251 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
242 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
252 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
243 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
253 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
244 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
254 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
245 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
255 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
246 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
256 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
247 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
257 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
248 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
258 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
249 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
259 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
250 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
260 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
251 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
261 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
262 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
252 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
263 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
253 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
264 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
254 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
265 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
255 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
266 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
256 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
267 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
257 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
268 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
258 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
269 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
259 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
270 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
260 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
271 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
261 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
272 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
262 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
273 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
263 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
274 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
264 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
275 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
265 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
276 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
266 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
277 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
267 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
278 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
268 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
279 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
269 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
280 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
270 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
281 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
271 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
282 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
272 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
283 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
273 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
284 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
274 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
285 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
275 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
286 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
276 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
287 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
277 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
288 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
278 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
289 pyroutes.register('search', '/_admin/search', []);
279 pyroutes.register('search', '/_admin/search', []);
290 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
280 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
291 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
281 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
292 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
282 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
293 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
283 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
294 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
284 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
295 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
285 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
296 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
286 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
297 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
287 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
298 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
299 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
300 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
288 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
301 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
289 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
302 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
290 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
303 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
291 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
304 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
292 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
305 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
293 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
306 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
294 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
307 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
295 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
308 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
296 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
309 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
297 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
310 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
298 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
311 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
299 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
312 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
300 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
313 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
301 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
314 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
302 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
315 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
303 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
316 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
304 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
317 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
305 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
318 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
306 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
319 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
307 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
320 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
308 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
321 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
309 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
322 pyroutes.register('gists_show', '/_admin/gists', []);
310 pyroutes.register('gists_show', '/_admin/gists', []);
323 pyroutes.register('gists_new', '/_admin/gists/new', []);
311 pyroutes.register('gists_new', '/_admin/gists/new', []);
324 pyroutes.register('gists_create', '/_admin/gists/create', []);
312 pyroutes.register('gists_create', '/_admin/gists/create', []);
325 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
313 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
326 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
314 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
327 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
315 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
328 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
316 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
329 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
317 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
330 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
318 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
331 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
319 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
332 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
320 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
333 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
321 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
334 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
322 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
335 pyroutes.register('apiv2', '/_admin/api', []);
323 pyroutes.register('apiv2', '/_admin/api', []);
324 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
325 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
326 pyroutes.register('login', '/_admin/login', []);
327 pyroutes.register('register', '/_admin/register', []);
328 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
329 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
330 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
331 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
332 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
333 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
334 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
335 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
336 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
337 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
338 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
339 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
340 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
341 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
342 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
343 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
344 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
345 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
346 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
347 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
348 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
349 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
350 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
351 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
352 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
353 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
354 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
336 }
355 }
General Comments 0
You need to be logged in to leave comments. Login now