repository: add check preventing of removal of repo with attached pull requests.

- fixes #5493
This commit is contained in:
Marcin Kuzminski 2018-09-25 12:05:44 +02:00
parent 4c45a5dbea
commit 39d181f715
5 changed files with 54 additions and 15 deletions

View file

@ -29,7 +29,7 @@ from rhodecode.lib import audit_logger
from rhodecode.lib.auth import (
LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired,
HasRepoPermissionAny)
from rhodecode.lib.exceptions import AttachedForksError
from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
from rhodecode.lib.utils2 import safe_int
from rhodecode.lib.vcs import RepositoryError
from rhodecode.model.db import Session, UserFollowing, User, Repository
@ -80,22 +80,23 @@ class RepoSettingsView(RepoAppView):
"""
_ = self.request.translate
handle_forks = self.request.POST.get('forks', None)
if handle_forks == 'detach_forks':
handle_forks = 'detach'
elif handle_forks == 'delete_forks':
handle_forks = 'delete'
try:
_forks = self.db_repo.forks.count()
if _forks and handle_forks:
if handle_forks == 'detach_forks':
handle_forks = 'detach'
h.flash(_('Detached %s forks') % _forks, category='success')
elif handle_forks == 'delete_forks':
handle_forks = 'delete'
h.flash(_('Deleted %s forks') % _forks, category='success')
old_data = self.db_repo.get_api_data()
RepoModel().delete(self.db_repo, forks=handle_forks)
repo = audit_logger.RepoWrap(repo_id=None,
repo_name=self.db_repo.repo_name)
_forks = self.db_repo.forks.count()
if _forks and handle_forks:
if handle_forks == 'detach_forks':
h.flash(_('Detached %s forks') % _forks, category='success')
elif handle_forks == 'delete_forks':
h.flash(_('Deleted %s forks') % _forks, category='success')
repo = audit_logger.RepoWrap(repo_id=None, repo_name=self.db_repo.repo_name)
audit_logger.store_web(
'repo.delete', action_data={'old_data': old_data},
user=self._rhodecode_user, repo=repo)
@ -118,6 +119,20 @@ class RepoSettingsView(RepoAppView):
# redirect to advanced for forks handle action ?
raise HTTPFound(repo_advanced_url)
except AttachedPullRequestsError:
repo_advanced_url = h.route_path(
'edit_repo_advanced', repo_name=self.db_repo_name,
_anchor='advanced-delete')
attached_prs = len(self.db_repo.pull_requests_source +
self.db_repo.pull_requests_target)
h.flash(
_('Cannot delete `{repo}` it still contains {num} attached pull requests. '
'Consider archiving the repository instead.').format(
repo=self.db_repo_name, num=attached_prs), category='warning')
# redirect to advanced for forks handle action ?
raise HTTPFound(repo_advanced_url)
except Exception:
log.exception("Exception during deletion of repository")
h.flash(_('An error occurred during deletion of `%s`')

View file

@ -70,6 +70,10 @@ class AttachedForksError(Exception):
pass
class AttachedPullRequestsError(Exception):
pass
class RepoGroupAssignmentError(Exception):
pass

View file

@ -32,7 +32,7 @@ from zope.cachedescriptors.property import Lazy as LazyProperty
from rhodecode import events
from rhodecode.lib.auth import HasUserGroupPermissionAny
from rhodecode.lib.caching_query import FromCache
from rhodecode.lib.exceptions import AttachedForksError
from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
from rhodecode.lib.hooks_base import log_delete_repository
from rhodecode.lib.user_log_filter import user_log_filter
from rhodecode.lib.utils import make_db_config
@ -608,7 +608,7 @@ class RepoModel(BaseModel):
from rhodecode.lib.celerylib import tasks, run_task
return run_task(tasks.create_repo_fork, form_data, cur_user)
def delete(self, repo, forks=None, fs_remove=True, cur_user=None):
def delete(self, repo, forks=None, pull_requests=None, fs_remove=True, cur_user=None):
"""
Delete given repository, forks parameter defines what do do with
attached forks. Throws AttachedForksError if deleted repo has attached
@ -632,6 +632,12 @@ class RepoModel(BaseModel):
elif [f for f in repo.forks]:
raise AttachedForksError()
# check for pull requests
pr_sources = repo.pull_requests_source
pr_targets = repo.pull_requests_target
if pull_requests != 'delete' and (pr_sources or pr_targets):
raise AttachedPullRequestsError()
old_repo_dict = repo.get_dict()
events.trigger(events.RepoPreDeleteEvent(repo))
try:

View file

@ -7,6 +7,8 @@
(_('Updated on'), h.format_date(c.rhodecode_db_repo.updated_on), '', ''),
(_('Cached Commit id'), lambda: h.link_to(c.rhodecode_db_repo.changeset_cache.get('short_id'), h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.rhodecode_db_repo.changeset_cache.get('raw_id'))), '', ''),
(_('Attached scoped tokens'), len(c.rhodecode_db_repo.scoped_tokens), '', [x.user for x in c.rhodecode_db_repo.scoped_tokens]),
(_('Pull requests source'), len(c.rhodecode_db_repo.pull_requests_source), '', ['pr_id:{}, repo:{}'.format(x.pull_request_id,x.source_repo.repo_name) for x in c.rhodecode_db_repo.pull_requests_source]),
(_('Pull requests target'), len(c.rhodecode_db_repo.pull_requests_target), '', ['pr_id:{}, repo:{}'.format(x.pull_request_id,x.target_repo.repo_name) for x in c.rhodecode_db_repo.pull_requests_target]),
]
%>
@ -131,6 +133,18 @@
%endif
</td>
</tr>
<% attached_prs = len(c.rhodecode_db_repo.pull_requests_source + c.rhodecode_db_repo.pull_requests_target) %>
% if c.rhodecode_db_repo.pull_requests_source or c.rhodecode_db_repo.pull_requests_target:
<tr>
<td>
${_ungettext('This repository has %s attached pull request.', 'This repository has %s attached pull requests.', attached_prs) % attached_prs}
<br/>
${_('Consider to archive this repository instead.')}
</td>
<td></td>
<td></td>
</tr>
% endif
</table>
<div style="margin: 0 0 20px 0" class="fake-space"></div>

View file

@ -226,7 +226,7 @@ class Fixture(object):
return r
def destroy_repo(self, repo_name, **kwargs):
RepoModel().delete(repo_name, **kwargs)
RepoModel().delete(repo_name, pull_requests='delete', **kwargs)
Session().commit()
def destroy_repo_on_filesystem(self, repo_name):