api: get_repos allows now to filter by root locations, and optionally traverse the returned data.

Fixes #5146
This commit is contained in:
Marcin Kuzminski 2016-12-29 14:41:46 +01:00
parent 707e498026
commit 340d1b02d9
3 changed files with 117 additions and 5 deletions

View file

@ -22,7 +22,8 @@
import pytest
from rhodecode.model.repo import RepoModel
from rhodecode.api.tests.utils import build_data, api_call, assert_ok, jsonify
from rhodecode.api.tests.utils import (
build_data, api_call, assert_ok, assert_error, jsonify)
from rhodecode.model.db import User
@ -40,6 +41,76 @@ class TestGetRepos(object):
expected = ret
assert_ok(id_, expected, given=response.body)
def test_api_get_repos_only_toplevel(self, user_util):
repo_group = user_util.create_repo_group(auto_cleanup=True)
user_util.create_repo(parent=repo_group)
id_, params = build_data(self.apikey, 'get_repos', traverse=0)
response = api_call(self.app, params)
result = []
for repo in RepoModel().get_repos_for_root(root=None):
result.append(repo.get_api_data(include_secrets=True))
expected = jsonify(result)
assert_ok(id_, expected, given=response.body)
def test_api_get_repos_with_wrong_root(self):
id_, params = build_data(self.apikey, 'get_repos', root='abracadabra')
response = api_call(self.app, params)
expected = 'Root repository group `abracadabra` does not exist'
assert_error(id_, expected, given=response.body)
def test_api_get_repos_with_root(self, user_util):
repo_group = user_util.create_repo_group(auto_cleanup=True)
repo_group_name = repo_group.group_name
user_util.create_repo(parent=repo_group)
user_util.create_repo(parent=repo_group)
# nested, should not show up
user_util._test_name = '{}/'.format(repo_group_name)
sub_repo_group = user_util.create_repo_group(auto_cleanup=True)
user_util.create_repo(parent=sub_repo_group)
id_, params = build_data(self.apikey, 'get_repos',
root=repo_group_name, traverse=0)
response = api_call(self.app, params)
result = []
for repo in RepoModel().get_repos_for_root(repo_group):
result.append(repo.get_api_data(include_secrets=True))
assert len(result) == 2
expected = jsonify(result)
assert_ok(id_, expected, given=response.body)
def test_api_get_repos_with_root_and_traverse(self, user_util):
repo_group = user_util.create_repo_group(auto_cleanup=True)
repo_group_name = repo_group.group_name
user_util.create_repo(parent=repo_group)
user_util.create_repo(parent=repo_group)
# nested, should not show up
user_util._test_name = '{}/'.format(repo_group_name)
sub_repo_group = user_util.create_repo_group(auto_cleanup=True)
user_util.create_repo(parent=sub_repo_group)
id_, params = build_data(self.apikey, 'get_repos',
root=repo_group_name, traverse=1)
response = api_call(self.app, params)
result = []
for repo in RepoModel().get_repos_for_root(
repo_group_name, traverse=True):
result.append(repo.get_api_data(include_secrets=True))
assert len(result) == 3
expected = jsonify(result)
assert_ok(id_, expected, given=response.body)
def test_api_get_repos_non_admin(self):
id_, params = build_data(self.apikey_regular, 'get_repos')
response = api_call(self.app, params)

View file

@ -36,7 +36,7 @@ from rhodecode.lib.ext_json import json
from rhodecode.model.changeset_status import ChangesetStatusModel
from rhodecode.model.comment import ChangesetCommentsModel
from rhodecode.model.db import (
Session, ChangesetStatus, RepositoryField, Repository)
Session, ChangesetStatus, RepositoryField, Repository, RepoGroup)
from rhodecode.model.repo import RepoModel
from rhodecode.model.scm import ScmModel, RepoList
from rhodecode.model.settings import SettingsModel, VcsSettingsModel
@ -217,7 +217,7 @@ def get_repo(request, apiuser, repoid, cache=Optional(True)):
@jsonrpc_method()
def get_repos(request, apiuser):
def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
"""
Lists all existing repositories.
@ -226,6 +226,14 @@ def get_repos(request, apiuser):
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param root: specify root repository group to fetch repositories.
filters the returned repositories to be members of given root group.
:type root: Optional(None)
:param traverse: traverse given root into subrepositories. With this flag
set to False, it will only return top-level repositories from `root`.
if root is empty it will return just top-level repositories.
:type traverse: Optional(True)
Example output:
@ -257,8 +265,28 @@ def get_repos(request, apiuser):
_perms = ('repository.read', 'repository.write', 'repository.admin',)
extras = {'user': apiuser}
repo_list = RepoList(
RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
root = Optional.extract(root)
traverse = Optional.extract(traverse, binary=True)
if root:
# verify parent existance, if it's empty return an error
parent = RepoGroup.get_by_group_name(root)
if not parent:
raise JSONRPCError(
'Root repository group `{}` does not exist'.format(root))
if traverse:
repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
else:
repos = RepoModel().get_repos_for_root(root=parent)
else:
if traverse:
repos = RepoModel().get_all()
else:
# return just top-level
repos = RepoModel().get_repos_for_root(root=None)
repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
return [repo.get_api_data(include_secrets=include_secrets)
for repo in repo_list]

View file

@ -143,6 +143,19 @@ class RepoModel(BaseModel):
return None
def get_repos_for_root(self, root, traverse=False):
if traverse:
like_expression = u'{}%'.format(safe_unicode(root))
repos = Repository.query().filter(
Repository.repo_name.like(like_expression)).all()
else:
if root and not isinstance(root, RepoGroup):
raise ValueError(
'Root must be an instance '
'of RepoGroup, got:{} instead'.format(type(root)))
repos = Repository.query().filter(Repository.group == root).all()
return repos
def get_url(self, repo):
return h.url('summary_home', repo_name=safe_str(repo.repo_name),
qualified=True)