##// END OF EJS Templates
codingstyle: trivial whitespace fixes...
Lars Kruse -
r6789:76912908 default
parent child Browse files
Show More
@@ -158,7 +158,7 b' class RcConf(object):'
158 """
158 """
159 try:
159 try:
160 with open(self._conf_name, 'rb') as conf:
160 with open(self._conf_name, 'rb') as conf:
161 return json.load(conf)
161 return json.load(conf)
162 except IOError as e:
162 except IOError as e:
163 #sys.stderr.write(str(e) + '\n')
163 #sys.stderr.write(str(e) + '\n')
164 pass
164 pass
@@ -121,5 +121,6 b' def main(argv=None):'
121 )
121 )
122 return 0
122 return 0
123
123
124
124 if __name__ == '__main__':
125 if __name__ == '__main__':
125 sys.exit(main(sys.argv))
126 sys.exit(main(sys.argv))
@@ -92,6 +92,7 b' class BackupManager(object):'
92 logging.info('Removing file %s', self.backup_file_name)
92 logging.info('Removing file %s', self.backup_file_name)
93 os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
93 os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
94
94
95
95 if __name__ == "__main__":
96 if __name__ == "__main__":
96
97
97 repo_location = '/home/repo_path'
98 repo_location = '/home/repo_path'
@@ -95,6 +95,7 b' class KallitheaAppConfig(AppConfig):'
95 # Disable transaction manager -- currently Kallithea takes care of transactions itself
95 # Disable transaction manager -- currently Kallithea takes care of transactions itself
96 self['tm.enabled'] = False
96 self['tm.enabled'] = False
97
97
98
98 base_config = KallitheaAppConfig()
99 base_config = KallitheaAppConfig()
99
100
100 # TODO still needed as long as we use pylonslib
101 # TODO still needed as long as we use pylonslib
@@ -174,6 +175,7 b' def setup_configuration(app):'
174 repo2db_mapper(ScmModel().repo_scan(repos_path),
175 repo2db_mapper(ScmModel().repo_scan(repos_path),
175 remove_obsolete=False, install_git_hooks=False)
176 remove_obsolete=False, install_git_hooks=False)
176
177
178
177 hooks.register('configure_new_app', setup_configuration)
179 hooks.register('configure_new_app', setup_configuration)
178
180
179
181
@@ -190,4 +192,5 b' def setup_application(app):'
190 app = HttpsFixup(app, config)
192 app = HttpsFixup(app, config)
191 return app
193 return app
192
194
195
193 hooks.register('before_config', setup_application)
196 hooks.register('before_config', setup_application)
@@ -23,10 +23,12 b' from kallithea.config.environment import'
23 # make_base_app will wrap the TurboGears2 app with all the middleware it needs.
23 # make_base_app will wrap the TurboGears2 app with all the middleware it needs.
24 make_base_app = base_config.setup_tg_wsgi_app(load_environment)
24 make_base_app = base_config.setup_tg_wsgi_app(load_environment)
25
25
26
26 def make_app_without_logging(global_conf, full_stack=True, **app_conf):
27 def make_app_without_logging(global_conf, full_stack=True, **app_conf):
27 """The core of make_app for use from gearbox commands (other than 'serve')"""
28 """The core of make_app for use from gearbox commands (other than 'serve')"""
28 return make_base_app(global_conf, full_stack=full_stack, **app_conf)
29 return make_base_app(global_conf, full_stack=full_stack, **app_conf)
29
30
31
30 def make_app(global_conf, full_stack=True, **app_conf):
32 def make_app(global_conf, full_stack=True, **app_conf):
31 """
33 """
32 Set up Kallithea with the settings found in the PasteDeploy configuration
34 Set up Kallithea with the settings found in the PasteDeploy configuration
@@ -25,5 +25,6 b' def main():'
25 _handler(repo_path, push_data, os.environ)
25 _handler(repo_path, push_data, os.environ)
26 sys.exit(0)
26 sys.exit(0)
27
27
28
28 if __name__ == '__main__':
29 if __name__ == '__main__':
29 main()
30 main()
@@ -25,5 +25,6 b' def main():'
25 _handler(repo_path, push_data, os.environ)
25 _handler(repo_path, push_data, os.environ)
26 sys.exit(0)
26 sys.exit(0)
27
27
28
28 if __name__ == '__main__':
29 if __name__ == '__main__':
29 main()
30 main()
@@ -49,6 +49,8 b' def _crrepohook(*args, **kwargs):'
49 :param created_by:
49 :param created_by:
50 """
50 """
51 return 0
51 return 0
52
53
52 CREATE_REPO_HOOK = _crrepohook
54 CREATE_REPO_HOOK = _crrepohook
53
55
54
56
@@ -73,6 +75,8 b' def _pre_cruserhook(*args, **kwargs):'
73 """
75 """
74 reason = 'allowed'
76 reason = 'allowed'
75 return True, reason
77 return True, reason
78
79
76 PRE_CREATE_USER_HOOK = _pre_cruserhook
80 PRE_CREATE_USER_HOOK = _pre_cruserhook
77
81
78 #==============================================================================
82 #==============================================================================
@@ -105,6 +109,8 b' def _cruserhook(*args, **kwargs):'
105 :param created_by:
109 :param created_by:
106 """
110 """
107 return 0
111 return 0
112
113
108 CREATE_USER_HOOK = _cruserhook
114 CREATE_USER_HOOK = _cruserhook
109
115
110
116
@@ -132,6 +138,8 b' def _dlrepohook(*args, **kwargs):'
132 :param deleted_on:
138 :param deleted_on:
133 """
139 """
134 return 0
140 return 0
141
142
135 DELETE_REPO_HOOK = _dlrepohook
143 DELETE_REPO_HOOK = _dlrepohook
136
144
137
145
@@ -165,6 +173,8 b' def _dluserhook(*args, **kwargs):'
165 :param deleted_by:
173 :param deleted_by:
166 """
174 """
167 return 0
175 return 0
176
177
168 DELETE_USER_HOOK = _dluserhook
178 DELETE_USER_HOOK = _dluserhook
169
179
170
180
@@ -189,6 +199,8 b' def _pushhook(*args, **kwargs):'
189 :param pushed_revs: list of pushed revisions
199 :param pushed_revs: list of pushed revisions
190 """
200 """
191 return 0
201 return 0
202
203
192 PUSH_HOOK = _pushhook
204 PUSH_HOOK = _pushhook
193
205
194
206
@@ -212,4 +224,6 b' def _pullhook(*args, **kwargs):'
212 :param repository: repository name
224 :param repository: repository name
213 """
225 """
214 return 0
226 return 0
227
228
215 PULL_HOOK = _pullhook
229 PULL_HOOK = _pullhook
@@ -94,7 +94,7 b' def make_map(config):'
94 # CUSTOM ROUTES HERE
94 # CUSTOM ROUTES HERE
95 #==========================================================================
95 #==========================================================================
96
96
97 #MAIN PAGE
97 # MAIN PAGE
98 rmap.connect('home', '/', controller='home', action='index')
98 rmap.connect('home', '/', controller='home', action='index')
99 rmap.connect('about', '/about', controller='home', action='about')
99 rmap.connect('about', '/about', controller='home', action='about')
100 rmap.connect('repo_switcher_data', '/_repos', controller='home',
100 rmap.connect('repo_switcher_data', '/_repos', controller='home',
@@ -106,7 +106,7 b' def make_map(config):'
106 rmap.connect('kallithea_project_url', "https://kallithea-scm.org/", _static=True)
106 rmap.connect('kallithea_project_url', "https://kallithea-scm.org/", _static=True)
107 rmap.connect('issues_url', 'https://bitbucket.org/conservancy/kallithea/issues', _static=True)
107 rmap.connect('issues_url', 'https://bitbucket.org/conservancy/kallithea/issues', _static=True)
108
108
109 #ADMIN REPOSITORY ROUTES
109 # ADMIN REPOSITORY ROUTES
110 with rmap.submapper(path_prefix=ADMIN_PREFIX,
110 with rmap.submapper(path_prefix=ADMIN_PREFIX,
111 controller='admin/repos') as m:
111 controller='admin/repos') as m:
112 m.connect("repos", "/repos",
112 m.connect("repos", "/repos",
@@ -121,7 +121,7 b' def make_map(config):'
121 m.connect("delete_repo", "/repos/{repo_name:.*?}/delete",
121 m.connect("delete_repo", "/repos/{repo_name:.*?}/delete",
122 action="delete", conditions=dict(method=["POST"]))
122 action="delete", conditions=dict(method=["POST"]))
123
123
124 #ADMIN REPOSITORY GROUPS ROUTES
124 # ADMIN REPOSITORY GROUPS ROUTES
125 with rmap.submapper(path_prefix=ADMIN_PREFIX,
125 with rmap.submapper(path_prefix=ADMIN_PREFIX,
126 controller='admin/repo_groups') as m:
126 controller='admin/repo_groups') as m:
127 m.connect("repos_groups", "/repo_groups",
127 m.connect("repos_groups", "/repo_groups",
@@ -138,7 +138,7 b' def make_map(config):'
138 action="show", conditions=dict(method=["GET"],
138 action="show", conditions=dict(method=["GET"],
139 function=check_group))
139 function=check_group))
140
140
141 #EXTRAS REPO GROUP ROUTES
141 # EXTRAS REPO GROUP ROUTES
142 m.connect("edit_repo_group", "/repo_groups/{group_name:.*?}/edit",
142 m.connect("edit_repo_group", "/repo_groups/{group_name:.*?}/edit",
143 action="edit",
143 action="edit",
144 conditions=dict(method=["GET"], function=check_group))
144 conditions=dict(method=["GET"], function=check_group))
@@ -161,8 +161,7 b' def make_map(config):'
161 action="delete", conditions=dict(method=["POST"],
161 action="delete", conditions=dict(method=["POST"],
162 function=check_group_skip_path))
162 function=check_group_skip_path))
163
163
164
164 # ADMIN USER ROUTES
165 #ADMIN USER ROUTES
166 with rmap.submapper(path_prefix=ADMIN_PREFIX,
165 with rmap.submapper(path_prefix=ADMIN_PREFIX,
167 controller='admin/users') as m:
166 controller='admin/users') as m:
168 m.connect("new_user", "/users/new",
167 m.connect("new_user", "/users/new",
@@ -180,7 +179,7 b' def make_map(config):'
180 m.connect("edit_user", "/users/{id}/edit",
179 m.connect("edit_user", "/users/{id}/edit",
181 action="edit", conditions=dict(method=["GET"]))
180 action="edit", conditions=dict(method=["GET"]))
182
181
183 #EXTRAS USER ROUTES
182 # EXTRAS USER ROUTES
184 m.connect("edit_user_advanced", "/users/{id}/edit/advanced",
183 m.connect("edit_user_advanced", "/users/{id}/edit/advanced",
185 action="edit_advanced", conditions=dict(method=["GET"]))
184 action="edit_advanced", conditions=dict(method=["GET"]))
186
185
@@ -210,7 +209,7 b' def make_map(config):'
210 m.connect("edit_user_ips_delete", "/users/{id}/edit/ips/delete",
209 m.connect("edit_user_ips_delete", "/users/{id}/edit/ips/delete",
211 action="delete_ip", conditions=dict(method=["POST"]))
210 action="delete_ip", conditions=dict(method=["POST"]))
212
211
213 #ADMIN USER GROUPS REST ROUTES
212 # ADMIN USER GROUPS REST ROUTES
214 with rmap.submapper(path_prefix=ADMIN_PREFIX,
213 with rmap.submapper(path_prefix=ADMIN_PREFIX,
215 controller='admin/user_groups') as m:
214 controller='admin/user_groups') as m:
216 m.connect("users_groups", "/user_groups",
215 m.connect("users_groups", "/user_groups",
@@ -227,13 +226,12 b' def make_map(config):'
227 action="edit", conditions=dict(method=["GET"]),
226 action="edit", conditions=dict(method=["GET"]),
228 function=check_user_group)
227 function=check_user_group)
229
228
230 #EXTRAS USER GROUP ROUTES
229 # EXTRAS USER GROUP ROUTES
231 m.connect("edit_user_group_default_perms", "/user_groups/{id}/edit/default_perms",
230 m.connect("edit_user_group_default_perms", "/user_groups/{id}/edit/default_perms",
232 action="edit_default_perms", conditions=dict(method=["GET"]))
231 action="edit_default_perms", conditions=dict(method=["GET"]))
233 m.connect("edit_user_group_default_perms_update", "/user_groups/{id}/edit/default_perms",
232 m.connect("edit_user_group_default_perms_update", "/user_groups/{id}/edit/default_perms",
234 action="update_default_perms", conditions=dict(method=["POST"]))
233 action="update_default_perms", conditions=dict(method=["POST"]))
235
234
236
237 m.connect("edit_user_group_perms", "/user_groups/{id}/edit/perms",
235 m.connect("edit_user_group_perms", "/user_groups/{id}/edit/perms",
238 action="edit_perms", conditions=dict(method=["GET"]))
236 action="edit_perms", conditions=dict(method=["GET"]))
239 m.connect("edit_user_group_perms_update", "/user_groups/{id}/edit/perms",
237 m.connect("edit_user_group_perms_update", "/user_groups/{id}/edit/perms",
@@ -247,9 +245,7 b' def make_map(config):'
247 m.connect("edit_user_group_members", "/user_groups/{id}/edit/members",
245 m.connect("edit_user_group_members", "/user_groups/{id}/edit/members",
248 action="edit_members", conditions=dict(method=["GET"]))
246 action="edit_members", conditions=dict(method=["GET"]))
249
247
250
248 # ADMIN PERMISSIONS ROUTES
251
252 #ADMIN PERMISSIONS ROUTES
253 with rmap.submapper(path_prefix=ADMIN_PREFIX,
249 with rmap.submapper(path_prefix=ADMIN_PREFIX,
254 controller='admin/permissions') as m:
250 controller='admin/permissions') as m:
255 m.connect("admin_permissions", "/permissions",
251 m.connect("admin_permissions", "/permissions",
@@ -263,8 +259,7 b' def make_map(config):'
263 m.connect("admin_permissions_perms", "/permissions/perms",
259 m.connect("admin_permissions_perms", "/permissions/perms",
264 action="permission_perms", conditions=dict(method=["GET"]))
260 action="permission_perms", conditions=dict(method=["GET"]))
265
261
266
262 # ADMIN DEFAULTS ROUTES
267 #ADMIN DEFAULTS ROUTES
268 with rmap.submapper(path_prefix=ADMIN_PREFIX,
263 with rmap.submapper(path_prefix=ADMIN_PREFIX,
269 controller='admin/defaults') as m:
264 controller='admin/defaults') as m:
270 m.connect('defaults', 'defaults',
265 m.connect('defaults', 'defaults',
@@ -272,14 +267,14 b' def make_map(config):'
272 m.connect('defaults_update', 'defaults/{id}/update',
267 m.connect('defaults_update', 'defaults/{id}/update',
273 action="update", conditions=dict(method=["POST"]))
268 action="update", conditions=dict(method=["POST"]))
274
269
275 #ADMIN AUTH SETTINGS
270 # ADMIN AUTH SETTINGS
276 rmap.connect('auth_settings', '%s/auth' % ADMIN_PREFIX,
271 rmap.connect('auth_settings', '%s/auth' % ADMIN_PREFIX,
277 controller='admin/auth_settings', action='auth_settings',
272 controller='admin/auth_settings', action='auth_settings',
278 conditions=dict(method=["POST"]))
273 conditions=dict(method=["POST"]))
279 rmap.connect('auth_home', '%s/auth' % ADMIN_PREFIX,
274 rmap.connect('auth_home', '%s/auth' % ADMIN_PREFIX,
280 controller='admin/auth_settings')
275 controller='admin/auth_settings')
281
276
282 #ADMIN SETTINGS ROUTES
277 # ADMIN SETTINGS ROUTES
283 with rmap.submapper(path_prefix=ADMIN_PREFIX,
278 with rmap.submapper(path_prefix=ADMIN_PREFIX,
284 controller='admin/settings') as m:
279 controller='admin/settings') as m:
285 m.connect("admin_settings", "/settings",
280 m.connect("admin_settings", "/settings",
@@ -326,7 +321,7 b' def make_map(config):'
326 m.connect("admin_settings_system_update", "/settings/system/updates",
321 m.connect("admin_settings_system_update", "/settings/system/updates",
327 action="settings_system_update", conditions=dict(method=["GET"]))
322 action="settings_system_update", conditions=dict(method=["GET"]))
328
323
329 #ADMIN MY ACCOUNT
324 # ADMIN MY ACCOUNT
330 with rmap.submapper(path_prefix=ADMIN_PREFIX,
325 with rmap.submapper(path_prefix=ADMIN_PREFIX,
331 controller='admin/my_account') as m:
326 controller='admin/my_account') as m:
332
327
@@ -363,7 +358,7 b' def make_map(config):'
363 m.connect("my_account_api_keys_delete", "/my_account/api_keys/delete",
358 m.connect("my_account_api_keys_delete", "/my_account/api_keys/delete",
364 action="my_account_api_keys_delete", conditions=dict(method=["POST"]))
359 action="my_account_api_keys_delete", conditions=dict(method=["POST"]))
365
360
366 #NOTIFICATION REST ROUTES
361 # NOTIFICATION REST ROUTES
367 with rmap.submapper(path_prefix=ADMIN_PREFIX,
362 with rmap.submapper(path_prefix=ADMIN_PREFIX,
368 controller='admin/notifications') as m:
363 controller='admin/notifications') as m:
369 m.connect("notifications", "/notifications",
364 m.connect("notifications", "/notifications",
@@ -381,7 +376,7 b' def make_map(config):'
381 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
376 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
382 action="show", conditions=dict(method=["GET"]))
377 action="show", conditions=dict(method=["GET"]))
383
378
384 #ADMIN GIST
379 # ADMIN GIST
385 with rmap.submapper(path_prefix=ADMIN_PREFIX,
380 with rmap.submapper(path_prefix=ADMIN_PREFIX,
386 controller='admin/gists') as m:
381 controller='admin/gists') as m:
387 m.connect("gists", "/gists",
382 m.connect("gists", "/gists",
@@ -391,7 +386,6 b' def make_map(config):'
391 m.connect("new_gist", "/gists/new",
386 m.connect("new_gist", "/gists/new",
392 action="new", conditions=dict(method=["GET"]))
387 action="new", conditions=dict(method=["GET"]))
393
388
394
395 m.connect("gist_delete", "/gists/{gist_id}/delete",
389 m.connect("gist_delete", "/gists/{gist_id}/delete",
396 action="delete", conditions=dict(method=["POST"]))
390 action="delete", conditions=dict(method=["POST"]))
397 m.connect("edit_gist", "/gists/{gist_id}/edit",
391 m.connect("edit_gist", "/gists/{gist_id}/edit",
@@ -399,7 +393,6 b' def make_map(config):'
399 m.connect("edit_gist_check_revision", "/gists/{gist_id}/edit/check_revision",
393 m.connect("edit_gist_check_revision", "/gists/{gist_id}/edit/check_revision",
400 action="check_revision", conditions=dict(method=["POST"]))
394 action="check_revision", conditions=dict(method=["POST"]))
401
395
402
403 m.connect("gist", "/gists/{gist_id}",
396 m.connect("gist", "/gists/{gist_id}",
404 action="show", conditions=dict(method=["GET"]))
397 action="show", conditions=dict(method=["GET"]))
405 m.connect("gist_rev", "/gists/{gist_id}/{revision}",
398 m.connect("gist_rev", "/gists/{gist_id}/{revision}",
@@ -412,7 +405,7 b' def make_map(config):'
412 revision='tip',
405 revision='tip',
413 action="show", conditions=dict(method=["GET"]))
406 action="show", conditions=dict(method=["GET"]))
414
407
415 #ADMIN MAIN PAGES
408 # ADMIN MAIN PAGES
416 with rmap.submapper(path_prefix=ADMIN_PREFIX,
409 with rmap.submapper(path_prefix=ADMIN_PREFIX,
417 controller='admin/admin') as m:
410 controller='admin/admin') as m:
418 m.connect('admin_home', '', action='index')
411 m.connect('admin_home', '', action='index')
@@ -425,7 +418,7 b' def make_map(config):'
425 action='_dispatch') as m:
418 action='_dispatch') as m:
426 m.connect('api', '/api')
419 m.connect('api', '/api')
427
420
428 #USER JOURNAL
421 # USER JOURNAL
429 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
422 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
430 controller='journal', action='index')
423 controller='journal', action='index')
431 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
424 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
@@ -454,7 +447,7 b' def make_map(config):'
454 controller='journal', action='toggle_following',
447 controller='journal', action='toggle_following',
455 conditions=dict(method=["POST"]))
448 conditions=dict(method=["POST"]))
456
449
457 #SEARCH
450 # SEARCH
458 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
451 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
459 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
452 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
460 controller='search',
453 controller='search',
@@ -464,7 +457,7 b' def make_map(config):'
464 conditions=dict(function=check_repo),
457 conditions=dict(function=check_repo),
465 )
458 )
466
459
467 #LOGIN/LOGOUT/REGISTER/SIGN IN
460 # LOGIN/LOGOUT/REGISTER/SIGN IN
468 rmap.connect('authentication_token', '%s/authentication_token' % ADMIN_PREFIX, controller='login', action='authentication_token')
461 rmap.connect('authentication_token', '%s/authentication_token' % ADMIN_PREFIX, controller='login', action='authentication_token')
469 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
462 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
470 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
463 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
@@ -480,7 +473,7 b' def make_map(config):'
480 '%s/password_reset_confirmation' % ADMIN_PREFIX,
473 '%s/password_reset_confirmation' % ADMIN_PREFIX,
481 controller='login', action='password_reset_confirmation')
474 controller='login', action='password_reset_confirmation')
482
475
483 #FEEDS
476 # FEEDS
484 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
477 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
485 controller='feed', action='rss',
478 controller='feed', action='rss',
486 conditions=dict(function=check_repo))
479 conditions=dict(function=check_repo))
@@ -551,7 +544,6 b' def make_map(config):'
551 controller='admin/repos', action="delete_repo_field",
544 controller='admin/repos', action="delete_repo_field",
552 conditions=dict(method=["POST"], function=check_repo))
545 conditions=dict(method=["POST"], function=check_repo))
553
546
554
555 rmap.connect("edit_repo_advanced", "/{repo_name:.*?}/settings/advanced",
547 rmap.connect("edit_repo_advanced", "/{repo_name:.*?}/settings/advanced",
556 controller='admin/repos', action="edit_advanced",
548 controller='admin/repos', action="edit_advanced",
557 conditions=dict(method=["GET"], function=check_repo))
549 conditions=dict(method=["GET"], function=check_repo))
@@ -571,7 +563,6 b' def make_map(config):'
571 controller='admin/repos', action="edit_advanced_fork",
563 controller='admin/repos', action="edit_advanced_fork",
572 conditions=dict(method=["POST"], function=check_repo))
564 conditions=dict(method=["POST"], function=check_repo))
573
565
574
575 rmap.connect("edit_repo_caches", "/{repo_name:.*?}/settings/caches",
566 rmap.connect("edit_repo_caches", "/{repo_name:.*?}/settings/caches",
576 controller='admin/repos', action="edit_caches",
567 controller='admin/repos', action="edit_caches",
577 conditions=dict(method=["GET"], function=check_repo))
568 conditions=dict(method=["GET"], function=check_repo))
@@ -579,7 +570,6 b' def make_map(config):'
579 controller='admin/repos', action="edit_caches",
570 controller='admin/repos', action="edit_caches",
580 conditions=dict(method=["POST"], function=check_repo))
571 conditions=dict(method=["POST"], function=check_repo))
581
572
582
583 rmap.connect("edit_repo_remote", "/{repo_name:.*?}/settings/remote",
573 rmap.connect("edit_repo_remote", "/{repo_name:.*?}/settings/remote",
584 controller='admin/repos', action="edit_remote",
574 controller='admin/repos', action="edit_remote",
585 conditions=dict(method=["GET"], function=check_repo))
575 conditions=dict(method=["GET"], function=check_repo))
@@ -594,7 +584,7 b' def make_map(config):'
594 controller='admin/repos', action="edit_statistics",
584 controller='admin/repos', action="edit_statistics",
595 conditions=dict(method=["POST"], function=check_repo))
585 conditions=dict(method=["POST"], function=check_repo))
596
586
597 #still working url for backward compat.
587 # still working url for backward compat.
598 rmap.connect('raw_changeset_home_depraced',
588 rmap.connect('raw_changeset_home_depraced',
599 '/{repo_name:.*?}/raw-changeset/{revision}',
589 '/{repo_name:.*?}/raw-changeset/{revision}',
600 controller='changeset', action='changeset_raw',
590 controller='changeset', action='changeset_raw',
@@ -812,7 +802,9 b' class UrlGenerator(object):'
812 """
802 """
813 def __call__(self, *args, **kwargs):
803 def __call__(self, *args, **kwargs):
814 return request.environ['routes.url'](*args, **kwargs)
804 return request.environ['routes.url'](*args, **kwargs)
805
815 def current(self, *args, **kwargs):
806 def current(self, *args, **kwargs):
816 return request.environ['routes.url'].current(*args, **kwargs)
807 return request.environ['routes.url'].current(*args, **kwargs)
817
808
809
818 url = UrlGenerator()
810 url = UrlGenerator()
@@ -65,11 +65,11 b' def _journal_filter(user_log, search_ter'
65
65
66 def wildcard_handler(col, wc_term):
66 def wildcard_handler(col, wc_term):
67 if wc_term.startswith('*') and not wc_term.endswith('*'):
67 if wc_term.startswith('*') and not wc_term.endswith('*'):
68 #postfix == endswith
68 # postfix == endswith
69 wc_term = remove_prefix(wc_term, prefix='*')
69 wc_term = remove_prefix(wc_term, prefix='*')
70 return func.lower(col).endswith(func.lower(wc_term))
70 return func.lower(col).endswith(func.lower(wc_term))
71 elif wc_term.startswith('*') and wc_term.endswith('*'):
71 elif wc_term.startswith('*') and wc_term.endswith('*'):
72 #wildcard == ilike
72 # wildcard == ilike
73 wc_term = remove_prefix(wc_term, prefix='*')
73 wc_term = remove_prefix(wc_term, prefix='*')
74 wc_term = remove_suffix(wc_term, suffix='*')
74 wc_term = remove_suffix(wc_term, suffix='*')
75 return func.lower(col).contains(func.lower(wc_term))
75 return func.lower(col).contains(func.lower(wc_term))
@@ -88,7 +88,7 b' def _journal_filter(user_log, search_ter'
88 field = getattr(UserLog, field)
88 field = getattr(UserLog, field)
89 log.debug('filter field: %s val=>%s', field, val)
89 log.debug('filter field: %s val=>%s', field, val)
90
90
91 #sql filtering
91 # sql filtering
92 if isinstance(term, query.Wildcard):
92 if isinstance(term, query.Wildcard):
93 return wildcard_handler(field, val)
93 return wildcard_handler(field, val)
94 elif isinstance(term, query.Prefix):
94 elif isinstance(term, query.Prefix):
@@ -130,7 +130,7 b' class AdminController(BaseController):'
130 .options(joinedload(UserLog.user)) \
130 .options(joinedload(UserLog.user)) \
131 .options(joinedload(UserLog.repository))
131 .options(joinedload(UserLog.repository))
132
132
133 #FILTERING
133 # FILTERING
134 c.search_term = request.GET.get('filter')
134 c.search_term = request.GET.get('filter')
135 users_log = _journal_filter(users_log, c.search_term)
135 users_log = _journal_filter(users_log, c.search_term)
136
136
@@ -106,7 +106,7 b' class GistsController(BaseController):'
106 gist_form = GistForm([x[0] for x in c.lifetime_values])()
106 gist_form = GistForm([x[0] for x in c.lifetime_values])()
107 try:
107 try:
108 form_result = gist_form.to_python(dict(request.POST))
108 form_result = gist_form.to_python(dict(request.POST))
109 #TODO: multiple files support, from the form
109 # TODO: multiple files support, from the form
110 filename = form_result['filename'] or Gist.DEFAULT_FILENAME
110 filename = form_result['filename'] or Gist.DEFAULT_FILENAME
111 nodes = {
111 nodes = {
112 filename: {
112 filename: {
@@ -250,7 +250,7 b' class GistsController(BaseController):'
250 success = True
250 success = True
251 revision = request.POST.get('revision')
251 revision = request.POST.get('revision')
252
252
253 ##TODO: maybe move this to model ?
253 # TODO: maybe move this to model ?
254 if revision != last_rev.raw_id:
254 if revision != last_rev.raw_id:
255 log.error('Last revision %s is different than submitted %s',
255 log.error('Last revision %s is different than submitted %s',
256 revision, last_rev)
256 revision, last_rev)
@@ -131,7 +131,7 b' class MyAccountController(BaseController'
131 force_defaults=False)
131 force_defaults=False)
132 except Exception:
132 except Exception:
133 log.error(traceback.format_exc())
133 log.error(traceback.format_exc())
134 h.flash(_('Error occurred during update of user %s') \
134 h.flash(_('Error occurred during update of user %s')
135 % form_result.get('username'), category='error')
135 % form_result.get('username'), category='error')
136 if update:
136 if update:
137 raise HTTPFound(location='my_account')
137 raise HTTPFound(location='my_account')
@@ -173,7 +173,7 b' class MyAccountController(BaseController'
173 c.active = 'repos'
173 c.active = 'repos'
174 self.__load_data()
174 self.__load_data()
175
175
176 #data used to render the grid
176 # data used to render the grid
177 c.data = self._load_my_repos_data()
177 c.data = self._load_my_repos_data()
178 return render('admin/my_account/my_account.html')
178 return render('admin/my_account/my_account.html')
179
179
@@ -181,7 +181,7 b' class MyAccountController(BaseController'
181 c.active = 'watched'
181 c.active = 'watched'
182 self.__load_data()
182 self.__load_data()
183
183
184 #data used to render the grid
184 # data used to render the grid
185 c.data = self._load_my_repos_data(watched=True)
185 c.data = self._load_my_repos_data(watched=True)
186 return render('admin/my_account/my_account.html')
186 return render('admin/my_account/my_account.html')
187
187
@@ -166,7 +166,7 b' class RepoGroupsController(BaseControlle'
166 copy_permissions=form_result['group_copy_permissions']
166 copy_permissions=form_result['group_copy_permissions']
167 )
167 )
168 Session().commit()
168 Session().commit()
169 #TODO: in future action_logger(, '', '', '')
169 # TODO: in future action_logger(, '', '', '')
170 except formencode.Invalid as errors:
170 except formencode.Invalid as errors:
171 return htmlfill.render(
171 return htmlfill.render(
172 render('admin/repo_groups/repo_group_add.html'),
172 render('admin/repo_groups/repo_group_add.html'),
@@ -177,10 +177,10 b' class RepoGroupsController(BaseControlle'
177 force_defaults=False)
177 force_defaults=False)
178 except Exception:
178 except Exception:
179 log.error(traceback.format_exc())
179 log.error(traceback.format_exc())
180 h.flash(_('Error occurred during creation of repository group %s') \
180 h.flash(_('Error occurred during creation of repository group %s')
181 % request.POST.get('group_name'), category='error')
181 % request.POST.get('group_name'), category='error')
182 parent_group_id = form_result['parent_group_id']
182 parent_group_id = form_result['parent_group_id']
183 #TODO: maybe we should get back to the main view, not the admin one
183 # TODO: maybe we should get back to the main view, not the admin one
184 raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id))
184 raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id))
185 h.flash(_('Created repository group %s') % gr.group_name,
185 h.flash(_('Created repository group %s') % gr.group_name,
186 category='success')
186 category='success')
@@ -188,7 +188,7 b' class RepoGroupsController(BaseControlle'
188
188
189 def new(self):
189 def new(self):
190 if HasPermissionAny('hg.admin')('group create'):
190 if HasPermissionAny('hg.admin')('group create'):
191 #we're global admin, we're ok and we can create TOP level groups
191 # we're global admin, we're ok and we can create TOP level groups
192 pass
192 pass
193 else:
193 else:
194 # we pass in parent group into creation form, thus we know
194 # we pass in parent group into creation form, thus we know
@@ -212,7 +212,7 b' class RepoGroupsController(BaseControlle'
212
212
213 # TODO: kill allow_empty_group - it is only used for redundant form validation!
213 # TODO: kill allow_empty_group - it is only used for redundant form validation!
214 if HasPermissionAny('hg.admin')('group edit'):
214 if HasPermissionAny('hg.admin')('group edit'):
215 #we're global admin, we're ok and we can create TOP level groups
215 # we're global admin, we're ok and we can create TOP level groups
216 allow_empty_group = True
216 allow_empty_group = True
217 elif not c.repo_group.parent_group:
217 elif not c.repo_group.parent_group:
218 allow_empty_group = True
218 allow_empty_group = True
@@ -229,11 +229,11 b' class RepoGroupsController(BaseControlle'
229
229
230 new_gr = RepoGroupModel().update(group_name, form_result)
230 new_gr = RepoGroupModel().update(group_name, form_result)
231 Session().commit()
231 Session().commit()
232 h.flash(_('Updated repository group %s') \
232 h.flash(_('Updated repository group %s')
233 % form_result['group_name'], category='success')
233 % form_result['group_name'], category='success')
234 # we now have new name !
234 # we now have new name !
235 group_name = new_gr.group_name
235 group_name = new_gr.group_name
236 #TODO: in future action_logger(, '', '', '')
236 # TODO: in future action_logger(, '', '', '')
237 except formencode.Invalid as errors:
237 except formencode.Invalid as errors:
238 c.active = 'settings'
238 c.active = 'settings'
239 return htmlfill.render(
239 return htmlfill.render(
@@ -245,7 +245,7 b' class RepoGroupsController(BaseControlle'
245 force_defaults=False)
245 force_defaults=False)
246 except Exception:
246 except Exception:
247 log.error(traceback.format_exc())
247 log.error(traceback.format_exc())
248 h.flash(_('Error occurred during update of repository group %s') \
248 h.flash(_('Error occurred during update of repository group %s')
249 % request.POST.get('group_name'), category='error')
249 % request.POST.get('group_name'), category='error')
250
250
251 raise HTTPFound(location=url('edit_repo_group', group_name=group_name))
251 raise HTTPFound(location=url('edit_repo_group', group_name=group_name))
@@ -270,7 +270,7 b' class RepoGroupsController(BaseControlle'
270 Session().commit()
270 Session().commit()
271 h.flash(_('Removed repository group %s') % group_name,
271 h.flash(_('Removed repository group %s') % group_name,
272 category='success')
272 category='success')
273 #TODO: in future action_logger(, '', '', '')
273 # TODO: in future action_logger(, '', '', '')
274 except Exception:
274 except Exception:
275 log.error(traceback.format_exc())
275 log.error(traceback.format_exc())
276 h.flash(_('Error occurred during deletion of repository group %s')
276 h.flash(_('Error occurred during deletion of repository group %s')
@@ -369,7 +369,7 b' class RepoGroupsController(BaseControlle'
369 form_result['perms_new'],
369 form_result['perms_new'],
370 form_result['perms_updates'],
370 form_result['perms_updates'],
371 recursive)
371 recursive)
372 #TODO: implement this
372 # TODO: implement this
373 #action_logger(request.authuser, 'admin_changed_repo_permissions',
373 #action_logger(request.authuser, 'admin_changed_repo_permissions',
374 # repo_name, request.ip_addr)
374 # repo_name, request.ip_addr)
375 Session().commit()
375 Session().commit()
@@ -104,7 +104,7 b' class ReposController(BaseRepoController'
104 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
104 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
105 admin=True,
105 admin=True,
106 super_user_actions=True)
106 super_user_actions=True)
107 #data used to render the grid
107 # data used to render the grid
108 c.data = repos_data
108 c.data = repos_data
109
109
110 return render('admin/repos/repos.html')
110 return render('admin/repos/repos.html')
@@ -257,7 +257,7 b' class ReposController(BaseRepoController'
257
257
258 except Exception:
258 except Exception:
259 log.error(traceback.format_exc())
259 log.error(traceback.format_exc())
260 h.flash(_('Error occurred during update of repository %s') \
260 h.flash(_('Error occurred during update of repository %s')
261 % repo_name, category='error')
261 % repo_name, category='error')
262 raise HTTPFound(location=url('edit_repo', repo_name=changed_name))
262 raise HTTPFound(location=url('edit_repo', repo_name=changed_name))
263
263
@@ -331,7 +331,7 b' class ReposController(BaseRepoController'
331 form = RepoPermsForm()().to_python(request.POST)
331 form = RepoPermsForm()().to_python(request.POST)
332 RepoModel()._update_permissions(repo_name, form['perms_new'],
332 RepoModel()._update_permissions(repo_name, form['perms_new'],
333 form['perms_updates'])
333 form['perms_updates'])
334 #TODO: implement this
334 # TODO: implement this
335 #action_logger(request.authuser, 'admin_changed_repo_permissions',
335 #action_logger(request.authuser, 'admin_changed_repo_permissions',
336 # repo_name, request.ip_addr)
336 # repo_name, request.ip_addr)
337 Session().commit()
337 Session().commit()
@@ -353,7 +353,7 b' class ReposController(BaseRepoController'
353 RepoModel().revoke_user_group_permission(
353 RepoModel().revoke_user_group_permission(
354 repo=repo_name, group_name=obj_id
354 repo=repo_name, group_name=obj_id
355 )
355 )
356 #TODO: implement this
356 # TODO: implement this
357 #action_logger(request.authuser, 'admin_revoked_repo_permissions',
357 #action_logger(request.authuser, 'admin_revoked_repo_permissions',
358 # repo_name, request.ip_addr)
358 # repo_name, request.ip_addr)
359 Session().commit()
359 Session().commit()
@@ -456,7 +456,6 b' class ReposController(BaseRepoController'
456 category='error')
456 category='error')
457 raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
457 raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
458
458
459
460 @HasRepoPermissionLevelDecorator('admin')
459 @HasRepoPermissionLevelDecorator('admin')
461 def edit_advanced_fork(self, repo_name):
460 def edit_advanced_fork(self, repo_name):
462 """
461 """
@@ -102,7 +102,7 b' class SettingsController(BaseController)'
102 sett = Ui.get_by_key('paths', '/')
102 sett = Ui.get_by_key('paths', '/')
103 sett.ui_value = form_result['paths_root_path']
103 sett.ui_value = form_result['paths_root_path']
104
104
105 #HOOKS
105 # HOOKS
106 sett = Ui.get_by_key('hooks', Ui.HOOK_UPDATE)
106 sett = Ui.get_by_key('hooks', Ui.HOOK_UPDATE)
107 sett.ui_active = form_result['hooks_changegroup_update']
107 sett.ui_active = form_result['hooks_changegroup_update']
108
108
@@ -160,7 +160,7 b' class SettingsController(BaseController)'
160 if request.POST:
160 if request.POST:
161 rm_obsolete = request.POST.get('destroy', False)
161 rm_obsolete = request.POST.get('destroy', False)
162 install_git_hooks = request.POST.get('hooks', False)
162 install_git_hooks = request.POST.get('hooks', False)
163 overwrite_git_hooks = request.POST.get('hooks_overwrite', False);
163 overwrite_git_hooks = request.POST.get('hooks_overwrite', False)
164 invalidate_cache = request.POST.get('invalidate', False)
164 invalidate_cache = request.POST.get('invalidate', False)
165 log.debug('rescanning repo location with destroy obsolete=%s, '
165 log.debug('rescanning repo location with destroy obsolete=%s, '
166 'install git hooks=%s and '
166 'install git hooks=%s and '
@@ -155,7 +155,7 b' class UserGroupsController(BaseControlle'
155 force_defaults=False)
155 force_defaults=False)
156 except Exception:
156 except Exception:
157 log.error(traceback.format_exc())
157 log.error(traceback.format_exc())
158 h.flash(_('Error occurred during creation of user group %s') \
158 h.flash(_('Error occurred during creation of user group %s')
159 % request.POST.get('users_group_name'), category='error')
159 % request.POST.get('users_group_name'), category='error')
160
160
161 raise HTTPFound(location=url('users_groups'))
161 raise HTTPFound(location=url('users_groups'))
@@ -205,7 +205,7 b' class UserGroupsController(BaseControlle'
205 force_defaults=False)
205 force_defaults=False)
206 except Exception:
206 except Exception:
207 log.error(traceback.format_exc())
207 log.error(traceback.format_exc())
208 h.flash(_('Error occurred during update of user group %s') \
208 h.flash(_('Error occurred during update of user group %s')
209 % request.POST.get('users_group_name'), category='error')
209 % request.POST.get('users_group_name'), category='error')
210
210
211 raise HTTPFound(location=url('edit_users_group', id=id))
211 raise HTTPFound(location=url('edit_users_group', id=id))
@@ -283,7 +283,7 b' class UserGroupsController(BaseControlle'
283 except RepoGroupAssignmentError:
283 except RepoGroupAssignmentError:
284 h.flash(_('Target group cannot be the same'), category='error')
284 h.flash(_('Target group cannot be the same'), category='error')
285 raise HTTPFound(location=url('edit_user_group_perms', id=id))
285 raise HTTPFound(location=url('edit_user_group_perms', id=id))
286 #TODO: implement this
286 # TODO: implement this
287 #action_logger(request.authuser, 'admin_changed_repo_permissions',
287 #action_logger(request.authuser, 'admin_changed_repo_permissions',
288 # repo_name, request.ip_addr)
288 # repo_name, request.ip_addr)
289 Session().commit()
289 Session().commit()
@@ -415,7 +415,6 b' class UserGroupsController(BaseControlle'
415 key=lambda u: u.username.lower())
415 key=lambda u: u.username.lower())
416 return render('admin/user_groups/user_group_edit.html')
416 return render('admin/user_groups/user_group_edit.html')
417
417
418
419 @HasUserGroupPermissionLevelDecorator('admin')
418 @HasUserGroupPermissionLevelDecorator('admin')
420 def edit_members(self, id):
419 def edit_members(self, id):
421 c.user_group = UserGroup.get_or_404(id)
420 c.user_group = UserGroup.get_or_404(id)
@@ -137,7 +137,7 b' class UsersController(BaseController):'
137 h.flash(e, 'error')
137 h.flash(e, 'error')
138 except Exception:
138 except Exception:
139 log.error(traceback.format_exc())
139 log.error(traceback.format_exc())
140 h.flash(_('Error occurred during creation of user %s') \
140 h.flash(_('Error occurred during creation of user %s')
141 % request.POST.get('username'), category='error')
141 % request.POST.get('username'), category='error')
142 raise HTTPFound(location=url('edit_user', id=user.user_id))
142 raise HTTPFound(location=url('edit_user', id=user.user_id))
143
143
@@ -180,7 +180,7 b' class UsersController(BaseController):'
180 force_defaults=False)
180 force_defaults=False)
181 except Exception:
181 except Exception:
182 log.error(traceback.format_exc())
182 log.error(traceback.format_exc())
183 h.flash(_('Error occurred during update of user %s') \
183 h.flash(_('Error occurred during update of user %s')
184 % form_result.get('username'), category='error')
184 % form_result.get('username'), category='error')
185 raise HTTPFound(location=url('edit_user', id=id))
185 raise HTTPFound(location=url('edit_user', id=id))
186
186
@@ -114,7 +114,7 b' class ChangelogController(BaseRepoContro'
114 try:
114 try:
115 collection = tip_cs.get_file_history(f_path)
115 collection = tip_cs.get_file_history(f_path)
116 except (NodeDoesNotExistError, ChangesetError):
116 except (NodeDoesNotExistError, ChangesetError):
117 #this node is not present at tip !
117 # this node is not present at tip !
118 try:
118 try:
119 cs = self.__get_cs(revision, repo_name)
119 cs = self.__get_cs(revision, repo_name)
120 collection = cs.get_file_history(f_path)
120 collection = cs.get_file_history(f_path)
@@ -115,7 +115,7 b' def get_line_ctx(fid, GET):'
115 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
115 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
116 else:
116 else:
117 _ln_ctx = filter(lambda k: k.startswith('C'), GET)
117 _ln_ctx = filter(lambda k: k.startswith('C'), GET)
118 ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global
118 ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global
119 if ln_ctx:
119 if ln_ctx:
120 ln_ctx = [ln_ctx]
120 ln_ctx = [ln_ctx]
121
121
@@ -207,7 +207,7 b' class ChangesetController(BaseRepoContro'
207 c.ignorews_url = _ignorews_url
207 c.ignorews_url = _ignorews_url
208 c.context_url = _context_url
208 c.context_url = _context_url
209 c.fulldiff = fulldiff = request.GET.get('fulldiff')
209 c.fulldiff = fulldiff = request.GET.get('fulldiff')
210 #get ranges of revisions if preset
210 # get ranges of revisions if preset
211 rev_range = revision.split('...')[:2]
211 rev_range = revision.split('...')[:2]
212 enable_comments = True
212 enable_comments = True
213 c.cs_repo = c.db_repo
213 c.cs_repo = c.db_repo
@@ -300,7 +300,7 b' class ChangesetController(BaseRepoContro'
300 file_diff_data.append(('', None, None, None, diff, None))
300 file_diff_data.append(('', None, None, None, diff, None))
301 c.changes[changeset.raw_id] = (cs1, cs2, file_diff_data)
301 c.changes[changeset.raw_id] = (cs1, cs2, file_diff_data)
302
302
303 #sort comments in creation order
303 # sort comments in creation order
304 c.comments = [com for com_id, com in sorted(comments.items())]
304 c.comments = [com for com_id, com in sorted(comments.items())]
305
305
306 # count inline comments
306 # count inline comments
@@ -94,7 +94,7 b' class CompareController(BaseRepoControll'
94 other_changesets = []
94 other_changesets = []
95
95
96 elif alias == 'hg':
96 elif alias == 'hg':
97 #case two independent repos
97 # case two independent repos
98 if org_repo != other_repo:
98 if org_repo != other_repo:
99 hgrepo = unionrepo.unionrepository(other_repo.baseui,
99 hgrepo = unionrepo.unionrepository(other_repo.baseui,
100 other_repo.path,
100 other_repo.path,
@@ -102,7 +102,7 b' class CompareController(BaseRepoControll'
102 # all ancestors of other_rev will be in other_repo and
102 # all ancestors of other_rev will be in other_repo and
103 # rev numbers from hgrepo can be used in other_repo - org_rev ancestors cannot
103 # rev numbers from hgrepo can be used in other_repo - org_rev ancestors cannot
104
104
105 #no remote compare do it on the same repository
105 # no remote compare do it on the same repository
106 else:
106 else:
107 hgrepo = other_repo._repo
107 hgrepo = other_repo._repo
108
108
@@ -83,7 +83,7 b' class FeedController(BaseRepoController)'
83 def __get_desc(self, cs):
83 def __get_desc(self, cs):
84 desc_msg = [(_('%s committed on %s')
84 desc_msg = [(_('%s committed on %s')
85 % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>']
85 % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>']
86 #branches, tags, bookmarks
86 # branches, tags, bookmarks
87 if cs.branch:
87 if cs.branch:
88 desc_msg.append('branch: %s<br/>' % cs.branch)
88 desc_msg.append('branch: %s<br/>' % cs.branch)
89 for book in cs.bookmarks:
89 for book in cs.bookmarks:
@@ -166,7 +166,7 b' class FilesController(BaseRepoController'
166
166
167 if c.file.is_file():
167 if c.file.is_file():
168 c.load_full_history = False
168 c.load_full_history = False
169 #determine if we're on branch head
169 # determine if we're on branch head
170 _branches = c.db_repo_scm_instance.branches
170 _branches = c.db_repo_scm_instance.branches
171 c.on_branch_head = revision in _branches.keys() + _branches.values()
171 c.on_branch_head = revision in _branches.keys() + _branches.values()
172 _hist = []
172 _hist = []
@@ -460,7 +460,7 b' class FilesController(BaseRepoController'
460 h.flash(_('No filename'), category='warning')
460 h.flash(_('No filename'), category='warning')
461 raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
461 raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
462 revision='tip'))
462 revision='tip'))
463 #strip all crap out of file, just leave the basename
463 # strip all crap out of file, just leave the basename
464 filename = os.path.basename(filename)
464 filename = os.path.basename(filename)
465 node_path = posixpath.join(location, filename)
465 node_path = posixpath.join(location, filename)
466 author = request.authuser.full_contact
466 author = request.authuser.full_contact
@@ -599,8 +599,8 b' class FilesController(BaseRepoController'
599 c.changes = OrderedDict()
599 c.changes = OrderedDict()
600 c.changes[diff2] = []
600 c.changes[diff2] = []
601
601
602 #special case if we want a show rev only, it's impl here
602 # special case if we want a show rev only, it's impl here
603 #to reduce JS and callbacks
603 # to reduce JS and callbacks
604
604
605 if request.GET.get('show_rev'):
605 if request.GET.get('show_rev'):
606 if str2bool(request.GET.get('annotate', 'False')):
606 if str2bool(request.GET.get('annotate', 'False')):
@@ -748,7 +748,7 b' class FilesController(BaseRepoController'
748 try:
748 try:
749 changesets = tip_cs.get_file_history(f_path)
749 changesets = tip_cs.get_file_history(f_path)
750 except (NodeDoesNotExistError, ChangesetError):
750 except (NodeDoesNotExistError, ChangesetError):
751 #this node is not present at tip !
751 # this node is not present at tip !
752 changesets = cs.get_file_history(f_path)
752 changesets = cs.get_file_history(f_path)
753 hist_l = []
753 hist_l = []
754
754
@@ -57,7 +57,7 b' class HomeController(BaseController):'
57
57
58 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
58 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
59 admin=False, short_name=True)
59 admin=False, short_name=True)
60 #data used to render the grid
60 # data used to render the grid
61 c.data = repos_data
61 c.data = repos_data
62
62
63 return render('/index.html')
63 return render('/index.html')
@@ -65,7 +65,7 b' class HomeController(BaseController):'
65 @LoginRequired()
65 @LoginRequired()
66 @jsonify
66 @jsonify
67 def repo_switcher_data(self):
67 def repo_switcher_data(self):
68 #wrapper for conditional cache
68 # wrapper for conditional cache
69 def _c():
69 def _c():
70 log.debug('generating switcher repo/groups list')
70 log.debug('generating switcher repo/groups list')
71 all_repos = Repository.query(sorted=True).all()
71 all_repos = Repository.query(sorted=True).all()
@@ -69,7 +69,7 b' class JournalController(BaseController):'
69 groups = []
69 groups = []
70 for k, g in groupby(journal, lambda x: x.action_as_day):
70 for k, g in groupby(journal, lambda x: x.action_as_day):
71 user_group = []
71 user_group = []
72 #groupby username if it's a present value, else fallback to journal username
72 # groupby username if it's a present value, else fallback to journal username
73 for _unused, g2 in groupby(list(g), lambda x: x.user.username if x.user else x.username):
73 for _unused, g2 in groupby(list(g), lambda x: x.user.username if x.user else x.username):
74 l = list(g2)
74 l = list(g2)
75 user_group.append((l[0].user, l))
75 user_group.append((l[0].user, l))
@@ -97,7 +97,7 b' class JournalController(BaseController):'
97 journal = UserLog.query() \
97 journal = UserLog.query() \
98 .options(joinedload(UserLog.user)) \
98 .options(joinedload(UserLog.user)) \
99 .options(joinedload(UserLog.repository))
99 .options(joinedload(UserLog.repository))
100 #filter
100 # filter
101 journal = _journal_filter(journal, c.search_term)
101 journal = _journal_filter(journal, c.search_term)
102 journal = journal.filter(filtering_criterion) \
102 journal = journal.filter(filtering_criterion) \
103 .order_by(UserLog.action_date.desc())
103 .order_by(UserLog.action_date.desc())
@@ -125,7 +125,7 b' class JournalController(BaseController):'
125 for entry in journal[:feed_nr]:
125 for entry in journal[:feed_nr]:
126 user = entry.user
126 user = entry.user
127 if user is None:
127 if user is None:
128 #fix deleted users
128 # fix deleted users
129 user = AttributeDict({'short_contact': entry.username,
129 user = AttributeDict({'short_contact': entry.username,
130 'email': '',
130 'email': '',
131 'full_contact': ''})
131 'full_contact': ''})
@@ -167,7 +167,7 b' class JournalController(BaseController):'
167 for entry in journal[:feed_nr]:
167 for entry in journal[:feed_nr]:
168 user = entry.user
168 user = entry.user
169 if user is None:
169 if user is None:
170 #fix deleted users
170 # fix deleted users
171 user = AttributeDict({'short_contact': entry.username,
171 user = AttributeDict({'short_contact': entry.username,
172 'email': '',
172 'email': '',
173 'full_contact': ''})
173 'full_contact': ''})
@@ -217,7 +217,7 b' class JournalController(BaseController):'
217
217
218 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
218 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
219 admin=True)
219 admin=True)
220 #data used to render the grid
220 # data used to render the grid
221 c.data = repos_data
221 c.data = repos_data
222
222
223 return render('journal/journal.html')
223 return render('journal/journal.html')
@@ -391,7 +391,7 b' class PullrequestsController(BaseRepoCon'
391 if pull_request.is_closed():
391 if pull_request.is_closed():
392 raise HTTPForbidden()
392 raise HTTPForbidden()
393 assert pull_request.other_repo.repo_name == repo_name
393 assert pull_request.other_repo.repo_name == repo_name
394 #only owner or admin can update it
394 # only owner or admin can update it
395 owner = pull_request.owner_id == request.authuser.user_id
395 owner = pull_request.owner_id == request.authuser.user_id
396 repo_admin = h.HasRepoPermissionLevel('admin')(c.repo_name)
396 repo_admin = h.HasRepoPermissionLevel('admin')(c.repo_name)
397 if not (h.HasPermissionAny('hg.admin')() or repo_admin or owner):
397 if not (h.HasPermissionAny('hg.admin')() or repo_admin or owner):
@@ -446,7 +446,7 b' class PullrequestsController(BaseRepoCon'
446 @jsonify
446 @jsonify
447 def delete(self, repo_name, pull_request_id):
447 def delete(self, repo_name, pull_request_id):
448 pull_request = PullRequest.get_or_404(pull_request_id)
448 pull_request = PullRequest.get_or_404(pull_request_id)
449 #only owner can delete it !
449 # only owner can delete it !
450 if pull_request.owner_id == request.authuser.user_id:
450 if pull_request.owner_id == request.authuser.user_id:
451 PullRequestModel().delete(pull_request)
451 PullRequestModel().delete(pull_request)
452 Session().commit()
452 Session().commit()
@@ -596,7 +596,7 b' class PullrequestsController(BaseRepoCon'
596 ignore_whitespace=ignore_whitespace,
596 ignore_whitespace=ignore_whitespace,
597 context=line_context)
597 context=line_context)
598 except ChangesetDoesNotExistError:
598 except ChangesetDoesNotExistError:
599 txtdiff = _("The diff can't be shown - the PR revisions could not be found.")
599 txtdiff = _("The diff can't be shown - the PR revisions could not be found.")
600 diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
600 diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
601 diff_limit=diff_limit)
601 diff_limit=diff_limit)
602 _parsed = diff_processor.prepare()
602 _parsed = diff_processor.prepare()
@@ -734,7 +734,7 b' class PullrequestsController(BaseRepoCon'
734 def delete_comment(self, repo_name, comment_id):
734 def delete_comment(self, repo_name, comment_id):
735 co = ChangesetComment.get(comment_id)
735 co = ChangesetComment.get(comment_id)
736 if co.pull_request.is_closed():
736 if co.pull_request.is_closed():
737 #don't allow deleting comments on closed pull request
737 # don't allow deleting comments on closed pull request
738 raise HTTPForbidden()
738 raise HTTPForbidden()
739
739
740 owner = co.author_id == request.authuser.user_id
740 owner = co.author_id == request.authuser.user_id
@@ -17,6 +17,7 b' from kallithea.lib.base import BaseContr'
17 from kallithea.controllers.error import ErrorController
17 from kallithea.controllers.error import ErrorController
18 from tg import config
18 from tg import config
19
19
20
20 # This is the main Kallithea entry point; TurboGears will forward all requests
21 # This is the main Kallithea entry point; TurboGears will forward all requests
21 # to an instance of 'controller.root.RootController' in the configured
22 # to an instance of 'controller.root.RootController' in the configured
22 # 'application' module (set by app_cfg.py). Requests are forwarded to
23 # 'application' module (set by app_cfg.py). Requests are forwarded to
@@ -149,7 +149,7 b' class AnnotateHtmlFormatter(HtmlFormatte'
149 for i in range(fl, fl + lncount):
149 for i in range(fl, fl + lncount):
150 if i % st == 0:
150 if i % st == 0:
151 if aln:
151 if aln:
152 lines.append('<a href="#%s-%d">%*d</a>' \
152 lines.append('<a href="#%s-%d">%*d</a>'
153 % (la, i, mw, i))
153 % (la, i, mw, i))
154 else:
154 else:
155 lines.append('%*d' % (mw, i))
155 lines.append('%*d' % (mw, i))
@@ -158,7 +158,7 b' class AnnotateHtmlFormatter(HtmlFormatte'
158 ls = '\n'.join(lines)
158 ls = '\n'.join(lines)
159
159
160 # annotate_changesets = [tup[1] for tup in self.filenode.annotate]
160 # annotate_changesets = [tup[1] for tup in self.filenode.annotate]
161 ## TODO: not sure what that fixes
161 # # TODO: not sure what that fixes
162 # # If pygments cropped last lines break we need do that too
162 # # If pygments cropped last lines break we need do that too
163 # ln_cs = len(annotate_changesets)
163 # ln_cs = len(annotate_changesets)
164 # ln_ = len(ls.splitlines())
164 # ln_ = len(ls.splitlines())
@@ -104,7 +104,7 b' def get_crypt_password(password):'
104 import bcrypt
104 import bcrypt
105 return bcrypt.hashpw(safe_str(password), bcrypt.gensalt(10))
105 return bcrypt.hashpw(safe_str(password), bcrypt.gensalt(10))
106 else:
106 else:
107 raise Exception('Unknown or unsupported platform %s' \
107 raise Exception('Unknown or unsupported platform %s'
108 % __platform__)
108 % __platform__)
109
109
110
110
@@ -121,7 +121,7 b' def check_password(password, hashed):'
121 return hashlib.sha256(password).hexdigest() == hashed
121 return hashlib.sha256(password).hexdigest() == hashed
122 elif is_unix:
122 elif is_unix:
123 import bcrypt
123 import bcrypt
124 print (safe_str(password), safe_str(hashed))
124 print(safe_str(password), safe_str(hashed))
125 try:
125 try:
126 return bcrypt.checkpw(safe_str(password), safe_str(hashed))
126 return bcrypt.checkpw(safe_str(password), safe_str(hashed))
127 except ValueError as e:
127 except ValueError as e:
@@ -129,7 +129,7 b' def check_password(password, hashed):'
129 log.error('error from bcrypt checking password: %s', e)
129 log.error('error from bcrypt checking password: %s', e)
130 return False
130 return False
131 else:
131 else:
132 raise Exception('Unknown or unsupported platform %s' \
132 raise Exception('Unknown or unsupported platform %s'
133 % __platform__)
133 % __platform__)
134
134
135
135
@@ -261,7 +261,7 b' def _cached_perms_data(user_id, user_is_'
261 for gr, perms in _grouped:
261 for gr, perms in _grouped:
262 # since user can be in multiple groups iterate over them and
262 # since user can be in multiple groups iterate over them and
263 # select the lowest permissions first (more explicit)
263 # select the lowest permissions first (more explicit)
264 ##TODO: do this^^
264 # TODO: do this^^
265 if not gr.inherit_default_permissions:
265 if not gr.inherit_default_permissions:
266 # NEED TO IGNORE all configurable permissions and
266 # NEED TO IGNORE all configurable permissions and
267 # replace them with explicitly set
267 # replace them with explicitly set
@@ -409,7 +409,7 b' def _cached_perms_data(user_id, user_is_'
409 p = _choose_perm(p, cur_perm)
409 p = _choose_perm(p, cur_perm)
410 permissions[UK][g_k] = p
410 permissions[UK][g_k] = p
411
411
412 #user explicit permission for user groups
412 # user explicit permission for user groups
413 user_user_groups_perms = Permission.get_default_user_group_perms(user_id)
413 user_user_groups_perms = Permission.get_default_user_group_perms(user_id)
414 for perm in user_user_groups_perms:
414 for perm in user_user_groups_perms:
415 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
415 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
@@ -437,7 +437,7 b' def allowed_api_access(controller_name, '
437 else:
437 else:
438 msg = 'controller: %s is *NOT* in API whitelist' % (controller_name)
438 msg = 'controller: %s is *NOT* in API whitelist' % (controller_name)
439 if api_key:
439 if api_key:
440 #if we use API key and don't have access it's a warning
440 # if we use API key and don't have access it's a warning
441 log.warning(msg)
441 log.warning(msg)
442 else:
442 else:
443 log.debug(msg)
443 log.debug(msg)
@@ -510,7 +510,7 b' class AuthUser(object):'
510
510
511 # If user cannot be found, try falling back to anonymous.
511 # If user cannot be found, try falling back to anonymous.
512 if not is_user_loaded:
512 if not is_user_loaded:
513 is_user_loaded = self._fill_data(self._default_user)
513 is_user_loaded = self._fill_data(self._default_user)
514
514
515 self.is_default_user = (self.user_id == self._default_user.user_id)
515 self.is_default_user = (self.user_id == self._default_user.user_id)
516 self.is_anonymous = not is_user_loaded or self.is_default_user
516 self.is_anonymous = not is_user_loaded or self.is_default_user
@@ -40,7 +40,7 b' class LazyFormencode(object):'
40 from inspect import isfunction
40 from inspect import isfunction
41 formencode_obj = self.formencode_obj
41 formencode_obj = self.formencode_obj
42 if isfunction(formencode_obj):
42 if isfunction(formencode_obj):
43 #case we wrap validators into functions
43 # case we wrap validators into functions
44 formencode_obj = self.formencode_obj(*args, **kwargs)
44 formencode_obj = self.formencode_obj(*args, **kwargs)
45 return formencode_obj(*self.args, **self.kwargs)
45 return formencode_obj(*self.args, **self.kwargs)
46
46
@@ -76,7 +76,6 b' class KallitheaAuthPluginBase(object):'
76 #log.debug('Initializing lazy formencode object: %s', obj)
76 #log.debug('Initializing lazy formencode object: %s', obj)
77 return LazyFormencode(obj, *args, **kwargs)
77 return LazyFormencode(obj, *args, **kwargs)
78
78
79
80 class ProxyGet(object):
79 class ProxyGet(object):
81 def __getattribute__(self, name):
80 def __getattribute__(self, name):
82 return LazyCaller(name)
81 return LazyCaller(name)
@@ -420,6 +419,7 b' def authenticate(username, password, env'
420 username, module)
419 username, module)
421 return None
420 return None
422
421
422
423 def get_managed_fields(user):
423 def get_managed_fields(user):
424 """return list of fields that are managed by the user's auth source, usually some of
424 """return list of fields that are managed by the user's auth source, usually some of
425 'username', 'firstname', 'lastname', 'email', 'active', 'password'
425 'username', 'firstname', 'lastname', 'email', 'active', 'password'
@@ -290,7 +290,7 b' class BaseVCSController(object):'
290 log.error(traceback.format_exc())
290 log.error(traceback.format_exc())
291 return None, webob.exc.HTTPInternalServerError()
291 return None, webob.exc.HTTPInternalServerError()
292
292
293 #check permissions for this repository
293 # check permissions for this repository
294 perm = self._check_permission(action, user, repo_name, ip_addr)
294 perm = self._check_permission(action, user, repo_name, ip_addr)
295 if not perm:
295 if not perm:
296 return None, webob.exc.HTTPForbidden()
296 return None, webob.exc.HTTPForbidden()
@@ -522,7 +522,7 b' class BaseController(TGController):'
522
522
523 self._basic_security_checks()
523 self._basic_security_checks()
524
524
525 #set globals for auth user
525 # set globals for auth user
526
526
527 bearer_token = None
527 bearer_token = None
528 try:
528 try:
@@ -220,8 +220,8 b' def _params_from_query(query):'
220
220
221 """
221 """
222 v = []
222 v = []
223
223 def visit_bindparam(bind):
224 def visit_bindparam(bind):
224
225 if bind.key in query._params:
225 if bind.key in query._params:
226 value = query._params[bind.key]
226 value = query._params[bind.key]
227 elif bind.callable:
227 elif bind.callable:
@@ -234,7 +234,7 b' def _params_from_query(query):'
234
234
235 v.append(value)
235 v.append(value)
236 if query._criterion is not None:
236 if query._criterion is not None:
237 visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam})
237 visitors.traverse(query._criterion, {}, {'bindparam': visit_bindparam})
238 for f in query._from_obj:
238 for f in query._from_obj:
239 visitors.traverse(f, {}, {'bindparam':visit_bindparam})
239 visitors.traverse(f, {}, {'bindparam': visit_bindparam})
240 return v
240 return v
@@ -74,6 +74,7 b' def task(f_org):'
74 f_async.__name__ = f_org.__name__
74 f_async.__name__ = f_org.__name__
75 from kallithea.lib import celerypylons
75 from kallithea.lib import celerypylons
76 runner = celerypylons.task(ignore_result=True)(f_async)
76 runner = celerypylons.task(ignore_result=True)(f_async)
77
77 def f_wrapped(*args, **kwargs):
78 def f_wrapped(*args, **kwargs):
78 t = runner.apply_async(args=args, kwargs=kwargs)
79 t = runner.apply_async(args=args, kwargs=kwargs)
79 log.info('executing task %s in async mode - id %s', f_org, t.task_id)
80 log.info('executing task %s in async mode - id %s', f_org, t.task_id)
@@ -180,7 +180,7 b' def get_commits_stats(repo_name, ts_min_'
180 "schema": ["commits"],
180 "schema": ["commits"],
181 }
181 }
182
182
183 #gather all data by day
183 # gather all data by day
184 if k in commits_by_day_aggregate:
184 if k in commits_by_day_aggregate:
185 commits_by_day_aggregate[k] += 1
185 commits_by_day_aggregate[k] += 1
186 else:
186 else:
@@ -321,6 +321,7 b' def send_email(recipients, subject, body'
321 return False
321 return False
322 return True
322 return True
323
323
324
324 @celerylib.task
325 @celerylib.task
325 @celerylib.dbsession
326 @celerylib.dbsession
326 def create_repo(form_data, cur_user):
327 def create_repo(form_data, cur_user):
@@ -471,7 +472,7 b' def create_repo_fork(form_data, cur_user'
471 except Exception as e:
472 except Exception as e:
472 log.warning('Exception %s occurred when forking repository, '
473 log.warning('Exception %s occurred when forking repository, '
473 'doing cleanup...' % e)
474 'doing cleanup...' % e)
474 #rollback things manually !
475 # rollback things manually !
475 repo = Repository.get_by_repo_name(repo_name_full)
476 repo = Repository.get_by_repo_name(repo_name_full)
476 if repo:
477 if repo:
477 Repository.delete(repo.repo_id)
478 Repository.delete(repo.repo_id)
@@ -27,7 +27,9 b' def celery_config(config):'
27 # Verify .ini file configuration has been loaded
27 # Verify .ini file configuration has been loaded
28 assert config['celery.imports'] == 'kallithea.lib.celerylib.tasks', 'Kallithea Celery configuration has not been loaded'
28 assert config['celery.imports'] == 'kallithea.lib.celerylib.tasks', 'Kallithea Celery configuration has not been loaded'
29
29
30 class CeleryConfig(object): pass
30 class CeleryConfig(object):
31 pass
32
31 celery_config = CeleryConfig()
33 celery_config = CeleryConfig()
32
34
33 PREFIXES = """ADMINS BROKER CASSANDRA CELERYBEAT CELERYD CELERYMON CELERY EMAIL SERVER""".split()
35 PREFIXES = """ADMINS BROKER CASSANDRA CELERYBEAT CELERYD CELERYMON CELERY EMAIL SERVER""".split()
@@ -55,6 +55,7 b' else:'
55
55
56 # Python Software Foundation License
56 # Python Software Foundation License
57
57
58
58 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
59 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
59 # "!=" should be faster.
60 # "!=" should be faster.
60 class _Nil(object):
61 class _Nil(object):
@@ -74,6 +75,7 b' class _Nil(object):'
74 else:
75 else:
75 return NotImplemented
76 return NotImplemented
76
77
78
77 _nil = _Nil()
79 _nil = _Nil()
78
80
79
81
@@ -84,7 +84,7 b' class DbManage(object):'
84 if SESSION:
84 if SESSION:
85 self.sa = SESSION
85 self.sa = SESSION
86 else:
86 else:
87 #init new sessions
87 # init new sessions
88 engine = create_engine(self.dburi)
88 engine = create_engine(self.dburi)
89 init_model(engine)
89 init_model(engine)
90 self.sa = Session()
90 self.sa = Session()
@@ -205,7 +205,7 b' class DbManage(object):'
205 if password is None:
205 if password is None:
206 password = get_password()
206 password = get_password()
207 if not password:
207 if not password:
208 #second try
208 # second try
209 password = get_password()
209 password = get_password()
210 if not password:
210 if not password:
211 sys.exit()
211 sys.exit()
@@ -234,7 +234,7 b' class DbManage(object):'
234 Creates ui settings, fills out hooks
234 Creates ui settings, fills out hooks
235 """
235 """
236
236
237 #HOOKS
237 # HOOKS
238 hooks1_key = Ui.HOOK_UPDATE
238 hooks1_key = Ui.HOOK_UPDATE
239 hooks1_ = Ui.query() \
239 hooks1_ = Ui.query() \
240 .filter(Ui.ui_key == hooks1_key).scalar()
240 .filter(Ui.ui_key == hooks1_key).scalar()
@@ -1,5 +1,6 b''
1 from gearbox.command import Command
1 from gearbox.command import Command
2
2
3
3 class UpgradeDb(Command):
4 class UpgradeDb(Command):
4 '''(removed)'''
5 '''(removed)'''
5
6
@@ -130,6 +130,7 b' def get_gitdiff(filenode_old, filenode_n'
130 ignore_whitespace, context)
130 ignore_whitespace, context)
131 return vcs_gitdiff
131 return vcs_gitdiff
132
132
133
133 NEW_FILENODE = 1
134 NEW_FILENODE = 1
134 DEL_FILENODE = 2
135 DEL_FILENODE = 2
135 MOD_FILENODE = 3
136 MOD_FILENODE = 3
@@ -205,7 +206,6 b' class DiffProcessor(object):'
205
206
206 _escape_re = re.compile(r'(&)|(<)|(>)|(\t)|(\r)|(?<=.)( \n| $)')
207 _escape_re = re.compile(r'(&)|(<)|(>)|(\t)|(\r)|(?<=.)( \n| $)')
207
208
208
209 def __init__(self, diff, vcs='hg', format='gitdiff', diff_limit=None):
209 def __init__(self, diff, vcs='hg', format='gitdiff', diff_limit=None):
210 """
210 """
211 :param diff: a text in diff format
211 :param diff: a text in diff format
@@ -375,7 +375,7 b' class DiffProcessor(object):'
375
375
376 def _clean_line(self, line, command):
376 def _clean_line(self, line, command):
377 if command in ['+', '-', ' ']:
377 if command in ['+', '-', ' ']:
378 #only modify the line if it's actually a diff thing
378 # only modify the line if it's actually a diff thing
379 line = line[1:]
379 line = line[1:]
380 return line
380 return line
381
381
@@ -383,7 +383,7 b' class DiffProcessor(object):'
383 _files = []
383 _files = []
384 diff_container = lambda arg: arg
384 diff_container = lambda arg: arg
385
385
386 ##split the diff in chunks of separate --git a/file b/file chunks
386 # split the diff in chunks of separate --git a/file b/file chunks
387 for raw_diff in ('\n' + self._diff).split('\ndiff --git')[1:]:
387 for raw_diff in ('\n' + self._diff).split('\ndiff --git')[1:]:
388 head, diff = self._get_header(raw_diff)
388 head, diff = self._get_header(raw_diff)
389
389
@@ -22,6 +22,7 b' def _is_tz_aware(value):'
22 return (value.tzinfo is not None
22 return (value.tzinfo is not None
23 and value.tzinfo.utcoffset(value) is not None)
23 and value.tzinfo.utcoffset(value) is not None)
24
24
25
25 def _obj_dump(obj):
26 def _obj_dump(obj):
26 """
27 """
27 Custom function for dumping objects to JSON, if obj has __json__ attribute
28 Custom function for dumping objects to JSON, if obj has __json__ attribute
@@ -19,6 +19,7 b' It allows to have a shared codebase for '
19
19
20 nullrev = -1
20 nullrev = -1
21
21
22
22 def _first_known_ancestors(parentrev_func, minrev, knownrevs, head):
23 def _first_known_ancestors(parentrev_func, minrev, knownrevs, head):
23 """
24 """
24 Return the apparent parents of the head revision in a filtered DAG.
25 Return the apparent parents of the head revision in a filtered DAG.
@@ -45,6 +46,7 b' def _first_known_ancestors(parentrev_fun'
45 seen.add(r)
46 seen.add(r)
46 return ancestors
47 return ancestors
47
48
49
48 def graph_data(repo, revs):
50 def graph_data(repo, revs):
49 """Return a DAG with colored edge information for revs
51 """Return a DAG with colored edge information for revs
50
52
@@ -61,6 +63,7 b' def graph_data(repo, revs):'
61 dag = _dagwalker(repo, revs)
63 dag = _dagwalker(repo, revs)
62 return list(_colored(repo, dag))
64 return list(_colored(repo, dag))
63
65
66
64 def _dagwalker(repo, revs):
67 def _dagwalker(repo, revs):
65 """Iterate over revs, yielding revs (highest first) and parents to show in the graph."""
68 """Iterate over revs, yielding revs (highest first) and parents to show in the graph."""
66 if not revs:
69 if not revs:
@@ -102,6 +105,7 b' def _colored(repo, dag):'
102 parents.
105 parents.
103 """
106 """
104 branch_cache = {}
107 branch_cache = {}
108
105 def branch(rev):
109 def branch(rev):
106 """Return branch for rev, using cache for efficiency.
110 """Return branch for rev, using cache for efficiency.
107 For Mercurial, always return the named branch name (which may be 'default').
111 For Mercurial, always return the named branch name (which may be 'default').
@@ -64,6 +64,7 b' def canonical_url(*args, **kargs):'
64 kargs['qualified'] = True
64 kargs['qualified'] = True
65 return url(*args, **kargs)
65 return url(*args, **kargs)
66
66
67
67 def canonical_hostname():
68 def canonical_hostname():
68 '''Return canonical hostname of system'''
69 '''Return canonical hostname of system'''
69 from kallithea import CONFIG
70 from kallithea import CONFIG
@@ -74,6 +75,7 b' def canonical_hostname():'
74 parts = url('home', qualified=True).split('://', 1)
75 parts = url('home', qualified=True).split('://', 1)
75 return parts[1].split('/', 1)[0]
76 return parts[1].split('/', 1)[0]
76
77
78
77 def html_escape(s):
79 def html_escape(s):
78 """Return string with all html escaped.
80 """Return string with all html escaped.
79 This is also safe for javascript in html but not necessarily correct.
81 This is also safe for javascript in html but not necessarily correct.
@@ -116,6 +118,7 b' def js(value):'
116 .replace('>', r'\x3e')
118 .replace('>', r'\x3e')
117 )
119 )
118
120
121
119 def jshtml(val):
122 def jshtml(val):
120 """HTML escapes a string value, then converts the resulting string
123 """HTML escapes a string value, then converts the resulting string
121 to its corresponding JavaScript representation (see `js`).
124 to its corresponding JavaScript representation (see `js`).
@@ -150,6 +153,7 b' def _reset(name, value=None, id=NotGiven'
150 convert_boolean_attrs(attrs, ["disabled"])
153 convert_boolean_attrs(attrs, ["disabled"])
151 return HTML.input(**attrs)
154 return HTML.input(**attrs)
152
155
156
153 reset = _reset
157 reset = _reset
154 safeid = _make_safe_id_component
158 safeid = _make_safe_id_component
155
159
@@ -190,6 +194,7 b' class _FilesBreadCrumbs(object):'
190
194
191 return literal('/'.join(url_l))
195 return literal('/'.join(url_l))
192
196
197
193 files_breadcrumbs = _FilesBreadCrumbs()
198 files_breadcrumbs = _FilesBreadCrumbs()
194
199
195
200
@@ -272,6 +277,7 b' class CodeHtmlFormatter(HtmlFormatter):'
272
277
273 _whitespace_re = re.compile(r'(\t)|( )(?=\n|</div>)')
278 _whitespace_re = re.compile(r'(\t)|( )(?=\n|</div>)')
274
279
280
275 def _markup_whitespace(m):
281 def _markup_whitespace(m):
276 groups = m.groups()
282 groups = m.groups()
277 if groups[0]:
283 if groups[0]:
@@ -279,9 +285,11 b' def _markup_whitespace(m):'
279 if groups[1]:
285 if groups[1]:
280 return ' <i></i>'
286 return ' <i></i>'
281
287
288
282 def markup_whitespace(s):
289 def markup_whitespace(s):
283 return _whitespace_re.sub(_markup_whitespace, s)
290 return _whitespace_re.sub(_markup_whitespace, s)
284
291
292
285 def pygmentize(filenode, **kwargs):
293 def pygmentize(filenode, **kwargs):
286 """
294 """
287 pygmentize function using pygments
295 pygmentize function using pygments
@@ -399,6 +407,7 b' class _Message(object):'
399 def __html__(self):
407 def __html__(self):
400 return escape(safe_unicode(self.message))
408 return escape(safe_unicode(self.message))
401
409
410
402 class Flash(_Flash):
411 class Flash(_Flash):
403
412
404 def __call__(self, message, category=None, ignore_duplicate=False, logf=None):
413 def __call__(self, message, category=None, ignore_duplicate=False, logf=None):
@@ -430,6 +439,7 b' class Flash(_Flash):'
430 session.save()
439 session.save()
431 return [_Message(*m) for m in messages]
440 return [_Message(*m) for m in messages]
432
441
442
433 flash = Flash()
443 flash = Flash()
434
444
435 #==============================================================================
445 #==============================================================================
@@ -438,7 +448,7 b' flash = Flash()'
438 from kallithea.lib.vcs.utils import author_name, author_email
448 from kallithea.lib.vcs.utils import author_name, author_email
439 from kallithea.lib.utils2 import credentials_filter, age as _age
449 from kallithea.lib.utils2 import credentials_filter, age as _age
440
450
441 age = lambda x, y=False: _age(x, y)
451 age = lambda x, y=False: _age(x, y)
442 capitalize = lambda x: x.capitalize()
452 capitalize = lambda x: x.capitalize()
443 email = author_email
453 email = author_email
444 short_id = lambda x: x[:12]
454 short_id = lambda x: x[:12]
@@ -499,6 +509,7 b' def user_or_none(author):'
499 return User.get_by_email(email, cache=True) # cache will only use sql_cache_short
509 return User.get_by_email(email, cache=True) # cache will only use sql_cache_short
500 return None
510 return None
501
511
512
502 def email_or_none(author):
513 def email_or_none(author):
503 """Try to match email part of VCS committer string with a local user.
514 """Try to match email part of VCS committer string with a local user.
504 Return primary email of user, email part of the specified author name, or None."""
515 Return primary email of user, email part of the specified author name, or None."""
@@ -516,6 +527,7 b' def email_or_none(author):'
516 # No valid email, not a valid user in the system, none!
527 # No valid email, not a valid user in the system, none!
517 return None
528 return None
518
529
530
519 def person(author, show_attr="username"):
531 def person(author, show_attr="username"):
520 """Find the user identified by 'author', return one of the users attributes,
532 """Find the user identified by 'author', return one of the users attributes,
521 default to the username attribute, None if there is no user"""
533 default to the username attribute, None if there is no user"""
@@ -540,7 +552,7 b' def person_by_id(id_, show_attr="usernam'
540 # attr to return from fetched user
552 # attr to return from fetched user
541 person_getter = lambda usr: getattr(usr, show_attr)
553 person_getter = lambda usr: getattr(usr, show_attr)
542
554
543 #maybe it's an ID ?
555 # maybe it's an ID ?
544 if str(id_).isdigit() or isinstance(id_, int):
556 if str(id_).isdigit() or isinstance(id_, int):
545 id_ = int(id_)
557 id_ = int(id_)
546 user = User.get(id_)
558 user = User.get(id_)
@@ -614,7 +626,7 b' def action_parser(user_log, feed=False, '
614 if parse_cs:
626 if parse_cs:
615 return link_to(lbl, url_, title=title_, **{'data-toggle': 'tooltip'})
627 return link_to(lbl, url_, title=title_, **{'data-toggle': 'tooltip'})
616 return link_to(lbl, url_, class_='lazy-cs' if lazy_cs else '',
628 return link_to(lbl, url_, class_='lazy-cs' if lazy_cs else '',
617 **{'data-raw_id':rev.raw_id, 'data-repo_name':repo_name})
629 **{'data-raw_id': rev.raw_id, 'data-repo_name': repo_name})
618
630
619 def _get_op(rev_txt):
631 def _get_op(rev_txt):
620 _op = None
632 _op = None
@@ -848,6 +860,7 b" def gravatar_div(email_address, cls='', "
848 (''.join(attributes),
860 (''.join(attributes),
849 gravatar(email_address, cls=cls, size=size)))
861 gravatar(email_address, cls=cls, size=size)))
850
862
863
851 def gravatar(email_address, cls='', size=30):
864 def gravatar(email_address, cls='', size=30):
852 """return html element of the gravatar
865 """return html element of the gravatar
853
866
@@ -875,6 +888,7 b" def gravatar(email_address, cls='', size"
875
888
876 return literal(html)
889 return literal(html)
877
890
891
878 def gravatar_url(email_address, size=30, default=''):
892 def gravatar_url(email_address, size=30, default=''):
879 # doh, we need to re-import those to mock it later
893 # doh, we need to re-import those to mock it later
880 from kallithea.config.routing import url
894 from kallithea.config.routing import url
@@ -931,7 +945,7 b' def fancy_file_stats(stats):'
931 width = 100
945 width = 100
932
946
933 if stats['binary']:
947 if stats['binary']:
934 #binary mode
948 # binary mode
935 lbl = ''
949 lbl = ''
936 bin_op = 1
950 bin_op = 1
937
951
@@ -951,7 +965,7 b' def fancy_file_stats(stats):'
951 lbl += _('rename')
965 lbl += _('rename')
952 bin_op = RENAMED_FILENODE
966 bin_op = RENAMED_FILENODE
953
967
954 #chmod can go with other operations
968 # chmod can go with other operations
955 if CHMOD_FILENODE in stats['ops']:
969 if CHMOD_FILENODE in stats['ops']:
956 _org_lbl = _('chmod')
970 _org_lbl = _('chmod')
957 lbl += _org_lbl if lbl.endswith('+') else '+%s' % _org_lbl
971 lbl += _org_lbl if lbl.endswith('+') else '+%s' % _org_lbl
@@ -970,7 +984,7 b' def fancy_file_stats(stats):'
970 p_sum = a_p + d_p
984 p_sum = a_p + d_p
971
985
972 if p_sum > width:
986 if p_sum > width:
973 #adjust the percentage to be == 100% since we adjusted to 9
987 # adjust the percentage to be == 100% since we adjusted to 9
974 if a_p > d_p:
988 if a_p > d_p:
975 a_p = a_p - (p_sum - width)
989 a_p = a_p - (p_sum - width)
976 else:
990 else:
@@ -1013,7 +1027,6 b' def fancy_file_stats(stats):'
1013 re.VERBOSE | re.MULTILINE | re.IGNORECASE)
1027 re.VERBOSE | re.MULTILINE | re.IGNORECASE)
1014
1028
1015
1029
1016
1017 def urlify_text(s, repo_name=None, link_=None, truncate=None, stylize=False, truncatef=truncate):
1030 def urlify_text(s, repo_name=None, link_=None, truncate=None, stylize=False, truncatef=truncate):
1018 """
1031 """
1019 Parses given text message and make literal html with markup.
1032 Parses given text message and make literal html with markup.
@@ -1131,6 +1144,7 b' def urlify_issues(newtext, repo_name):'
1131
1144
1132 # Wrap tmp_urlify_issues_f with substitution of this pattern, while making sure all loop variables (and compiled regexpes) are bound
1145 # Wrap tmp_urlify_issues_f with substitution of this pattern, while making sure all loop variables (and compiled regexpes) are bound
1133 issue_re = re.compile(issue_pat)
1146 issue_re = re.compile(issue_pat)
1147
1134 def issues_replace(match_obj,
1148 def issues_replace(match_obj,
1135 issue_server_link=issue_server_link, issue_prefix=issue_prefix):
1149 issue_server_link=issue_server_link, issue_prefix=issue_prefix):
1136 leadingspace = ' ' if match_obj.group().startswith(' ') else ''
1150 leadingspace = ' ' if match_obj.group().startswith(' ') else ''
@@ -1174,6 +1188,7 b' def short_ref(ref_type, ref_name):'
1174 return short_id(ref_name)
1188 return short_id(ref_name)
1175 return ref_name
1189 return ref_name
1176
1190
1191
1177 def link_to_ref(repo_name, ref_type, ref_name, rev=None):
1192 def link_to_ref(repo_name, ref_type, ref_name, rev=None):
1178 """
1193 """
1179 Return full markup for a href to changeset_home for a changeset.
1194 Return full markup for a href to changeset_home for a changeset.
@@ -1191,6 +1206,7 b' def link_to_ref(repo_name, ref_type, ref'
1191 l = literal('%s (%s)' % (l, link_to(short_id(rev), url('changeset_home', repo_name=repo_name, revision=rev))))
1206 l = literal('%s (%s)' % (l, link_to(short_id(rev), url('changeset_home', repo_name=repo_name, revision=rev))))
1192 return l
1207 return l
1193
1208
1209
1194 def changeset_status(repo, revision):
1210 def changeset_status(repo, revision):
1195 from kallithea.model.changeset_status import ChangesetStatusModel
1211 from kallithea.model.changeset_status import ChangesetStatusModel
1196 return ChangesetStatusModel().get_status(repo, revision)
1212 return ChangesetStatusModel().get_status(repo, revision)
@@ -98,7 +98,7 b' def pre_push(ui, repo, **kwargs):'
98 # on that proper return code is server to client
98 # on that proper return code is server to client
99 _http_ret = HTTPLockedRC(ex.repository, locked_by)
99 _http_ret = HTTPLockedRC(ex.repository, locked_by)
100 if str(_http_ret.code).startswith('2'):
100 if str(_http_ret.code).startswith('2'):
101 #2xx Codes don't raise exceptions
101 # 2xx Codes don't raise exceptions
102 ui.status(safe_str(_http_ret.title))
102 ui.status(safe_str(_http_ret.title))
103 else:
103 else:
104 raise _http_ret
104 raise _http_ret
@@ -113,7 +113,7 b' def pre_pull(ui, repo, **kwargs):'
113 # on that proper return code is server to client
113 # on that proper return code is server to client
114 _http_ret = HTTPLockedRC(ex.repository, locked_by)
114 _http_ret = HTTPLockedRC(ex.repository, locked_by)
115 if str(_http_ret.code).startswith('2'):
115 if str(_http_ret.code).startswith('2'):
116 #2xx Codes don't raise exceptions
116 # 2xx Codes don't raise exceptions
117 ui.status(safe_str(_http_ret.title))
117 ui.status(safe_str(_http_ret.title))
118 else:
118 else:
119 raise _http_ret
119 raise _http_ret
@@ -148,7 +148,7 b' def log_pull_action(ui, repo, **kwargs):'
148 locked_by = User.get(ex.locked_by[0]).username
148 locked_by = User.get(ex.locked_by[0]).username
149 _http_ret = HTTPLockedRC(ex.repository, locked_by)
149 _http_ret = HTTPLockedRC(ex.repository, locked_by)
150 if str(_http_ret.code).startswith('2'):
150 if str(_http_ret.code).startswith('2'):
151 #2xx Codes don't raise exceptions
151 # 2xx Codes don't raise exceptions
152 ui.status(safe_str(_http_ret.title))
152 ui.status(safe_str(_http_ret.title))
153 return 0
153 return 0
154
154
@@ -203,7 +203,7 b' def log_push_action(ui, repo, **kwargs):'
203 locked_by = User.get(ex.locked_by[0]).username
203 locked_by = User.get(ex.locked_by[0]).username
204 _http_ret = HTTPLockedRC(ex.repository, locked_by)
204 _http_ret = HTTPLockedRC(ex.repository, locked_by)
205 if str(_http_ret.code).startswith('2'):
205 if str(_http_ret.code).startswith('2'):
206 #2xx Codes don't raise exceptions
206 # 2xx Codes don't raise exceptions
207 ui.status(safe_str(_http_ret.title))
207 ui.status(safe_str(_http_ret.title))
208
208
209 return 0
209 return 0
@@ -446,7 +446,7 b' def handle_git_receive(repo_path, revs, '
446 repo._repo.refs.set_symbolic_ref('HEAD',
446 repo._repo.refs.set_symbolic_ref('HEAD',
447 'refs/heads/%s' % push_ref['name'])
447 'refs/heads/%s' % push_ref['name'])
448
448
449 cmd = ['for-each-ref', '--format=%(refname)','refs/heads/*']
449 cmd = ['for-each-ref', '--format=%(refname)', 'refs/heads/*']
450 heads = repo.run_git_command(cmd)[0]
450 heads = repo.run_git_command(cmd)[0]
451 cmd = ['log', push_ref['new_rev'],
451 cmd = ['log', push_ref['new_rev'],
452 '--reverse', '--pretty=format:%H', '--not']
452 '--reverse', '--pretty=format:%H', '--not']
@@ -456,7 +456,7 b' def handle_git_receive(repo_path, revs, '
456 git_revs += repo.run_git_command(cmd)[0].splitlines()
456 git_revs += repo.run_git_command(cmd)[0].splitlines()
457
457
458 elif push_ref['new_rev'] == EmptyChangeset().raw_id:
458 elif push_ref['new_rev'] == EmptyChangeset().raw_id:
459 #delete branch case
459 # delete branch case
460 git_revs += ['delete_branch=>%s' % push_ref['name']]
460 git_revs += ['delete_branch=>%s' % push_ref['name']]
461 else:
461 else:
462 cmd = ['log', '%(old_rev)s..%(new_rev)s' % push_ref,
462 cmd = ['log', '%(old_rev)s..%(new_rev)s' % push_ref,
@@ -50,7 +50,7 b' ANALYZER = RegexTokenizer(expression=r"\\'
50 # - avoid removing "stop words" from text
50 # - avoid removing "stop words" from text
51 # - search case-insensitively
51 # - search case-insensitively
52 #
52 #
53 EMAILADDRANALYZER = RegexTokenizer() | LowercaseFilter()
53 EMAILADDRANALYZER = RegexTokenizer() | LowercaseFilter()
54
54
55 # CUSTOM ANALYZER raw-string + lowercase filter
55 # CUSTOM ANALYZER raw-string + lowercase filter
56 #
56 #
@@ -77,7 +77,7 b' IDANALYZER = IDTokenizer()'
77 #
77 #
78 PATHANALYZER = RegexTokenizer() | LowercaseFilter()
78 PATHANALYZER = RegexTokenizer() | LowercaseFilter()
79
79
80 #INDEX SCHEMA DEFINITION
80 # INDEX SCHEMA DEFINITION
81 SCHEMA = Schema(
81 SCHEMA = Schema(
82 fileid=ID(unique=True),
82 fileid=ID(unique=True),
83 owner=TEXT(analyzer=EMAILADDRANALYZER),
83 owner=TEXT(analyzer=EMAILADDRANALYZER),
@@ -77,9 +77,9 b' class WhooshIndexingDaemon(object):'
77
77
78 self.repo_paths = ScmModel().repo_scan(self.repo_location)
78 self.repo_paths = ScmModel().repo_scan(self.repo_location)
79
79
80 #filter repo list
80 # filter repo list
81 if repo_list:
81 if repo_list:
82 #Fix non-ascii repo names to unicode
82 # Fix non-ascii repo names to unicode
83 repo_list = map(safe_unicode, repo_list)
83 repo_list = map(safe_unicode, repo_list)
84 self.filtered_repo_paths = {}
84 self.filtered_repo_paths = {}
85 for repo_name, repo in self.repo_paths.items():
85 for repo_name, repo in self.repo_paths.items():
@@ -88,7 +88,7 b' class WhooshIndexingDaemon(object):'
88
88
89 self.repo_paths = self.filtered_repo_paths
89 self.repo_paths = self.filtered_repo_paths
90
90
91 #filter update repo list
91 # filter update repo list
92 self.filtered_repo_update_paths = {}
92 self.filtered_repo_update_paths = {}
93 if repo_update_list:
93 if repo_update_list:
94 self.filtered_repo_update_paths = {}
94 self.filtered_repo_update_paths = {}
@@ -367,9 +367,11 b' def collapse_address_list(addresses):'
367 return _collapse_address_list_recursive(sorted(
367 return _collapse_address_list_recursive(sorted(
368 addrs + nets, key=_BaseNet._get_networks_key))
368 addrs + nets, key=_BaseNet._get_networks_key))
369
369
370
370 # backwards compatibility
371 # backwards compatibility
371 CollapseAddrList = collapse_address_list
372 CollapseAddrList = collapse_address_list
372
373
374
373 # We need to distinguish between the string and packed-bytes representations
375 # We need to distinguish between the string and packed-bytes representations
374 # of an IP address. For example, b'0::1' is the IPv4 address 48.58.58.49,
376 # of an IP address. For example, b'0::1' is the IPv4 address 48.58.58.49,
375 # while '0::1' is an IPv6 address.
377 # while '0::1' is an IPv6 address.
@@ -79,6 +79,7 b' class MarkupRenderer(object):'
79
79
80 # Extract pre blocks.
80 # Extract pre blocks.
81 extractions = {}
81 extractions = {}
82
82 def pre_extraction_callback(matchobj):
83 def pre_extraction_callback(matchobj):
83 digest = md5(matchobj.group(0)).hexdigest()
84 digest = md5(matchobj.group(0)).hexdigest()
84 extractions[digest] = matchobj.group(0)
85 extractions[digest] = matchobj.group(0)
@@ -72,7 +72,7 b' class GitRepository(object):'
72
72
73 def __init__(self, repo_name, content_path, extras):
73 def __init__(self, repo_name, content_path, extras):
74 files = set([f.lower() for f in os.listdir(content_path)])
74 files = set([f.lower() for f in os.listdir(content_path)])
75 if not (self.git_folder_signature.intersection(files)
75 if not (self.git_folder_signature.intersection(files)
76 == self.git_folder_signature):
76 == self.git_folder_signature):
77 raise OSError('%s missing git signature' % content_path)
77 raise OSError('%s missing git signature' % content_path)
78 self.content_path = content_path
78 self.content_path = content_path
@@ -26,6 +26,7 b' Original Beaker SessionMiddleware class '
26 from beaker.session import SessionObject
26 from beaker.session import SessionObject
27 from beaker.middleware import SessionMiddleware
27 from beaker.middleware import SessionMiddleware
28
28
29
29 class SecureSessionMiddleware(SessionMiddleware):
30 class SecureSessionMiddleware(SessionMiddleware):
30 def __call__(self, environ, start_response):
31 def __call__(self, environ, start_response):
31 """
32 """
@@ -62,6 +62,7 b' def is_mercurial(environ):'
62 )
62 )
63 return ishg_path
63 return ishg_path
64
64
65
65 class SimpleHg(BaseVCSController):
66 class SimpleHg(BaseVCSController):
66
67
67 def _handle_request(self, environ, start_response):
68 def _handle_request(self, environ, start_response):
@@ -229,7 +230,7 b' class SimpleHg(BaseVCSController):'
229 repoui = make_ui('file', hgrc)
230 repoui = make_ui('file', hgrc)
230
231
231 if repoui:
232 if repoui:
232 #overwrite our ui instance with the section from hgrc file
233 # overwrite our ui instance with the section from hgrc file
233 for section in ui_sections:
234 for section in ui_sections:
234 for k, v in repoui.configitems(section):
235 for k, v in repoui.configitems(section):
235 baseui.setconfig(section, k, v)
236 baseui.setconfig(section, k, v)
@@ -21,6 +21,7 b' from kallithea.config.routing import url'
21 from webhelpers.html import literal, HTML
21 from webhelpers.html import literal, HTML
22 from webhelpers.paginate import Page as _Page
22 from webhelpers.paginate import Page as _Page
23
23
24
24 class Page(_Page):
25 class Page(_Page):
25 """
26 """
26 Custom pager to match rendering style with YUI paginator emitting Bootstrap paginators
27 Custom pager to match rendering style with YUI paginator emitting Bootstrap paginators
@@ -84,7 +84,7 b' class Command(BasePasterCommand):'
84 if dirs:
84 if dirs:
85 print 'Scanning: %s' % dn_
85 print 'Scanning: %s' % dn_
86
86
87 #filter older than (if present)!
87 # filter older than (if present)!
88 now = datetime.datetime.now()
88 now = datetime.datetime.now()
89 older_than = args.older_than
89 older_than = args.older_than
90 if older_than:
90 if older_than:
@@ -61,6 +61,7 b" if __name__=='__main__':"
61 HandleCommandLine(params)
61 HandleCommandLine(params)
62 '''
62 '''
63
63
64
64 class Command(BasePasterCommand):
65 class Command(BasePasterCommand):
65 '''Kallithea: Install into IIS using isapi-wsgi'''
66 '''Kallithea: Install into IIS using isapi-wsgi'''
66
67
@@ -118,7 +118,7 b' def _run(args):'
118 tmpl_stored_args.update(kwargs)
118 tmpl_stored_args.update(kwargs)
119
119
120 if args.show_defaults:
120 if args.show_defaults:
121 for k,v in tmpl_stored_args.iteritems():
121 for k, v in tmpl_stored_args.iteritems():
122 print '%s=%s' % (k, v)
122 print '%s=%s' % (k, v)
123 sys.exit(0)
123 sys.exit(0)
124
124
@@ -42,7 +42,7 b' class DaemonLock(object):'
42 self.desc = desc
42 self.desc = desc
43 self.debug = debug
43 self.debug = debug
44 self.held = False
44 self.held = False
45 #run the lock automatically !
45 # run the lock automatically!
46 self.lock()
46 self.lock()
47 self._finalize = Finalize(self, DaemonLock._on_finalize,
47 self._finalize = Finalize(self, DaemonLock._on_finalize,
48 args=(self, debug), exitpriority=10)
48 args=(self, debug), exitpriority=10)
@@ -196,7 +196,7 b' class MailResponse(object):'
196 self.attachments.append({'filename': filename,
196 self.attachments.append({'filename': filename,
197 'content_type': content_type,
197 'content_type': content_type,
198 'data': data,
198 'data': data,
199 'disposition': disposition,})
199 'disposition': disposition})
200
200
201 def attach_part(self, part):
201 def attach_part(self, part):
202 """
202 """
@@ -16,4 +16,5 b' class CachedDnsName(object):'
16 self._fqdn = socket.getfqdn()
16 self._fqdn = socket.getfqdn()
17 return self._fqdn
17 return self._fqdn
18
18
19
19 DNS_NAME = CachedDnsName()
20 DNS_NAME = CachedDnsName()
@@ -214,7 +214,7 b' def get_filesystem_repos(path):'
214 if REMOVED_REPO_PAT.match(subdir):
214 if REMOVED_REPO_PAT.match(subdir):
215 continue
215 continue
216
216
217 #skip .<something> dirs TODO: rly? then we should prevent creating them ...
217 # skip .<something> dirs TODO: rly? then we should prevent creating them ...
218 if subdir.startswith('.'):
218 if subdir.startswith('.'):
219 continue
219 continue
220
220
@@ -303,7 +303,7 b' def is_valid_repo_group(repo_group_name,'
303 return False
303 return False
304
304
305
305
306 #propagated from mercurial documentation
306 # propagated from mercurial documentation
307 ui_sections = ['alias', 'auth',
307 ui_sections = ['alias', 'auth',
308 'decode/encode', 'defaults',
308 'decode/encode', 'defaults',
309 'diff', 'email',
309 'diff', 'email',
@@ -479,7 +479,7 b' def repo2db_mapper(initial_repo_list, re'
479 user = User.get_first_admin()
479 user = User.get_first_admin()
480 added = []
480 added = []
481
481
482 ##creation defaults
482 # creation defaults
483 defs = Setting.get_default_repo_settings(strip_prefix=True)
483 defs = Setting.get_default_repo_settings(strip_prefix=True)
484 enable_statistics = defs.get('repo_enable_statistics')
484 enable_statistics = defs.get('repo_enable_statistics')
485 enable_locking = defs.get('repo_enable_locking')
485 enable_locking = defs.get('repo_enable_locking')
@@ -556,13 +556,13 b' def load_rcextensions(root_path):'
556 # Additional mappings that are not present in the pygments lexers
556 # Additional mappings that are not present in the pygments lexers
557 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
557 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
558
558
559 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
559 # OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
560
560
561 if getattr(EXT, 'INDEX_EXTENSIONS', []):
561 if getattr(EXT, 'INDEX_EXTENSIONS', []):
562 log.debug('settings custom INDEX_EXTENSIONS')
562 log.debug('settings custom INDEX_EXTENSIONS')
563 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
563 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
564
564
565 #ADDITIONAL MAPPINGS
565 # ADDITIONAL MAPPINGS
566 log.debug('adding extra into INDEX_EXTENSIONS')
566 log.debug('adding extra into INDEX_EXTENSIONS')
567 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
567 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
568
568
@@ -297,7 +297,7 b' def engine_from_config(configuration, pr'
297 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
297 return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
298
298
299 if configuration['debug']:
299 if configuration['debug']:
300 #attach events only for debug configuration
300 # attach events only for debug configuration
301
301
302 def before_cursor_execute(conn, cursor, statement,
302 def before_cursor_execute(conn, cursor, statement,
303 parameters, context, executemany):
303 parameters, context, executemany):
@@ -458,7 +458,7 b' def credentials_filter(uri):'
458 """
458 """
459
459
460 uri = uri_filter(uri)
460 uri = uri_filter(uri)
461 #check if we have port
461 # check if we have port
462 if len(uri) > 2 and uri[2]:
462 if len(uri) > 2 and uri[2]:
463 uri[2] = ':' + uri[2]
463 uri[2] = ':' + uri[2]
464
464
@@ -531,6 +531,7 b' def time_to_datetime(tm):'
531 # Matching is greedy so we don't have to look beyond the end.
531 # Matching is greedy so we don't have to look beyond the end.
532 MENTIONS_REGEX = re.compile(r'(?:^|(?<=[^a-zA-Z0-9]))@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])')
532 MENTIONS_REGEX = re.compile(r'(?:^|(?<=[^a-zA-Z0-9]))@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])')
533
533
534
534 def extract_mentioned_usernames(text):
535 def extract_mentioned_usernames(text):
535 r"""
536 r"""
536 Returns list of (possible) usernames @mentioned in given text.
537 Returns list of (possible) usernames @mentioned in given text.
@@ -540,6 +541,7 b' def extract_mentioned_usernames(text):'
540 """
541 """
541 return MENTIONS_REGEX.findall(text)
542 return MENTIONS_REGEX.findall(text)
542
543
544
543 def extract_mentioned_users(text):
545 def extract_mentioned_users(text):
544 """ Returns set of actual database Users @mentioned in given text. """
546 """ Returns set of actual database Users @mentioned in given text. """
545 from kallithea.model.db import User
547 from kallithea.model.db import User
@@ -649,7 +651,8 b' class OptionalAttr(object):'
649 def __call__(self):
651 def __call__(self):
650 return self
652 return self
651
653
652 #alias
654
655 # alias
653 OAttr = OptionalAttr
656 OAttr = OptionalAttr
654
657
655
658
@@ -697,5 +700,6 b' class Optional(object):'
697 return val.getval()
700 return val.getval()
698 return val
701 return val
699
702
703
700 def urlreadable(s, _cleanstringsub=re.compile('[^-a-zA-Z0-9./]+').sub):
704 def urlreadable(s, _cleanstringsub=re.compile('[^-a-zA-Z0-9./]+').sub):
701 return _cleanstringsub('_', safe_str(s)).rstrip('_')
705 return _cleanstringsub('_', safe_str(s)).rstrip('_')
@@ -700,6 +700,7 b' class BaseChangeset(object):'
700 def phase(self):
700 def phase(self):
701 return ''
701 return ''
702
702
703
703 class BaseWorkdir(object):
704 class BaseWorkdir(object):
704 """
705 """
705 Working directory representation of single repository.
706 Working directory representation of single repository.
@@ -118,7 +118,7 b' class GitRepository(BaseRepository):'
118 _copts = ['-c', 'core.quotepath=false', ]
118 _copts = ['-c', 'core.quotepath=false', ]
119 safe_call = False
119 safe_call = False
120 if '_safe' in opts:
120 if '_safe' in opts:
121 #no exc on failure
121 # no exc on failure
122 del opts['_safe']
122 del opts['_safe']
123 safe_call = True
123 safe_call = True
124
124
@@ -189,7 +189,7 b' class GitRepository(BaseRepository):'
189 test_uri = test_uri.rstrip('/') + '/info/refs'
189 test_uri = test_uri.rstrip('/') + '/info/refs'
190
190
191 if authinfo:
191 if authinfo:
192 #create a password manager
192 # create a password manager
193 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
193 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
194 passmgr.add_password(*authinfo)
194 passmgr.add_password(*authinfo)
195
195
@@ -262,7 +262,7 b' class GitRepository(BaseRepository):'
262 return so.splitlines()
262 return so.splitlines()
263
263
264 def _get_all_revisions2(self):
264 def _get_all_revisions2(self):
265 #alternate implementation using dulwich
265 # alternate implementation using dulwich
266 includes = [x[1][0] for x in self._parsed_refs.iteritems()
266 includes = [x[1][0] for x in self._parsed_refs.iteritems()
267 if x[1][1] != 'T']
267 if x[1][1] != 'T']
268 return [c.commit.id for c in self._repo.get_walker(include=includes)]
268 return [c.commit.id for c in self._repo.get_walker(include=includes)]
@@ -527,7 +527,7 b' class GitRepository(BaseRepository):'
527
527
528 """
528 """
529 if branch_name and branch_name not in self.branches:
529 if branch_name and branch_name not in self.branches:
530 raise BranchDoesNotExistError("Branch '%s' not found" \
530 raise BranchDoesNotExistError("Branch '%s' not found"
531 % branch_name)
531 % branch_name)
532 # actually we should check now if it's not an empty repo to not spaw
532 # actually we should check now if it's not an empty repo to not spaw
533 # subprocess commands
533 # subprocess commands
@@ -18,6 +18,7 b' from kallithea.lib.vcs.utils.hgcompat im'
18
18
19 from mercurial import obsolete
19 from mercurial import obsolete
20
20
21
21 class MercurialChangeset(BaseChangeset):
22 class MercurialChangeset(BaseChangeset):
22 """
23 """
23 Represents state of the repository at the single revision.
24 Represents state of the repository at the single revision.
@@ -37,7 +38,7 b' class MercurialChangeset(BaseChangeset):'
37
38
38 @LazyProperty
39 @LazyProperty
39 def branch(self):
40 def branch(self):
40 return safe_unicode(self._ctx.branch())
41 return safe_unicode(self._ctx.branch())
41
42
42 @LazyProperty
43 @LazyProperty
43 def closesbranch(self):
44 def closesbranch(self):
@@ -411,7 +412,7 b' class MercurialChangeset(BaseChangeset):'
411 """
412 """
412 Returns list of modified ``FileNode`` objects.
413 Returns list of modified ``FileNode`` objects.
413 """
414 """
414 return ChangedFileNodesGenerator([n for n in self.status[0]], self)
415 return ChangedFileNodesGenerator([n for n in self.status[0]], self)
415
416
416 @property
417 @property
417 def removed(self):
418 def removed(self):
@@ -300,7 +300,7 b' class MercurialRepository(BaseRepository'
300 cleaned_uri = str(url_obj)
300 cleaned_uri = str(url_obj)
301
301
302 if authinfo:
302 if authinfo:
303 #create a password manager
303 # create a password manager
304 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
304 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
305 passmgr.add_password(*authinfo)
305 passmgr.add_password(*authinfo)
306
306
@@ -395,7 +395,7 b' class MercurialRepository(BaseRepository'
395 try:
395 try:
396 return time.mktime(self.get_changeset().date.timetuple())
396 return time.mktime(self.get_changeset().date.timetuple())
397 except RepositoryError:
397 except RepositoryError:
398 #fallback to filesystem
398 # fallback to filesystem
399 cl_path = os.path.join(self.path, '.hg', "00changelog.i")
399 cl_path = os.path.join(self.path, '.hg', "00changelog.i")
400 st_path = os.path.join(self.path, '.hg', "store")
400 st_path = os.path.join(self.path, '.hg', "store")
401 if os.path.exists(cl_path):
401 if os.path.exists(cl_path):
@@ -529,7 +529,7 b' class MercurialRepository(BaseRepository'
529 raise BranchDoesNotExistError(msg)
529 raise BranchDoesNotExistError(msg)
530 if end_pos is not None:
530 if end_pos is not None:
531 end_pos += 1
531 end_pos += 1
532 #filter branches
532 # filter branches
533 filter_ = []
533 filter_ = []
534 if branch_name:
534 if branch_name:
535 filter_.append('branch("%s")' % (branch_name))
535 filter_.append('branch("%s")' % (branch_name))
@@ -328,7 +328,7 b' class FileNode(Node):'
328 mtype = 'text/plain'
328 mtype = 'text/plain'
329 encoding = None
329 encoding = None
330
330
331 #try with pygments
331 # try with pygments
332 try:
332 try:
333 from pygments import lexers
333 from pygments import lexers
334 mt = lexers.get_lexer_for_filename(self.name).mimetypes
334 mt = lexers.get_lexer_for_filename(self.name).mimetypes
@@ -609,7 +609,7 b' class SubModuleNode(Node):'
609
609
610 def _extract_submodule_url(self):
610 def _extract_submodule_url(self):
611 if self.alias == 'git':
611 if self.alias == 'git':
612 #TODO: find a way to parse gits submodule file and extract the
612 # TODO: find a way to parse gits submodule file and extract the
613 # linking URL
613 # linking URL
614 return self.path
614 return self.path
615 if self.alias == 'hg':
615 if self.alias == 'hg':
@@ -45,7 +45,7 b' class StreamFeeder(threading.Thread):'
45 self.bytes = bytes(source)
45 self.bytes = bytes(source)
46 else: # can be either file pointer or file-like
46 else: # can be either file pointer or file-like
47 if type(source) in (int, long): # file pointer it is
47 if type(source) in (int, long): # file pointer it is
48 ## converting file descriptor (int) stdin into file-like
48 # converting file descriptor (int) stdin into file-like
49 source = os.fdopen(source, 'rb', 16384)
49 source = os.fdopen(source, 'rb', 16384)
50 # let's see if source is file-like by now
50 # let's see if source is file-like by now
51 filelike = hasattr(source, 'read')
51 filelike = hasattr(source, 'read')
@@ -157,6 +157,7 b' email_re = re.compile('
157 r"""(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?""",
157 r"""(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?""",
158 re.IGNORECASE)
158 re.IGNORECASE)
159
159
160
160 def author_email(author):
161 def author_email(author):
161 """
162 """
162 Returns email address of given author string.
163 Returns email address of given author string.
@@ -122,7 +122,7 b' class AnnotateHtmlFormatter(HtmlFormatte'
122 for i in range(fl, fl + lncount):
122 for i in range(fl, fl + lncount):
123 if i % st == 0:
123 if i % st == 0:
124 if aln:
124 if aln:
125 lines.append('<a href="#%s-%d">%*d</a>' \
125 lines.append('<a href="#%s-%d">%*d</a>'
126 % (la, i, mw, i))
126 % (la, i, mw, i))
127 else:
127 else:
128 lines.append('%*d' % (mw, i))
128 lines.append('%*d' % (mw, i))
@@ -134,7 +134,7 b' class AnnotateHtmlFormatter(HtmlFormatte'
134 # If pygments cropped last lines break we need do that too
134 # If pygments cropped last lines break we need do that too
135 ln_cs = len(annotate_changesets)
135 ln_cs = len(annotate_changesets)
136 ln_ = len(ls.splitlines())
136 ln_ = len(ls.splitlines())
137 if ln_cs > ln_:
137 if ln_cs > ln_:
138 annotate_changesets = annotate_changesets[:ln_ - ln_cs]
138 annotate_changesets = annotate_changesets[:ln_ - ln_cs]
139 annotate = ''.join((self.annotate_from_changeset(changeset)
139 annotate = ''.join((self.annotate_from_changeset(changeset)
140 for changeset in annotate_changesets))
140 for changeset in annotate_changesets))
@@ -160,7 +160,7 b' class DiffProcessor(object):'
160 l.extend(output[1].splitlines(1))
160 l.extend(output[1].splitlines(1))
161 return map(line_decoder, l)
161 return map(line_decoder, l)
162 elif size == 1:
162 elif size == 1:
163 return map(line_decoder, output[0].splitlines(1))
163 return map(line_decoder, output[0].splitlines(1))
164 elif size == 0:
164 elif size == 0:
165 return []
165 return []
166
166
@@ -4,7 +4,7 b' Mercurial libs compatibility'
4
4
5 import mercurial
5 import mercurial
6 import mercurial.demandimport
6 import mercurial.demandimport
7 ## patch demandimport, due to bug in mercurial when it always triggers demandimport.enable()
7 # patch demandimport, due to bug in mercurial when it always triggers demandimport.enable()
8 mercurial.demandimport.enable = lambda *args, **kwargs: 1
8 mercurial.demandimport.enable = lambda *args, **kwargs: 1
9 from mercurial import archival, merge as hg_merge, patch, ui
9 from mercurial import archival, merge as hg_merge, patch, ui
10 from mercurial import discovery
10 from mercurial import discovery
@@ -37,7 +37,8 b' from mercurial.url import httpbasicauthh'
37 import inspect
37 import inspect
38 # Mercurial 3.1 503bb3af70fe
38 # Mercurial 3.1 503bb3af70fe
39 if inspect.getargspec(memfilectx.__init__).args[1] != 'repo':
39 if inspect.getargspec(memfilectx.__init__).args[1] != 'repo':
40 _org__init__=memfilectx.__init__
40 _org__init__ = memfilectx.__init__
41
41 def _memfilectx__init__(self, repo, *a, **b):
42 def _memfilectx__init__(self, repo, *a, **b):
42 return _org__init__(self, *a, **b)
43 return _org__init__(self, *a, **b)
43 memfilectx.__init__ = _memfilectx__init__
44 memfilectx.__init__ = _memfilectx__init__
@@ -9,6 +9,7 b' class _Missing(object):'
9 def __reduce__(self):
9 def __reduce__(self):
10 return '_missing'
10 return '_missing'
11
11
12
12 _missing = _Missing()
13 _missing = _Missing()
13
14
14
15
@@ -10,6 +10,7 b' from kallithea.lib.vcs.utils.helpers imp'
10 class ProgressBarError(Exception):
10 class ProgressBarError(Exception):
11 pass
11 pass
12
12
13
13 class AlreadyFinishedError(ProgressBarError):
14 class AlreadyFinishedError(ProgressBarError):
14 pass
15 pass
15
16
@@ -179,6 +180,7 b" background = dict([(color_names[x], '4%s"
179 RESET = '0'
180 RESET = '0'
180 opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
181 opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
181
182
183
182 def colorize(text='', opts=(), **kwargs):
184 def colorize(text='', opts=(), **kwargs):
183 """
185 """
184 Returns your text, enclosed in ANSI graphics codes.
186 Returns your text, enclosed in ANSI graphics codes.
@@ -223,6 +225,7 b" def colorize(text='', opts=(), **kwargs)"
223 text = text + '\x1b[%sm' % RESET
225 text = text + '\x1b[%sm' % RESET
224 return ('\x1b[%sm' % ';'.join(code_list)) + text
226 return ('\x1b[%sm' % ';'.join(code_list)) + text
225
227
228
226 def make_style(opts=(), **kwargs):
229 def make_style(opts=(), **kwargs):
227 """
230 """
228 Returns a function with default parameters for colorize()
231 Returns a function with default parameters for colorize()
@@ -235,6 +238,7 b' def make_style(opts=(), **kwargs):'
235 """
238 """
236 return lambda text: colorize(text, opts, **kwargs)
239 return lambda text: colorize(text, opts, **kwargs)
237
240
241
238 NOCOLOR_PALETTE = 'nocolor'
242 NOCOLOR_PALETTE = 'nocolor'
239 DARK_PALETTE = 'dark'
243 DARK_PALETTE = 'dark'
240 LIGHT_PALETTE = 'light'
244 LIGHT_PALETTE = 'light'
@@ -348,7 +352,6 b' class BarOnlyColoredProgressBar(ColoredP'
348 pass
352 pass
349
353
350
354
351
352 def main():
355 def main():
353 import time
356 import time
354
357
@@ -11,6 +11,7 b" background = dict([(color_names[x], '4%s"
11 RESET = '0'
11 RESET = '0'
12 opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
12 opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
13
13
14
14 def colorize(text='', opts=(), **kwargs):
15 def colorize(text='', opts=(), **kwargs):
15 """
16 """
16 Returns your text, enclosed in ANSI graphics codes.
17 Returns your text, enclosed in ANSI graphics codes.
@@ -55,6 +56,7 b" def colorize(text='', opts=(), **kwargs)"
55 text = text + '\x1b[%sm' % RESET
56 text = text + '\x1b[%sm' % RESET
56 return ('\x1b[%sm' % ';'.join(code_list)) + text
57 return ('\x1b[%sm' % ';'.join(code_list)) + text
57
58
59
58 def make_style(opts=(), **kwargs):
60 def make_style(opts=(), **kwargs):
59 """
61 """
60 Returns a function with default parameters for colorize()
62 Returns a function with default parameters for colorize()
@@ -67,6 +69,7 b' def make_style(opts=(), **kwargs):'
67 """
69 """
68 return lambda text: colorize(text, opts, **kwargs)
70 return lambda text: colorize(text, opts, **kwargs)
69
71
72
70 NOCOLOR_PALETTE = 'nocolor'
73 NOCOLOR_PALETTE = 'nocolor'
71 DARK_PALETTE = 'dark'
74 DARK_PALETTE = 'dark'
72 LIGHT_PALETTE = 'light'
75 LIGHT_PALETTE = 'light'
@@ -120,6 +123,7 b' PALETTES = {'
120 }
123 }
121 DEFAULT_PALETTE = DARK_PALETTE
124 DEFAULT_PALETTE = DARK_PALETTE
122
125
126
123 def parse_color_setting(config_string):
127 def parse_color_setting(config_string):
124 """Parse a DJANGO_COLORS environment variable to produce the system palette
128 """Parse a DJANGO_COLORS environment variable to produce the system palette
125
129
@@ -5,10 +5,12 b' discussion at PyCon 2009.'
5
5
6 import re
6 import re
7
7
8
8 class IrrationalVersionError(Exception):
9 class IrrationalVersionError(Exception):
9 """This is an irrational version."""
10 """This is an irrational version."""
10 pass
11 pass
11
12
13
12 class HugeMajorVersionNumError(IrrationalVersionError):
14 class HugeMajorVersionNumError(IrrationalVersionError):
13 """An irrational version because the major version number is huge
15 """An irrational version because the major version number is huge
14 (often because a year or date was used).
16 (often because a year or date was used).
@@ -18,6 +20,7 b' class HugeMajorVersionNumError(Irrationa'
18 """
20 """
19 pass
21 pass
20
22
23
21 # A marker used in the second and third parts of the `parts` tuple, for
24 # A marker used in the second and third parts of the `parts` tuple, for
22 # versions that don't have those segments, to sort properly. An example
25 # versions that don't have those segments, to sort properly. An example
23 # of versions in sort order ('highest' last):
26 # of versions in sort order ('highest' last):
@@ -47,6 +50,7 b" VERSION_RE = re.compile(r'''"
47 (?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)?
50 (?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)?
48 $''', re.VERBOSE)
51 $''', re.VERBOSE)
49
52
53
50 class NormalizedVersion(object):
54 class NormalizedVersion(object):
51 """A rational version.
55 """A rational version.
52
56
@@ -212,6 +216,7 b' class NormalizedVersion(object):'
212 def __ge__(self, other):
216 def __ge__(self, other):
213 return self.__eq__(other) or self.__gt__(other)
217 return self.__eq__(other) or self.__gt__(other)
214
218
219
215 def suggest_normalized_version(s):
220 def suggest_normalized_version(s):
216 """Suggest a normalized version close to the given version string.
221 """Suggest a normalized version close to the given version string.
217
222
@@ -267,7 +272,7 b' def suggest_normalized_version(s):'
267 rs = rs[1:]
272 rs = rs[1:]
268
273
269 # Clean leading '0's on numbers.
274 # Clean leading '0's on numbers.
270 #TODO: unintended side-effect on, e.g., "2003.05.09"
275 # TODO: unintended side-effect on, e.g., "2003.05.09"
271 # PyPI stats: 77 (~2%) better
276 # PyPI stats: 77 (~2%) better
272 rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs)
277 rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs)
273
278
@@ -313,7 +318,6 b' def suggest_normalized_version(s):'
313 # PyPI stats: ~21 (0.62%) better
318 # PyPI stats: ~21 (0.62%) better
314 rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs)
319 rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs)
315
320
316
317 # Tcl/Tk uses "px" for their post release markers
321 # Tcl/Tk uses "px" for their post release markers
318 rs = re.sub(r"p(\d+)$", r".post\1", rs)
322 rs = re.sub(r"p(\d+)$", r".post\1", rs)
319
323
@@ -165,7 +165,7 b' class ChangesetStatusModel(object):'
165 revisions = pull_request.revisions
165 revisions = pull_request.revisions
166 cur_statuses = q.all()
166 cur_statuses = q.all()
167
167
168 #if statuses exists and last is associated with a closed pull request
168 # if statuses exists and last is associated with a closed pull request
169 # we need to check if we can allow this status change
169 # we need to check if we can allow this status change
170 if (dont_allow_on_closed_pull_request and cur_statuses
170 if (dont_allow_on_closed_pull_request and cur_statuses
171 and getattr(cur_statuses[0].pull_request, 'status', '')
171 and getattr(cur_statuses[0].pull_request, 'status', '')
@@ -174,7 +174,7 b' class ChangesetStatusModel(object):'
174 'Changing status on closed pull request is not allowed'
174 'Changing status on closed pull request is not allowed'
175 )
175 )
176
176
177 #update all current statuses with older version
177 # update all current statuses with older version
178 for st in cur_statuses:
178 for st in cur_statuses:
179 st.version += 1
179 st.version += 1
180
180
@@ -67,7 +67,7 b' class ChangesetCommentsModel(object):'
67 if line_no:
67 if line_no:
68 line = _('on line %s') % line_no
68 line = _('on line %s') % line_no
69
69
70 #changeset
70 # changeset
71 if revision:
71 if revision:
72 notification_type = Notification.TYPE_CHANGESET_COMMENT
72 notification_type = Notification.TYPE_CHANGESET_COMMENT
73 cs = repo.scm_instance.get_changeset(revision)
73 cs = repo.scm_instance.get_changeset(revision)
@@ -91,7 +91,7 b' class ChangesetCommentsModel(object):'
91 # add changeset author if it's known locally
91 # add changeset author if it's known locally
92 cs_author = User.get_from_cs_author(cs.author)
92 cs_author = User.get_from_cs_author(cs.author)
93 if not cs_author:
93 if not cs_author:
94 #use repo owner if we cannot extract the author correctly
94 # use repo owner if we cannot extract the author correctly
95 # FIXME: just use committer name even if not a user
95 # FIXME: just use committer name even if not a user
96 cs_author = repo.owner
96 cs_author = repo.owner
97 recipients.append(cs_author)
97 recipients.append(cs_author)
@@ -112,7 +112,7 b' class ChangesetCommentsModel(object):'
112 'comment_username': author.username,
112 'comment_username': author.username,
113 'threading': threading,
113 'threading': threading,
114 }
114 }
115 #pull request
115 # pull request
116 elif pull_request:
116 elif pull_request:
117 notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
117 notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
118 desc = comment.pull_request.title
118 desc = comment.pull_request.title
@@ -128,7 +128,7 b' class ChangesetCommentsModel(object):'
128 comment_url = pull_request.url(canonical=True,
128 comment_url = pull_request.url(canonical=True,
129 anchor='comment-%s' % comment.comment_id)
129 anchor='comment-%s' % comment.comment_id)
130 subj = safe_unicode(
130 subj = safe_unicode(
131 h.link_to('Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % \
131 h.link_to('Re pull request %(pr_nice_id)s: %(desc)s %(line)s' %
132 {'desc': desc,
132 {'desc': desc,
133 'pr_nice_id': comment.pull_request.nice_id(),
133 'pr_nice_id': comment.pull_request.nice_id(),
134 'line': line},
134 'line': line},
@@ -139,7 +139,7 b' class ChangesetCommentsModel(object):'
139 recipients.append(pull_request.owner)
139 recipients.append(pull_request.owner)
140 recipients += pull_request.get_reviewer_users()
140 recipients += pull_request.get_reviewer_users()
141
141
142 #set some variables for email notification
142 # set some variables for email notification
143 email_kwargs = {
143 email_kwargs = {
144 'pr_title': pull_request.title,
144 'pr_title': pull_request.title,
145 'pr_title_short': h.shorter(pull_request.title, 50),
145 'pr_title_short': h.shorter(pull_request.title, 50),
@@ -457,12 +457,11 b' class User(Base, BaseDbModel):'
457 user_created_notifications = relationship('Notification', cascade='all')
457 user_created_notifications = relationship('Notification', cascade='all')
458 # comments created by this user
458 # comments created by this user
459 user_comments = relationship('ChangesetComment', cascade='all')
459 user_comments = relationship('ChangesetComment', cascade='all')
460 #extra emails for this user
460 # extra emails for this user
461 user_emails = relationship('UserEmailMap', cascade='all')
461 user_emails = relationship('UserEmailMap', cascade='all')
462 #extra API keys
462 # extra API keys
463 user_api_keys = relationship('UserApiKeys', cascade='all')
463 user_api_keys = relationship('UserApiKeys', cascade='all')
464
464
465
466 @hybrid_property
465 @hybrid_property
467 def email(self):
466 def email(self):
468 return self._email
467 return self._email
@@ -478,12 +477,12 b' class User(Base, BaseDbModel):'
478
477
479 @property
478 @property
480 def emails(self):
479 def emails(self):
481 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
480 other = UserEmailMap.query().filter(UserEmailMap.user == self).all()
482 return [self.email] + [x.email for x in other]
481 return [self.email] + [x.email for x in other]
483
482
484 @property
483 @property
485 def api_keys(self):
484 def api_keys(self):
486 other = UserApiKeys.query().filter(UserApiKeys.user==self).all()
485 other = UserApiKeys.query().filter(UserApiKeys.user == self).all()
487 return [self.api_key] + [x.api_key for x in other]
486 return [self.api_key] + [x.api_key for x in other]
488
487
489 @property
488 @property
@@ -615,7 +614,7 b' class User(Base, BaseDbModel):'
615 res = q.scalar()
614 res = q.scalar()
616
615
617 if fallback and not res:
616 if fallback and not res:
618 #fallback to additional keys
617 # fallback to additional keys
619 _res = UserApiKeys.query().filter_by(api_key=api_key, is_expired=False).first()
618 _res = UserApiKeys.query().filter_by(api_key=api_key, is_expired=False).first()
620 if _res:
619 if _res:
621 res = _res.user
620 res = _res.user
@@ -801,6 +800,7 b' class UserIpMap(Base, BaseDbModel):'
801 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
800 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
802 self.user_id, self.ip_addr)
801 self.user_id, self.ip_addr)
803
802
803
804 class UserLog(Base, BaseDbModel):
804 class UserLog(Base, BaseDbModel):
805 __tablename__ = 'user_logs'
805 __tablename__ = 'user_logs'
806 __table_args__ = (
806 __table_args__ = (
@@ -1752,7 +1752,7 b' class Permission(Base, BaseDbModel):'
1752 ('hg.extern_activate.auto', _('Automatic activation of external account')),
1752 ('hg.extern_activate.auto', _('Automatic activation of external account')),
1753 ]
1753 ]
1754
1754
1755 #definition of system default permissions for DEFAULT user
1755 # definition of system default permissions for DEFAULT user
1756 DEFAULT_USER_PERMISSIONS = [
1756 DEFAULT_USER_PERMISSIONS = [
1757 'repository.read',
1757 'repository.read',
1758 'group.read',
1758 'group.read',
@@ -2051,9 +2051,9 b' class Statistics(Base, BaseDbModel):'
2051 stat_id = Column(Integer(), primary_key=True)
2051 stat_id = Column(Integer(), primary_key=True)
2052 repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True)
2052 repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True)
2053 stat_on_revision = Column(Integer(), nullable=False)
2053 stat_on_revision = Column(Integer(), nullable=False)
2054 commit_activity = Column(LargeBinary(1000000), nullable=False)#JSON data
2054 commit_activity = Column(LargeBinary(1000000), nullable=False) # JSON data
2055 commit_activity_combined = Column(LargeBinary(), nullable=False)#JSON data
2055 commit_activity_combined = Column(LargeBinary(), nullable=False) # JSON data
2056 languages = Column(LargeBinary(1000000), nullable=False)#JSON data
2056 languages = Column(LargeBinary(1000000), nullable=False) # JSON data
2057
2057
2058 repository = relationship('Repository', single_parent=True)
2058 repository = relationship('Repository', single_parent=True)
2059
2059
@@ -2455,6 +2455,7 b' class PullRequest(Base, BaseDbModel):'
2455 return h.url('pullrequest_show', repo_name=self.other_repo.repo_name,
2455 return h.url('pullrequest_show', repo_name=self.other_repo.repo_name,
2456 pull_request_id=self.pull_request_id, **kwargs)
2456 pull_request_id=self.pull_request_id, **kwargs)
2457
2457
2458
2458 class PullRequestReviewer(Base, BaseDbModel):
2459 class PullRequestReviewer(Base, BaseDbModel):
2459 __tablename__ = 'pull_request_reviewers'
2460 __tablename__ = 'pull_request_reviewers'
2460 __table_args__ = (
2461 __table_args__ = (
@@ -90,6 +90,7 b' def PasswordChangeForm(username):'
90
90
91 def UserForm(edit=False, old_data=None):
91 def UserForm(edit=False, old_data=None):
92 old_data = old_data or {}
92 old_data = old_data or {}
93
93 class _UserForm(formencode.Schema):
94 class _UserForm(formencode.Schema):
94 allow_extra_fields = True
95 allow_extra_fields = True
95 filter_extra_fields = True
96 filter_extra_fields = True
@@ -131,6 +132,7 b' def UserForm(edit=False, old_data=None):'
131 def UserGroupForm(edit=False, old_data=None, available_members=None):
132 def UserGroupForm(edit=False, old_data=None, available_members=None):
132 old_data = old_data or {}
133 old_data = old_data or {}
133 available_members = available_members or []
134 available_members = available_members or []
135
134 class _UserGroupForm(formencode.Schema):
136 class _UserGroupForm(formencode.Schema):
135 allow_extra_fields = True
137 allow_extra_fields = True
136 filter_extra_fields = True
138 filter_extra_fields = True
@@ -158,6 +160,7 b' def RepoGroupForm(edit=False, old_data=N'
158 old_data = old_data or {}
160 old_data = old_data or {}
159 repo_groups = repo_groups or []
161 repo_groups = repo_groups or []
160 repo_group_ids = [rg[0] for rg in repo_groups]
162 repo_group_ids = [rg[0] for rg in repo_groups]
163
161 class _RepoGroupForm(formencode.Schema):
164 class _RepoGroupForm(formencode.Schema):
162 allow_extra_fields = True
165 allow_extra_fields = True
163 filter_extra_fields = False
166 filter_extra_fields = False
@@ -170,8 +173,8 b' def RepoGroupForm(edit=False, old_data=N'
170 group_copy_permissions = v.StringBoolean(if_missing=False)
173 group_copy_permissions = v.StringBoolean(if_missing=False)
171
174
172 if edit:
175 if edit:
173 #FIXME: do a special check that we cannot move a group to one of
176 # FIXME: do a special check that we cannot move a group to one of
174 #its children
177 # its children
175 pass
178 pass
176
179
177 parent_group_id = All(v.CanCreateGroup(can_create_in_root),
180 parent_group_id = All(v.CanCreateGroup(can_create_in_root),
@@ -219,6 +222,7 b' def PasswordResetRequestForm():'
219 email = v.Email(not_empty=True)
222 email = v.Email(not_empty=True)
220 return _PasswordResetRequestForm
223 return _PasswordResetRequestForm
221
224
225
222 def PasswordResetConfirmationForm():
226 def PasswordResetConfirmationForm():
223 class _PasswordResetConfirmationForm(formencode.Schema):
227 class _PasswordResetConfirmationForm(formencode.Schema):
224 allow_extra_fields = True
228 allow_extra_fields = True
@@ -234,12 +238,14 b' def PasswordResetConfirmationForm():'
234 'password_confirm')]
238 'password_confirm')]
235 return _PasswordResetConfirmationForm
239 return _PasswordResetConfirmationForm
236
240
241
237 def RepoForm(edit=False, old_data=None, supported_backends=BACKENDS.keys(),
242 def RepoForm(edit=False, old_data=None, supported_backends=BACKENDS.keys(),
238 repo_groups=None, landing_revs=None):
243 repo_groups=None, landing_revs=None):
239 old_data = old_data or {}
244 old_data = old_data or {}
240 repo_groups = repo_groups or []
245 repo_groups = repo_groups or []
241 landing_revs = landing_revs or []
246 landing_revs = landing_revs or []
242 repo_group_ids = [rg[0] for rg in repo_groups]
247 repo_group_ids = [rg[0] for rg in repo_groups]
248
243 class _RepoForm(formencode.Schema):
249 class _RepoForm(formencode.Schema):
244 allow_extra_fields = True
250 allow_extra_fields = True
245 filter_extra_fields = False
251 filter_extra_fields = False
@@ -317,6 +323,7 b' def RepoForkForm(edit=False, old_data=No'
317 repo_groups = repo_groups or []
323 repo_groups = repo_groups or []
318 landing_revs = landing_revs or []
324 landing_revs = landing_revs or []
319 repo_group_ids = [rg[0] for rg in repo_groups]
325 repo_group_ids = [rg[0] for rg in repo_groups]
326
320 class _RepoForkForm(formencode.Schema):
327 class _RepoForkForm(formencode.Schema):
321 allow_extra_fields = True
328 allow_extra_fields = True
322 filter_extra_fields = False
329 filter_extra_fields = False
@@ -466,7 +473,7 b' def AuthSettingsForm(current_active_modu'
466 validator = sv["validator"]
473 validator = sv["validator"]
467 if isinstance(validator, LazyFormencode):
474 if isinstance(validator, LazyFormencode):
468 validator = validator()
475 validator = validator()
469 #init all lazy validators from formencode.All
476 # init all lazy validators from formencode.All
470 if isinstance(validator, All):
477 if isinstance(validator, All):
471 init_validators = []
478 init_validators = []
472 for validator in validator.validators:
479 for validator in validator.validators:
@@ -114,7 +114,7 b' class GistModel(object):'
114 log.debug('set GIST expiration date to: %s',
114 log.debug('set GIST expiration date to: %s',
115 time_to_datetime(gist_expires)
115 time_to_datetime(gist_expires)
116 if gist_expires != -1 else 'forever')
116 if gist_expires != -1 else 'forever')
117 #create the Database version
117 # create the Database version
118 gist = Gist()
118 gist = Gist()
119 gist.gist_description = description
119 gist.gist_description = description
120 gist.gist_access_id = gist_id
120 gist.gist_access_id = gist_id
@@ -139,7 +139,7 b' class GistModel(object):'
139 raise Exception('Filename cannot be inside a directory')
139 raise Exception('Filename cannot be inside a directory')
140
140
141 content = gist_mapping[filename]['content']
141 content = gist_mapping[filename]['content']
142 #TODO: expand support for setting explicit lexers
142 # TODO: expand support for setting explicit lexers
143 # if lexer is None:
143 # if lexer is None:
144 # try:
144 # try:
145 # guess_lexer = pygments.lexers.guess_lexer_for_filename
145 # guess_lexer = pygments.lexers.guess_lexer_for_filename
@@ -153,7 +153,7 b' class GistModel(object):'
153 message += 's: ' if len(processed_mapping) > 1 else ': '
153 message += 's: ' if len(processed_mapping) > 1 else ': '
154 message += ', '.join([x for x in processed_mapping])
154 message += ', '.join([x for x in processed_mapping])
155
155
156 #fake Kallithea Repository object
156 # fake Kallithea Repository object
157 fake_repo = AttributeDict(dict(
157 fake_repo = AttributeDict(dict(
158 repo_name=gist_repo_path,
158 repo_name=gist_repo_path,
159 scm_instance_no_cache=lambda: repo,
159 scm_instance_no_cache=lambda: repo,
@@ -192,7 +192,7 b' class GistModel(object):'
192 else:
192 else:
193 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
193 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
194
194
195 #calculate operation type based on given data
195 # calculate operation type based on given data
196 gist_mapping_op = {}
196 gist_mapping_op = {}
197 for k, v in gist_mapping.items():
197 for k, v in gist_mapping.items():
198 # add, mod, del
198 # add, mod, del
@@ -215,7 +215,7 b' class GistModel(object):'
215 message += 's: ' if len(gist_mapping) > 1 else ': '
215 message += 's: ' if len(gist_mapping) > 1 else ': '
216 message += ', '.join([x for x in gist_mapping])
216 message += ', '.join([x for x in gist_mapping])
217
217
218 #fake Kallithea Repository object
218 # fake Kallithea Repository object
219 fake_repo = AttributeDict(dict(
219 fake_repo = AttributeDict(dict(
220 repo_name=gist_repo.path,
220 repo_name=gist_repo.path,
221 scm_instance_no_cache=lambda: gist_repo,
221 scm_instance_no_cache=lambda: gist_repo,
@@ -38,8 +38,8 b' Session = scoped_session(session_factory'
38 # Engine is injected when model.__init__.init_model() sets meta.Base.metadata.bind
38 # Engine is injected when model.__init__.init_model() sets meta.Base.metadata.bind
39 Base = declarative_base()
39 Base = declarative_base()
40
40
41 #to use cache use this in query
41 # to use cache use this in query:
42 #.options(FromCache("sqlalchemy_cache_type", "cachekey"))
42 # .options(FromCache("sqlalchemy_cache_type", "cachekey"))
43
43
44
44
45 # Define naming conventions for foreign keys, primary keys, indexes,
45 # Define naming conventions for foreign keys, primary keys, indexes,
@@ -98,7 +98,7 b' class NotificationModel(object):'
98 if not with_email:
98 if not with_email:
99 return notif
99 return notif
100
100
101 #don't send email to person who created this comment
101 # don't send email to person who created this comment
102 rec_objs = set(recipients_objs).difference(set([created_by_obj]))
102 rec_objs = set(recipients_objs).difference(set([created_by_obj]))
103
103
104 headers = {}
104 headers = {}
@@ -108,7 +108,7 b' class NotificationModel(object):'
108
108
109 # send email with notification to all other participants
109 # send email with notification to all other participants
110 for rec in rec_objs:
110 for rec in rec_objs:
111 ## this is passed into template
111 # this is passed into template
112 html_kwargs = {
112 html_kwargs = {
113 'subject': subject,
113 'subject': subject,
114 'body': h.render_w_mentions(body, repo_name),
114 'body': h.render_w_mentions(body, repo_name),
@@ -232,7 +232,7 b' class NotificationModel(object):'
232 Creates a human readable description based on properties
232 Creates a human readable description based on properties
233 of notification object
233 of notification object
234 """
234 """
235 #alias
235 # alias
236 _n = notification
236 _n = notification
237
237
238 if show_age:
238 if show_age:
@@ -116,13 +116,13 b' class PermissionModel(object):'
116 .all()
116 .all()
117 for p in u2p:
117 for p in u2p:
118 Session().delete(p)
118 Session().delete(p)
119 #create fresh set of permissions
119 # create fresh set of permissions
120 for def_perm_key in ['default_repo_perm',
120 for def_perm_key in ['default_repo_perm',
121 'default_group_perm',
121 'default_group_perm',
122 'default_user_group_perm',
122 'default_user_group_perm',
123 'default_repo_create',
123 'default_repo_create',
124 'create_on_write', # special case for create repos on write access to group
124 'create_on_write', # special case for create repos on write access to group
125 #'default_repo_group_create', #not implemented yet
125 #'default_repo_group_create', # not implemented yet
126 'default_user_group_create',
126 'default_user_group_create',
127 'default_fork',
127 'default_fork',
128 'default_register',
128 'default_register',
@@ -130,7 +130,7 b' class PermissionModel(object):'
130 p = _make_new(perm_user, form_result[def_perm_key])
130 p = _make_new(perm_user, form_result[def_perm_key])
131 Session().add(p)
131 Session().add(p)
132
132
133 #stage 3 update all default permissions for repos if checked
133 # stage 3 update all default permissions for repos if checked
134 if form_result['overwrite_default_repo']:
134 if form_result['overwrite_default_repo']:
135 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
135 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
136 _def = Permission.get_by_key('repository.' + _def_name)
136 _def = Permission.get_by_key('repository.' + _def_name)
@@ -139,7 +139,7 b' class PermissionModel(object):'
139 .filter(UserRepoToPerm.user == perm_user) \
139 .filter(UserRepoToPerm.user == perm_user) \
140 .all():
140 .all():
141
141
142 #don't reset PRIVATE repositories
142 # don't reset PRIVATE repositories
143 if not r2p.repository.private:
143 if not r2p.repository.private:
144 r2p.permission = _def
144 r2p.permission = _def
145
145
@@ -61,12 +61,12 b' class PullRequestModel(object):'
61 mention_recipients = set(mention_recipients) - reviewers
61 mention_recipients = set(mention_recipients) - reviewers
62 _assert_valid_reviewers(mention_recipients)
62 _assert_valid_reviewers(mention_recipients)
63
63
64 #members
64 # members
65 for reviewer in reviewers:
65 for reviewer in reviewers:
66 prr = PullRequestReviewer(reviewer, pr)
66 prr = PullRequestReviewer(reviewer, pr)
67 Session().add(prr)
67 Session().add(prr)
68
68
69 #notification to reviewers
69 # notification to reviewers
70 pr_url = pr.url(canonical=True)
70 pr_url = pr.url(canonical=True)
71 threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name,
71 threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name,
72 pr.pull_request_id,
72 pr.pull_request_id,
@@ -265,7 +265,7 b' class CreatePullRequestAction(object):'
265 # create a ref under refs/pull/ so that commits don't get garbage-collected
265 # create a ref under refs/pull/ so that commits don't get garbage-collected
266 self.org_repo.scm_instance._repo["refs/pull/%d/head" % pr.pull_request_id] = safe_str(self.org_rev)
266 self.org_repo.scm_instance._repo["refs/pull/%d/head" % pr.pull_request_id] = safe_str(self.org_rev)
267
267
268 #reset state to under-review
268 # reset state to under-review
269 from kallithea.model.changeset_status import ChangesetStatusModel
269 from kallithea.model.changeset_status import ChangesetStatusModel
270 from kallithea.model.comment import ChangesetCommentsModel
270 from kallithea.model.comment import ChangesetCommentsModel
271 comment = ChangesetCommentsModel().create(
271 comment = ChangesetCommentsModel().create(
@@ -317,13 +317,13 b' class RepoModel(object):'
317 if 'repo_name' in kwargs:
317 if 'repo_name' in kwargs:
318 cur_repo.repo_name = cur_repo.get_new_name(kwargs['repo_name'])
318 cur_repo.repo_name = cur_repo.get_new_name(kwargs['repo_name'])
319
319
320 #if private flag is set, reset default permission to NONE
320 # if private flag is set, reset default permission to NONE
321 if kwargs.get('repo_private'):
321 if kwargs.get('repo_private'):
322 EMPTY_PERM = 'repository.none'
322 EMPTY_PERM = 'repository.none'
323 RepoModel().grant_user_permission(
323 RepoModel().grant_user_permission(
324 repo=cur_repo, user='default', perm=EMPTY_PERM
324 repo=cur_repo, user='default', perm=EMPTY_PERM
325 )
325 )
326 #handle extra fields
326 # handle extra fields
327 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
327 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
328 kwargs):
328 kwargs):
329 k = RepositoryField.un_prefix_key(field)
329 k = RepositoryField.un_prefix_key(field)
@@ -460,7 +460,7 b' class RepoModel(object):'
460 repo=repo, user=member, perm=perm
460 repo=repo, user=member, perm=perm
461 )
461 )
462 else:
462 else:
463 #check if we have permissions to alter this usergroup's access
463 # check if we have permissions to alter this usergroup's access
464 if not check_perms or HasUserGroupPermissionLevel('read')(member):
464 if not check_perms or HasUserGroupPermissionLevel('read')(member):
465 self.grant_user_group_permission(
465 self.grant_user_group_permission(
466 repo=repo, group_name=member, perm=perm
466 repo=repo, group_name=member, perm=perm
@@ -472,7 +472,7 b' class RepoModel(object):'
472 repo=repo, user=member, perm=perm
472 repo=repo, user=member, perm=perm
473 )
473 )
474 else:
474 else:
475 #check if we have permissions to alter this usergroup's access
475 # check if we have permissions to alter this usergroup's access
476 if not check_perms or HasUserGroupPermissionLevel('read')(member):
476 if not check_perms or HasUserGroupPermissionLevel('read')(member):
477 self.grant_user_group_permission(
477 self.grant_user_group_permission(
478 repo=repo, group_name=member, perm=perm
478 repo=repo, group_name=member, perm=perm
@@ -125,7 +125,7 b' class RepoGroupModel(object):'
125 if force_delete:
125 if force_delete:
126 shutil.rmtree(rm_path)
126 shutil.rmtree(rm_path)
127 else:
127 else:
128 #archive that group`
128 # archive that group
129 _now = datetime.datetime.now()
129 _now = datetime.datetime.now()
130 _ms = str(_now.microsecond).rjust(6, '0')
130 _ms = str(_now.microsecond).rjust(6, '0')
131 _d = 'rm__%s_GROUP_%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
131 _d = 'rm__%s_GROUP_%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
@@ -254,7 +254,7 b' class RepoGroupModel(object):'
254 _set_perm_user(obj, user=member, perm=perm)
254 _set_perm_user(obj, user=member, perm=perm)
255 ## set for user group
255 ## set for user group
256 else:
256 else:
257 #check if we have permissions to alter this usergroup's access
257 # check if we have permissions to alter this usergroup's access
258 if not check_perms or HasUserGroupPermissionLevel('read')(member):
258 if not check_perms or HasUserGroupPermissionLevel('read')(member):
259 _set_perm_group(obj, users_group=member, perm=perm)
259 _set_perm_group(obj, users_group=member, perm=perm)
260 # set new permissions
260 # set new permissions
@@ -262,7 +262,7 b' class RepoGroupModel(object):'
262 if member_type == 'user':
262 if member_type == 'user':
263 _set_perm_user(obj, user=member, perm=perm)
263 _set_perm_user(obj, user=member, perm=perm)
264 else:
264 else:
265 #check if we have permissions to alter this usergroup's access
265 # check if we have permissions to alter this usergroup's access
266 if not check_perms or HasUserGroupPermissionLevel('read')(member):
266 if not check_perms or HasUserGroupPermissionLevel('read')(member):
267 _set_perm_group(obj, users_group=member, perm=perm)
267 _set_perm_group(obj, users_group=member, perm=perm)
268 updates.append(obj)
268 updates.append(obj)
@@ -301,7 +301,7 b' class RepoGroupModel(object):'
301 # if obj is a Repo fix it's name
301 # if obj is a Repo fix it's name
302 # this can be potentially heavy operation
302 # this can be potentially heavy operation
303 for obj in repo_group.recursive_groups_and_repos():
303 for obj in repo_group.recursive_groups_and_repos():
304 #set the value from it's parent
304 # set the value from it's parent
305 obj.enable_locking = repo_group.enable_locking
305 obj.enable_locking = repo_group.enable_locking
306 if isinstance(obj, RepoGroup):
306 if isinstance(obj, RepoGroup):
307 new_name = obj.get_new_name(obj.name)
307 new_name = obj.get_new_name(obj.name)
@@ -600,7 +600,7 b' class ScmModel(object):'
600 imc.remove(filenode)
600 imc.remove(filenode)
601 elif op == 'mod':
601 elif op == 'mod':
602 if filename != old_filename:
602 if filename != old_filename:
603 #TODO: handle renames, needs vcs lib changes
603 # TODO: handle renames, needs vcs lib changes
604 imc.remove(filenode)
604 imc.remove(filenode)
605 imc.add(FileNode(filename, content=content))
605 imc.add(FileNode(filename, content=content))
606 else:
606 else:
@@ -776,6 +776,7 b' class ScmModel(object):'
776 else:
776 else:
777 log.debug('skipping writing hook file')
777 log.debug('skipping writing hook file')
778
778
779
779 def AvailableRepoGroupChoices(top_perms, repo_group_perm_level, extras=()):
780 def AvailableRepoGroupChoices(top_perms, repo_group_perm_level, extras=()):
780 """Return group_id,string tuples with choices for all the repo groups where
781 """Return group_id,string tuples with choices for all the repo groups where
781 the user has the necessary permissions.
782 the user has the necessary permissions.
@@ -71,7 +71,7 b' class UserGroupModel(object):'
71 user_group=user_group, user=member, perm=perm
71 user_group=user_group, user=member, perm=perm
72 )
72 )
73 else:
73 else:
74 #check if we have permissions to alter this usergroup's access
74 # check if we have permissions to alter this usergroup's access
75 if HasUserGroupPermissionLevel('read')(member):
75 if HasUserGroupPermissionLevel('read')(member):
76 self.grant_user_group_permission(
76 self.grant_user_group_permission(
77 target_user_group=user_group, user_group=member, perm=perm
77 target_user_group=user_group, user_group=member, perm=perm
@@ -83,7 +83,7 b' class UserGroupModel(object):'
83 user_group=user_group, user=member, perm=perm
83 user_group=user_group, user=member, perm=perm
84 )
84 )
85 else:
85 else:
86 #check if we have permissions to alter this usergroup's access
86 # check if we have permissions to alter this usergroup's access
87 if HasUserGroupPermissionLevel('read')(member):
87 if HasUserGroupPermissionLevel('read')(member):
88 self.grant_user_group_permission(
88 self.grant_user_group_permission(
89 target_user_group=user_group, user_group=member, perm=perm
89 target_user_group=user_group, user_group=member, perm=perm
@@ -68,6 +68,7 b' def UniqueListFromString():'
68
68
69 def ValidUsername(edit=False, old_data=None):
69 def ValidUsername(edit=False, old_data=None):
70 old_data = old_data or {}
70 old_data = old_data or {}
71
71 class _validator(formencode.validators.FancyValidator):
72 class _validator(formencode.validators.FancyValidator):
72 messages = {
73 messages = {
73 'username_exists': _('Username "%(username)s" already exists'),
74 'username_exists': _('Username "%(username)s" already exists'),
@@ -83,7 +84,7 b' def ValidUsername(edit=False, old_data=N'
83 if value in ['default', 'new_user']:
84 if value in ['default', 'new_user']:
84 msg = self.message('system_invalid_username', state, username=value)
85 msg = self.message('system_invalid_username', state, username=value)
85 raise formencode.Invalid(msg, value, state)
86 raise formencode.Invalid(msg, value, state)
86 #check if user is unique
87 # check if user is unique
87 old_un = None
88 old_un = None
88 if edit:
89 if edit:
89 old_un = User.get(old_data.get('user_id')).username
90 old_un = User.get(old_data.get('user_id')).username
@@ -126,6 +127,7 b' def ValidRepoUser():'
126
127
127 def ValidUserGroup(edit=False, old_data=None):
128 def ValidUserGroup(edit=False, old_data=None):
128 old_data = old_data or {}
129 old_data = old_data or {}
130
129 class _validator(formencode.validators.FancyValidator):
131 class _validator(formencode.validators.FancyValidator):
130 messages = {
132 messages = {
131 'invalid_group': _('Invalid user group name'),
133 'invalid_group': _('Invalid user group name'),
@@ -142,7 +144,7 b' def ValidUserGroup(edit=False, old_data='
142 raise formencode.Invalid(msg, value, state,
144 raise formencode.Invalid(msg, value, state,
143 error_dict=dict(users_group_name=msg)
145 error_dict=dict(users_group_name=msg)
144 )
146 )
145 #check if group is unique
147 # check if group is unique
146 old_ugname = None
148 old_ugname = None
147 if edit:
149 if edit:
148 old_id = old_data.get('users_group_id')
150 old_id = old_data.get('users_group_id')
@@ -494,7 +496,7 b' def CanWriteGroup(old_data=None):'
494 }
496 }
495
497
496 def _to_python(self, value, state):
498 def _to_python(self, value, state):
497 #root location
499 # root location
498 if value == -1:
500 if value == -1:
499 return None
501 return None
500 return value
502 return value
@@ -520,7 +522,7 b' def CanWriteGroup(old_data=None):'
520 # don't need to check permission if he didn't change the value of
522 # don't need to check permission if he didn't change the value of
521 # groups in form box
523 # groups in form box
522 if value_changed or new:
524 if value_changed or new:
523 #parent group need to be existing
525 # parent group need to be existing
524 if gr and forbidden:
526 if gr and forbidden:
525 msg = self.message('permission_denied', state)
527 msg = self.message('permission_denied', state)
526 raise formencode.Invalid(msg, value, state,
528 raise formencode.Invalid(msg, value, state,
@@ -544,7 +546,7 b' def CanCreateGroup(can_create_in_root=Fa'
544 }
546 }
545
547
546 def to_python(self, value, state):
548 def to_python(self, value, state):
547 #root location
549 # root location
548 if value == -1:
550 if value == -1:
549 return None
551 return None
550 return value
552 return value
@@ -554,7 +556,7 b' def CanCreateGroup(can_create_in_root=Fa'
554 gr_name = gr.group_name if gr is not None else None # None means ROOT location
556 gr_name = gr.group_name if gr is not None else None # None means ROOT location
555
557
556 if can_create_in_root and gr is None:
558 if can_create_in_root and gr is None:
557 #we can create in root, we're fine no validations required
559 # we can create in root, we're fine no validations required
558 return
560 return
559
561
560 forbidden_in_root = gr is None and not can_create_in_root
562 forbidden_in_root = gr is None and not can_create_in_root
@@ -587,7 +589,7 b" def ValidPerms(type_='repo'):"
587 perms_new = OrderedSet()
589 perms_new = OrderedSet()
588 # build a list of permission to update and new permission to create
590 # build a list of permission to update and new permission to create
589
591
590 #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
592 # CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
591 new_perms_group = defaultdict(dict)
593 new_perms_group = defaultdict(dict)
592 for k, v in value.copy().iteritems():
594 for k, v in value.copy().iteritems():
593 if k.startswith('perm_new_member'):
595 if k.startswith('perm_new_member'):
@@ -768,11 +770,11 b' def ValidIp():'
768 v = v.strip()
770 v = v.strip()
769 net = ipaddr.IPNetwork(address=v)
771 net = ipaddr.IPNetwork(address=v)
770 if isinstance(net, ipaddr.IPv4Network):
772 if isinstance(net, ipaddr.IPv4Network):
771 #if IPv4 doesn't end with a mask, add /32
773 # if IPv4 doesn't end with a mask, add /32
772 if '/' not in value:
774 if '/' not in value:
773 v += '/32'
775 v += '/32'
774 if isinstance(net, ipaddr.IPv6Network):
776 if isinstance(net, ipaddr.IPv6Network):
775 #if IPv6 doesn't end with a mask, add /128
777 # if IPv6 doesn't end with a mask, add /128
776 if '/' not in value:
778 if '/' not in value:
777 v += '/128'
779 v += '/128'
778 return v
780 return v
@@ -780,7 +782,7 b' def ValidIp():'
780 def validate_python(self, value, state):
782 def validate_python(self, value, state):
781 try:
783 try:
782 addr = value.strip()
784 addr = value.strip()
783 #this raises an ValueError if address is not IPv4 or IPv6
785 # this raises an ValueError if address is not IPv4 or IPv6
784 ipaddr.IPNetwork(address=addr)
786 ipaddr.IPNetwork(address=addr)
785 except ValueError:
787 except ValueError:
786 raise formencode.Invalid(self.message('badFormat', state),
788 raise formencode.Invalid(self.message('badFormat', state),
@@ -2482,7 +2482,7 b' class _BaseTestApi(object):'
2482 def test_api_get_changeset(self):
2482 def test_api_get_changeset(self):
2483 review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2483 review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2484 id_, params = _build_data(self.apikey, 'get_changeset',
2484 id_, params = _build_data(self.apikey, 'get_changeset',
2485 repoid=self.REPO, raw_id = self.TEST_REVISION)
2485 repoid=self.REPO, raw_id=self.TEST_REVISION)
2486 response = api_call(self, params)
2486 response = api_call(self, params)
2487 result = json.loads(response.body)["result"]
2487 result = json.loads(response.body)["result"]
2488 assert result["raw_id"] == self.TEST_REVISION
2488 assert result["raw_id"] == self.TEST_REVISION
@@ -2491,8 +2491,8 b' class _BaseTestApi(object):'
2491 def test_api_get_changeset_with_reviews(self):
2491 def test_api_get_changeset_with_reviews(self):
2492 reviewobjs = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2492 reviewobjs = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2493 id_, params = _build_data(self.apikey, 'get_changeset',
2493 id_, params = _build_data(self.apikey, 'get_changeset',
2494 repoid=self.REPO, raw_id = self.TEST_REVISION,
2494 repoid=self.REPO, raw_id=self.TEST_REVISION,
2495 with_reviews = True)
2495 with_reviews=True)
2496 response = api_call(self, params)
2496 response = api_call(self, params)
2497 result = json.loads(response.body)["result"]
2497 result = json.loads(response.body)["result"]
2498 assert result["raw_id"] == self.TEST_REVISION
2498 assert result["raw_id"] == self.TEST_REVISION
@@ -2522,7 +2522,7 b' class _BaseTestApi(object):'
2522 RepoModel().revoke_user_permission(repo=self.REPO, user=self.TEST_USER_LOGIN)
2522 RepoModel().revoke_user_permission(repo=self.REPO, user=self.TEST_USER_LOGIN)
2523 RepoModel().revoke_user_permission(repo=self.REPO, user="default")
2523 RepoModel().revoke_user_permission(repo=self.REPO, user="default")
2524 id_, params = _build_data(self.apikey_regular, 'get_changeset',
2524 id_, params = _build_data(self.apikey_regular, 'get_changeset',
2525 repoid=self.REPO, raw_id = self.TEST_REVISION)
2525 repoid=self.REPO, raw_id=self.TEST_REVISION)
2526 response = api_call(self, params)
2526 response = api_call(self, params)
2527 expected = u'Access denied to repo %s' % self.REPO
2527 expected = u'Access denied to repo %s' % self.REPO
2528 self._compare_error(id_, expected, given=response.body)
2528 self._compare_error(id_, expected, given=response.body)
@@ -54,7 +54,7 b' testapp = None'
54 # Invoke websetup with the current config file
54 # Invoke websetup with the current config file
55 # SetupCommand('setup-app').run([config_file])
55 # SetupCommand('setup-app').run([config_file])
56
56
57 #SOME GLOBALS FOR TESTS
57 ## SOME GLOBALS FOR TESTS
58
58
59 TESTS_TMP_PATH = os.environ.get('KALLITHEA_TESTS_TMP_PATH', tempfile.mkdtemp(prefix='kallithea-test-'))
59 TESTS_TMP_PATH = os.environ.get('KALLITHEA_TESTS_TMP_PATH', tempfile.mkdtemp(prefix='kallithea-test-'))
60 os.environ['VCS_TEST_ROOT'] = TESTS_TMP_PATH
60 os.environ['VCS_TEST_ROOT'] = TESTS_TMP_PATH
@@ -106,7 +106,7 b' TEST_HG_REPO_PULL = os.path.join(TESTS_T'
106 GIT_REMOTE_REPO = os.path.join(TESTS_TMP_PATH, GIT_REPO)
106 GIT_REMOTE_REPO = os.path.join(TESTS_TMP_PATH, GIT_REPO)
107 HG_REMOTE_REPO = os.path.join(TESTS_TMP_PATH, HG_REPO)
107 HG_REMOTE_REPO = os.path.join(TESTS_TMP_PATH, HG_REPO)
108
108
109 #skip ldap tests if LDAP lib is not installed
109 # skip ldap tests if LDAP lib is not installed
110 ldap_lib_installed = False
110 ldap_lib_installed = False
111 try:
111 try:
112 import ldap
112 import ldap
@@ -123,6 +123,7 b' try:'
123 except ImportError:
123 except ImportError:
124 pam_lib_installed = False
124 pam_lib_installed = False
125
125
126
126 def invalidate_all_caches():
127 def invalidate_all_caches():
127 """Invalidate all beaker caches currently configured.
128 """Invalidate all beaker caches currently configured.
128 Useful when manipulating IP permissions in a test and changes need to take
129 Useful when manipulating IP permissions in a test and changes need to take
@@ -133,10 +134,12 b' def invalidate_all_caches():'
133 for cache in cache_managers.values():
134 for cache in cache_managers.values():
134 cache.clear()
135 cache.clear()
135
136
137
136 class NullHandler(logging.Handler):
138 class NullHandler(logging.Handler):
137 def emit(self, record):
139 def emit(self, record):
138 pass
140 pass
139
141
142
140 class TestController(object):
143 class TestController(object):
141 """Pytest-style test controller"""
144 """Pytest-style test controller"""
142
145
@@ -23,6 +23,7 b' import kallithea.tests.base # FIXME: nee'
23
23
24 from tg.util.webtest import test_context
24 from tg.util.webtest import test_context
25
25
26
26 def pytest_configure():
27 def pytest_configure():
27 os.environ['TZ'] = 'UTC'
28 os.environ['TZ'] = 'UTC'
28 if not kallithea.is_windows:
29 if not kallithea.is_windows:
@@ -70,10 +71,12 b' def pytest_configure():'
70 # set fixed language for form messages, regardless of environment settings
71 # set fixed language for form messages, regardless of environment settings
71 formencode.api.set_stdtranslation(languages=[])
72 formencode.api.set_stdtranslation(languages=[])
72
73
74
73 @pytest.fixture
75 @pytest.fixture
74 def create_test_user():
76 def create_test_user():
75 """Provide users that automatically disappear after test is over."""
77 """Provide users that automatically disappear after test is over."""
76 test_user_ids = []
78 test_user_ids = []
79
77 def _create_test_user(user_form):
80 def _create_test_user(user_form):
78 user = UserModel().create(user_form)
81 user = UserModel().create(user_form)
79 test_user_ids.append(user.user_id)
82 test_user_ids.append(user.user_id)
@@ -115,6 +118,7 b' def set_test_settings():'
115 Setting.create_or_update(k, v, t)
118 Setting.create_or_update(k, v, t)
116 session.commit()
119 session.commit()
117
120
121
118 @pytest.fixture
122 @pytest.fixture
119 def auto_clear_ip_permissions():
123 def auto_clear_ip_permissions():
120 """Fixture that provides nothing but clearing IP permissions upon test
124 """Fixture that provides nothing but clearing IP permissions upon test
@@ -135,6 +139,7 b' def auto_clear_ip_permissions():'
135 # IP permissions are cached, need to invalidate this cache explicitly
139 # IP permissions are cached, need to invalidate this cache explicitly
136 invalidate_all_caches()
140 invalidate_all_caches()
137
141
142
138 @pytest.fixture
143 @pytest.fixture
139 def test_context_fixture(app_fixture):
144 def test_context_fixture(app_fixture):
140 """
145 """
@@ -177,6 +182,7 b' class MyWSGIServer(WSGIServer):'
177 auth += '@'
182 auth += '@'
178 return '%s://%s%s:%s/%s' % (proto, auth, host, port, repo_name)
183 return '%s://%s%s:%s/%s' % (proto, auth, host, port, repo_name)
179
184
185
180 @pytest.yield_fixture(scope="session")
186 @pytest.yield_fixture(scope="session")
181 def webserver():
187 def webserver():
182 """Start web server while tests are running.
188 """Start web server while tests are running.
@@ -257,11 +257,11 b' class Fixture(object):'
257 'owner': TEST_USER_ADMIN_LOGIN,
257 'owner': TEST_USER_ADMIN_LOGIN,
258 'gist_type': Gist.GIST_PUBLIC,
258 'gist_type': Gist.GIST_PUBLIC,
259 'lifetime': -1,
259 'lifetime': -1,
260 'gist_mapping': {'filename1.txt':{'content':'hello world'},}
260 'gist_mapping': {'filename1.txt': {'content': 'hello world'}}
261 }
261 }
262 form_data.update(kwargs)
262 form_data.update(kwargs)
263 gist = GistModel().create(
263 gist = GistModel().create(
264 description=form_data['description'],owner=form_data['owner'],
264 description=form_data['description'], owner=form_data['owner'],
265 gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
265 gist_mapping=form_data['gist_mapping'], gist_type=form_data['gist_type'],
266 lifetime=form_data['lifetime']
266 lifetime=form_data['lifetime']
267 )
267 )
@@ -376,7 +376,7 b' def create_test_env(repos_test_path, con'
376 idx_path = config['index_dir']
376 idx_path = config['index_dir']
377 data_path = config['cache_dir']
377 data_path = config['cache_dir']
378
378
379 #clean index and data
379 # clean index and data
380 if idx_path and os.path.exists(idx_path):
380 if idx_path and os.path.exists(idx_path):
381 log.debug('remove %s', idx_path)
381 log.debug('remove %s', idx_path)
382 shutil.rmtree(idx_path)
382 shutil.rmtree(idx_path)
@@ -385,7 +385,7 b' def create_test_env(repos_test_path, con'
385 log.debug('remove %s', data_path)
385 log.debug('remove %s', data_path)
386 shutil.rmtree(data_path)
386 shutil.rmtree(data_path)
387
387
388 #CREATE DEFAULT TEST REPOS
388 # CREATE DEFAULT TEST REPOS
389 tar = tarfile.open(os.path.join(FIXTURES, 'vcs_test_hg.tar.gz'))
389 tar = tarfile.open(os.path.join(FIXTURES, 'vcs_test_hg.tar.gz'))
390 tar.extractall(os.path.join(TESTS_TMP_PATH, HG_REPO))
390 tar.extractall(os.path.join(TESTS_TMP_PATH, HG_REPO))
391 tar.close()
391 tar.close()
@@ -394,7 +394,7 b' def create_test_env(repos_test_path, con'
394 tar.extractall(os.path.join(TESTS_TMP_PATH, GIT_REPO))
394 tar.extractall(os.path.join(TESTS_TMP_PATH, GIT_REPO))
395 tar.close()
395 tar.close()
396
396
397 #LOAD VCS test stuff
397 # LOAD VCS test stuff
398 from kallithea.tests.vcs import setup_package
398 from kallithea.tests.vcs import setup_package
399 setup_package()
399 setup_package()
400
400
@@ -164,7 +164,6 b' class TestAuthSettingsController(TestCon'
164 assert response.form['firstname'].value == 'John'
164 assert response.form['firstname'].value == 'John'
165 assert response.form['lastname'].value == 'Doe'
165 assert response.form['lastname'].value == 'Doe'
166
166
167
168 def test_container_auth_login_fallback_header(self):
167 def test_container_auth_login_fallback_header(self):
169 self._container_auth_setup(
168 self._container_auth_setup(
170 auth_container_header='THE_USER_NAME',
169 auth_container_header='THE_USER_NAME',
@@ -50,7 +50,7 b' class TestGistsController(TestController'
50 response = self.app.get(url('gists', private=1))
50 response = self.app.get(url('gists', private=1))
51 # Test response...
51 # Test response...
52
52
53 #and privates
53 # and privates
54 response.mustcontain('gist: %s' % gist.gist_access_id)
54 response.mustcontain('gist: %s' % gist.gist_access_id)
55
55
56 def test_create_missing_description(self):
56 def test_create_missing_description(self):
@@ -8,6 +8,7 b' from kallithea.lib import helpers as h'
8
8
9 from tg.util.webtest import test_context
9 from tg.util.webtest import test_context
10
10
11
11 class TestNotificationsController(TestController):
12 class TestNotificationsController(TestController):
12 def setup_method(self, method):
13 def setup_method(self, method):
13 self.remove_all_notifications()
14 self.remove_all_notifications()
@@ -74,7 +74,6 b' class TestAdminPermissionsController(Tes'
74 response.mustcontain(no=['127.0.0.0/24'])
74 response.mustcontain(no=['127.0.0.0/24'])
75 response.mustcontain(no=['127.0.0.0 - 127.0.0.255'])
75 response.mustcontain(no=['127.0.0.0 - 127.0.0.255'])
76
76
77
78 def test_index_overview(self):
77 def test_index_overview(self):
79 self.log_user()
78 self.log_user()
80 response = self.app.get(url('admin_permissions_perms'))
79 response = self.app.get(url('admin_permissions_perms'))
@@ -7,6 +7,7 b' from kallithea.tests.fixture import Fixt'
7
7
8 fixture = Fixture()
8 fixture = Fixture()
9
9
10
10 class TestRepoGroupsController(TestController):
11 class TestRepoGroupsController(TestController):
11
12
12 def test_case_insensitivity(self):
13 def test_case_insensitivity(self):
@@ -305,7 +305,7 b' class _BaseTestCase(TestController):'
305 Session().commit()
305 Session().commit()
306 pytest.fail('no repo %s in filesystem' % repo_name)
306 pytest.fail('no repo %s in filesystem' % repo_name)
307
307
308 #check if inherited permissiona are applied
308 # check if inherited permissiona are applied
309 inherited_perms = UserRepoToPerm.query() \
309 inherited_perms = UserRepoToPerm.query() \
310 .filter(UserRepoToPerm.repository_id == new_repo_id).all()
310 .filter(UserRepoToPerm.repository_id == new_repo_id).all()
311 assert len(inherited_perms) == 2
311 assert len(inherited_perms) == 2
@@ -332,7 +332,6 b' class _BaseTestCase(TestController):'
332 _authentication_token=self.authentication_token()))
332 _authentication_token=self.authentication_token()))
333 response.mustcontain('Invalid repository URL')
333 response.mustcontain('Invalid repository URL')
334
334
335
336 def test_create_remote_repo_wrong_clone_uri_hg_svn(self):
335 def test_create_remote_repo_wrong_clone_uri_hg_svn(self):
337 self.log_user()
336 self.log_user()
338 repo_name = self.NEW_REPO
337 repo_name = self.NEW_REPO
@@ -346,7 +345,6 b' class _BaseTestCase(TestController):'
346 _authentication_token=self.authentication_token()))
345 _authentication_token=self.authentication_token()))
347 response.mustcontain('Invalid repository URL')
346 response.mustcontain('Invalid repository URL')
348
347
349
350 def test_delete(self):
348 def test_delete(self):
351 self.log_user()
349 self.log_user()
352 repo_name = u'vcs_test_new_to_delete_%s' % self.REPO_TYPE
350 repo_name = u'vcs_test_new_to_delete_%s' % self.REPO_TYPE
@@ -387,7 +385,7 b' class _BaseTestCase(TestController):'
387
385
388 response.follow()
386 response.follow()
389
387
390 #check if repo was deleted from db
388 # check if repo was deleted from db
391 deleted_repo = Session().query(Repository) \
389 deleted_repo = Session().query(Repository) \
392 .filter(Repository.repo_name == repo_name).scalar()
390 .filter(Repository.repo_name == repo_name).scalar()
393
391
@@ -437,7 +435,7 b' class _BaseTestCase(TestController):'
437 self.checkSessionFlash(response, 'Deleted repository %s' % (repo_name_unicode))
435 self.checkSessionFlash(response, 'Deleted repository %s' % (repo_name_unicode))
438 response.follow()
436 response.follow()
439
437
440 #check if repo was deleted from db
438 # check if repo was deleted from db
441 deleted_repo = Session().query(Repository) \
439 deleted_repo = Session().query(Repository) \
442 .filter(Repository.repo_name == repo_name_unicode).scalar()
440 .filter(Repository.repo_name == repo_name_unicode).scalar()
443
441
@@ -446,7 +444,7 b' class _BaseTestCase(TestController):'
446 assert os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_unicode)) == False
444 assert os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_unicode)) == False
447
445
448 def test_delete_repo_with_group(self):
446 def test_delete_repo_with_group(self):
449 #TODO:
447 # TODO:
450 pass
448 pass
451
449
452 def test_delete_browser_fakeout(self):
450 def test_delete_browser_fakeout(self):
@@ -462,7 +460,7 b' class _BaseTestCase(TestController):'
462
460
463 def test_set_private_flag_sets_default_to_none(self):
461 def test_set_private_flag_sets_default_to_none(self):
464 self.log_user()
462 self.log_user()
465 #initially repository perm should be read
463 # initially repository perm should be read
466 perm = _get_permission_for_user(user='default', repo=self.REPO)
464 perm = _get_permission_for_user(user='default', repo=self.REPO)
467 assert len(perm), 1
465 assert len(perm), 1
468 assert perm[0].permission.permission_name == 'repository.read'
466 assert perm[0].permission.permission_name == 'repository.read'
@@ -478,7 +476,7 b' class _BaseTestCase(TestController):'
478 msg='Repository %s updated successfully' % (self.REPO))
476 msg='Repository %s updated successfully' % (self.REPO))
479 assert Repository.get_by_repo_name(self.REPO).private == True
477 assert Repository.get_by_repo_name(self.REPO).private == True
480
478
481 #now the repo default permission should be None
479 # now the repo default permission should be None
482 perm = _get_permission_for_user(user='default', repo=self.REPO)
480 perm = _get_permission_for_user(user='default', repo=self.REPO)
483 assert len(perm), 1
481 assert len(perm), 1
484 assert perm[0].permission.permission_name == 'repository.none'
482 assert perm[0].permission.permission_name == 'repository.none'
@@ -493,12 +491,12 b' class _BaseTestCase(TestController):'
493 msg='Repository %s updated successfully' % (self.REPO))
491 msg='Repository %s updated successfully' % (self.REPO))
494 assert Repository.get_by_repo_name(self.REPO).private == False
492 assert Repository.get_by_repo_name(self.REPO).private == False
495
493
496 #we turn off private now the repo default permission should stay None
494 # we turn off private now the repo default permission should stay None
497 perm = _get_permission_for_user(user='default', repo=self.REPO)
495 perm = _get_permission_for_user(user='default', repo=self.REPO)
498 assert len(perm), 1
496 assert len(perm), 1
499 assert perm[0].permission.permission_name == 'repository.none'
497 assert perm[0].permission.permission_name == 'repository.none'
500
498
501 #update this permission back
499 # update this permission back
502 perm[0].permission = Permission.get_by_key('repository.read')
500 perm[0].permission = Permission.get_by_key('repository.read')
503 Session().commit()
501 Session().commit()
504
502
@@ -42,7 +42,7 b' class TestAdminUsersGroupsController(Tes'
42 self.log_user()
42 self.log_user()
43 users_group_name = TEST_USER_GROUP + 'another'
43 users_group_name = TEST_USER_GROUP + 'another'
44 response = self.app.post(url('users_groups'),
44 response = self.app.post(url('users_groups'),
45 {'users_group_name':users_group_name,
45 {'users_group_name': users_group_name,
46 'user_group_description': u'DESC',
46 'user_group_description': u'DESC',
47 'active': True,
47 'active': True,
48 '_authentication_token': self.authentication_token()})
48 '_authentication_token': self.authentication_token()})
@@ -30,6 +30,7 b' from tg.util.webtest import test_context'
30
30
31 fixture = Fixture()
31 fixture = Fixture()
32
32
33
33 @pytest.fixture
34 @pytest.fixture
34 def user_and_repo_group_fail():
35 def user_and_repo_group_fail():
35 username = 'repogrouperr'
36 username = 'repogrouperr'
@@ -44,6 +45,7 b' def user_and_repo_group_fail():'
44 # delete already succeeded in test body
45 # delete already succeeded in test body
45 pass
46 pass
46
47
48
47 class TestAdminUsersController(TestController):
49 class TestAdminUsersController(TestController):
48 test_user_1 = 'testme'
50 test_user_1 = 'testme'
49
51
@@ -159,14 +161,13 b' class TestAdminUsersController(TestContr'
159 if name == 'email':
161 if name == 'email':
160 params['emails'] = [attrs['email']]
162 params['emails'] = [attrs['email']]
161 if name == 'extern_type':
163 if name == 'extern_type':
162 #cannot update this via form, expected value is original one
164 # cannot update this via form, expected value is original one
163 params['extern_type'] = "internal"
165 params['extern_type'] = "internal"
164 if name == 'extern_name':
166 if name == 'extern_name':
165 #cannot update this via form, expected value is original one
167 # cannot update this via form, expected value is original one
166 params['extern_name'] = self.test_user_1
168 params['extern_name'] = self.test_user_1
167 # special case since this user is not
169 # special case since this user is not logged in yet his data is
168 # logged in yet his data is not filled
170 # not filled so we use creation data
169 # so we use creation data
170
171
171 params.update({'_authentication_token': self.authentication_token()})
172 params.update({'_authentication_token': self.authentication_token()})
172 response = self.app.post(url('update_user', id=usr.user_id), params)
173 response = self.app.post(url('update_user', id=usr.user_id), params)
@@ -288,7 +289,7 b' class TestAdminUsersController(TestContr'
288 uid = user.user_id
289 uid = user.user_id
289
290
290 try:
291 try:
291 #User should have None permission on creation repository
292 # User should have None permission on creation repository
292 assert UserModel().has_perm(user, perm_none) == False
293 assert UserModel().has_perm(user, perm_none) == False
293 assert UserModel().has_perm(user, perm_create) == False
294 assert UserModel().has_perm(user, perm_create) == False
294
295
@@ -299,7 +300,7 b' class TestAdminUsersController(TestContr'
299 perm_none = Permission.get_by_key('hg.create.none')
300 perm_none = Permission.get_by_key('hg.create.none')
300 perm_create = Permission.get_by_key('hg.create.repository')
301 perm_create = Permission.get_by_key('hg.create.repository')
301
302
302 #User should have None permission on creation repository
303 # User should have None permission on creation repository
303 assert UserModel().has_perm(uid, perm_none) == False
304 assert UserModel().has_perm(uid, perm_none) == False
304 assert UserModel().has_perm(uid, perm_create) == True
305 assert UserModel().has_perm(uid, perm_create) == True
305 finally:
306 finally:
@@ -318,7 +319,7 b' class TestAdminUsersController(TestContr'
318 uid = user.user_id
319 uid = user.user_id
319
320
320 try:
321 try:
321 #User should have None permission on creation repository
322 # User should have None permission on creation repository
322 assert UserModel().has_perm(user, perm_none) == False
323 assert UserModel().has_perm(user, perm_none) == False
323 assert UserModel().has_perm(user, perm_create) == False
324 assert UserModel().has_perm(user, perm_create) == False
324
325
@@ -328,7 +329,7 b' class TestAdminUsersController(TestContr'
328 perm_none = Permission.get_by_key('hg.create.none')
329 perm_none = Permission.get_by_key('hg.create.none')
329 perm_create = Permission.get_by_key('hg.create.repository')
330 perm_create = Permission.get_by_key('hg.create.repository')
330
331
331 #User should have None permission on creation repository
332 # User should have None permission on creation repository
332 assert UserModel().has_perm(uid, perm_none) == True
333 assert UserModel().has_perm(uid, perm_none) == True
333 assert UserModel().has_perm(uid, perm_create) == False
334 assert UserModel().has_perm(uid, perm_create) == False
334 finally:
335 finally:
@@ -347,7 +348,7 b' class TestAdminUsersController(TestContr'
347 uid = user.user_id
348 uid = user.user_id
348
349
349 try:
350 try:
350 #User should have None permission on creation repository
351 # User should have None permission on creation repository
351 assert UserModel().has_perm(user, perm_none) == False
352 assert UserModel().has_perm(user, perm_none) == False
352 assert UserModel().has_perm(user, perm_fork) == False
353 assert UserModel().has_perm(user, perm_fork) == False
353
354
@@ -358,7 +359,7 b' class TestAdminUsersController(TestContr'
358 perm_none = Permission.get_by_key('hg.create.none')
359 perm_none = Permission.get_by_key('hg.create.none')
359 perm_create = Permission.get_by_key('hg.create.repository')
360 perm_create = Permission.get_by_key('hg.create.repository')
360
361
361 #User should have None permission on creation repository
362 # User should have None permission on creation repository
362 assert UserModel().has_perm(uid, perm_none) == False
363 assert UserModel().has_perm(uid, perm_none) == False
363 assert UserModel().has_perm(uid, perm_create) == True
364 assert UserModel().has_perm(uid, perm_create) == True
364 finally:
365 finally:
@@ -377,7 +378,7 b' class TestAdminUsersController(TestContr'
377 uid = user.user_id
378 uid = user.user_id
378
379
379 try:
380 try:
380 #User should have None permission on creation repository
381 # User should have None permission on creation repository
381 assert UserModel().has_perm(user, perm_none) == False
382 assert UserModel().has_perm(user, perm_none) == False
382 assert UserModel().has_perm(user, perm_fork) == False
383 assert UserModel().has_perm(user, perm_fork) == False
383
384
@@ -387,7 +388,7 b' class TestAdminUsersController(TestContr'
387 perm_none = Permission.get_by_key('hg.create.none')
388 perm_none = Permission.get_by_key('hg.create.none')
388 perm_create = Permission.get_by_key('hg.create.repository')
389 perm_create = Permission.get_by_key('hg.create.repository')
389
390
390 #User should have None permission on creation repository
391 # User should have None permission on creation repository
391 assert UserModel().has_perm(uid, perm_none) == True
392 assert UserModel().has_perm(uid, perm_none) == True
392 assert UserModel().has_perm(uid, perm_create) == False
393 assert UserModel().has_perm(uid, perm_create) == False
393 finally:
394 finally:
@@ -491,7 +492,7 b' class TestAdminUsersController(TestContr'
491 self.checkSessionFlash(response, 'API key successfully created')
492 self.checkSessionFlash(response, 'API key successfully created')
492 response = response.follow()
493 response = response.follow()
493
494
494 #now delete our key
495 # now delete our key
495 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
496 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
496 assert 1 == len(keys)
497 assert 1 == len(keys)
497
498
@@ -15,7 +15,7 b' class TestChangelogController(TestContro'
15 """name="7b22a518347bb9bc19679f6af07cd0a61bfe16e7" """
15 """name="7b22a518347bb9bc19679f6af07cd0a61bfe16e7" """
16 """type="checkbox" value="1" />"""
16 """type="checkbox" value="1" />"""
17 )
17 )
18 #rev 640: code garden
18 # rev 640: code garden
19 response.mustcontain(
19 response.mustcontain(
20 """<a class="changeset_hash" href="/%s/changeset/0a4e54a4460401d6dbbd6a3604b17cd2b3606b82">r640:0a4e54a44604</a>""" % HG_REPO
20 """<a class="changeset_hash" href="/%s/changeset/0a4e54a4460401d6dbbd6a3604b17cd2b3606b82">r640:0a4e54a44604</a>""" % HG_REPO
21 )
21 )
@@ -25,7 +25,7 b' class TestChangelogController(TestContro'
25
25
26 def test_index_pagination_hg(self):
26 def test_index_pagination_hg(self):
27 self.log_user()
27 self.log_user()
28 #pagination
28 # pagination
29 self.app.get(url(controller='changelog', action='index',
29 self.app.get(url(controller='changelog', action='index',
30 repo_name=HG_REPO), {'page': 1})
30 repo_name=HG_REPO), {'page': 1})
31 self.app.get(url(controller='changelog', action='index',
31 self.app.get(url(controller='changelog', action='index',
@@ -81,7 +81,7 b' class TestChangelogController(TestContro'
81
81
82 def test_index_pagination_git(self):
82 def test_index_pagination_git(self):
83 self.log_user()
83 self.log_user()
84 #pagination
84 # pagination
85 self.app.get(url(controller='changelog', action='index',
85 self.app.get(url(controller='changelog', action='index',
86 repo_name=GIT_REPO), {'page': 1})
86 repo_name=GIT_REPO), {'page': 1})
87 self.app.get(url(controller='changelog', action='index',
87 self.app.get(url(controller='changelog', action='index',
@@ -112,7 +112,7 b' class TestChangelogController(TestContro'
112 response = self.app.get(url(controller='changelog', action='index',
112 response = self.app.get(url(controller='changelog', action='index',
113 revision='tip', f_path='/vcs/exceptions.py',
113 revision='tip', f_path='/vcs/exceptions.py',
114 repo_name=HG_REPO))
114 repo_name=HG_REPO))
115 #history commits messages
115 # history commits messages
116 response.mustcontain('Added exceptions module, this time for real')
116 response.mustcontain('Added exceptions module, this time for real')
117 response.mustcontain('Added not implemented hg backend test case')
117 response.mustcontain('Added not implemented hg backend test case')
118 response.mustcontain('Added BaseChangeset class')
118 response.mustcontain('Added BaseChangeset class')
@@ -123,7 +123,7 b' class TestChangelogController(TestContro'
123 response = self.app.get(url(controller='changelog', action='index',
123 response = self.app.get(url(controller='changelog', action='index',
124 revision='tip', f_path='/vcs/exceptions.py',
124 revision='tip', f_path='/vcs/exceptions.py',
125 repo_name=GIT_REPO))
125 repo_name=GIT_REPO))
126 #history commits messages
126 # history commits messages
127 response.mustcontain('Added exceptions module, this time for real')
127 response.mustcontain('Added exceptions module, this time for real')
128 response.mustcontain('Added not implemented hg backend test case')
128 response.mustcontain('Added not implemented hg backend test case')
129 response.mustcontain('Added BaseChangeset class')
129 response.mustcontain('Added BaseChangeset class')
@@ -62,7 +62,7 b' class TestChangeSetCommentsController(Te'
62
62
63 response = self.app.get(url(controller='changeset', action='index',
63 response = self.app.get(url(controller='changeset', action='index',
64 repo_name=HG_REPO, revision=rev))
64 repo_name=HG_REPO, revision=rev))
65 #test DB
65 # test DB
66 assert ChangesetComment.query().count() == 1
66 assert ChangesetComment.query().count() == 1
67 response.mustcontain(
67 response.mustcontain(
68 '''<div class="comments-number">'''
68 '''<div class="comments-number">'''
@@ -6,6 +6,7 b' from kallithea.tests.fixture import Fixt'
6
6
7 fixture = Fixture()
7 fixture = Fixture()
8
8
9
9 def _commit_ref(repo_name, sha, msg):
10 def _commit_ref(repo_name, sha, msg):
10 return '''<div class="message-firstline"><a class="message-link" href="/%s/changeset/%s">%s</a></div>''' % (repo_name, sha, msg)
11 return '''<div class="message-firstline"><a class="message-link" href="/%s/changeset/%s">%s</a></div>''' % (repo_name, sha, msg)
11
12
@@ -30,16 +31,16 b' class TestCompareController(TestControll'
30 repo_description='diff-test',
31 repo_description='diff-test',
31 cur_user=TEST_USER_ADMIN_LOGIN)
32 cur_user=TEST_USER_ADMIN_LOGIN)
32 self.r1_id = repo1.repo_id
33 self.r1_id = repo1.repo_id
33 #commit something !
34 # commit something !
34 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
35 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
35 content='line1\n', message='commit1', vcs_type='hg',
36 content='line1\n', message='commit1', vcs_type='hg',
36 parent=None, newfile=True)
37 parent=None, newfile=True)
37
38
38 #fork this repo
39 # fork this repo
39 repo2 = fixture.create_fork(u'one', u'one-fork')
40 repo2 = fixture.create_fork(u'one', u'one-fork')
40 self.r2_id = repo2.repo_id
41 self.r2_id = repo2.repo_id
41
42
42 #add two extra commit into fork
43 # add two extra commit into fork
43 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
44 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
44 content='line1\nline2\n', message='commit2', vcs_type='hg',
45 content='line1\nline2\n', message='commit2', vcs_type='hg',
45 parent=cs0)
46 parent=cs0)
@@ -72,7 +73,7 b' class TestCompareController(TestControll'
72 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
73 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
73 ## files
74 ## files
74 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
75 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
75 #swap
76 # swap
76 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
77 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
77
78
78 def test_compare_forks_on_branch_extra_commits_git(self):
79 def test_compare_forks_on_branch_extra_commits_git(self):
@@ -81,16 +82,16 b' class TestCompareController(TestControll'
81 repo_description='diff-test',
82 repo_description='diff-test',
82 cur_user=TEST_USER_ADMIN_LOGIN)
83 cur_user=TEST_USER_ADMIN_LOGIN)
83 self.r1_id = repo1.repo_id
84 self.r1_id = repo1.repo_id
84 #commit something !
85 # commit something !
85 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
86 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
86 content='line1\n', message='commit1', vcs_type='git',
87 content='line1\n', message='commit1', vcs_type='git',
87 parent=None, newfile=True)
88 parent=None, newfile=True)
88
89
89 #fork this repo
90 # fork this repo
90 repo2 = fixture.create_fork(u'one-git', u'one-git-fork')
91 repo2 = fixture.create_fork(u'one-git', u'one-git-fork')
91 self.r2_id = repo2.repo_id
92 self.r2_id = repo2.repo_id
92
93
93 #add two extra commit into fork
94 # add two extra commit into fork
94 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
95 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
95 content='line1\nline2\n', message='commit2', vcs_type='git',
96 content='line1\nline2\n', message='commit2', vcs_type='git',
96 parent=cs0)
97 parent=cs0)
@@ -123,7 +124,7 b' class TestCompareController(TestControll'
123 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
124 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
124 ## files
125 ## files
125 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
126 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
126 #swap
127 # swap
127 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
128 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
128
129
129 def test_compare_forks_on_branch_extra_commits_origin_has_incoming_hg(self):
130 def test_compare_forks_on_branch_extra_commits_origin_has_incoming_hg(self):
@@ -135,21 +136,21 b' class TestCompareController(TestControll'
135
136
136 self.r1_id = repo1.repo_id
137 self.r1_id = repo1.repo_id
137
138
138 #commit something !
139 # commit something !
139 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
140 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
140 content='line1\n', message='commit1', vcs_type='hg',
141 content='line1\n', message='commit1', vcs_type='hg',
141 parent=None, newfile=True)
142 parent=None, newfile=True)
142
143
143 #fork this repo
144 # fork this repo
144 repo2 = fixture.create_fork(u'one', u'one-fork')
145 repo2 = fixture.create_fork(u'one', u'one-fork')
145 self.r2_id = repo2.repo_id
146 self.r2_id = repo2.repo_id
146
147
147 #now commit something to origin repo
148 # now commit something to origin repo
148 cs1_prim = fixture.commit_change(repo1.repo_name, filename='file2',
149 cs1_prim = fixture.commit_change(repo1.repo_name, filename='file2',
149 content='line1file2\n', message='commit2', vcs_type='hg',
150 content='line1file2\n', message='commit2', vcs_type='hg',
150 parent=cs0, newfile=True)
151 parent=cs0, newfile=True)
151
152
152 #add two extra commit into fork
153 # add two extra commit into fork
153 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
154 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
154 content='line1\nline2\n', message='commit2', vcs_type='hg',
155 content='line1\nline2\n', message='commit2', vcs_type='hg',
155 parent=cs0)
156 parent=cs0)
@@ -182,7 +183,7 b' class TestCompareController(TestControll'
182 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
183 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
183 ## files
184 ## files
184 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
185 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
185 #swap
186 # swap
186 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
187 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
187
188
188 def test_compare_forks_on_branch_extra_commits_origin_has_incoming_git(self):
189 def test_compare_forks_on_branch_extra_commits_origin_has_incoming_git(self):
@@ -194,21 +195,21 b' class TestCompareController(TestControll'
194
195
195 self.r1_id = repo1.repo_id
196 self.r1_id = repo1.repo_id
196
197
197 #commit something !
198 # commit something !
198 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
199 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
199 content='line1\n', message='commit1', vcs_type='git',
200 content='line1\n', message='commit1', vcs_type='git',
200 parent=None, newfile=True)
201 parent=None, newfile=True)
201
202
202 #fork this repo
203 # fork this repo
203 repo2 = fixture.create_fork(u'one-git', u'one-git-fork')
204 repo2 = fixture.create_fork(u'one-git', u'one-git-fork')
204 self.r2_id = repo2.repo_id
205 self.r2_id = repo2.repo_id
205
206
206 #now commit something to origin repo
207 # now commit something to origin repo
207 cs1_prim = fixture.commit_change(repo1.repo_name, filename='file2',
208 cs1_prim = fixture.commit_change(repo1.repo_name, filename='file2',
208 content='line1file2\n', message='commit2', vcs_type='git',
209 content='line1file2\n', message='commit2', vcs_type='git',
209 parent=cs0, newfile=True)
210 parent=cs0, newfile=True)
210
211
211 #add two extra commit into fork
212 # add two extra commit into fork
212 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
213 cs1 = fixture.commit_change(repo2.repo_name, filename='file1',
213 content='line1\nline2\n', message='commit2', vcs_type='git',
214 content='line1\nline2\n', message='commit2', vcs_type='git',
214 parent=cs0)
215 parent=cs0)
@@ -241,11 +242,11 b' class TestCompareController(TestControll'
241 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
242 response.mustcontain("""<a class="changeset_hash" href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
242 ## files
243 ## files
243 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
244 response.mustcontain("""<a href="#C--826e8142e6ba">file1</a>""")
244 #swap
245 # swap
245 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
246 response.mustcontain("""<a class="btn btn-default btn-sm" href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True"><i class="icon-arrows-cw"></i> Swap</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
246
247
247 def test_compare_cherry_pick_changesets_from_bottom(self):
248 def test_compare_cherry_pick_changesets_from_bottom(self):
248
249 pass
249 # repo1:
250 # repo1:
250 # cs0:
251 # cs0:
251 # cs1:
252 # cs1:
@@ -256,7 +257,7 b' class TestCompareController(TestControll'
256 # cs3: x
257 # cs3: x
257 # cs4: x
258 # cs4: x
258 # cs5:
259 # cs5:
259 #make repo1, and cs1+cs2
260 # make repo1, and cs1+cs2
260 self.log_user()
261 self.log_user()
261
262
262 repo1 = fixture.create_repo(u'repo1', repo_type='hg',
263 repo1 = fixture.create_repo(u'repo1', repo_type='hg',
@@ -264,17 +265,17 b' class TestCompareController(TestControll'
264 cur_user=TEST_USER_ADMIN_LOGIN)
265 cur_user=TEST_USER_ADMIN_LOGIN)
265 self.r1_id = repo1.repo_id
266 self.r1_id = repo1.repo_id
266
267
267 #commit something !
268 # commit something !
268 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
269 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
269 content='line1\n', message='commit1', vcs_type='hg',
270 content='line1\n', message='commit1', vcs_type='hg',
270 parent=None, newfile=True)
271 parent=None, newfile=True)
271 cs1 = fixture.commit_change(repo1.repo_name, filename='file1',
272 cs1 = fixture.commit_change(repo1.repo_name, filename='file1',
272 content='line1\nline2\n', message='commit2', vcs_type='hg',
273 content='line1\nline2\n', message='commit2', vcs_type='hg',
273 parent=cs0)
274 parent=cs0)
274 #fork this repo
275 # fork this repo
275 repo2 = fixture.create_fork(u'repo1', u'repo1-fork')
276 repo2 = fixture.create_fork(u'repo1', u'repo1-fork')
276 self.r2_id = repo2.repo_id
277 self.r2_id = repo2.repo_id
277 #now make cs3-6
278 # now make cs3-6
278 cs2 = fixture.commit_change(repo1.repo_name, filename='file1',
279 cs2 = fixture.commit_change(repo1.repo_name, filename='file1',
279 content='line1\nline2\nline3\n', message='commit3',
280 content='line1\nline2\nline3\n', message='commit3',
280 vcs_type='hg', parent=cs1)
281 vcs_type='hg', parent=cs1)
@@ -313,6 +314,7 b' class TestCompareController(TestControll'
313 response.mustcontain("""#C--826e8142e6ba">file1</a>""")
314 response.mustcontain("""#C--826e8142e6ba">file1</a>""")
314
315
315 def test_compare_cherry_pick_changesets_from_top(self):
316 def test_compare_cherry_pick_changesets_from_top(self):
317 pass
316 # repo1:
318 # repo1:
317 # cs0:
319 # cs0:
318 # cs1:
320 # cs1:
@@ -324,24 +326,24 b' class TestCompareController(TestControll'
324 # cs4: x
326 # cs4: x
325 # cs5: x
327 # cs5: x
326 #
328 #
327 #make repo1, and cs1+cs2
329 # make repo1, and cs1+cs2
328 self.log_user()
330 self.log_user()
329 repo1 = fixture.create_repo(u'repo1', repo_type='hg',
331 repo1 = fixture.create_repo(u'repo1', repo_type='hg',
330 repo_description='diff-test',
332 repo_description='diff-test',
331 cur_user=TEST_USER_ADMIN_LOGIN)
333 cur_user=TEST_USER_ADMIN_LOGIN)
332 self.r1_id = repo1.repo_id
334 self.r1_id = repo1.repo_id
333
335
334 #commit something !
336 # commit something !
335 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
337 cs0 = fixture.commit_change(repo1.repo_name, filename='file1',
336 content='line1\n', message='commit1', vcs_type='hg',
338 content='line1\n', message='commit1', vcs_type='hg',
337 parent=None, newfile=True)
339 parent=None, newfile=True)
338 cs1 = fixture.commit_change(repo1.repo_name, filename='file1',
340 cs1 = fixture.commit_change(repo1.repo_name, filename='file1',
339 content='line1\nline2\n', message='commit2', vcs_type='hg',
341 content='line1\nline2\n', message='commit2', vcs_type='hg',
340 parent=cs0)
342 parent=cs0)
341 #fork this repo
343 # fork this repo
342 repo2 = fixture.create_fork(u'repo1', u'repo1-fork')
344 repo2 = fixture.create_fork(u'repo1', u'repo1-fork')
343 self.r2_id = repo2.repo_id
345 self.r2_id = repo2.repo_id
344 #now make cs3-6
346 # now make cs3-6
345 cs2 = fixture.commit_change(repo1.repo_name, filename='file1',
347 cs2 = fixture.commit_change(repo1.repo_name, filename='file1',
346 content='line1\nline2\nline3\n', message='commit3',
348 content='line1\nline2\nline3\n', message='commit3',
347 vcs_type='hg', parent=cs1)
349 vcs_type='hg', parent=cs1)
@@ -379,7 +381,7 b' class TestCompareController(TestControll'
379 response.mustcontain("""#C--826e8142e6ba">file1</a>""")
381 response.mustcontain("""#C--826e8142e6ba">file1</a>""")
380
382
381 def test_compare_cherry_pick_changeset_mixed_branches(self):
383 def test_compare_cherry_pick_changeset_mixed_branches(self):
382 #TODO: write this
384 # TODO: write this
383 assert 1
385 assert 1
384
386
385 def test_compare_remote_branches_hg(self):
387 def test_compare_remote_branches_hg(self):
@@ -456,7 +458,7 b' class TestCompareController(TestControll'
456 content='line1', message='commit1', vcs_type='hg', newfile=True)
458 content='line1', message='commit1', vcs_type='hg', newfile=True)
457 Session().commit()
459 Session().commit()
458 assert repo1.scm_instance.revisions == [cs0.raw_id]
460 assert repo1.scm_instance.revisions == [cs0.raw_id]
459 #fork the repo1
461 # fork the repo1
460 repo2 = fixture.create_repo(u'one-fork', repo_type='hg',
462 repo2 = fixture.create_repo(u'one-fork', repo_type='hg',
461 repo_description='diff-test',
463 repo_description='diff-test',
462 cur_user=TEST_USER_ADMIN_LOGIN,
464 cur_user=TEST_USER_ADMIN_LOGIN,
@@ -478,7 +480,7 b' class TestCompareController(TestControll'
478 cs3 = fixture.commit_change(repo=r2_name, filename='file3-fork',
480 cs3 = fixture.commit_change(repo=r2_name, filename='file3-fork',
479 content='file3-line1-from-fork', message='commit3-fork',
481 content='file3-line1-from-fork', message='commit3-fork',
480 vcs_type='hg', parent=cs2, newfile=True)
482 vcs_type='hg', parent=cs2, newfile=True)
481 #compare !
483 # compare !
482 rev1 = 'default'
484 rev1 = 'default'
483 rev2 = 'default'
485 rev2 = 'default'
484
486
@@ -497,7 +499,7 b' class TestCompareController(TestControll'
497 content='line1-added-after-fork', message='commit2-parent',
499 content='line1-added-after-fork', message='commit2-parent',
498 vcs_type='hg', parent=None, newfile=True)
500 vcs_type='hg', parent=None, newfile=True)
499
501
500 #compare !
502 # compare !
501 rev1 = 'default'
503 rev1 = 'default'
502 rev2 = 'default'
504 rev2 = 'default'
503 response = self.app.get(url('compare_url',
505 response = self.app.get(url('compare_url',
@@ -532,7 +534,7 b' class TestCompareController(TestControll'
532 newfile=True)
534 newfile=True)
533 Session().commit()
535 Session().commit()
534 assert repo1.scm_instance.revisions == [cs0.raw_id]
536 assert repo1.scm_instance.revisions == [cs0.raw_id]
535 #fork the repo1
537 # fork the repo1
536 repo2 = fixture.create_repo(u'one-git-fork', repo_type='git',
538 repo2 = fixture.create_repo(u'one-git-fork', repo_type='git',
537 repo_description='diff-test',
539 repo_description='diff-test',
538 cur_user=TEST_USER_ADMIN_LOGIN,
540 cur_user=TEST_USER_ADMIN_LOGIN,
@@ -555,7 +557,7 b' class TestCompareController(TestControll'
555 cs3 = fixture.commit_change(repo=r2_name, filename='file3-fork',
557 cs3 = fixture.commit_change(repo=r2_name, filename='file3-fork',
556 content='file3-line1-from-fork', message='commit3-fork',
558 content='file3-line1-from-fork', message='commit3-fork',
557 vcs_type='git', parent=cs2, newfile=True)
559 vcs_type='git', parent=cs2, newfile=True)
558 #compare !
560 # compare !
559 rev1 = 'master'
561 rev1 = 'master'
560 rev2 = 'master'
562 rev2 = 'master'
561
563
@@ -574,7 +576,7 b' class TestCompareController(TestControll'
574 content='line1-added-after-fork', message='commit2-parent',
576 content='line1-added-after-fork', message='commit2-parent',
575 vcs_type='git', parent=None, newfile=True)
577 vcs_type='git', parent=None, newfile=True)
576
578
577 #compare !
579 # compare !
578 rev1 = 'master'
580 rev1 = 'master'
579 rev2 = 'master'
581 rev2 = 'master'
580 response = self.app.get(url('compare_url',
582 response = self.app.get(url('compare_url',
@@ -100,7 +100,7 b' class TestCompareController(TestControll'
100
100
101 response.mustcontain('11 files changed with 94 insertions and 64 deletions')
101 response.mustcontain('11 files changed with 94 insertions and 64 deletions')
102
102
103 #files
103 # files
104 response.mustcontain('''<a href="#C--1c5cf9e91c12">docs/api/utils/index.rst</a>''')
104 response.mustcontain('''<a href="#C--1c5cf9e91c12">docs/api/utils/index.rst</a>''')
105 response.mustcontain('''<a href="#C--e3305437df55">test_and_report.sh</a>''')
105 response.mustcontain('''<a href="#C--e3305437df55">test_and_report.sh</a>''')
106 response.mustcontain('''<a href="#C--c8e92ef85cd1">.hgignore</a>''')
106 response.mustcontain('''<a href="#C--c8e92ef85cd1">.hgignore</a>''')
@@ -7,8 +7,6 b' class TestFeedController(TestController)'
7 response = self.app.get(url(controller='feed', action='rss',
7 response = self.app.get(url(controller='feed', action='rss',
8 repo_name=HG_REPO))
8 repo_name=HG_REPO))
9
9
10
11
12 assert response.content_type == "application/rss+xml"
10 assert response.content_type == "application/rss+xml"
13 assert """<rss version="2.0">""" in response
11 assert """<rss version="2.0">""" in response
14
12
@@ -58,7 +58,7 b' class TestFilesController(TestController'
58 f_path='/')
58 f_path='/')
59 )
59 )
60
60
61 #Test response...
61 # Test response...
62
62
63 response.mustcontain('<a class="browser-dir ypjax-link" href="/%s/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/docs"><i class="icon-folder-open"></i><span>docs</span></a>' % HG_REPO)
63 response.mustcontain('<a class="browser-dir ypjax-link" href="/%s/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/docs"><i class="icon-folder-open"></i><span>docs</span></a>' % HG_REPO)
64 response.mustcontain('<a class="browser-dir ypjax-link" href="/%s/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/tests"><i class="icon-folder-open"></i><span>tests</span></a>' % HG_REPO)
64 response.mustcontain('<a class="browser-dir ypjax-link" href="/%s/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/tests"><i class="icon-folder-open"></i><span>tests</span></a>' % HG_REPO)
@@ -14,6 +14,7 b' from kallithea.model.meta import Session'
14
14
15 fixture = Fixture()
15 fixture = Fixture()
16
16
17
17 class _BaseTestCase(TestController):
18 class _BaseTestCase(TestController):
18 """
19 """
19 Write all tests here
20 Write all tests here
@@ -34,7 +35,6 b' class _BaseTestCase(TestController):'
34 Session().delete(self.u1)
35 Session().delete(self.u1)
35 Session().commit()
36 Session().commit()
36
37
37
38 def test_index(self):
38 def test_index(self):
39 self.log_user()
39 self.log_user()
40 repo_name = self.REPO
40 repo_name = self.REPO
@@ -114,12 +114,12 b' class _BaseTestCase(TestController):'
114
114
115 ## run the check page that triggers the flash message
115 ## run the check page that triggers the flash message
116 response = self.app.get(url('repo_check_home', repo_name=fork_name_full))
116 response = self.app.get(url('repo_check_home', repo_name=fork_name_full))
117 #test if we have a message that fork is ok
117 # test if we have a message that fork is ok
118 self.checkSessionFlash(response,
118 self.checkSessionFlash(response,
119 'Forked repository %s as <a href="/%s">%s</a>'
119 'Forked repository %s as <a href="/%s">%s</a>'
120 % (repo_name, fork_name_full, fork_name_full))
120 % (repo_name, fork_name_full, fork_name_full))
121
121
122 #test if the fork was created in the database
122 # test if the fork was created in the database
123 fork_repo = Session().query(Repository) \
123 fork_repo = Session().query(Repository) \
124 .filter(Repository.repo_name == fork_name_full).one()
124 .filter(Repository.repo_name == fork_name_full).one()
125
125
@@ -208,12 +208,12 b' class _BaseTestCase(TestController):'
208
208
209 ## run the check page that triggers the flash message
209 ## run the check page that triggers the flash message
210 response = self.app.get(url('repo_check_home', repo_name=fork_name))
210 response = self.app.get(url('repo_check_home', repo_name=fork_name))
211 #test if we have a message that fork is ok
211 # test if we have a message that fork is ok
212 self.checkSessionFlash(response,
212 self.checkSessionFlash(response,
213 'Forked repository %s as <a href="/%s">%s</a>'
213 'Forked repository %s as <a href="/%s">%s</a>'
214 % (repo_name, fork_name, fork_name))
214 % (repo_name, fork_name, fork_name))
215
215
216 #test if the fork was created in the database
216 # test if the fork was created in the database
217 fork_repo = Session().query(Repository) \
217 fork_repo = Session().query(Repository) \
218 .filter(Repository.repo_name == fork_name).one()
218 .filter(Repository.repo_name == fork_name).one()
219
219
@@ -14,7 +14,7 b' class TestHomeController(TestController)'
14 def test_index(self):
14 def test_index(self):
15 self.log_user()
15 self.log_user()
16 response = self.app.get(url(controller='home', action='index'))
16 response = self.app.get(url(controller='home', action='index'))
17 #if global permission is set
17 # if global permission is set
18 response.mustcontain('Add Repository')
18 response.mustcontain('Add Repository')
19
19
20 response.mustcontain('<span class="repotag">git')
20 response.mustcontain('<span class="repotag">git')
@@ -181,7 +181,7 b' class TestLoginController(TestController'
181 ])
181 ])
182 def test_redirection_after_successful_login_preserves_get_args(self, args, args_encoded):
182 def test_redirection_after_successful_login_preserves_get_args(self, args, args_encoded):
183 response = self.app.post(url(controller='login', action='index',
183 response = self.app.post(url(controller='login', action='index',
184 came_from = url('/_admin/users', **args)),
184 came_from=url('/_admin/users', **args)),
185 {'username': TEST_USER_ADMIN_LOGIN,
185 {'username': TEST_USER_ADMIN_LOGIN,
186 'password': TEST_USER_ADMIN_PASS})
186 'password': TEST_USER_ADMIN_PASS})
187 assert response.status == '302 Found'
187 assert response.status == '302 Found'
@@ -510,7 +510,7 b' class TestLoginController(TestController'
510
510
511 new_api_key = ApiKeyModel().create(TEST_USER_ADMIN_LOGIN, u'test')
511 new_api_key = ApiKeyModel().create(TEST_USER_ADMIN_LOGIN, u'test')
512 Session().commit()
512 Session().commit()
513 #patch the API key and make it expired
513 # patch the API key and make it expired
514 new_api_key.expires = 0
514 new_api_key.expires = 0
515 Session().commit()
515 Session().commit()
516 self._api_key_test(new_api_key.api_key, status=403)
516 self._api_key_test(new_api_key.api_key, status=403)
@@ -134,16 +134,16 b' class TestMyAccountController(TestContro'
134 if name == 'email':
134 if name == 'email':
135 params['emails'] = [attrs['email']]
135 params['emails'] = [attrs['email']]
136 if name == 'extern_type':
136 if name == 'extern_type':
137 #cannot update this via form, expected value is original one
137 # cannot update this via form, expected value is original one
138 params['extern_type'] = "internal"
138 params['extern_type'] = "internal"
139 if name == 'extern_name':
139 if name == 'extern_name':
140 #cannot update this via form, expected value is original one
140 # cannot update this via form, expected value is original one
141 params['extern_name'] = str(user_id)
141 params['extern_name'] = str(user_id)
142 if name == 'active':
142 if name == 'active':
143 #my account cannot deactivate account
143 # my account cannot deactivate account
144 params['active'] = True
144 params['active'] = True
145 if name == 'admin':
145 if name == 'admin':
146 #my account cannot make you an admin !
146 # my account cannot make you an admin !
147 params['admin'] = False
147 params['admin'] = False
148
148
149 params.pop('_authentication_token')
149 params.pop('_authentication_token')
@@ -224,7 +224,7 b' class TestMyAccountController(TestContro'
224 self.checkSessionFlash(response, 'API key successfully created')
224 self.checkSessionFlash(response, 'API key successfully created')
225 response = response.follow()
225 response = response.follow()
226
226
227 #now delete our key
227 # now delete our key
228 keys = UserApiKeys.query().all()
228 keys = UserApiKeys.query().all()
229 assert 1 == len(keys)
229 assert 1 == len(keys)
230
230
@@ -234,7 +234,6 b' class TestMyAccountController(TestContro'
234 keys = UserApiKeys.query().all()
234 keys = UserApiKeys.query().all()
235 assert 0 == len(keys)
235 assert 0 == len(keys)
236
236
237
238 def test_my_account_reset_main_api_key(self):
237 def test_my_account_reset_main_api_key(self):
239 usr = self.log_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS)
238 usr = self.log_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS)
240 user = User.get(usr['user_id'])
239 user = User.get(usr['user_id'])
@@ -12,6 +12,7 b' from kallithea.controllers.pullrequests '
12
12
13 fixture = Fixture()
13 fixture = Fixture()
14
14
15
15 class TestPullrequestsController(TestController):
16 class TestPullrequestsController(TestController):
16
17
17 def test_index(self):
18 def test_index(self):
@@ -208,7 +209,6 b' class TestPullrequestsController(TestCon'
208 status=400)
209 status=400)
209 response.mustcontain('Invalid reviewer &#34;%s&#34; specified' % invalid_user_id)
210 response.mustcontain('Invalid reviewer &#34;%s&#34; specified' % invalid_user_id)
210
211
211
212 def test_iteration_refs(self):
212 def test_iteration_refs(self):
213 # Repo graph excerpt:
213 # Repo graph excerpt:
214 # o fb95b340e0d0 webvcs
214 # o fb95b340e0d0 webvcs
@@ -10,6 +10,7 b' from kallithea.tests.fixture import crea'
10
10
11 fixture = Fixture()
11 fixture = Fixture()
12
12
13
13 def init_indexing_test(repo):
14 def init_indexing_test(repo):
14 prev = fixture.commit_change(repo.repo_name,
15 prev = fixture.commit_change(repo.repo_name,
15 filename='this_should_be_unique_filename.txt',
16 filename='this_should_be_unique_filename.txt',
@@ -34,6 +35,7 b' def init_stopword_test(repo):'
34 parent=prev,
35 parent=prev,
35 newfile=True)
36 newfile=True)
36
37
38
37 repos = [
39 repos = [
38 # reponame, init func or fork base, groupname
40 # reponame, init func or fork base, groupname
39 (u'indexing_test', init_indexing_test, None),
41 (u'indexing_test', init_indexing_test, None),
@@ -44,10 +46,12 b' repos = ['
44 (u'stopword_test', init_stopword_test, None),
46 (u'stopword_test', init_stopword_test, None),
45 ]
47 ]
46
48
49
47 # map: name => id
50 # map: name => id
48 repoids = {}
51 repoids = {}
49 groupids = {}
52 groupids = {}
50
53
54
51 def rebuild_index(full_index):
55 def rebuild_index(full_index):
52 with mock.patch('kallithea.lib.indexers.daemon.log.debug',
56 with mock.patch('kallithea.lib.indexers.daemon.log.debug',
53 lambda *args, **kwargs: None):
57 lambda *args, **kwargs: None):
@@ -31,11 +31,11 b' class TestSummaryController(TestControll'
31 action='index',
31 action='index',
32 repo_name=HG_REPO))
32 repo_name=HG_REPO))
33
33
34 #repo type
34 # repo type
35 response.mustcontain(
35 response.mustcontain(
36 """<span class="repotag">hg"""
36 """<span class="repotag">hg"""
37 )
37 )
38 #public/private
38 # public/private
39 response.mustcontain(
39 response.mustcontain(
40 """<i class="icon-globe">"""
40 """<i class="icon-globe">"""
41 )
41 )
@@ -57,11 +57,11 b' class TestSummaryController(TestControll'
57 action='index',
57 action='index',
58 repo_name=GIT_REPO))
58 repo_name=GIT_REPO))
59
59
60 #repo type
60 # repo type
61 response.mustcontain(
61 response.mustcontain(
62 """<span class="repotag">git"""
62 """<span class="repotag">git"""
63 )
63 )
64 #public/private
64 # public/private
65 response.mustcontain(
65 response.mustcontain(
66 """<i class="icon-globe">"""
66 """<i class="icon-globe">"""
67 )
67 )
@@ -82,11 +82,11 b' class TestSummaryController(TestControll'
82 action='index',
82 action='index',
83 repo_name='_%s' % ID))
83 repo_name='_%s' % ID))
84
84
85 #repo type
85 # repo type
86 response.mustcontain(
86 response.mustcontain(
87 """<span class="repotag">hg"""
87 """<span class="repotag">hg"""
88 )
88 )
89 #public/private
89 # public/private
90 response.mustcontain(
90 response.mustcontain(
91 """<i class="icon-globe">"""
91 """<i class="icon-globe">"""
92 )
92 )
@@ -111,11 +111,11 b' class TestSummaryController(TestControll'
111 action='index',
111 action='index',
112 repo_name='_%s' % ID))
112 repo_name='_%s' % ID))
113
113
114 #repo type
114 # repo type
115 response.mustcontain(
115 response.mustcontain(
116 """<span class="repotag">git"""
116 """<span class="repotag">git"""
117 )
117 )
118 #public/private
118 # public/private
119 response.mustcontain(
119 response.mustcontain(
120 """<i class="icon-globe">"""
120 """<i class="icon-globe">"""
121 )
121 )
@@ -127,7 +127,7 b' class TestSummaryController(TestControll'
127
127
128 def test_index_trending(self):
128 def test_index_trending(self):
129 self.log_user()
129 self.log_user()
130 #codes stats
130 # codes stats
131 self._enable_stats(HG_REPO)
131 self._enable_stats(HG_REPO)
132
132
133 ScmModel().mark_for_invalidation(HG_REPO)
133 ScmModel().mark_for_invalidation(HG_REPO)
@@ -151,7 +151,7 b' class TestSummaryController(TestControll'
151
151
152 def test_index_statistics(self):
152 def test_index_statistics(self):
153 self.log_user()
153 self.log_user()
154 #codes stats
154 # codes stats
155 self._enable_stats(HG_REPO)
155 self._enable_stats(HG_REPO)
156
156
157 ScmModel().mark_for_invalidation(HG_REPO)
157 ScmModel().mark_for_invalidation(HG_REPO)
@@ -160,7 +160,7 b' class TestSummaryController(TestControll'
160
160
161 def test_index_trending_git(self):
161 def test_index_trending_git(self):
162 self.log_user()
162 self.log_user()
163 #codes stats
163 # codes stats
164 self._enable_stats(GIT_REPO)
164 self._enable_stats(GIT_REPO)
165
165
166 ScmModel().mark_for_invalidation(GIT_REPO)
166 ScmModel().mark_for_invalidation(GIT_REPO)
@@ -184,7 +184,7 b' class TestSummaryController(TestControll'
184
184
185 def test_index_statistics_git(self):
185 def test_index_statistics_git(self):
186 self.log_user()
186 self.log_user()
187 #codes stats
187 # codes stats
188 self._enable_stats(GIT_REPO)
188 self._enable_stats(GIT_REPO)
189
189
190 ScmModel().mark_for_invalidation(GIT_REPO)
190 ScmModel().mark_for_invalidation(GIT_REPO)
@@ -2,11 +2,13 b' from kallithea.tests.base import *'
2 from kallithea.model.changeset_status import ChangesetStatusModel
2 from kallithea.model.changeset_status import ChangesetStatusModel
3 from kallithea.model.db import ChangesetStatus as CS
3 from kallithea.model.db import ChangesetStatus as CS
4
4
5
5 class CSM(object): # ChangesetStatusMock
6 class CSM(object): # ChangesetStatusMock
6
7
7 def __init__(self, status):
8 def __init__(self, status):
8 self.status = status
9 self.status = status
9
10
11
10 class TestChangesetStatusCalculation(TestController):
12 class TestChangesetStatusCalculation(TestController):
11
13
12 def setup_method(self, method):
14 def setup_method(self, method):
@@ -16,6 +16,7 b' import kallithea.lib.celerylib.tasks'
16
16
17 from tg.util.webtest import test_context
17 from tg.util.webtest import test_context
18
18
19
19 class TestNotifications(TestController):
20 class TestNotifications(TestController):
20
21
21 def setup_method(self, method):
22 def setup_method(self, method):
@@ -48,6 +49,7 b' class TestNotifications(TestController):'
48 def test_create_notification(self):
49 def test_create_notification(self):
49 with test_context(self.app):
50 with test_context(self.app):
50 usrs = [self.u1, self.u2]
51 usrs = [self.u1, self.u2]
52
51 def send_email(recipients, subject, body='', html_body='', headers=None, author=None):
53 def send_email(recipients, subject, body='', html_body='', headers=None, author=None):
52 assert recipients == ['u2@example.com']
54 assert recipients == ['u2@example.com']
53 assert subject == 'Test Message'
55 assert subject == 'Test Message'
@@ -137,7 +139,7 b' class TestNotifications(TestController):'
137 # notification object is still there
139 # notification object is still there
138 assert Notification.query().all() == [notification]
140 assert Notification.query().all() == [notification]
139
141
140 #u1 and u2 still have assignments
142 # u1 and u2 still have assignments
141 u1notification = UserNotification.query() \
143 u1notification = UserNotification.query() \
142 .filter(UserNotification.notification ==
144 .filter(UserNotification.notification ==
143 notification) \
145 notification) \
@@ -19,7 +19,7 b' class TestPermissions(TestController):'
19
19
20 @classmethod
20 @classmethod
21 def setup_class(cls):
21 def setup_class(cls):
22 #recreate default user to get a clean start
22 # recreate default user to get a clean start
23 PermissionModel().create_default_permissions(user=User.DEFAULT_USER,
23 PermissionModel().create_default_permissions(user=User.DEFAULT_USER,
24 force=True)
24 force=True)
25 Session().commit()
25 Session().commit()
@@ -218,7 +218,7 b' class TestPermissions(TestController):'
218 a1_auth = AuthUser(user_id=self.anon.user_id)
218 a1_auth = AuthUser(user_id=self.anon.user_id)
219 assert a1_auth.permissions['repositories_groups'] == {u'group1': u'group.read', u'group2': u'group.read'}
219 assert a1_auth.permissions['repositories_groups'] == {u'group1': u'group.read', u'group2': u'group.read'}
220
220
221 #Change perms to none for both groups
221 # Change perms to none for both groups
222 RepoGroupModel().grant_user_permission(repo_group=self.g1,
222 RepoGroupModel().grant_user_permission(repo_group=self.g1,
223 user=self.anon,
223 user=self.anon,
224 perm='group.none')
224 perm='group.none')
@@ -245,14 +245,14 b' class TestPermissions(TestController):'
245 a1_auth = AuthUser(user_id=self.anon.user_id)
245 a1_auth = AuthUser(user_id=self.anon.user_id)
246 assert a1_auth.permissions['repositories_groups'] == {u'group1': u'group.none', u'group2': u'group.none'}
246 assert a1_auth.permissions['repositories_groups'] == {u'group1': u'group.none', u'group2': u'group.none'}
247
247
248 #grant permission for u2 !
248 # grant permission for u2 !
249 RepoGroupModel().grant_user_permission(repo_group=self.g1, user=self.u2,
249 RepoGroupModel().grant_user_permission(repo_group=self.g1, user=self.u2,
250 perm='group.read')
250 perm='group.read')
251 RepoGroupModel().grant_user_permission(repo_group=self.g2, user=self.u2,
251 RepoGroupModel().grant_user_permission(repo_group=self.g2, user=self.u2,
252 perm='group.read')
252 perm='group.read')
253 Session().commit()
253 Session().commit()
254 assert self.u1 != self.u2
254 assert self.u1 != self.u2
255 #u1 and anon should have not change perms while u2 should !
255 # u1 and anon should have not change perms while u2 should !
256 u1_auth = AuthUser(user_id=self.u1.user_id)
256 u1_auth = AuthUser(user_id=self.u1.user_id)
257 assert u1_auth.permissions['repositories_groups'] == {u'group1': u'group.none', u'group2': u'group.none'}
257 assert u1_auth.permissions['repositories_groups'] == {u'group1': u'group.none', u'group2': u'group.none'}
258
258
@@ -357,7 +357,7 b' class TestPermissions(TestController):'
357 user_model.revoke_perm(usr, 'hg.fork.none')
357 user_model.revoke_perm(usr, 'hg.fork.none')
358 user_model.grant_perm(usr, 'hg.fork.repository')
358 user_model.grant_perm(usr, 'hg.fork.repository')
359
359
360 #disable global perms on specific user
360 # disable global perms on specific user
361 user_model.revoke_perm(self.u1, 'hg.create.repository')
361 user_model.revoke_perm(self.u1, 'hg.create.repository')
362 user_model.grant_perm(self.u1, 'hg.create.none')
362 user_model.grant_perm(self.u1, 'hg.create.none')
363 user_model.revoke_perm(self.u1, 'hg.fork.repository')
363 user_model.revoke_perm(self.u1, 'hg.fork.repository')
@@ -384,7 +384,7 b' class TestPermissions(TestController):'
384 user_model.revoke_perm(usr, 'hg.fork.repository')
384 user_model.revoke_perm(usr, 'hg.fork.repository')
385 user_model.grant_perm(usr, 'hg.fork.none')
385 user_model.grant_perm(usr, 'hg.fork.none')
386
386
387 #enable global perms on specific user
387 # enable global perms on specific user
388 user_model.revoke_perm(self.u1, 'hg.create.none')
388 user_model.revoke_perm(self.u1, 'hg.create.none')
389 user_model.grant_perm(self.u1, 'hg.create.repository')
389 user_model.grant_perm(self.u1, 'hg.create.repository')
390 user_model.revoke_perm(self.u1, 'hg.fork.none')
390 user_model.revoke_perm(self.u1, 'hg.fork.none')
@@ -609,15 +609,15 b' class TestPermissions(TestController):'
609 assert u1_auth.permissions['user_groups'][u'G2'] == u'usergroup.admin'
609 assert u1_auth.permissions['user_groups'][u'G2'] == u'usergroup.admin'
610
610
611 def test_owner_permissions_doesnot_get_overwritten_by_group(self):
611 def test_owner_permissions_doesnot_get_overwritten_by_group(self):
612 #create repo as USER,
612 # create repo as USER,
613 self.test_repo = fixture.create_repo(name=u'myownrepo',
613 self.test_repo = fixture.create_repo(name=u'myownrepo',
614 repo_type='hg',
614 repo_type='hg',
615 cur_user=self.u1)
615 cur_user=self.u1)
616
616
617 #he has permissions of admin as owner
617 # he has permissions of admin as owner
618 u1_auth = AuthUser(user_id=self.u1.user_id)
618 u1_auth = AuthUser(user_id=self.u1.user_id)
619 assert u1_auth.permissions['repositories']['myownrepo'] == 'repository.admin'
619 assert u1_auth.permissions['repositories']['myownrepo'] == 'repository.admin'
620 #set his permission as user group, he should still be admin
620 # set his permission as user group, he should still be admin
621 self.ug1 = fixture.create_user_group(u'G1')
621 self.ug1 = fixture.create_user_group(u'G1')
622 UserGroupModel().add_user_to_group(self.ug1, self.u1)
622 UserGroupModel().add_user_to_group(self.ug1, self.u1)
623 RepoModel().grant_user_group_permission(self.test_repo,
623 RepoModel().grant_user_group_permission(self.test_repo,
@@ -629,15 +629,15 b' class TestPermissions(TestController):'
629 assert u1_auth.permissions['repositories']['myownrepo'] == 'repository.admin'
629 assert u1_auth.permissions['repositories']['myownrepo'] == 'repository.admin'
630
630
631 def test_owner_permissions_doesnot_get_overwritten_by_others(self):
631 def test_owner_permissions_doesnot_get_overwritten_by_others(self):
632 #create repo as USER,
632 # create repo as USER,
633 self.test_repo = fixture.create_repo(name=u'myownrepo',
633 self.test_repo = fixture.create_repo(name=u'myownrepo',
634 repo_type='hg',
634 repo_type='hg',
635 cur_user=self.u1)
635 cur_user=self.u1)
636
636
637 #he has permissions of admin as owner
637 # he has permissions of admin as owner
638 u1_auth = AuthUser(user_id=self.u1.user_id)
638 u1_auth = AuthUser(user_id=self.u1.user_id)
639 assert u1_auth.permissions['repositories']['myownrepo'] == 'repository.admin'
639 assert u1_auth.permissions['repositories']['myownrepo'] == 'repository.admin'
640 #set his permission as user, he should still be admin
640 # set his permission as user, he should still be admin
641 RepoModel().grant_user_permission(self.test_repo, user=self.u1,
641 RepoModel().grant_user_permission(self.test_repo, user=self.u1,
642 perm='repository.none')
642 perm='repository.none')
643 Session().commit()
643 Session().commit()
@@ -657,7 +657,7 b' class TestPermissions(TestController):'
657 def test_set_default_permissions_after_one_is_missing(self):
657 def test_set_default_permissions_after_one_is_missing(self):
658 PermissionModel().create_default_permissions(user=self.u1)
658 PermissionModel().create_default_permissions(user=self.u1)
659 self._test_def_perm_equal(user=self.u1)
659 self._test_def_perm_equal(user=self.u1)
660 #now we delete one, it should be re-created after another call
660 # now we delete one, it should be re-created after another call
661 perms = UserToPerm.query() \
661 perms = UserToPerm.query() \
662 .filter(UserToPerm.user == self.u1) \
662 .filter(UserToPerm.user == self.u1) \
663 .all()
663 .all()
@@ -666,7 +666,7 b' class TestPermissions(TestController):'
666
666
667 self._test_def_perm_equal(user=self.u1, change_factor=-1)
667 self._test_def_perm_equal(user=self.u1, change_factor=-1)
668
668
669 #create missing one !
669 # create missing one !
670 PermissionModel().create_default_permissions(user=self.u1)
670 PermissionModel().create_default_permissions(user=self.u1)
671 self._test_def_perm_equal(user=self.u1)
671 self._test_def_perm_equal(user=self.u1)
672
672
@@ -687,7 +687,7 b' class TestPermissions(TestController):'
687 assert old != None
687 assert old != None
688 assert new != None
688 assert new != None
689
689
690 #now modify permissions
690 # now modify permissions
691 p = UserToPerm.query() \
691 p = UserToPerm.query() \
692 .filter(UserToPerm.user == self.u1) \
692 .filter(UserToPerm.user == self.u1) \
693 .filter(UserToPerm.permission == old) \
693 .filter(UserToPerm.permission == old) \
@@ -161,7 +161,7 b' class TestRepoGroups(TestController):'
161
161
162 r = fixture.create_repo(u'L1/L2/L3/L3_REPO', repo_group=g3.group_id)
162 r = fixture.create_repo(u'L1/L2/L3/L3_REPO', repo_group=g3.group_id)
163
163
164 ##rename L1 all groups should be now changed
164 ## rename L1 all groups should be now changed
165 _update_repo_group(g1.group_id, u'L1_NEW')
165 _update_repo_group(g1.group_id, u'L1_NEW')
166 Session().commit()
166 Session().commit()
167 assert g1.full_path == 'L1_NEW'
167 assert g1.full_path == 'L1_NEW'
@@ -176,7 +176,7 b' class TestRepoGroups(TestController):'
176 g4 = fixture.create_repo_group(u'R1_NEW')
176 g4 = fixture.create_repo_group(u'R1_NEW')
177
177
178 r = fixture.create_repo(u'R1/R2/R3/R3_REPO', repo_group=g3.group_id)
178 r = fixture.create_repo(u'R1/R2/R3/R3_REPO', repo_group=g3.group_id)
179 ##rename L1 all groups should be now changed
179 ## rename L1 all groups should be now changed
180 _update_repo_group(g1.group_id, u'R1', parent_id=g4.group_id)
180 _update_repo_group(g1.group_id, u'R1', parent_id=g4.group_id)
181 Session().commit()
181 Session().commit()
182 assert g1.full_path == 'R1_NEW/R1'
182 assert g1.full_path == 'R1_NEW/R1'
@@ -192,7 +192,7 b' class TestRepoGroups(TestController):'
192
192
193 r = fixture.create_repo(u'X1/X2/X3/X3_REPO', repo_group=g3.group_id)
193 r = fixture.create_repo(u'X1/X2/X3/X3_REPO', repo_group=g3.group_id)
194
194
195 ##rename L1 all groups should be now changed
195 ## rename L1 all groups should be now changed
196 _update_repo_group(g1.group_id, u'X1_PRIM', parent_id=g4.group_id)
196 _update_repo_group(g1.group_id, u'X1_PRIM', parent_id=g4.group_id)
197 Session().commit()
197 Session().commit()
198 assert g1.full_path == 'X1_NEW/X1_PRIM'
198 assert g1.full_path == 'X1_NEW/X1_PRIM'
@@ -45,7 +45,7 b' class TestRepos(TestController):'
45 fork = fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
45 fork = fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
46 Session().commit()
46 Session().commit()
47
47
48 #fork of fork
48 # fork of fork
49 fixture.create_fork(fork.repo_name, u'test-repo-fork-fork-1')
49 fixture.create_fork(fork.repo_name, u'test-repo-fork-fork-1')
50 Session().commit()
50 Session().commit()
51
51
@@ -63,7 +63,7 b' class TestRepos(TestController):'
63 fork = fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
63 fork = fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
64 Session().commit()
64 Session().commit()
65
65
66 #fork of fork
66 # fork of fork
67 fixture.create_fork(fork.repo_name, u'test-repo-fork-fork-1')
67 fixture.create_fork(fork.repo_name, u'test-repo-fork-fork-1')
68 Session().commit()
68 Session().commit()
69
69
@@ -4,6 +4,7 b' from kallithea.model.db import Setting'
4
4
5 name = 'spam-setting-name'
5 name = 'spam-setting-name'
6
6
7
7 def test_passing_list_setting_value_results_in_string_valued_setting():
8 def test_passing_list_setting_value_results_in_string_valued_setting():
8 assert Setting.get_by_name(name) is None
9 assert Setting.get_by_name(name) is None
9 setting = Setting.create_or_update(name, ['spam', 'eggs'])
10 setting = Setting.create_or_update(name, ['spam', 'eggs'])
@@ -17,6 +18,7 b' def test_passing_list_setting_value_resu'
17 finally:
18 finally:
18 Session().delete(setting)
19 Session().delete(setting)
19
20
21
20 def test_list_valued_setting_creation_requires_manual_value_formatting():
22 def test_list_valued_setting_creation_requires_manual_value_formatting():
21 assert Setting.get_by_name(name) is None
23 assert Setting.get_by_name(name) is None
22 # Quirk: need manual formatting of list setting value.
24 # Quirk: need manual formatting of list setting value.
@@ -27,6 +29,7 b' def test_list_valued_setting_creation_re'
27 finally:
29 finally:
28 Session().delete(setting)
30 Session().delete(setting)
29
31
32
30 def test_list_valued_setting_update():
33 def test_list_valued_setting_update():
31 assert Setting.get_by_name(name) is None
34 assert Setting.get_by_name(name) is None
32 setting = Setting.create_or_update(name, 'spam', type='list')
35 setting = Setting.create_or_update(name, 'spam', type='list')
@@ -1,1 +1,1 b''
1 #TODO; write tests when we activate algo for permissions.
1 # TODO; write tests when we activate algo for permissions.
@@ -4,7 +4,6 b' from kallithea.tests.base import *'
4 from kallithea.model.db import User, UserGroup, UserGroupMember, UserEmailMap, \
4 from kallithea.model.db import User, UserGroup, UserGroupMember, UserEmailMap, \
5 Permission
5 Permission
6 from kallithea.model.user import UserModel
6 from kallithea.model.user import UserModel
7
8 from kallithea.model.meta import Session
7 from kallithea.model.meta import Session
9 from kallithea.model.user_group import UserGroupModel
8 from kallithea.model.user_group import UserGroupModel
10 from kallithea.tests.fixture import Fixture
9 from kallithea.tests.fixture import Fixture
@@ -138,7 +137,7 b' class TestUsers(TestController):'
138 Session().commit()
137 Session().commit()
139 assert UserModel().has_perm(self.u1, perm) == True
138 assert UserModel().has_perm(self.u1, perm) == True
140
139
141 #revoke
140 # revoke
142 UserModel().revoke_perm(self.u1, perm)
141 UserModel().revoke_perm(self.u1, perm)
143 Session().commit()
142 Session().commit()
144 assert UserModel().has_perm(self.u1, perm) == False
143 assert UserModel().has_perm(self.u1, perm) == False
@@ -67,6 +67,7 b' TEST_URLS += ['
67 '%s://example.com:8080' % proto),
67 '%s://example.com:8080' % proto),
68 ]
68 ]
69
69
70
70 class FakeUrlGenerator(object):
71 class FakeUrlGenerator(object):
71
72
72 def __init__(self, current_url=None, default_route=None, **routes):
73 def __init__(self, current_url=None, default_route=None, **routes):
@@ -86,6 +87,7 b' class FakeUrlGenerator(object):'
86 def current(self, *args, **kwargs):
87 def current(self, *args, **kwargs):
87 return self.current_url % kwargs
88 return self.current_url % kwargs
88
89
90
89 class TestLibs(TestController):
91 class TestLibs(TestController):
90
92
91 @parametrize('test_url,expected,expected_creds', TEST_URLS)
93 @parametrize('test_url,expected,expected_creds', TEST_URLS)
@@ -4,6 +4,7 b' import kallithea'
4 from kallithea.tests.base import *
4 from kallithea.tests.base import *
5 from kallithea.model.db import User
5 from kallithea.model.db import User
6
6
7
7 class smtplib_mock(object):
8 class smtplib_mock(object):
8
9
9 @classmethod
10 @classmethod
@@ -12,14 +13,17 b' class smtplib_mock(object):'
12
13
13 def ehlo(self):
14 def ehlo(self):
14 pass
15 pass
16
15 def quit(self):
17 def quit(self):
16 pass
18 pass
19
17 def sendmail(self, sender, dest, msg):
20 def sendmail(self, sender, dest, msg):
18 smtplib_mock.lastsender = sender
21 smtplib_mock.lastsender = sender
19 smtplib_mock.lastdest = dest
22 smtplib_mock.lastdest = dest
20 smtplib_mock.lastmsg = msg
23 smtplib_mock.lastmsg = msg
21 pass
24 pass
22
25
26
23 @mock.patch('kallithea.lib.rcmail.smtp_mailer.smtplib', smtplib_mock)
27 @mock.patch('kallithea.lib.rcmail.smtp_mailer.smtplib', smtplib_mock)
24 class TestMail(TestController):
28 class TestMail(TestController):
25
29
@@ -162,7 +162,7 b' class TestRepoGroups(TestController):'
162 with pytest.raises(formencode.Invalid):
162 with pytest.raises(formencode.Invalid):
163 validator.to_python({'repo_name': gr.group_name})
163 validator.to_python({'repo_name': gr.group_name})
164
164
165 #TODO: write an error case for that ie. create a repo withinh a group
165 # TODO: write an error case for that ie. create a repo withinh a group
166 # self.assertRaises(formencode.Invalid,
166 # self.assertRaises(formencode.Invalid,
167 # validator.to_python, {'repo_name': 'some',
167 # validator.to_python, {'repo_name': 'some',
168 # 'repo_group': gr.group_id})
168 # 'repo_group': gr.group_id})
@@ -181,7 +181,7 b' class TestRepoGroups(TestController):'
181 assert expected == validator.to_python(name)
181 assert expected == validator.to_python(name)
182
182
183 def test_ValidCloneUri(self):
183 def test_ValidCloneUri(self):
184 #TODO: write this one
184 # TODO: write this one
185 pass
185 pass
186
186
187 def test_ValidForkType(self):
187 def test_ValidForkType(self):
@@ -191,7 +191,7 b' class TestRepoGroups(TestController):'
191 validator.to_python('git')
191 validator.to_python('git')
192
192
193 def test_ValidPerms(self):
193 def test_ValidPerms(self):
194 #TODO: write this one
194 # TODO: write this one
195 pass
195 pass
196
196
197 def test_ValidSettings(self):
197 def test_ValidSettings(self):
@@ -152,7 +152,7 b' def set_anonymous_access(enable=True):'
152
152
153
153
154 def _check_proper_git_push(stdout, stderr):
154 def _check_proper_git_push(stdout, stderr):
155 #WTF Git stderr is output ?!
155 # WTF Git stderr is output ?!
156 assert 'fatal' not in stderr
156 assert 'fatal' not in stderr
157 assert 'rejected' not in stderr
157 assert 'rejected' not in stderr
158 assert 'Pushing to' in stderr
158 assert 'Pushing to' in stderr
@@ -164,7 +164,7 b' class TestVCSOperations(TestController):'
164
164
165 @classmethod
165 @classmethod
166 def setup_class(cls):
166 def setup_class(cls):
167 #DISABLE ANONYMOUS ACCESS
167 # DISABLE ANONYMOUS ACCESS
168 set_anonymous_access(False)
168 set_anonymous_access(False)
169
169
170 def setup_method(self, method):
170 def setup_method(self, method):
@@ -255,7 +255,7 b' class TestVCSOperations(TestController):'
255
255
256 def test_push_invalidates_cache_hg(self, webserver):
256 def test_push_invalidates_cache_hg(self, webserver):
257 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
257 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
258 ==HG_REPO).scalar()
258 == HG_REPO).scalar()
259 if not key:
259 if not key:
260 key = CacheInvalidation(HG_REPO, HG_REPO)
260 key = CacheInvalidation(HG_REPO, HG_REPO)
261 Session().add(key)
261 Session().add(key)
@@ -273,12 +273,12 b' class TestVCSOperations(TestController):'
273 stdout, stderr = _add_files_and_push(webserver, 'hg', DEST, files_no=1, clone_url=clone_url)
273 stdout, stderr = _add_files_and_push(webserver, 'hg', DEST, files_no=1, clone_url=clone_url)
274
274
275 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
275 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
276 ==fork_name).all()
276 == fork_name).all()
277 assert key == []
277 assert key == []
278
278
279 def test_push_invalidates_cache_git(self, webserver):
279 def test_push_invalidates_cache_git(self, webserver):
280 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
280 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
281 ==GIT_REPO).scalar()
281 == GIT_REPO).scalar()
282 if not key:
282 if not key:
283 key = CacheInvalidation(GIT_REPO, GIT_REPO)
283 key = CacheInvalidation(GIT_REPO, GIT_REPO)
284 Session().add(key)
284 Session().add(key)
@@ -298,7 +298,7 b' class TestVCSOperations(TestController):'
298 _check_proper_git_push(stdout, stderr)
298 _check_proper_git_push(stdout, stderr)
299
299
300 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
300 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
301 ==fork_name).all()
301 == fork_name).all()
302 assert key == []
302 assert key == []
303
303
304 def test_push_wrong_credentials_hg(self, webserver):
304 def test_push_wrong_credentials_hg(self, webserver):
@@ -352,7 +352,7 b' class TestVCSOperations(TestController):'
352 clone_url = webserver.repo_url(HG_REPO)
352 clone_url = webserver.repo_url(HG_REPO)
353 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir())
353 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir())
354
354
355 #check if lock was made
355 # check if lock was made
356 r = Repository.get_by_repo_name(HG_REPO)
356 r = Repository.get_by_repo_name(HG_REPO)
357 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
357 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
358
358
@@ -365,15 +365,15 b' class TestVCSOperations(TestController):'
365 clone_url = webserver.repo_url(GIT_REPO)
365 clone_url = webserver.repo_url(GIT_REPO)
366 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir())
366 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir())
367
367
368 #check if lock was made
368 # check if lock was made
369 r = Repository.get_by_repo_name(GIT_REPO)
369 r = Repository.get_by_repo_name(GIT_REPO)
370 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
370 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
371
371
372 def test_clone_after_repo_was_locked_hg(self, webserver):
372 def test_clone_after_repo_was_locked_hg(self, webserver):
373 #lock repo
373 # lock repo
374 r = Repository.get_by_repo_name(HG_REPO)
374 r = Repository.get_by_repo_name(HG_REPO)
375 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
375 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
376 #pull fails since repo is locked
376 # pull fails since repo is locked
377 clone_url = webserver.repo_url(HG_REPO)
377 clone_url = webserver.repo_url(HG_REPO)
378 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
378 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
379 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
379 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
@@ -381,22 +381,22 b' class TestVCSOperations(TestController):'
381 assert msg in stderr
381 assert msg in stderr
382
382
383 def test_clone_after_repo_was_locked_git(self, webserver):
383 def test_clone_after_repo_was_locked_git(self, webserver):
384 #lock repo
384 # lock repo
385 r = Repository.get_by_repo_name(GIT_REPO)
385 r = Repository.get_by_repo_name(GIT_REPO)
386 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
386 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
387 #pull fails since repo is locked
387 # pull fails since repo is locked
388 clone_url = webserver.repo_url(GIT_REPO)
388 clone_url = webserver.repo_url(GIT_REPO)
389 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
389 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
390 msg = ("""The requested URL returned error: 423""")
390 msg = ("""The requested URL returned error: 423""")
391 assert msg in stderr
391 assert msg in stderr
392
392
393 def test_push_on_locked_repo_by_other_user_hg(self, webserver):
393 def test_push_on_locked_repo_by_other_user_hg(self, webserver):
394 #clone some temp
394 # clone some temp
395 DEST = _get_tmp_dir()
395 DEST = _get_tmp_dir()
396 clone_url = webserver.repo_url(HG_REPO)
396 clone_url = webserver.repo_url(HG_REPO)
397 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, DEST)
397 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, DEST)
398
398
399 #lock repo
399 # lock repo
400 r = Repository.get_by_repo_name(HG_REPO)
400 r = Repository.get_by_repo_name(HG_REPO)
401 # let this user actually push !
401 # let this user actually push !
402 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
402 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
@@ -404,7 +404,7 b' class TestVCSOperations(TestController):'
404 Session().commit()
404 Session().commit()
405 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
405 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
406
406
407 #push fails repo is locked by other user !
407 # push fails repo is locked by other user !
408 stdout, stderr = _add_files_and_push(webserver, 'hg', DEST,
408 stdout, stderr = _add_files_and_push(webserver, 'hg', DEST,
409 username=TEST_USER_REGULAR_LOGIN,
409 username=TEST_USER_REGULAR_LOGIN,
410 password=TEST_USER_REGULAR_PASS,
410 password=TEST_USER_REGULAR_PASS,
@@ -417,12 +417,12 b' class TestVCSOperations(TestController):'
417 # Note: Git hooks must be executable on unix. This test will thus fail
417 # Note: Git hooks must be executable on unix. This test will thus fail
418 # for example on Linux if /tmp is mounted noexec.
418 # for example on Linux if /tmp is mounted noexec.
419
419
420 #clone some temp
420 # clone some temp
421 DEST = _get_tmp_dir()
421 DEST = _get_tmp_dir()
422 clone_url = webserver.repo_url(GIT_REPO)
422 clone_url = webserver.repo_url(GIT_REPO)
423 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, DEST)
423 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, DEST)
424
424
425 #lock repo
425 # lock repo
426 r = Repository.get_by_repo_name(GIT_REPO)
426 r = Repository.get_by_repo_name(GIT_REPO)
427 # let this user actually push !
427 # let this user actually push !
428 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
428 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
@@ -430,7 +430,7 b' class TestVCSOperations(TestController):'
430 Session().commit()
430 Session().commit()
431 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
431 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
432
432
433 #push fails repo is locked by other user !
433 # push fails repo is locked by other user !
434 stdout, stderr = _add_files_and_push(webserver, 'git', DEST,
434 stdout, stderr = _add_files_and_push(webserver, 'git', DEST,
435 username=TEST_USER_REGULAR_LOGIN,
435 username=TEST_USER_REGULAR_LOGIN,
436 password=TEST_USER_REGULAR_PASS,
436 password=TEST_USER_REGULAR_PASS,
@@ -438,8 +438,8 b' class TestVCSOperations(TestController):'
438 err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN)
438 err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN)
439 assert err in stderr
439 assert err in stderr
440
440
441 #TODO: fix this somehow later on Git, Git is stupid and even if we throw
441 # TODO: fix this somehow later on Git, Git is stupid and even if we throw
442 #back 423 to it, it makes ANOTHER request and we fail there with 405 :/
442 # back 423 to it, it makes ANOTHER request and we fail there with 405 :/
443
443
444 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
444 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
445 % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
445 % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
@@ -453,25 +453,25 b' class TestVCSOperations(TestController):'
453 r = Repository.get_by_repo_name(fork_name)
453 r = Repository.get_by_repo_name(fork_name)
454 r.enable_locking = True
454 r.enable_locking = True
455 Session().commit()
455 Session().commit()
456 #clone some temp
456 # clone some temp
457 DEST = _get_tmp_dir()
457 DEST = _get_tmp_dir()
458 clone_url = webserver.repo_url(fork_name)
458 clone_url = webserver.repo_url(fork_name)
459 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, DEST)
459 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, DEST)
460
460
461 #check for lock repo after clone
461 # check for lock repo after clone
462 r = Repository.get_by_repo_name(fork_name)
462 r = Repository.get_by_repo_name(fork_name)
463 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
463 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
464 assert r.locked[0] == uid
464 assert r.locked[0] == uid
465
465
466 #push is ok and repo is now unlocked
466 # push is ok and repo is now unlocked
467 stdout, stderr = _add_files_and_push(webserver, 'hg', DEST, clone_url=clone_url)
467 stdout, stderr = _add_files_and_push(webserver, 'hg', DEST, clone_url=clone_url)
468 assert str('remote: Released lock on repo `%s`' % fork_name) in stdout
468 assert str('remote: Released lock on repo `%s`' % fork_name) in stdout
469 #we need to cleanup the Session Here !
469 # we need to cleanup the Session Here !
470 Session.remove()
470 Session.remove()
471 r = Repository.get_by_repo_name(fork_name)
471 r = Repository.get_by_repo_name(fork_name)
472 assert r.locked == [None, None]
472 assert r.locked == [None, None]
473
473
474 #TODO: fix me ! somehow during tests hooks don't get called on Git
474 # TODO: fix me ! somehow during tests hooks don't get called on Git
475 def test_push_unlocks_repository_git(self, webserver):
475 def test_push_unlocks_repository_git(self, webserver):
476 # enable locking
476 # enable locking
477 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
477 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
@@ -479,21 +479,21 b' class TestVCSOperations(TestController):'
479 r = Repository.get_by_repo_name(fork_name)
479 r = Repository.get_by_repo_name(fork_name)
480 r.enable_locking = True
480 r.enable_locking = True
481 Session().commit()
481 Session().commit()
482 #clone some temp
482 # clone some temp
483 DEST = _get_tmp_dir()
483 DEST = _get_tmp_dir()
484 clone_url = webserver.repo_url(fork_name)
484 clone_url = webserver.repo_url(fork_name)
485 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, DEST)
485 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, DEST)
486
486
487 #check for lock repo after clone
487 # check for lock repo after clone
488 r = Repository.get_by_repo_name(fork_name)
488 r = Repository.get_by_repo_name(fork_name)
489 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
489 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
490
490
491 #push is ok and repo is now unlocked
491 # push is ok and repo is now unlocked
492 stdout, stderr = _add_files_and_push(webserver, 'git', DEST, clone_url=clone_url)
492 stdout, stderr = _add_files_and_push(webserver, 'git', DEST, clone_url=clone_url)
493 _check_proper_git_push(stdout, stderr)
493 _check_proper_git_push(stdout, stderr)
494
494
495 assert ('remote: Released lock on repo `%s`' % fork_name) in stderr
495 assert ('remote: Released lock on repo `%s`' % fork_name) in stderr
496 #we need to cleanup the Session Here !
496 # we need to cleanup the Session Here !
497 Session.remove()
497 Session.remove()
498 r = Repository.get_by_repo_name(fork_name)
498 r = Repository.get_by_repo_name(fork_name)
499 assert r.locked == [None, None]
499 assert r.locked == [None, None]
@@ -507,7 +507,7 b' class TestVCSOperations(TestController):'
507 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
507 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
508 assert 'abort: HTTP Error 403: Forbidden' in stderr
508 assert 'abort: HTTP Error 403: Forbidden' in stderr
509 finally:
509 finally:
510 #release IP restrictions
510 # release IP restrictions
511 for ip in UserIpMap.query():
511 for ip in UserIpMap.query():
512 UserIpMap.delete(ip.ip_id)
512 UserIpMap.delete(ip.ip_id)
513 Session().commit()
513 Session().commit()
@@ -535,7 +535,7 b' class TestVCSOperations(TestController):'
535 # The message apparently changed in Git 1.8.3, so match it loosely.
535 # The message apparently changed in Git 1.8.3, so match it loosely.
536 assert re.search(r'\b403\b', stderr)
536 assert re.search(r'\b403\b', stderr)
537 finally:
537 finally:
538 #release IP restrictions
538 # release IP restrictions
539 for ip in UserIpMap.query():
539 for ip in UserIpMap.query():
540 UserIpMap.delete(ip.ip_id)
540 UserIpMap.delete(ip.ip_id)
541 Session().commit()
541 Session().commit()
@@ -13,6 +13,7 b''
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
14
15 import pytest
15 import pytest
16
16 from kallithea.model.db import Repository
17 from kallithea.model.db import Repository
17 from kallithea.tests.base import *
18 from kallithea.tests.base import *
18
19
@@ -132,8 +132,8 b' def create_test_repo(force=True):'
132
132
133 form_data = {'repo_name': HG_REPO,
133 form_data = {'repo_name': HG_REPO,
134 'repo_type': 'hg',
134 'repo_type': 'hg',
135 'private':False,
135 'private': False,
136 'clone_uri': '' }
136 'clone_uri': ''}
137 rm = RepoModel()
137 rm = RepoModel()
138 rm.base_path = '/home/hg'
138 rm.base_path = '/home/hg'
139 rm.create(form_data, user)
139 rm.create(form_data, user)
@@ -182,10 +182,11 b' def test_clone_with_credentials(no_error'
182 if not no_errors:
182 if not no_errors:
183 if backend == 'hg':
183 if backend == 'hg':
184 assert """adding file changes""" in stdout, 'no messages about cloning'
184 assert """adding file changes""" in stdout, 'no messages about cloning'
185 assert """abort""" not in stderr , 'got error from clone'
185 assert """abort""" not in stderr, 'got error from clone'
186 elif backend == 'git':
186 elif backend == 'git':
187 assert """Cloning into""" in stdout, 'no messages about cloning'
187 assert """Cloning into""" in stdout, 'no messages about cloning'
188
188
189
189 if __name__ == '__main__':
190 if __name__ == '__main__':
190 try:
191 try:
191 create_test_user(force=False)
192 create_test_user(force=False)
@@ -63,7 +63,7 b" print 'Crawling @ %s' % BASE_URI"
63 BASE_URI += '%s'
63 BASE_URI += '%s'
64 PROJECT_PATH = os.path.join('/', 'home', 'username', 'repos')
64 PROJECT_PATH = os.path.join('/', 'home', 'username', 'repos')
65 PROJECTS = [
65 PROJECTS = [
66 #'linux-magx-pbranch',
66 # 'linux-magx-pbranch',
67 'CPython',
67 'CPython',
68 'kallithea',
68 'kallithea',
69 ]
69 ]
@@ -61,5 +61,6 b' def main():'
61 collector()
61 collector()
62 unittest.main()
62 unittest.main()
63
63
64
64 #if __name__ == '__main__':
65 #if __name__ == '__main__':
65 # main()
66 # main()
@@ -83,5 +83,5 b' PACKAGE_DIR = os.path.abspath(os.path.jo'
83 shutil.copy(os.path.join(THIS, 'aconfig'), _dest)
83 shutil.copy(os.path.join(THIS, 'aconfig'), _dest)
84 TEST_USER_CONFIG_FILE = _dest
84 TEST_USER_CONFIG_FILE = _dest
85
85
86 #overide default configurations with kallithea ones
86 # overide default configurations with kallithea ones
87 from kallithea.tests.base import *
87 from kallithea.tests.base import *
@@ -100,6 +100,7 b' class ArchivesTestCaseMixin(_BackendTest'
100 with self.assertRaises(VCSError):
100 with self.assertRaises(VCSError):
101 self.tip.fill_archive(prefix='/any')
101 self.tip.fill_archive(prefix='/any')
102
102
103
103 # For each backend create test case class
104 # For each backend create test case class
104 for alias in SCM_TESTS:
105 for alias in SCM_TESTS:
105 attrs = {
106 attrs = {
@@ -49,6 +49,7 b' class TestBaseChangeset(unittest.TestCas'
49 'removed': [],
49 'removed': [],
50 })
50 })
51
51
52
52 class _ChangesetsWithCommitsTestCaseixin(_BackendTestMixin):
53 class _ChangesetsWithCommitsTestCaseixin(_BackendTestMixin):
53 recreate_repo_per_test = True
54 recreate_repo_per_test = True
54
55
@@ -365,6 +366,7 b' class _ChangesetsChangesTestCaseMixin(_B'
365 self.assertEqual(33188, changeset.get_file_mode('foo/bał'))
366 self.assertEqual(33188, changeset.get_file_mode('foo/bał'))
366 self.assertEqual(33188, changeset.get_file_mode(u'foo/bał'))
367 self.assertEqual(33188, changeset.get_file_mode(u'foo/bał'))
367
368
369
368 # For each backend create test case class
370 # For each backend create test case class
369 for alias in SCM_TESTS:
371 for alias in SCM_TESTS:
370 attrs = {
372 attrs = {
@@ -104,7 +104,7 b' class GitRepositoryTest(unittest.TestCas'
104 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
104 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
105 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
105 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
106
106
107 #check if current workdir was updated
107 # check if current workdir was updated
108 fpath = os.path.join(clone_path, 'MANIFEST.in')
108 fpath = os.path.join(clone_path, 'MANIFEST.in')
109 self.assertEqual(True, os.path.isfile(fpath),
109 self.assertEqual(True, os.path.isfile(fpath),
110 'Repo was cloned and updated but file %s could not be found'
110 'Repo was cloned and updated but file %s could not be found'
@@ -116,7 +116,7 b' class GitRepositoryTest(unittest.TestCas'
116 repo_clone = GitRepository(clone_path,
116 repo_clone = GitRepository(clone_path,
117 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
117 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
118 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
118 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
119 #check if current workdir was *NOT* updated
119 # check if current workdir was *NOT* updated
120 fpath = os.path.join(clone_path, 'MANIFEST.in')
120 fpath = os.path.join(clone_path, 'MANIFEST.in')
121 # Make sure it's not bare repo
121 # Make sure it's not bare repo
122 self.assertFalse(repo_clone._repo.bare)
122 self.assertFalse(repo_clone._repo.bare)
@@ -170,10 +170,8 b' class GitRepositoryTest(unittest.TestCas'
170 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
170 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
171 self.assertTrue(subset.issubset(set(self.repo.revisions)))
171 self.assertTrue(subset.issubset(set(self.repo.revisions)))
172
172
173
174
175 def test_slicing(self):
173 def test_slicing(self):
176 #4 1 5 10 95
174 # 4 1 5 10 95
177 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
175 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
178 (10, 20, 10), (5, 100, 95)]:
176 (10, 20, 10), (5, 100, 95)]:
179 revs = list(self.repo[sfrom:sto])
177 revs = list(self.repo[sfrom:sto])
@@ -181,7 +179,6 b' class GitRepositoryTest(unittest.TestCas'
181 self.assertEqual(revs[0], self.repo.get_changeset(sfrom))
179 self.assertEqual(revs[0], self.repo.get_changeset(sfrom))
182 self.assertEqual(revs[-1], self.repo.get_changeset(sto - 1))
180 self.assertEqual(revs[-1], self.repo.get_changeset(sto - 1))
183
181
184
185 def test_branches(self):
182 def test_branches(self):
186 # TODO: Need more tests here
183 # TODO: Need more tests here
187 # Removed (those are 'remotes' branches for cloned repo)
184 # Removed (those are 'remotes' branches for cloned repo)
@@ -370,7 +367,6 b' class GitChangesetTest(unittest.TestCase'
370 'vcs/backends/hg.py', 854),
367 'vcs/backends/hg.py', 854),
371 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
368 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
372 'setup.py', 1068),
369 'setup.py', 1068),
373
374 ('d955cd312c17b02143c04fa1099a352b04368118',
370 ('d955cd312c17b02143c04fa1099a352b04368118',
375 'vcs/backends/base.py', 2921),
371 'vcs/backends/base.py', 2921),
376 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
372 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
@@ -548,7 +544,7 b' class GitChangesetTest(unittest.TestCase'
548 self.assertEqual(l1_1, l1_2)
544 self.assertEqual(l1_1, l1_2)
549 l1 = l1_1
545 l1 = l1_1
550 l2 = files[fname][rev]['changesets']
546 l2 = files[fname][rev]['changesets']
551 self.assertTrue(l1 == l2 , "The lists of revision for %s@rev %s"
547 self.assertTrue(l1 == l2, "The lists of revision for %s@rev %s"
552 "from annotation list should match each other, "
548 "from annotation list should match each other, "
553 "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
549 "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
554
550
@@ -766,7 +762,7 b' class GitRegressionTest(_BackendTestMixi'
766
762
767 def test_similar_paths(self):
763 def test_similar_paths(self):
768 cs = self.repo.get_changeset()
764 cs = self.repo.get_changeset()
769 paths = lambda *n:[x.path for x in n]
765 paths = lambda *n: [x.path for x in n]
770 self.assertEqual(paths(*cs.get_nodes('bot')), ['bot/build', 'bot/templates', 'bot/__init__.py'])
766 self.assertEqual(paths(*cs.get_nodes('bot')), ['bot/build', 'bot/templates', 'bot/__init__.py'])
771 self.assertEqual(paths(*cs.get_nodes('bot/build')), ['bot/build/migrations', 'bot/build/static', 'bot/build/templates'])
767 self.assertEqual(paths(*cs.get_nodes('bot/build')), ['bot/build/migrations', 'bot/build/static', 'bot/build/templates'])
772 self.assertEqual(paths(*cs.get_nodes('bot/build/static')), ['bot/build/static/templates'])
768 self.assertEqual(paths(*cs.get_nodes('bot/build/static')), ['bot/build/static/templates'])
@@ -28,7 +28,7 b' class MercurialRepositoryTest(unittest.T'
28 self.assertRaises(RepositoryError, MercurialRepository, wrong_repo_path)
28 self.assertRaises(RepositoryError, MercurialRepository, wrong_repo_path)
29
29
30 def test_unicode_path_repo(self):
30 def test_unicode_path_repo(self):
31 self.assertRaises(VCSError,lambda:MercurialRepository(u'iShouldFail'))
31 self.assertRaises(VCSError, lambda: MercurialRepository(u'iShouldFail'))
32
32
33 def test_repo_clone(self):
33 def test_repo_clone(self):
34 self.__check_for_existing_repo()
34 self.__check_for_existing_repo()
@@ -47,7 +47,7 b' class MercurialRepositoryTest(unittest.T'
47 src_url=TEST_HG_REPO, update_after_clone=True)
47 src_url=TEST_HG_REPO, update_after_clone=True)
48 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
48 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
49
49
50 #check if current workdir was updated
50 # check if current workdir was updated
51 self.assertEqual(os.path.isfile(os.path.join(TEST_HG_REPO_CLONE \
51 self.assertEqual(os.path.isfile(os.path.join(TEST_HG_REPO_CLONE \
52 + '_w_update',
52 + '_w_update',
53 'MANIFEST.in')), True,)
53 'MANIFEST.in')), True,)
@@ -98,7 +98,6 b' class MercurialRepositoryTest(unittest.T'
98 ])
98 ])
99 self.assertTrue(subset.issubset(set(self.repo.revisions)))
99 self.assertTrue(subset.issubset(set(self.repo.revisions)))
100
100
101
102 # check if we have the proper order of revisions
101 # check if we have the proper order of revisions
103 org = ['b986218ba1c9b0d6a259fac9b050b1724ed8e545',
102 org = ['b986218ba1c9b0d6a259fac9b050b1724ed8e545',
104 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
103 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
@@ -139,7 +138,7 b' class MercurialRepositoryTest(unittest.T'
139 self.assertEqual(sliced, itered)
138 self.assertEqual(sliced, itered)
140
139
141 def test_slicing(self):
140 def test_slicing(self):
142 #4 1 5 10 95
141 # 4 1 5 10 95
143 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
142 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
144 (10, 20, 10), (5, 100, 95)]:
143 (10, 20, 10), (5, 100, 95)]:
145 revs = list(self.repo[sfrom:sto])
144 revs = list(self.repo[sfrom:sto])
@@ -150,7 +149,7 b' class MercurialRepositoryTest(unittest.T'
150 def test_branches(self):
149 def test_branches(self):
151 # TODO: Need more tests here
150 # TODO: Need more tests here
152
151
153 #active branches
152 # active branches
154 self.assertTrue('default' in self.repo.branches)
153 self.assertTrue('default' in self.repo.branches)
155 self.assertTrue('stable' in self.repo.branches)
154 self.assertTrue('stable' in self.repo.branches)
156
155
@@ -201,13 +200,13 b' class MercurialRepositoryTest(unittest.T'
201 self.assertEqual(node.kind, NodeKind.FILE)
200 self.assertEqual(node.kind, NodeKind.FILE)
202
201
203 def test_not_existing_changeset(self):
202 def test_not_existing_changeset(self):
204 #rawid
203 # rawid
205 self.assertRaises(RepositoryError, self.repo.get_changeset,
204 self.assertRaises(RepositoryError, self.repo.get_changeset,
206 'abcd' * 10)
205 'abcd' * 10)
207 #shortid
206 # shortid
208 self.assertRaises(RepositoryError, self.repo.get_changeset,
207 self.assertRaises(RepositoryError, self.repo.get_changeset,
209 'erro' * 4)
208 'erro' * 4)
210 #numeric
209 # numeric
211 self.assertRaises(RepositoryError, self.repo.get_changeset,
210 self.assertRaises(RepositoryError, self.repo.get_changeset,
212 self.repo.count() + 1)
211 self.repo.count() + 1)
213
212
@@ -414,7 +413,7 b' class MercurialChangesetTest(unittest.Te'
414 self.assertEqual(l1_1, l1_2)
413 self.assertEqual(l1_1, l1_2)
415 l1 = l1_2 = [x[2]().revision for x in cs.get_file_annotate(fname)]
414 l1 = l1_2 = [x[2]().revision for x in cs.get_file_annotate(fname)]
416 l2 = files[fname][rev]['changesets']
415 l2 = files[fname][rev]['changesets']
417 self.assertTrue(l1 == l2 , "The lists of revision for %s@rev%s"
416 self.assertTrue(l1 == l2, "The lists of revision for %s@rev%s"
418 "from annotation list should match each other,"
417 "from annotation list should match each other,"
419 "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
418 "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
420
419
@@ -462,7 +461,7 b' class MercurialChangesetTest(unittest.Te'
462 self.assertEqual(set((node.path for node in chset88.changed)),
461 self.assertEqual(set((node.path for node in chset88.changed)),
463 set(['.hgignore']))
462 set(['.hgignore']))
464 self.assertEqual(set((node.path for node in chset88.removed)), set())
463 self.assertEqual(set((node.path for node in chset88.removed)), set())
465 #
464
466 # 85:
465 # 85:
467 # added: 2 ['vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
466 # added: 2 ['vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
468 # changed: 4 ['vcs/web/simplevcs/models.py', ...]
467 # changed: 4 ['vcs/web/simplevcs/models.py', ...]
@@ -536,13 +535,12 b' class MercurialChangesetTest(unittest.Te'
536 path = 'foo/bar/setup.py'
535 path = 'foo/bar/setup.py'
537 self.assertRaises(VCSError, self.repo.get_changeset().get_node, path)
536 self.assertRaises(VCSError, self.repo.get_changeset().get_node, path)
538
537
539
540 def test_archival_file(self):
538 def test_archival_file(self):
541 #TODO:
539 # TODO:
542 pass
540 pass
543
541
544 def test_archival_as_generator(self):
542 def test_archival_as_generator(self):
545 #TODO:
543 # TODO:
546 pass
544 pass
547
545
548 def test_archival_wrong_kind(self):
546 def test_archival_wrong_kind(self):
@@ -550,10 +548,9 b' class MercurialChangesetTest(unittest.Te'
550 self.assertRaises(VCSError, tip.fill_archive, kind='error')
548 self.assertRaises(VCSError, tip.fill_archive, kind='error')
551
549
552 def test_archival_empty_prefix(self):
550 def test_archival_empty_prefix(self):
553 #TODO:
551 # TODO:
554 pass
552 pass
555
553
556
557 def test_author_email(self):
554 def test_author_email(self):
558 self.assertEqual('marcin@python-blog.com',
555 self.assertEqual('marcin@python-blog.com',
559 self.repo.get_changeset('b986218ba1c9').author_email)
556 self.repo.get_changeset('b986218ba1c9').author_email)
@@ -170,6 +170,7 b' class NodeBasicTest(unittest.TestCase):'
170 self.assertEqual(my_node3.mimetype, 'application/octet-stream')
170 self.assertEqual(my_node3.mimetype, 'application/octet-stream')
171 self.assertEqual(my_node3.get_mimetype(), ('application/octet-stream', None))
171 self.assertEqual(my_node3.get_mimetype(), ('application/octet-stream', None))
172
172
173
173 class NodeContentTest(unittest.TestCase):
174 class NodeContentTest(unittest.TestCase):
174
175
175 def test_if_binary(self):
176 def test_if_binary(self):
@@ -46,6 +46,7 b' class TagsTestCaseMixin(_BackendTestMixi'
46 self.repo.tag('11', 'joe')
46 self.repo.tag('11', 'joe')
47 self.assertTrue('11' in self.repo.tags)
47 self.assertTrue('11' in self.repo.tags)
48
48
49
49 # For each backend create test case class
50 # For each backend create test case class
50 for alias in SCM_TESTS:
51 for alias in SCM_TESTS:
51 attrs = {
52 attrs = {
@@ -43,7 +43,6 b' class PathsTest(unittest.TestCase):'
43 for path, expected in paths_and_results:
43 for path, expected in paths_and_results:
44 self._test_get_dirs_for_path(path, expected)
44 self._test_get_dirs_for_path(path, expected)
45
45
46
47 def test_get_scm(self):
46 def test_get_scm(self):
48 self.assertEqual(('hg', TEST_HG_REPO), get_scm(TEST_HG_REPO))
47 self.assertEqual(('hg', TEST_HG_REPO), get_scm(TEST_HG_REPO))
49 self.assertEqual(('git', TEST_GIT_REPO), get_scm(TEST_GIT_REPO))
48 self.assertEqual(('git', TEST_GIT_REPO), get_scm(TEST_GIT_REPO))
@@ -209,13 +208,10 b' class TestAuthorExtractors(unittest.Test'
209 ]
208 ]
210
209
211 def test_author_email(self):
210 def test_author_email(self):
212
213 for test_str, result in self.TEST_AUTHORS:
211 for test_str, result in self.TEST_AUTHORS:
214 self.assertEqual(result[1], author_email(test_str))
212 self.assertEqual(result[1], author_email(test_str))
215
213
216
217 def test_author_name(self):
214 def test_author_name(self):
218
219 for test_str, result in self.TEST_AUTHORS:
215 for test_str, result in self.TEST_AUTHORS:
220 self.assertEqual(result[0], author_name(test_str))
216 self.assertEqual(result[0], author_name(test_str))
221
217
@@ -1,4 +1,3 b''
1
2 import os
1 import os
3 import shutil
2 import shutil
4
3
@@ -9,7 +8,6 b' from kallithea.lib.vcs.utils.compat impo'
9 from kallithea.tests.vcs.conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
8 from kallithea.tests.vcs.conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
10
9
11
10
12
13 class VCSTest(unittest.TestCase):
11 class VCSTest(unittest.TestCase):
14 """
12 """
15 Tests for main module's methods.
13 Tests for main module's methods.
@@ -24,14 +22,14 b' class VCSTest(unittest.TestCase):'
24 path = TEST_HG_REPO
22 path = TEST_HG_REPO
25 backend = get_backend(alias)
23 backend = get_backend(alias)
26 repo = backend(safe_str(path))
24 repo = backend(safe_str(path))
27 self.assertEqual('hg',repo.alias)
25 self.assertEqual('hg', repo.alias)
28
26
29 def test_alias_detect_git(self):
27 def test_alias_detect_git(self):
30 alias = 'git'
28 alias = 'git'
31 path = TEST_GIT_REPO
29 path = TEST_GIT_REPO
32 backend = get_backend(alias)
30 backend = get_backend(alias)
33 repo = backend(safe_str(path))
31 repo = backend(safe_str(path))
34 self.assertEqual('git',repo.alias)
32 self.assertEqual('git', repo.alias)
35
33
36 def test_wrong_alias(self):
34 def test_wrong_alias(self):
37 alias = 'wrong_alias'
35 alias = 'wrong_alias'
@@ -64,7 +62,6 b' class VCSTest(unittest.TestCase):'
64 self.assertEqual(repo.__class__, get_repo(safe_str(path)).__class__)
62 self.assertEqual(repo.__class__, get_repo(safe_str(path)).__class__)
65 self.assertEqual(repo.path, get_repo(safe_str(path)).path)
63 self.assertEqual(repo.path, get_repo(safe_str(path)).path)
66
64
67
68 def test_get_repo_err(self):
65 def test_get_repo_err(self):
69 blank_repo_path = os.path.join(TEST_TMP_PATH, 'blank-error-repo')
66 blank_repo_path = os.path.join(TEST_TMP_PATH, 'blank-error-repo')
70 if os.path.isdir(blank_repo_path):
67 if os.path.isdir(blank_repo_path):
General Comments 0
You need to be logged in to leave comments. Login now