@@ -107,96 +107,118 @@ API METHODS
pull
----
Pulls given repo from remote location. Can be used to automatically keep
remote repos up to date. This command can be executed only using api_key
belonging to user with admin rights
INPUT::
id : <id_for_response>
api_key : "<api_key>"
method : "pull"
args : {
"repoid" : "<reponame or repo_id>"
}
OUTPUT::
id : <id_given_in_input>
result : "Pulled from `<reponame>`"
error : null
rescan_repos
------------
Dispatch rescan repositories action. If remove_obsolete is set
RhodeCode will delete repos that are in database but not in the filesystem.
This command can be executed only using api_key belonging to user with admin
rights.
method : "rescan_repos"
"remove_obsolete" : "<boolean = Optional(False)>"
result : "{'added': [<list of names of added repos>],
'removed': [<list of names of removed repos>]}"
invalidate_cache
----------------
Invalidate cache for repository.
rights or regular user that have write or admin or write access to repository.
method : "invalidate_cache"
result : "Cache for repository `<reponame>` was invalidated: invalidated cache keys: <list_of_cache_keys>"
lock
Set locking state on given repository by given user. If userid param is skipped
, then it is set to id of user whos calling this method.
rights or regular user that have admin or write access to repository.
method : "lock"
"userid" : "<user_id or username = Optional(=apiuser)>",
"locked" : "<bool true|false>"
result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
show_ip
-------
Shows IP address as seen from RhodeCode server, together with all
defined IP addresses for given user.
method : "show_ip"
"userid" : "<user_id or username>",
result : {
"ip_addr_server": <ip_from_clien>",
@@ -157,96 +157,122 @@ class ApiController(JSONRPCController):
Each function should also **raise** JSONRPCError for any
errors that happens
"""
@HasPermissionAllDecorator('hg.admin')
def pull(self, apiuser, repoid):
Dispatch pull action on given repo
:param apiuser:
:param repoid:
repo = get_repo_or_error(repoid)
try:
ScmModel().pull_changes(repo.repo_name,
self.rhodecode_user.username)
return 'Pulled from `%s`' % repo.repo_name
except Exception:
log.error(traceback.format_exc())
raise JSONRPCError(
'Unable to pull changes from `%s`' % repo.repo_name
)
def rescan_repos(self, apiuser, remove_obsolete=Optional(False)):
than also delete repos that are in database but not in the filesystem.
aka "clean zombies"
:param remove_obsolete:
rm_obsolete = Optional.extract(remove_obsolete)
added, removed = repo2db_mapper(ScmModel().repo_scan(),
remove_obsolete=rm_obsolete)
return {'added': added, 'removed': removed}
'Error occurred during rescan repositories action'
def invalidate_cache(self, apiuser, repoid):
Dispatch cache invalidation action on given repo
if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
# check if we have admin permission for this repo !
if HasRepoPermissionAnyApi('repository.admin',
'repository.write')(user=apiuser,
repo_name=repo.repo_name) is False:
raise JSONRPCError('repository `%s` does not exist' % (repoid))
invalidated_keys = ScmModel().mark_for_invalidation(repo.repo_name)
Session().commit()
return ('Cache for repository `%s` was invalidated: '
'invalidated cache keys: %s' % (repoid, invalidated_keys))
'Error occurred during cache invalidation action'
def lock(self, apiuser, repoid, locked, userid=Optional(OAttr('apiuser'))):
Set locking state on particular repository by given user, if
this command is runned by non-admin account userid is set to user
who is calling this method
:param userid:
:param locked:
if HasPermissionAnyApi('hg.admin')(user=apiuser):
pass
elif HasRepoPermissionAnyApi('repository.admin',
repo_name=repo.repo_name):
#make sure normal user does not pass someone else userid,
#he is not allowed to do that
if not isinstance(userid, Optional) and userid != apiuser.user_id:
'userid is not the same as your user'
else:
if isinstance(userid, Optional):
userid = apiuser.user_id
user = get_user_or_error(userid)
locked = bool(locked)
if locked:
Repository.lock(repo, user.user_id)
Repository.unlock(repo)
return ('User `%s` set lock state for repo `%s` to `%s`'
% (user.username, repo.repo_name, locked))
'Error occurred locking repository `%s`' % repo.repo_name
def show_ip(self, apiuser, userid):
@@ -241,96 +241,115 @@ class BaseTestApi(object):
response = api_call(self, params)
expected = 'userid is not the same as your user'
self._compare_error(id_, expected, given=response.body)
def test_api_pull(self):
#TODO: issues with rhodecode_extras here.. not sure why !
# repo_name = 'test_pull'
# r = create_repo(repo_name, self.REPO_TYPE)
# r.clone_uri = TEST_self.REPO
# Session.add(r)
# Session.commit()
#
# id_, params = _build_data(self.apikey, 'pull',
# repoid=repo_name,)
# response = self.app.post(API_URL, content_type='application/json',
# params=params)
# expected = 'Pulled from `%s`' % repo_name
# self._compare_ok(id_, expected, given=response.body)
# destroy_repo(repo_name)
def test_api_pull_error(self):
id_, params = _build_data(self.apikey, 'pull',
repoid=self.REPO,)
expected = 'Unable to pull changes from `%s`' % self.REPO
def test_api_rescan_repos(self):
id_, params = _build_data(self.apikey, 'rescan_repos')
expected = {'added': [], 'removed': []}
self._compare_ok(id_, expected, given=response.body)
@mock.patch.object(ScmModel, 'repo_scan', crash)
def test_api_rescann_error(self):
id_, params = _build_data(self.apikey, 'rescan_repos',)
expected = 'Error occurred during rescan repositories action'
def test_api_invalidate_cache(self):
id_, params = _build_data(self.apikey, 'invalidate_cache',
repoid=self.REPO)
expected = ("Cache for repository `%s` was invalidated: "
"invalidated cache keys: %s" % (self.REPO,
[unicode(self.REPO)]))
@mock.patch.object(ScmModel, 'mark_for_invalidation', crash)
def test_api_invalidate_cache_error(self):
expected = 'Error occurred during cache invalidation action'
def test_api_lock_repo_lock_aquire(self):
id_, params = _build_data(self.apikey, 'lock',
userid=TEST_USER_ADMIN_LOGIN,
repoid=self.REPO,
locked=True)
expected = ('User `%s` set lock state for repo `%s` to `%s`'
% (TEST_USER_ADMIN_LOGIN, self.REPO, True))
def test_api_lock_repo_lock_aquire_by_non_admin(self):
repo_name = 'api_delete_me'
create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
id_, params = _build_data(self.apikey_regular, 'lock',
repoid=repo_name,
% (self.TEST_USER_LOGIN, repo_name, True))
finally:
destroy_repo(repo_name)
def test_api_lock_repo_lock_aquire_non_admin_with_userid(self):
def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self):
expected = 'repository `%s` does not exist' % (self.REPO)
def test_api_lock_repo_lock_release(self):
Status change: