forks: moved pylons code into pyramid.
This commit is contained in:
parent
81eb5a6b72
commit
05386904e7
15 changed files with 683 additions and 609 deletions
|
|
@ -219,10 +219,31 @@ def includeme(config):
|
|||
name='branches_home',
|
||||
pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
|
||||
|
||||
# Bookmarks
|
||||
config.add_route(
|
||||
name='bookmarks_home',
|
||||
pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
|
||||
|
||||
# Forks
|
||||
config.add_route(
|
||||
name='repo_fork_new',
|
||||
pattern='/{repo_name:.*?[^/]}/fork', repo_route=True,
|
||||
repo_accepted_types=['hg', 'git'])
|
||||
|
||||
config.add_route(
|
||||
name='repo_fork_create',
|
||||
pattern='/{repo_name:.*?[^/]}/fork/create', repo_route=True,
|
||||
repo_accepted_types=['hg', 'git'])
|
||||
|
||||
config.add_route(
|
||||
name='repo_forks_show_all',
|
||||
pattern='/{repo_name:.*?[^/]}/forks', repo_route=True,
|
||||
repo_accepted_types=['hg', 'git'])
|
||||
config.add_route(
|
||||
name='repo_forks_data',
|
||||
pattern='/{repo_name:.*?[^/]}/forks/data', repo_route=True,
|
||||
repo_accepted_types=['hg', 'git'])
|
||||
|
||||
# Pull Requests
|
||||
config.add_route(
|
||||
name='pullrequest_show',
|
||||
|
|
|
|||
315
rhodecode/apps/repository/tests/test_repo_forks.py
Normal file
315
rhodecode/apps/repository/tests/test_repo_forks.py
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import pytest
|
||||
|
||||
from rhodecode.tests import TestController, assert_session_flash, HG_FORK, GIT_FORK
|
||||
|
||||
from rhodecode.tests.fixture import Fixture
|
||||
from rhodecode.lib import helpers as h
|
||||
|
||||
from rhodecode.model.db import Repository
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.user import UserModel
|
||||
from rhodecode.model.meta import Session
|
||||
|
||||
fixture = Fixture()
|
||||
|
||||
|
||||
def route_path(name, params=None, **kwargs):
|
||||
import urllib
|
||||
|
||||
base_url = {
|
||||
'repo_summary': '/{repo_name}',
|
||||
'repo_creating_check': '/{repo_name}/repo_creating_check',
|
||||
'repo_fork_new': '/{repo_name}/fork',
|
||||
'repo_fork_create': '/{repo_name}/fork/create',
|
||||
'repo_forks_show_all': '/{repo_name}/forks',
|
||||
'repo_forks_data': '/{repo_name}/forks/data',
|
||||
}[name].format(**kwargs)
|
||||
|
||||
if params:
|
||||
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
|
||||
return base_url
|
||||
|
||||
|
||||
FORK_NAME = {
|
||||
'hg': HG_FORK,
|
||||
'git': GIT_FORK
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.skip_backends('svn')
|
||||
class TestRepoForkViewTests(TestController):
|
||||
|
||||
def test_show_forks(self, backend, xhr_header):
|
||||
self.log_user()
|
||||
response = self.app.get(
|
||||
route_path('repo_forks_data', repo_name=backend.repo_name),
|
||||
extra_environ=xhr_header)
|
||||
|
||||
assert response.json == {u'data': [], u'draw': None,
|
||||
u'recordsFiltered': 0, u'recordsTotal': 0}
|
||||
|
||||
def test_no_permissions_to_fork_page(self, backend, user_util):
|
||||
user = user_util.create_user(password='qweqwe')
|
||||
user_id = user.user_id
|
||||
self.log_user(user.username, 'qweqwe')
|
||||
|
||||
user_model = UserModel()
|
||||
user_model.revoke_perm(user_id, 'hg.fork.repository')
|
||||
user_model.grant_perm(user_id, 'hg.fork.none')
|
||||
u = UserModel().get(user_id)
|
||||
u.inherit_default_permissions = False
|
||||
Session().commit()
|
||||
# try create a fork
|
||||
self.app.get(
|
||||
route_path('repo_fork_new', repo_name=backend.repo_name),
|
||||
status=404)
|
||||
|
||||
def test_no_permissions_to_fork_submit(self, backend, csrf_token, user_util):
|
||||
user = user_util.create_user(password='qweqwe')
|
||||
user_id = user.user_id
|
||||
self.log_user(user.username, 'qweqwe')
|
||||
|
||||
user_model = UserModel()
|
||||
user_model.revoke_perm(user_id, 'hg.fork.repository')
|
||||
user_model.grant_perm(user_id, 'hg.fork.none')
|
||||
u = UserModel().get(user_id)
|
||||
u.inherit_default_permissions = False
|
||||
Session().commit()
|
||||
# try create a fork
|
||||
self.app.post(
|
||||
route_path('repo_fork_create', repo_name=backend.repo_name),
|
||||
{'csrf_token': csrf_token},
|
||||
status=404)
|
||||
|
||||
def test_fork_missing_data(self, autologin_user, backend, csrf_token):
|
||||
# try create a fork
|
||||
response = self.app.post(
|
||||
route_path('repo_fork_create', repo_name=backend.repo_name),
|
||||
{'csrf_token': csrf_token},
|
||||
status=200)
|
||||
# test if html fill works fine
|
||||
response.mustcontain('Missing value')
|
||||
|
||||
def test_create_fork_page(self, autologin_user, backend):
|
||||
self.app.get(
|
||||
route_path('repo_fork_new', repo_name=backend.repo_name),
|
||||
status=200)
|
||||
|
||||
def test_create_and_show_fork(
|
||||
self, autologin_user, backend, csrf_token, xhr_header):
|
||||
|
||||
# create a fork
|
||||
fork_name = FORK_NAME[backend.alias]
|
||||
description = 'fork of vcs test'
|
||||
repo_name = backend.repo_name
|
||||
source_repo = Repository.get_by_repo_name(repo_name)
|
||||
creation_args = {
|
||||
'repo_name': fork_name,
|
||||
'repo_group': '',
|
||||
'fork_parent_id': source_repo.repo_id,
|
||||
'repo_type': backend.alias,
|
||||
'description': description,
|
||||
'private': 'False',
|
||||
'landing_rev': 'rev:tip',
|
||||
'csrf_token': csrf_token,
|
||||
}
|
||||
|
||||
self.app.post(
|
||||
route_path('repo_fork_create', repo_name=repo_name), creation_args)
|
||||
|
||||
response = self.app.get(
|
||||
route_path('repo_forks_data', repo_name=repo_name),
|
||||
extra_environ=xhr_header)
|
||||
|
||||
assert response.json['data'][0]['fork_name'] == \
|
||||
"""<a href="/%s">%s</a>""" % (fork_name, fork_name)
|
||||
|
||||
# remove this fork
|
||||
fixture.destroy_repo(fork_name)
|
||||
|
||||
def test_fork_create(self, autologin_user, backend, csrf_token):
|
||||
fork_name = FORK_NAME[backend.alias]
|
||||
description = 'fork of vcs test'
|
||||
repo_name = backend.repo_name
|
||||
source_repo = Repository.get_by_repo_name(repo_name)
|
||||
creation_args = {
|
||||
'repo_name': fork_name,
|
||||
'repo_group': '',
|
||||
'fork_parent_id': source_repo.repo_id,
|
||||
'repo_type': backend.alias,
|
||||
'description': description,
|
||||
'private': 'False',
|
||||
'landing_rev': 'rev:tip',
|
||||
'csrf_token': csrf_token,
|
||||
}
|
||||
self.app.post(
|
||||
route_path('repo_fork_create', repo_name=repo_name), creation_args)
|
||||
repo = Repository.get_by_repo_name(FORK_NAME[backend.alias])
|
||||
assert repo.fork.repo_name == backend.repo_name
|
||||
|
||||
# run the check page that triggers the flash message
|
||||
response = self.app.get(
|
||||
route_path('repo_creating_check', repo_name=fork_name))
|
||||
# test if we have a message that fork is ok
|
||||
assert_session_flash(response,
|
||||
'Forked repository %s as <a href="/%s">%s</a>'
|
||||
% (repo_name, fork_name, fork_name))
|
||||
|
||||
# test if the fork was created in the database
|
||||
fork_repo = Session().query(Repository)\
|
||||
.filter(Repository.repo_name == fork_name).one()
|
||||
|
||||
assert fork_repo.repo_name == fork_name
|
||||
assert fork_repo.fork.repo_name == repo_name
|
||||
|
||||
# test if the repository is visible in the list ?
|
||||
response = self.app.get(
|
||||
h.route_path('repo_summary', repo_name=fork_name))
|
||||
response.mustcontain(fork_name)
|
||||
response.mustcontain(backend.alias)
|
||||
response.mustcontain('Fork of')
|
||||
response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
|
||||
|
||||
def test_fork_create_into_group(self, autologin_user, backend, csrf_token):
|
||||
group = fixture.create_repo_group('vc')
|
||||
group_id = group.group_id
|
||||
fork_name = FORK_NAME[backend.alias]
|
||||
fork_name_full = 'vc/%s' % fork_name
|
||||
description = 'fork of vcs test'
|
||||
repo_name = backend.repo_name
|
||||
source_repo = Repository.get_by_repo_name(repo_name)
|
||||
creation_args = {
|
||||
'repo_name': fork_name,
|
||||
'repo_group': group_id,
|
||||
'fork_parent_id': source_repo.repo_id,
|
||||
'repo_type': backend.alias,
|
||||
'description': description,
|
||||
'private': 'False',
|
||||
'landing_rev': 'rev:tip',
|
||||
'csrf_token': csrf_token,
|
||||
}
|
||||
self.app.post(
|
||||
route_path('repo_fork_create', repo_name=repo_name), creation_args)
|
||||
repo = Repository.get_by_repo_name(fork_name_full)
|
||||
assert repo.fork.repo_name == backend.repo_name
|
||||
|
||||
# run the check page that triggers the flash message
|
||||
response = self.app.get(
|
||||
route_path('repo_creating_check', repo_name=fork_name_full))
|
||||
# test if we have a message that fork is ok
|
||||
assert_session_flash(response,
|
||||
'Forked repository %s as <a href="/%s">%s</a>'
|
||||
% (repo_name, fork_name_full, fork_name_full))
|
||||
|
||||
# test if the fork was created in the database
|
||||
fork_repo = Session().query(Repository)\
|
||||
.filter(Repository.repo_name == fork_name_full).one()
|
||||
|
||||
assert fork_repo.repo_name == fork_name_full
|
||||
assert fork_repo.fork.repo_name == repo_name
|
||||
|
||||
# test if the repository is visible in the list ?
|
||||
response = self.app.get(
|
||||
h.route_path('repo_summary', repo_name=fork_name_full))
|
||||
response.mustcontain(fork_name_full)
|
||||
response.mustcontain(backend.alias)
|
||||
|
||||
response.mustcontain('Fork of')
|
||||
response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
|
||||
|
||||
fixture.destroy_repo(fork_name_full)
|
||||
fixture.destroy_repo_group(group_id)
|
||||
|
||||
def test_fork_read_permission(self, backend, xhr_header, user_util):
|
||||
user = user_util.create_user(password='qweqwe')
|
||||
user_id = user.user_id
|
||||
self.log_user(user.username, 'qweqwe')
|
||||
|
||||
# create a fake fork
|
||||
fork = user_util.create_repo(repo_type=backend.alias)
|
||||
source = user_util.create_repo(repo_type=backend.alias)
|
||||
repo_name = source.repo_name
|
||||
|
||||
fork.fork_id = source.repo_id
|
||||
fork_name = fork.repo_name
|
||||
Session().commit()
|
||||
|
||||
forks = Repository.query()\
|
||||
.filter(Repository.repo_type == backend.alias)\
|
||||
.filter(Repository.fork_id == source.repo_id).all()
|
||||
assert 1 == len(forks)
|
||||
|
||||
# set read permissions for this
|
||||
RepoModel().grant_user_permission(
|
||||
repo=forks[0], user=user_id, perm='repository.read')
|
||||
Session().commit()
|
||||
|
||||
response = self.app.get(
|
||||
route_path('repo_forks_data', repo_name=repo_name),
|
||||
extra_environ=xhr_header)
|
||||
|
||||
assert response.json['data'][0]['fork_name'] == \
|
||||
"""<a href="/%s">%s</a>""" % (fork_name, fork_name)
|
||||
|
||||
def test_fork_none_permission(self, backend, xhr_header, user_util):
|
||||
user = user_util.create_user(password='qweqwe')
|
||||
user_id = user.user_id
|
||||
self.log_user(user.username, 'qweqwe')
|
||||
|
||||
# create a fake fork
|
||||
fork = user_util.create_repo(repo_type=backend.alias)
|
||||
source = user_util.create_repo(repo_type=backend.alias)
|
||||
repo_name = source.repo_name
|
||||
|
||||
fork.fork_id = source.repo_id
|
||||
|
||||
Session().commit()
|
||||
|
||||
forks = Repository.query()\
|
||||
.filter(Repository.repo_type == backend.alias)\
|
||||
.filter(Repository.fork_id == source.repo_id).all()
|
||||
assert 1 == len(forks)
|
||||
|
||||
# set none
|
||||
RepoModel().grant_user_permission(
|
||||
repo=forks[0], user=user_id, perm='repository.none')
|
||||
Session().commit()
|
||||
|
||||
# fork shouldn't be there
|
||||
response = self.app.get(
|
||||
route_path('repo_forks_data', repo_name=repo_name),
|
||||
extra_environ=xhr_header)
|
||||
|
||||
assert response.json == {u'data': [], u'draw': None,
|
||||
u'recordsFiltered': 0, u'recordsTotal': 0}
|
||||
|
||||
|
||||
class TestSVNFork(TestController):
|
||||
@pytest.mark.parametrize('route_name', [
|
||||
'repo_fork_create', 'repo_fork_new'
|
||||
])
|
||||
def test_fork_redirects(self, autologin_user, backend_svn, route_name):
|
||||
|
||||
self.app.get(route_path(
|
||||
route_name, repo_name=backend_svn.repo_name),
|
||||
status=404)
|
||||
256
rhodecode/apps/repository/views/repo_forks.py
Normal file
256
rhodecode/apps/repository/views/repo_forks.py
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2011-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import logging
|
||||
import datetime
|
||||
import formencode
|
||||
from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
|
||||
from pyramid.view import view_config
|
||||
from pyramid.renderers import render
|
||||
from pyramid.response import Response
|
||||
|
||||
from rhodecode.apps._base import RepoAppView, DataGridAppView
|
||||
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
|
||||
HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
|
||||
import rhodecode.lib.helpers as h
|
||||
from rhodecode.model.db import (
|
||||
coalesce, or_, Repository, RepoGroup, UserFollowing, User)
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.forms import RepoForkForm
|
||||
from rhodecode.model.scm import ScmModel, RepoGroupList
|
||||
from rhodecode.lib.utils2 import safe_int, safe_unicode
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RepoForksView(RepoAppView, DataGridAppView):
|
||||
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context(include_app_defaults=True)
|
||||
|
||||
# TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
|
||||
c.repo_info = self.db_repo
|
||||
c.rhodecode_repo = self.rhodecode_vcs_repo
|
||||
|
||||
acl_groups = RepoGroupList(
|
||||
RepoGroup.query().all(),
|
||||
perm_set=['group.write', 'group.admin'])
|
||||
c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
|
||||
c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
|
||||
choices, c.landing_revs = ScmModel().get_repo_landing_revs()
|
||||
c.landing_revs_choices = choices
|
||||
c.personal_repo_group = c.rhodecode_user.personal_repo_group
|
||||
|
||||
self._register_global_c(c)
|
||||
return c
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
@view_config(
|
||||
route_name='repo_forks_show_all', request_method='GET',
|
||||
renderer='rhodecode:templates/forks/forks.mako')
|
||||
def repo_forks_show_all(self):
|
||||
c = self.load_default_context()
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
@view_config(
|
||||
route_name='repo_forks_data', request_method='GET',
|
||||
renderer='json_ext', xhr=True)
|
||||
def repo_forks_data(self):
|
||||
_ = self.request.translate
|
||||
column_map = {
|
||||
'fork_name': 'repo_name',
|
||||
'fork_date': 'created_on',
|
||||
'last_activity': 'updated_on'
|
||||
}
|
||||
draw, start, limit = self._extract_chunk(self.request)
|
||||
search_q, order_by, order_dir = self._extract_ordering(
|
||||
self.request, column_map=column_map)
|
||||
|
||||
acl_check = HasRepoPermissionAny(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
repo_id = self.db_repo.repo_id
|
||||
allowed_ids = []
|
||||
for f in Repository.query().filter(Repository.fork_id == repo_id):
|
||||
if acl_check(f.repo_name, 'get forks check'):
|
||||
allowed_ids.append(f.repo_id)
|
||||
|
||||
forks_data_total_count = Repository.query()\
|
||||
.filter(Repository.fork_id == repo_id)\
|
||||
.filter(Repository.repo_id.in_(allowed_ids))\
|
||||
.count()
|
||||
|
||||
# json generate
|
||||
base_q = Repository.query()\
|
||||
.filter(Repository.fork_id == repo_id)\
|
||||
.filter(Repository.repo_id.in_(allowed_ids))\
|
||||
|
||||
if search_q:
|
||||
like_expression = u'%{}%'.format(safe_unicode(search_q))
|
||||
base_q = base_q.filter(or_(
|
||||
Repository.repo_name.ilike(like_expression),
|
||||
Repository.description.ilike(like_expression),
|
||||
))
|
||||
|
||||
forks_data_total_filtered_count = base_q.count()
|
||||
|
||||
sort_col = getattr(Repository, order_by, None)
|
||||
if sort_col:
|
||||
if order_dir == 'asc':
|
||||
# handle null values properly to order by NULL last
|
||||
if order_by in ['last_activity']:
|
||||
sort_col = coalesce(sort_col, datetime.date.max)
|
||||
sort_col = sort_col.asc()
|
||||
else:
|
||||
# handle null values properly to order by NULL last
|
||||
if order_by in ['last_activity']:
|
||||
sort_col = coalesce(sort_col, datetime.date.min)
|
||||
sort_col = sort_col.desc()
|
||||
|
||||
base_q = base_q.order_by(sort_col)
|
||||
base_q = base_q.offset(start).limit(limit)
|
||||
|
||||
fork_list = base_q.all()
|
||||
|
||||
def fork_actions(fork):
|
||||
url_link = h.route_path(
|
||||
'repo_compare',
|
||||
repo_name=fork.repo_name,
|
||||
source_ref_type=self.db_repo.landing_rev[0],
|
||||
source_ref=self.db_repo.landing_rev[1],
|
||||
target_ref_type=self.db_repo.landing_rev[0],
|
||||
target_ref=self.db_repo.landing_rev[1],
|
||||
_query=dict(merge=1, target_repo=f.repo_name))
|
||||
return h.link_to(_('Compare fork'), url_link, class_='btn-link')
|
||||
|
||||
def fork_name(fork):
|
||||
return h.link_to(fork.repo_name,
|
||||
h.route_path('repo_summary', repo_name=fork.repo_name))
|
||||
|
||||
forks_data = []
|
||||
for fork in fork_list:
|
||||
forks_data.append({
|
||||
"username": h.gravatar_with_user(self.request, fork.user.username),
|
||||
"fork_name": fork_name(fork),
|
||||
"description": fork.description,
|
||||
"fork_date": h.age_component(fork.created_on, time_is_local=True),
|
||||
"last_activity": h.format_date(fork.updated_on),
|
||||
"action": fork_actions(fork),
|
||||
})
|
||||
|
||||
data = ({
|
||||
'draw': draw,
|
||||
'data': forks_data,
|
||||
'recordsTotal': forks_data_total_count,
|
||||
'recordsFiltered': forks_data_total_filtered_count,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
@view_config(
|
||||
route_name='repo_fork_new', request_method='GET',
|
||||
renderer='rhodecode:templates/forks/forks.mako')
|
||||
def repo_fork_new(self):
|
||||
c = self.load_default_context()
|
||||
|
||||
defaults = RepoModel()._get_defaults(self.db_repo_name)
|
||||
# alter the description to indicate a fork
|
||||
defaults['description'] = (
|
||||
'fork of repository: %s \n%s' % (
|
||||
defaults['repo_name'], defaults['description']))
|
||||
# add suffix to fork
|
||||
defaults['repo_name'] = '%s-fork' % defaults['repo_name']
|
||||
|
||||
data = render('rhodecode:templates/forks/fork.mako',
|
||||
self._get_template_context(c), self.request)
|
||||
html = formencode.htmlfill.render(
|
||||
data,
|
||||
defaults=defaults,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False
|
||||
)
|
||||
return Response(html)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
route_name='repo_fork_create', request_method='POST',
|
||||
renderer='rhodecode:templates/forks/fork.mako')
|
||||
def repo_fork_create(self):
|
||||
_ = self.request.translate
|
||||
c = self.load_default_context()
|
||||
|
||||
_form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type},
|
||||
repo_groups=c.repo_groups_choices,
|
||||
landing_revs=c.landing_revs_choices)()
|
||||
form_result = {}
|
||||
task_id = None
|
||||
try:
|
||||
form_result = _form.to_python(dict(self.request.POST))
|
||||
# create fork is done sometimes async on celery, db transaction
|
||||
# management is handled there.
|
||||
task = RepoModel().create_fork(
|
||||
form_result, c.rhodecode_user.user_id)
|
||||
from celery.result import BaseAsyncResult
|
||||
if isinstance(task, BaseAsyncResult):
|
||||
task_id = task.task_id
|
||||
except formencode.Invalid as errors:
|
||||
c.repo_info = self.db_repo
|
||||
|
||||
data = render('rhodecode:templates/forks/fork.mako',
|
||||
self._get_template_context(c), self.request)
|
||||
html = formencode.htmlfill.render(
|
||||
data,
|
||||
defaults=errors.value,
|
||||
errors=errors.error_dict or {},
|
||||
prefix_error=False,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False
|
||||
)
|
||||
return Response(html)
|
||||
except Exception:
|
||||
log.exception(
|
||||
u'Exception while trying to fork the repository %s',
|
||||
self.db_repo_name)
|
||||
msg = (
|
||||
_('An error occurred during repository forking %s') % (
|
||||
self.db_repo_name, ))
|
||||
h.flash(msg, category='error')
|
||||
|
||||
repo_name = form_result.get('repo_name_full', self.db_repo_name)
|
||||
raise HTTPFound(
|
||||
h.route_path('repo_creating',
|
||||
repo_name=repo_name,
|
||||
_query=dict(task_id=task_id)))
|
||||
|
|
@ -489,20 +489,4 @@ def make_map(config):
|
|||
conditions={'method': ['GET', 'POST'], 'function': check_repo},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
|
||||
rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
|
||||
controller='forks', action='fork_create',
|
||||
conditions={'function': check_repo, 'method': ['POST']},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
rmap.connect('repo_fork_home', '/{repo_name}/fork',
|
||||
controller='forks', action='fork',
|
||||
conditions={'function': check_repo},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
rmap.connect('repo_forks_home', '/{repo_name}/forks',
|
||||
controller='forks', action='forks',
|
||||
conditions={'function': check_repo},
|
||||
requirements=URL_NAME_REQUIREMENTS)
|
||||
|
||||
return rmap
|
||||
|
|
|
|||
|
|
@ -1,198 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2011-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
"""
|
||||
forks controller for rhodecode
|
||||
"""
|
||||
|
||||
import formencode
|
||||
import logging
|
||||
from formencode import htmlfill
|
||||
|
||||
from pylons import tmpl_context as c, request, url
|
||||
from pylons.controllers.util import redirect
|
||||
from pylons.i18n.translation import _
|
||||
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
import rhodecode.lib.helpers as h
|
||||
|
||||
from rhodecode.lib import auth
|
||||
from rhodecode.lib.helpers import Page
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
|
||||
HasRepoPermissionAny, HasPermissionAnyDecorator, HasAcceptedRepoType)
|
||||
from rhodecode.lib.base import BaseRepoController, render
|
||||
from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.forms import RepoForkForm
|
||||
from rhodecode.model.scm import ScmModel, RepoGroupList
|
||||
from rhodecode.lib.utils2 import safe_int
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ForksController(BaseRepoController):
|
||||
|
||||
def __before__(self):
|
||||
super(ForksController, self).__before__()
|
||||
|
||||
def __load_defaults(self):
|
||||
acl_groups = RepoGroupList(
|
||||
RepoGroup.query().all(),
|
||||
perm_set=['group.write', 'group.admin'])
|
||||
c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
|
||||
c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
|
||||
choices, c.landing_revs = ScmModel().get_repo_landing_revs()
|
||||
c.landing_revs_choices = choices
|
||||
c.personal_repo_group = c.rhodecode_user.personal_repo_group
|
||||
|
||||
def __load_data(self, repo_name=None):
|
||||
"""
|
||||
Load defaults settings for edit, and update
|
||||
|
||||
:param repo_name:
|
||||
"""
|
||||
self.__load_defaults()
|
||||
|
||||
c.repo_info = Repository.get_by_repo_name(repo_name)
|
||||
repo = c.repo_info.scm_instance()
|
||||
|
||||
if c.repo_info is None:
|
||||
h.not_mapped_error(repo_name)
|
||||
return redirect(url('repos'))
|
||||
|
||||
c.default_user_id = User.get_default_user().user_id
|
||||
c.in_public_journal = UserFollowing.query()\
|
||||
.filter(UserFollowing.user_id == c.default_user_id)\
|
||||
.filter(UserFollowing.follows_repository == c.repo_info).scalar()
|
||||
|
||||
if c.repo_info.stats:
|
||||
last_rev = c.repo_info.stats.stat_on_revision+1
|
||||
else:
|
||||
last_rev = 0
|
||||
c.stats_revision = last_rev
|
||||
|
||||
c.repo_last_rev = repo.count()
|
||||
|
||||
if last_rev == 0 or c.repo_last_rev == 0:
|
||||
c.stats_percentage = 0
|
||||
else:
|
||||
c.stats_percentage = '%.2f' % ((float((last_rev)) /
|
||||
c.repo_last_rev) * 100)
|
||||
|
||||
defaults = RepoModel()._get_defaults(repo_name)
|
||||
# alter the description to indicate a fork
|
||||
defaults['description'] = ('fork of repository: %s \n%s'
|
||||
% (defaults['repo_name'],
|
||||
defaults['description']))
|
||||
# add suffix to fork
|
||||
defaults['repo_name'] = '%s-fork' % defaults['repo_name']
|
||||
|
||||
return defaults
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
|
||||
'repository.admin')
|
||||
@HasAcceptedRepoType('git', 'hg')
|
||||
def forks(self, repo_name):
|
||||
p = safe_int(request.GET.get('page', 1), 1)
|
||||
repo_id = c.rhodecode_db_repo.repo_id
|
||||
d = []
|
||||
for r in Repository.get_repo_forks(repo_id):
|
||||
if not HasRepoPermissionAny(
|
||||
'repository.read', 'repository.write', 'repository.admin'
|
||||
)(r.repo_name, 'get forks check'):
|
||||
continue
|
||||
d.append(r)
|
||||
c.forks_pager = Page(d, page=p, items_per_page=20)
|
||||
|
||||
c.forks_data = render('/forks/forks_data.mako')
|
||||
|
||||
if request.environ.get('HTTP_X_PJAX'):
|
||||
return c.forks_data
|
||||
|
||||
return render('/forks/forks.mako')
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
|
||||
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
|
||||
'repository.admin')
|
||||
@HasAcceptedRepoType('git', 'hg')
|
||||
def fork(self, repo_name):
|
||||
c.repo_info = Repository.get_by_repo_name(repo_name)
|
||||
if not c.repo_info:
|
||||
h.not_mapped_error(repo_name)
|
||||
return redirect(h.route_path('home'))
|
||||
|
||||
defaults = self.__load_data(repo_name)
|
||||
|
||||
return htmlfill.render(
|
||||
render('forks/fork.mako'),
|
||||
defaults=defaults,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False
|
||||
)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
|
||||
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
|
||||
'repository.admin')
|
||||
@HasAcceptedRepoType('git', 'hg')
|
||||
@auth.CSRFRequired()
|
||||
def fork_create(self, repo_name):
|
||||
self.__load_defaults()
|
||||
c.repo_info = Repository.get_by_repo_name(repo_name)
|
||||
_form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
|
||||
repo_groups=c.repo_groups_choices,
|
||||
landing_revs=c.landing_revs_choices)()
|
||||
form_result = {}
|
||||
task_id = None
|
||||
try:
|
||||
form_result = _form.to_python(dict(request.POST))
|
||||
# create fork is done sometimes async on celery, db transaction
|
||||
# management is handled there.
|
||||
task = RepoModel().create_fork(
|
||||
form_result, c.rhodecode_user.user_id)
|
||||
from celery.result import BaseAsyncResult
|
||||
if isinstance(task, BaseAsyncResult):
|
||||
task_id = task.task_id
|
||||
except formencode.Invalid as errors:
|
||||
c.new_repo = errors.value['repo_name']
|
||||
return htmlfill.render(
|
||||
render('forks/fork.mako'),
|
||||
defaults=errors.value,
|
||||
errors=errors.error_dict or {},
|
||||
prefix_error=False,
|
||||
encoding="UTF-8",
|
||||
force_defaults=False)
|
||||
except Exception:
|
||||
log.exception(
|
||||
u'Exception while trying to fork the repository %s', repo_name)
|
||||
msg = (
|
||||
_('An error occurred during repository forking %s') %
|
||||
(repo_name, ))
|
||||
h.flash(msg, category='error')
|
||||
|
||||
raise HTTPFound(
|
||||
h.route_path('repo_creating',
|
||||
repo_name=form_result['repo_name_full'],
|
||||
_query=dict(task_id=task_id)))
|
||||
|
|
@ -1340,39 +1340,6 @@ class XHRRequired(object):
|
|||
return func(*fargs, **fkwargs)
|
||||
|
||||
|
||||
class HasAcceptedRepoType(object):
|
||||
"""
|
||||
Check if requested repo is within given repo type aliases
|
||||
"""
|
||||
|
||||
# TODO(marcink): remove this in favor of the predicates in pyramid routes
|
||||
|
||||
def __init__(self, *repo_type_list):
|
||||
self.repo_type_list = set(repo_type_list)
|
||||
|
||||
def __call__(self, func):
|
||||
return get_cython_compat_decorator(self.__wrapper, func)
|
||||
|
||||
def __wrapper(self, func, *fargs, **fkwargs):
|
||||
import rhodecode.lib.helpers as h
|
||||
cls = fargs[0]
|
||||
rhodecode_repo = cls.rhodecode_repo
|
||||
|
||||
log.debug('%s checking repo type for %s in %s',
|
||||
self.__class__.__name__,
|
||||
rhodecode_repo.alias, self.repo_type_list)
|
||||
|
||||
if rhodecode_repo.alias in self.repo_type_list:
|
||||
return func(*fargs, **fkwargs)
|
||||
else:
|
||||
h.flash(h.literal(
|
||||
_('Action not supported for %s.' % rhodecode_repo.alias)),
|
||||
category='warning')
|
||||
raise HTTPFound(
|
||||
h.route_path('repo_summary',
|
||||
repo_name=cls.rhodecode_db_repo.repo_name))
|
||||
|
||||
|
||||
class PermsDecorator(object):
|
||||
"""
|
||||
Base class for controller decorators, we extract the current user from
|
||||
|
|
|
|||
|
|
@ -145,6 +145,10 @@ function registerRCRoutes() {
|
|||
pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
|
||||
pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
|
||||
pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
|
||||
pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
|
||||
pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
|
||||
pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
|
||||
pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
|
||||
pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
|
||||
pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
|
||||
pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@
|
|||
%endif
|
||||
%if c.rhodecode_user.username != h.DEFAULT_USER:
|
||||
%if c.rhodecode_db_repo.repo_type in ['git','hg']:
|
||||
<li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
|
||||
<li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
|
||||
<li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
|
||||
%endif
|
||||
%endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
|
||||
<a title="${_('Fork')}" href="${h.route_path('repo_fork_new',repo_name=repo_name)}">
|
||||
<span>${_('Fork')}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
${self.breadcrumbs()}
|
||||
</div>
|
||||
|
||||
${h.secure_form(h.url('repo_fork_create_home',repo_name=c.repo_info.repo_name))}
|
||||
${h.secure_form(h.route_path('repo_fork_create',repo_name=c.repo_info.repo_name), method='POST', request=request)}
|
||||
<div class="form">
|
||||
<!-- fields -->
|
||||
<div class="fields">
|
||||
|
|
|
|||
|
|
@ -26,20 +26,94 @@
|
|||
${self.repo_page_title(c.rhodecode_db_repo)}
|
||||
<ul class="links">
|
||||
<li>
|
||||
## fork open link
|
||||
<span>
|
||||
<a class="btn btn-small btn-success" href="${h.url('repo_fork_home',repo_name=c.repo_name)}">
|
||||
<a class="btn btn-small btn-success" href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">
|
||||
${_('Create new fork')}
|
||||
</a>
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="table">
|
||||
<div id="forks">
|
||||
${c.forks_data}
|
||||
</div>
|
||||
|
||||
<div id="fork_list_wrap">
|
||||
<table id="fork_list_table" class="display"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function() {
|
||||
var $userListTable = $('#fork_list_table');
|
||||
|
||||
var getDatatableCount = function(){
|
||||
var table = $userListTable.dataTable();
|
||||
var page = table.api().page.info();
|
||||
var active = page.recordsDisplay;
|
||||
var total = page.recordsTotal;
|
||||
|
||||
var _text = _gettext("{0} out of {1} users").format(active, total);
|
||||
$('#user_count').text(_text);
|
||||
};
|
||||
|
||||
// user list
|
||||
$userListTable.DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: "${h.route_path('repo_forks_data', repo_name=c.repo_name)}",
|
||||
dom: 'rtp',
|
||||
pageLength: ${c.visual.dashboard_items},
|
||||
order: [[ 0, "asc" ]],
|
||||
columns: [
|
||||
{ data: {"_": "username",
|
||||
"sort": "username"}, title: "${_('Owner')}", className: "td-user" },
|
||||
{ data: {"_": "fork_name",
|
||||
"sort": "fork_name"}, title: "${_('Fork name')}", className: "td-email" },
|
||||
{ data: {"_": "description",
|
||||
"sort": "description"}, title: "${_('Description')}", className: "td-user" },
|
||||
{ data: {"_": "fork_date",
|
||||
"sort": "fork_date"}, title: "${_('Forked')}", className: "td-user" },
|
||||
{ data: {"_": "last_activity",
|
||||
"sort": "last_activity",
|
||||
"type": Number}, title: "${_('Last activity')}", className: "td-time" },
|
||||
{ data: {"_": "action",
|
||||
"sort": "action"}, title: "${_('Action')}", className: "td-action", orderable: false }
|
||||
],
|
||||
|
||||
language: {
|
||||
paginate: DEFAULT_GRID_PAGINATION,
|
||||
sProcessing: _gettext('loading...'),
|
||||
emptyTable: _gettext("No forks available yet.")
|
||||
},
|
||||
|
||||
"createdRow": function ( row, data, index ) {
|
||||
if (!data['active_raw']){
|
||||
$(row).addClass('closed')
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$userListTable.on('xhr.dt', function(e, settings, json, xhr){
|
||||
$userListTable.css('opacity', 1);
|
||||
});
|
||||
|
||||
$userListTable.on('preXhr.dt', function(e, settings, data){
|
||||
$userListTable.css('opacity', 0.3);
|
||||
});
|
||||
|
||||
// refresh counters on draw
|
||||
$userListTable.on('draw.dt', function(){
|
||||
getDatatableCount();
|
||||
});
|
||||
|
||||
// filter
|
||||
$('#q_filter').on('keyup',
|
||||
$.debounce(250, function() {
|
||||
$userListTable.DataTable().search(
|
||||
$('#q_filter').val()
|
||||
).draw();
|
||||
})
|
||||
);
|
||||
|
||||
});
|
||||
</script>
|
||||
</%def>
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%namespace name="base" file="/base/base.mako"/>
|
||||
|
||||
% if c.forks_pager:
|
||||
<table class="rctable fork_summary">
|
||||
<tr>
|
||||
<th>${_('Owner')}</th>
|
||||
<th>${_('Fork')}</th>
|
||||
<th>${_('Description')}</th>
|
||||
<th>${_('Forked')}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
% for f in c.forks_pager:
|
||||
<tr>
|
||||
<td class="td-user fork_user">
|
||||
${base.gravatar_with_user(f.user.email, 16)}
|
||||
</td>
|
||||
<td class="td-componentname">
|
||||
${h.link_to(f.repo_name,h.route_path('repo_summary',repo_name=f.repo_name))}
|
||||
</td>
|
||||
<td class="td-description">
|
||||
<div class="truncate">${f.description}</div>
|
||||
</td>
|
||||
<td class="td-time follower_date">
|
||||
${h.age_component(f.created_on, time_is_local=True)}
|
||||
</td>
|
||||
<td class="td-compare">
|
||||
<a title="${h.tooltip(_('Compare fork with %s' % c.repo_name))}"
|
||||
class="btn-link"
|
||||
href="${h.route_path('repo_compare',
|
||||
repo_name=c.repo_name,
|
||||
source_ref_type=c.rhodecode_db_repo.landing_rev[0],
|
||||
source_ref=c.rhodecode_db_repo.landing_rev[1],
|
||||
target_ref_type=c.rhodecode_db_repo.landing_rev[0],
|
||||
target_ref=c.rhodecode_db_repo.landing_rev[1],
|
||||
_query=dict(merge=1, target_repo=f.repo_name))}"
|
||||
>
|
||||
${_('Compare fork')}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
% endfor
|
||||
</table>
|
||||
<div class="pagination-wh pagination-left">
|
||||
<script type="text/javascript">
|
||||
$(document).pjax('#forks .pager_link','#forks');
|
||||
$(document).on('pjax:success',function(){
|
||||
show_more_event();
|
||||
timeagoActivate();
|
||||
});
|
||||
</script>
|
||||
${c.forks_pager.pager('$link_previous ~2~ $link_next')}
|
||||
</div>
|
||||
% else:
|
||||
${_('There are no forks yet')}
|
||||
% endif
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
% endif
|
||||
|
||||
## forks
|
||||
<a title="${_('Number of Repository Forks')}" href="${h.url('repo_forks_home', repo_name=c.repo_name)}">
|
||||
<a title="${_('Number of Repository Forks')}" href="${h.route_path('repo_forks_show_all', repo_name=c.repo_name)}">
|
||||
${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)}</a>,
|
||||
|
||||
## repo size
|
||||
|
|
|
|||
|
|
@ -1,288 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-2017 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import pytest
|
||||
|
||||
from rhodecode.tests import *
|
||||
from rhodecode.tests.fixture import Fixture
|
||||
from rhodecode.lib import helpers as h
|
||||
|
||||
from rhodecode.model.db import Repository
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.user import UserModel
|
||||
from rhodecode.model.meta import Session
|
||||
|
||||
fixture = Fixture()
|
||||
|
||||
|
||||
def route_path(name, params=None, **kwargs):
|
||||
import urllib
|
||||
|
||||
base_url = {
|
||||
'repo_summary': '/{repo_name}',
|
||||
'repo_creating_check': '/{repo_name}/repo_creating_check',
|
||||
}[name].format(**kwargs)
|
||||
|
||||
if params:
|
||||
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
|
||||
return base_url
|
||||
|
||||
|
||||
class _BaseTest(TestController):
|
||||
|
||||
REPO = None
|
||||
REPO_TYPE = None
|
||||
NEW_REPO = None
|
||||
REPO_FORK = None
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def prepare(self, request, pylonsapp):
|
||||
self.username = u'forkuser'
|
||||
self.password = u'qweqwe'
|
||||
self.u1 = fixture.create_user(self.username, password=self.password,
|
||||
email=u'fork_king@rhodecode.org')
|
||||
Session().commit()
|
||||
self.u1id = self.u1.user_id
|
||||
request.addfinalizer(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
u1 = UserModel().get(self.u1id)
|
||||
Session().delete(u1)
|
||||
Session().commit()
|
||||
|
||||
def test_index(self):
|
||||
self.log_user()
|
||||
repo_name = self.REPO
|
||||
response = self.app.get(url(controller='forks', action='forks',
|
||||
repo_name=repo_name))
|
||||
|
||||
response.mustcontain("""There are no forks yet""")
|
||||
|
||||
def test_no_permissions_to_fork(self):
|
||||
usr = self.log_user(TEST_USER_REGULAR_LOGIN,
|
||||
TEST_USER_REGULAR_PASS)['user_id']
|
||||
user_model = UserModel()
|
||||
user_model.revoke_perm(usr, 'hg.fork.repository')
|
||||
user_model.grant_perm(usr, 'hg.fork.none')
|
||||
u = UserModel().get(usr)
|
||||
u.inherit_default_permissions = False
|
||||
Session().commit()
|
||||
# try create a fork
|
||||
repo_name = self.REPO
|
||||
self.app.post(
|
||||
url(controller='forks', action='fork_create', repo_name=repo_name),
|
||||
{'csrf_token': self.csrf_token}, status=404)
|
||||
|
||||
def test_index_with_fork(self):
|
||||
self.log_user()
|
||||
|
||||
# create a fork
|
||||
fork_name = self.REPO_FORK
|
||||
description = 'fork of vcs test'
|
||||
repo_name = self.REPO
|
||||
source_repo = Repository.get_by_repo_name(repo_name)
|
||||
creation_args = {
|
||||
'repo_name': fork_name,
|
||||
'repo_group': '',
|
||||
'fork_parent_id': source_repo.repo_id,
|
||||
'repo_type': self.REPO_TYPE,
|
||||
'description': description,
|
||||
'private': 'False',
|
||||
'landing_rev': 'rev:tip',
|
||||
'csrf_token': self.csrf_token,
|
||||
}
|
||||
|
||||
self.app.post(url(controller='forks', action='fork_create',
|
||||
repo_name=repo_name), creation_args)
|
||||
|
||||
response = self.app.get(url(controller='forks', action='forks',
|
||||
repo_name=repo_name))
|
||||
|
||||
response.mustcontain(
|
||||
"""<a href="/%s">%s</a>""" % (fork_name, fork_name)
|
||||
)
|
||||
|
||||
# remove this fork
|
||||
fixture.destroy_repo(fork_name)
|
||||
|
||||
def test_fork_create_into_group(self):
|
||||
self.log_user()
|
||||
group = fixture.create_repo_group('vc')
|
||||
group_id = group.group_id
|
||||
fork_name = self.REPO_FORK
|
||||
fork_name_full = 'vc/%s' % fork_name
|
||||
description = 'fork of vcs test'
|
||||
repo_name = self.REPO
|
||||
source_repo = Repository.get_by_repo_name(repo_name)
|
||||
creation_args = {
|
||||
'repo_name': fork_name,
|
||||
'repo_group': group_id,
|
||||
'fork_parent_id': source_repo.repo_id,
|
||||
'repo_type': self.REPO_TYPE,
|
||||
'description': description,
|
||||
'private': 'False',
|
||||
'landing_rev': 'rev:tip',
|
||||
'csrf_token': self.csrf_token,
|
||||
}
|
||||
self.app.post(url(controller='forks', action='fork_create',
|
||||
repo_name=repo_name), creation_args)
|
||||
repo = Repository.get_by_repo_name(fork_name_full)
|
||||
assert repo.fork.repo_name == self.REPO
|
||||
|
||||
# run the check page that triggers the flash message
|
||||
response = self.app.get(
|
||||
route_path('repo_creating_check', repo_name=fork_name_full))
|
||||
# test if we have a message that fork is ok
|
||||
assert_session_flash(response,
|
||||
'Forked repository %s as <a href="/%s">%s</a>'
|
||||
% (repo_name, fork_name_full, fork_name_full))
|
||||
|
||||
# test if the fork was created in the database
|
||||
fork_repo = Session().query(Repository)\
|
||||
.filter(Repository.repo_name == fork_name_full).one()
|
||||
|
||||
assert fork_repo.repo_name == fork_name_full
|
||||
assert fork_repo.fork.repo_name == repo_name
|
||||
|
||||
# test if the repository is visible in the list ?
|
||||
response = self.app.get(h.route_path('repo_summary', repo_name=fork_name_full))
|
||||
response.mustcontain(fork_name_full)
|
||||
response.mustcontain(self.REPO_TYPE)
|
||||
|
||||
response.mustcontain('Fork of')
|
||||
response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
|
||||
|
||||
fixture.destroy_repo(fork_name_full)
|
||||
fixture.destroy_repo_group(group_id)
|
||||
|
||||
def test_z_fork_create(self):
|
||||
self.log_user()
|
||||
fork_name = self.REPO_FORK
|
||||
description = 'fork of vcs test'
|
||||
repo_name = self.REPO
|
||||
source_repo = Repository.get_by_repo_name(repo_name)
|
||||
creation_args = {
|
||||
'repo_name': fork_name,
|
||||
'repo_group': '',
|
||||
'fork_parent_id': source_repo.repo_id,
|
||||
'repo_type': self.REPO_TYPE,
|
||||
'description': description,
|
||||
'private': 'False',
|
||||
'landing_rev': 'rev:tip',
|
||||
'csrf_token': self.csrf_token,
|
||||
}
|
||||
self.app.post(url(controller='forks', action='fork_create',
|
||||
repo_name=repo_name), creation_args)
|
||||
repo = Repository.get_by_repo_name(self.REPO_FORK)
|
||||
assert repo.fork.repo_name == self.REPO
|
||||
|
||||
# run the check page that triggers the flash message
|
||||
response = self.app.get(
|
||||
route_path('repo_creating_check', repo_name=fork_name))
|
||||
# test if we have a message that fork is ok
|
||||
assert_session_flash(response,
|
||||
'Forked repository %s as <a href="/%s">%s</a>'
|
||||
% (repo_name, fork_name, fork_name))
|
||||
|
||||
# test if the fork was created in the database
|
||||
fork_repo = Session().query(Repository)\
|
||||
.filter(Repository.repo_name == fork_name).one()
|
||||
|
||||
assert fork_repo.repo_name == fork_name
|
||||
assert fork_repo.fork.repo_name == repo_name
|
||||
|
||||
# test if the repository is visible in the list ?
|
||||
response = self.app.get(h.route_path('repo_summary', repo_name=fork_name))
|
||||
response.mustcontain(fork_name)
|
||||
response.mustcontain(self.REPO_TYPE)
|
||||
response.mustcontain('Fork of')
|
||||
response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
|
||||
|
||||
def test_zz_fork_permission_page(self):
|
||||
usr = self.log_user(self.username, self.password)['user_id']
|
||||
repo_name = self.REPO
|
||||
|
||||
forks = Repository.query()\
|
||||
.filter(Repository.repo_type == self.REPO_TYPE)\
|
||||
.filter(Repository.fork_id != None).all()
|
||||
assert 1 == len(forks)
|
||||
|
||||
# set read permissions for this
|
||||
RepoModel().grant_user_permission(repo=forks[0],
|
||||
user=usr,
|
||||
perm='repository.read')
|
||||
Session().commit()
|
||||
|
||||
response = self.app.get(url(controller='forks', action='forks',
|
||||
repo_name=repo_name))
|
||||
|
||||
response.mustcontain('fork of vcs test')
|
||||
|
||||
def test_zzz_fork_permission_page(self):
|
||||
usr = self.log_user(self.username, self.password)['user_id']
|
||||
repo_name = self.REPO
|
||||
|
||||
forks = Repository.query()\
|
||||
.filter(Repository.repo_type == self.REPO_TYPE)\
|
||||
.filter(Repository.fork_id != None).all()
|
||||
assert 1 == len(forks)
|
||||
|
||||
# set none
|
||||
RepoModel().grant_user_permission(repo=forks[0],
|
||||
user=usr, perm='repository.none')
|
||||
Session().commit()
|
||||
# fork shouldn't be there
|
||||
response = self.app.get(url(controller='forks', action='forks',
|
||||
repo_name=repo_name))
|
||||
response.mustcontain('There are no forks yet')
|
||||
|
||||
|
||||
class TestGIT(_BaseTest):
|
||||
REPO = GIT_REPO
|
||||
NEW_REPO = NEW_GIT_REPO
|
||||
REPO_TYPE = 'git'
|
||||
REPO_FORK = GIT_FORK
|
||||
|
||||
|
||||
class TestHG(_BaseTest):
|
||||
REPO = HG_REPO
|
||||
NEW_REPO = NEW_HG_REPO
|
||||
REPO_TYPE = 'hg'
|
||||
REPO_FORK = HG_FORK
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('app', 'autologin_user')
|
||||
@pytest.mark.skip_backends('git','hg')
|
||||
class TestSVNFork(object):
|
||||
|
||||
def test_fork_redirects(self, backend):
|
||||
denied_actions = ['fork','fork_create']
|
||||
for action in denied_actions:
|
||||
response = self.app.get(url(
|
||||
controller='forks', action=action,
|
||||
repo_name=backend.repo_name))
|
||||
assert response.status_int == 302
|
||||
|
||||
# Not allowed, redirect to the summary
|
||||
redirected = response.follow()
|
||||
summary_url = h.route_path('repo_summary', repo_name=backend.repo_name)
|
||||
|
||||
# URL adds leading slash and path doesn't have it
|
||||
assert redirected.request.path == summary_url
|
||||
|
|
@ -18,15 +18,10 @@
|
|||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import mock
|
||||
import pytest
|
||||
from webob.exc import HTTPNotFound
|
||||
|
||||
import rhodecode
|
||||
from rhodecode.model.db import Integration
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.tests import assert_session_flash, url, TEST_USER_ADMIN_LOGIN
|
||||
from rhodecode.tests.utils import AssertResponse
|
||||
from rhodecode.integrations import integration_type_registry
|
||||
from rhodecode.config.routing import ADMIN_PREFIX
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue