# HG changeset patch # User Marcin Kuzminski # Date 2013-03-31 14:18:09 # Node ID b44979649915052ea5b70497028a9cd3ee6cd3ba # Parent 4f80df0d45c8c9f38d71ea8256c4a6c6acccd107 recursive forks detach - added API attrs for option to delete or detach forks - deleting repos with attached forks raises an special Exception diff --git a/docs/api/api.rst b/docs/api/api.rst --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -848,8 +848,10 @@ OUTPUT:: delete_repo ----------- -Deletes a repository. This command can be executed only using api_key belonging to user with admin -rights or regular user that have admin access to repository. +Deletes a repository. This command can be executed only using api_key belonging +to user with admin rights or regular user that have admin access to repository. +When `forks` param is set it's possible to detach or delete forks of deleting +repository INPUT:: @@ -858,7 +860,8 @@ INPUT:: api_key : "" method : "delete_repo" args: { - "repoid" : "" + "repoid" : "", + "forks" : "`delete` or `detach` = Optional(None)" } OUTPUT:: diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -50,6 +50,7 @@ from rhodecode.model.scm import ScmModel from rhodecode.model.repo import RepoModel from rhodecode.lib.compat import json from sqlalchemy.sql.expression import func +from rhodecode.lib.exceptions import AttachedForksError log = logging.getLogger(__name__) @@ -302,38 +303,26 @@ class ReposController(BaseRepoController return redirect(url('repos')) try: _forks = repo.forks.count() + handle_forks = None if _forks and request.POST.get('forks'): do = request.POST['forks'] if do == 'detach_forks': - for r in repo.forks: - log.debug('Detaching fork %s from repo %s' % (r, repo)) - r.fork = None - Session().add(r) + handle_forks = 'detach' h.flash(_('Detached %s forks') % _forks, category='success') elif do == 'delete_forks': - for r in repo.forks: - log.debug('Deleting fork %s of repo %s' % (r, repo)) - repo_model.delete(r) + handle_forks = 'delete' h.flash(_('Deleted %s forks') % _forks, category='success') + repo_model.delete(repo, forks=handle_forks) action_logger(self.rhodecode_user, 'admin_deleted_repo', - repo_name, self.ip_addr, self.sa) - repo_model.delete(repo) + repo_name, self.ip_addr, self.sa) invalidate_cache('get_repo_cached_%s' % repo_name) h.flash(_('Deleted repository %s') % repo_name, category='success') Session().commit() - except IntegrityError, e: - if e.message.find('repositories_fork_id_fkey') != -1: - log.error(traceback.format_exc()) - h.flash(_('Cannot delete %s it still contains attached ' - 'forks') % repo_name, - category='warning') - else: - log.error(traceback.format_exc()) - h.flash(_('An error occurred during ' - 'deletion of %s') % repo_name, - category='error') + except AttachedForksError: + h.flash(_('Cannot delete %s it still contains attached forks') + % repo_name, category='warning') - except Exception, e: + except Exception: log.error(traceback.format_exc()) h.flash(_('An error occurred during deletion of %s') % repo_name, category='error') diff --git a/rhodecode/controllers/api/api.py b/rhodecode/controllers/api/api.py --- a/rhodecode/controllers/api/api.py +++ b/rhodecode/controllers/api/api.py @@ -853,12 +853,13 @@ class ApiController(JSONRPCController): fork_name) ) - def delete_repo(self, apiuser, repoid): + def delete_repo(self, apiuser, repoid, forks=Optional(None)): """ Deletes a given repository :param apiuser: :param repoid: + :param forks: detach or delete, what do do with attached forks for repo """ repo = get_repo_or_error(repoid) @@ -866,13 +867,26 @@ class ApiController(JSONRPCController): # check if we have admin permission for this repo ! if HasRepoPermissionAnyApi('repository.admin')(user=apiuser, repo_name=repo.repo_name) is False: - raise JSONRPCError('repository `%s` does not exist' % (repoid)) + raise JSONRPCError('repository `%s` does not exist' % (repoid)) try: - RepoModel().delete(repo) + handle_forks = Optional.extract(forks) + _forks_msg = '' + _forks = [f for f in repo.forks] + if handle_forks == 'detach': + _forks_msg = ' ' + _('Detached %s forks') % len(_forks) + elif handle_forks == 'delete': + _forks_msg = ' ' + _('Deleted %s forks') % len(_forks) + elif _forks: + raise JSONRPCError( + 'Cannot delete `%s` it still contains attached forks' + % repo.repo_name + ) + + RepoModel().delete(repo, forks=forks) Session().commit() return dict( - msg='Deleted repository `%s`' % repo.repo_name, + msg='Deleted repository `%s`%s' % (repo.repo_name, _forks_msg), success=True ) except Exception: diff --git a/rhodecode/lib/exceptions.py b/rhodecode/lib/exceptions.py --- a/rhodecode/lib/exceptions.py +++ b/rhodecode/lib/exceptions.py @@ -58,6 +58,10 @@ class StatusChangeOnClosedPullRequestErr pass +class AttachedForksError(Exception): + pass + + class HTTPLockedRC(HTTPClientError): """ Special Exception For locked Repos in RhodeCode, the return code can diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py --- a/rhodecode/model/repo.py +++ b/rhodecode/model/repo.py @@ -42,6 +42,7 @@ from rhodecode.model.db import Repositor RhodeCodeSetting, RepositoryField from rhodecode.lib import helpers as h from rhodecode.lib.auth import HasRepoPermissionAny +from rhodecode.lib.exceptions import AttachedForksError log = logging.getLogger(__name__) @@ -465,9 +466,27 @@ class RepoModel(BaseModel): from rhodecode.lib.celerylib import tasks, run_task run_task(tasks.create_repo_fork, form_data, cur_user) - def delete(self, repo): + def delete(self, repo, forks=None): + """ + Delete given repository, forks parameter defines what do do with + attached forks. Throws AttachedForksError if deleted repo has attached + forks + + :param repo: + :param forks: str 'delete' or 'detach' + """ repo = self._get_repo(repo) if repo: + if forks == 'detach': + for r in repo.forks: + r.fork = None + self.sa.add(r) + elif forks == 'delete': + for r in repo.forks: + self.delete(r, forks='delete') + elif [f for f in repo.forks]: + raise AttachedForksError() + old_repo_dict = repo.get_dict() owner = repo.user try: