feature: makes forks and PR's link to clearly show admin what will be done
This commit is contained in:
parent
03fc3ab570
commit
d392589e5c
8 changed files with 92 additions and 83 deletions
|
|
@ -50,7 +50,7 @@ from rhodecode.model.comment import CommentsModel
|
|||
from rhodecode.model.db import Session, ChangesetStatus, RepositoryField, Repository, RepoGroup, ChangesetComment
|
||||
from rhodecode.model.permission import PermissionModel
|
||||
from rhodecode.model.pull_request import PullRequestModel
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.repo import RepoModel, ForksAction
|
||||
from rhodecode.model.scm import ScmModel, RepoList
|
||||
from rhodecode.model.settings import SettingsModel, VcsSettingsModel
|
||||
from rhodecode.model import validation_schema
|
||||
|
|
@ -1373,7 +1373,7 @@ def delete_repo(request, apiuser, repoid, forks=Optional("")):
|
|||
raise JSONRPCError(f"Cannot delete `{repo.repo_name}` it still contains attached forks")
|
||||
|
||||
old_data = repo.get_api_data()
|
||||
RepoModel().delete(repo, forks=RepoModel.ForkAction(handle_forks))
|
||||
RepoModel().delete(repo, forks_action=ForksAction(handle_forks))
|
||||
|
||||
repo = audit_logger.RepoWrap(repo_id=None, repo_name=repo.repo_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ from rhodecode.lib.utils2 import safe_int
|
|||
from rhodecode.lib.vcs import RepositoryError
|
||||
from rhodecode.model.db import Session, UserFollowing, User, Repository
|
||||
from rhodecode.model.permission import PermissionModel
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.repo import RepoModel, ForksAction
|
||||
from rhodecode.model.scm import ScmModel
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -56,6 +56,9 @@ class RepoSettingsAdvancedView(RepoAppView):
|
|||
c = self.load_default_context()
|
||||
c.active = "advanced"
|
||||
|
||||
c.fork_links = self._resolve_repo_forks_links()
|
||||
c.pr_link = h.route_path("pullrequest_show_all", repo_name=self.db_repo_name)
|
||||
|
||||
c.default_user_id = User.get_default_user_id()
|
||||
c.in_public_journal = (
|
||||
UserFollowing.query()
|
||||
|
|
@ -80,6 +83,14 @@ class RepoSettingsAdvancedView(RepoAppView):
|
|||
|
||||
return self._get_template_context(c)
|
||||
|
||||
def _resolve_repo_forks_links(self):
|
||||
def resolve_fork_link(repo):
|
||||
for fork in repo.forks:
|
||||
yield h.route_path("repo_summary", repo_name=fork.repo_name)
|
||||
yield from resolve_fork_link(fork)
|
||||
|
||||
return list(resolve_fork_link(self.db_repo))
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoPermissionAnyDecorator("repository.admin")
|
||||
@CSRFRequired()
|
||||
|
|
@ -125,8 +136,6 @@ class RepoSettingsAdvancedView(RepoAppView):
|
|||
"""
|
||||
_ = self.request.translate
|
||||
|
||||
fork_action = self._get_fork_action()
|
||||
|
||||
repo_advanced_url = h.route_path("edit_repo_advanced", repo_name=self.db_repo_name, _anchor="advanced-delete")
|
||||
try:
|
||||
old_data = self.db_repo.get_api_data()
|
||||
|
|
@ -134,14 +143,16 @@ class RepoSettingsAdvancedView(RepoAppView):
|
|||
delete_cache = True
|
||||
self._invalidate_remote_cache(delete=delete_cache)
|
||||
|
||||
RepoModel().delete(self.db_repo, forks=fork_action)
|
||||
delete_res = RepoModel().delete(self.db_repo)
|
||||
|
||||
_forks = self.db_repo.forks.count()
|
||||
if _forks and fork_action:
|
||||
if fork_action is RepoModel.ForkAction.DETACH:
|
||||
h.flash(_("Detached %s forks") % _forks, category="success")
|
||||
elif fork_action is RepoModel.ForkAction.DELETE:
|
||||
h.flash(_("Deleted %s forks") % _forks, category="success")
|
||||
fork_action = delete_res.fork_action_result.action
|
||||
fork_cnt = delete_res.fork_action_result.fork_count
|
||||
|
||||
if fork_action is not None:
|
||||
if fork_action is ForksAction.DETACH:
|
||||
h.flash(_("Detached %s forks") % fork_cnt, category="success")
|
||||
elif fork_action is ForksAction.DELETE:
|
||||
h.flash(_("Deleted %s forks") % fork_cnt, category="success")
|
||||
|
||||
repo = audit_logger.RepoWrap(repo_id=None, repo_name=self.db_repo.repo_name)
|
||||
audit_logger.store_web(
|
||||
|
|
@ -196,16 +207,6 @@ class RepoSettingsAdvancedView(RepoAppView):
|
|||
|
||||
raise HTTPFound(h.route_path("home"))
|
||||
|
||||
def _get_fork_action(self):
|
||||
fork_action = self.request.POST.get("forks", None)
|
||||
if fork_action == "detach_forks":
|
||||
return RepoModel.ForkAction.DETACH
|
||||
|
||||
if fork_action == "delete_forks":
|
||||
return RepoModel.ForkAction.DELETE
|
||||
|
||||
return RepoModel.ForkAction.UNKNOWN
|
||||
|
||||
def _invalidate_remote_cache(self, delete: bool):
|
||||
log.debug(f"Invalidating remote cache, for repository: {self.db_repo_name}")
|
||||
scm_repo = self.db_repo.scm_instance(cache=False)
|
||||
|
|
|
|||
|
|
@ -2583,10 +2583,10 @@ msgstr ""
|
|||
msgid "Confirm to delete this repository"
|
||||
msgstr ""
|
||||
|
||||
#: rhodecode/templates/admin/repos/repo_edit.html:310
|
||||
#: rhodecode/templates/admin/repos/repo_edit.html:208
|
||||
#, python-format
|
||||
msgid "this repository has %s fork"
|
||||
msgid_plural "this repository has %s forks"
|
||||
msgid "Following fork will be %s"
|
||||
msgid_plural "Following forks will be %s"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
|
|
|
|||
|
|
@ -7567,7 +7567,7 @@ msgstr ""
|
|||
msgid "Delete this repository"
|
||||
msgstr ""
|
||||
|
||||
#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:237
|
||||
#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:242
|
||||
msgid "Warning: You are about to delete the repository. This action cannot be undone!"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ from rhodecode.model import meta
|
|||
from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup
|
||||
from rhodecode.model.meta import Session
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
REMOVED_REPO_PAT = re.compile(r"rm__\d{8}_\d{6}_\d{6}__.*")
|
||||
|
|
@ -665,7 +664,7 @@ def repo2db_mapper(initial_repo_list, force_hooks_rebuild=False):
|
|||
|
||||
|
||||
def repo2db_cleanup(skip_repos=None, skip_groups=None):
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.repo import RepoModel, ForksAction
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
|
||||
sa = meta.Session()
|
||||
|
|
@ -688,7 +687,7 @@ def repo2db_cleanup(skip_repos=None, skip_groups=None):
|
|||
if not instance:
|
||||
log.debug("Removing non-existing repository found in db `%s`", db_repo_name)
|
||||
try:
|
||||
RepoModel(sa).delete(db_repo, forks=RepoModel.ForkAction.DETACH, fs_remove=False, call_events=False)
|
||||
RepoModel(sa).delete(db_repo, forks_action=ForksAction.DETACH, fs_remove=False, call_events=False)
|
||||
sa.commit()
|
||||
removed.append(db_repo_name)
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import time
|
|||
import logging
|
||||
import traceback
|
||||
import datetime
|
||||
from dataclasses import dataclass, field
|
||||
from enum import StrEnum, auto
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy.orm import aliased
|
||||
from zope.cachedescriptors.property import Lazy as LazyProperty
|
||||
|
|
@ -75,18 +75,31 @@ from rhodecode.model.permission import PermissionModel
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ForksAction(StrEnum):
|
||||
DELETE = auto()
|
||||
DETACH = auto()
|
||||
UNKNOWN = auto()
|
||||
|
||||
@classmethod
|
||||
def _missing_(cls, value):
|
||||
return cls(cls.UNKNOWN)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ForkActionResult:
|
||||
fork_count: int = 0
|
||||
action: ForksAction = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class DeleteRepoResult:
|
||||
is_success: bool
|
||||
fork_action_result: ForkActionResult = field(default_factory=ForkActionResult)
|
||||
|
||||
|
||||
class RepoModel(BaseModel):
|
||||
cls = Repository
|
||||
|
||||
class ForkAction(StrEnum):
|
||||
DELETE = auto()
|
||||
DETACH = auto()
|
||||
UNKNOWN = auto()
|
||||
|
||||
@classmethod
|
||||
def _missing_(cls, value):
|
||||
return cls(cls.UNKNOWN)
|
||||
|
||||
def _get_user_group(self, users_group):
|
||||
return self._get_instance(UserGroup, users_group, callback=UserGroup.get_by_group_name)
|
||||
|
||||
|
|
@ -762,37 +775,43 @@ class RepoModel(BaseModel):
|
|||
def delete(
|
||||
self,
|
||||
repo: Repository,
|
||||
forks: ForkAction = None,
|
||||
forks_action: ForksAction = None, # used only in API to enforce action
|
||||
fs_remove: bool = True,
|
||||
cur_user: User = None,
|
||||
call_events: bool = True,
|
||||
) -> bool:
|
||||
) -> DeleteRepoResult:
|
||||
"""
|
||||
Delete given repository, forks parameter defines what do do with
|
||||
attached forks. Throws AttachedForksError if deleted repo has attached
|
||||
forks
|
||||
Delete a given repository.
|
||||
Throws AttachedForksError if a deleted repo has attached forks
|
||||
|
||||
:param repo:
|
||||
:param forks: ForkAction 'delete' or 'detach', NOTE: left for backward compatibility, do not use it
|
||||
:param forks_action:
|
||||
NOTE: used only in API to enforce action;
|
||||
If the repository is private, then forks will be removed.
|
||||
If the repository is public, then forks will be detached.
|
||||
|
||||
:param fs_remove: remove(archive) repo from filesystem
|
||||
"""
|
||||
if not cur_user:
|
||||
cur_user = getattr(get_current_rhodecode_user(), "username", None)
|
||||
repo = self._get_repo(repo)
|
||||
if not repo:
|
||||
return False
|
||||
return DeleteRepoResult(is_success=False)
|
||||
|
||||
if forks is None or forks is self.ForkAction.UNKNOWN:
|
||||
if not cur_user:
|
||||
cur_user = getattr(get_current_rhodecode_user(), "username", None)
|
||||
|
||||
if forks_action is None or forks_action is ForksAction.UNKNOWN:
|
||||
is_private = repo.private
|
||||
forks = self.ForkAction.DELETE if is_private else self.ForkAction.DETACH
|
||||
forks_action = ForksAction.DELETE if is_private else ForksAction.DETACH
|
||||
|
||||
if forks is self.ForkAction.DETACH:
|
||||
forks_cnt = repo.forks.count()
|
||||
|
||||
if forks_action is ForksAction.DETACH:
|
||||
for r in repo.forks:
|
||||
r.fork = None
|
||||
self.sa.add(r)
|
||||
elif forks is self.ForkAction.DELETE:
|
||||
elif forks_action is ForksAction.DELETE:
|
||||
for r in repo.forks:
|
||||
self.delete(r, forks=self.ForkAction.DELETE)
|
||||
self.delete(r, forks_action=forks_action)
|
||||
elif repo.forks.first() is not None:
|
||||
raise AttachedForksError()
|
||||
|
||||
|
|
@ -821,7 +840,9 @@ class RepoModel(BaseModel):
|
|||
log.error(traceback.format_exc())
|
||||
raise
|
||||
|
||||
return True
|
||||
return DeleteRepoResult(
|
||||
is_success=True, fork_action_result=ForkActionResult(action=forks_action, fork_count=forks_cnt)
|
||||
)
|
||||
|
||||
def _delete_repo_related_assets(self, repo):
|
||||
pr_sources = repo.pull_requests_source
|
||||
|
|
|
|||
|
|
@ -200,21 +200,19 @@
|
|||
<div class="panel-body">
|
||||
${h.secure_form(h.route_path('edit_repo_advanced_delete', repo_name=c.repo_name), request=request)}
|
||||
<table class="display">
|
||||
<% forks = c.rhodecode_db_repo.forks.count() %>
|
||||
<% forks = len(c.fork_links) %>
|
||||
<% delete_forks = c.rhodecode_db_repo.private %>
|
||||
% if forks:
|
||||
<tr>
|
||||
<td>
|
||||
${_ungettext('This repository has %s fork.', 'This repository has %s forks.', forks) % forks}
|
||||
<td class="alert-${'error' if delete_forks else 'warning'}" style="padding: 10px">
|
||||
${_ungettext('Following fork will be %s:', 'Following forks will be %s:', forks) % ('deleted' if delete_forks else 'detached')}
|
||||
</td>
|
||||
<td>
|
||||
%if forks:
|
||||
<input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
|
||||
%endif
|
||||
</td>
|
||||
<td>
|
||||
%if forks:
|
||||
<input type="radio" name="forks" value="delete_forks"/> <label for="forks">${_('Delete forks')}</label>
|
||||
%endif
|
||||
<ul>
|
||||
% for fork in c.fork_links:
|
||||
<li class="list-unstyled"><a href="${fork}" target="_blank" rel="noopener noreferrer">${fork.replace("/", "")} <span aria-hidden="true" style="font-size: 0.9em;">↗️</span></a></li>
|
||||
% endfor
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
|
|
@ -222,8 +220,10 @@
|
|||
<% attached_prs = len(c.rhodecode_db_repo.pull_requests_source + c.rhodecode_db_repo.pull_requests_target) %>
|
||||
% if attached_prs:
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
${_ungettext('This repository has %s attached pull request.', 'This repository has %s attached pull requests.', attached_prs) % attached_prs}
|
||||
<td colspan="2" style="padding: 10px">
|
||||
<a href="${c.pr_link}" target="_blank" rel="noopener noreferrer">
|
||||
${_ungettext('This repository has %s attached pull request (open/close).', 'This repository has %s attached pull requests (open/close).', attached_prs) % attached_prs} <span aria-hidden="true" style="font-size: 0.9em;">↗️</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
|
|
@ -231,23 +231,11 @@
|
|||
<% attached_artifacts = len(c.rhodecode_db_repo.artifacts) %>
|
||||
% if attached_artifacts:
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<td colspan="2">
|
||||
${_ungettext('This repository has %s attached artifact.', 'This repository has %s attached artifacts.', attached_artifacts) % attached_artifacts}
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
% if attached_artifacts or attached_prs or forks:
|
||||
<br/>
|
||||
<br/>
|
||||
% endif
|
||||
<span class="alert-warning" style="padding: 10px">
|
||||
<strong>${_('Warning: You are about to delete the repository. This action cannot be undone!')}</strong>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<div style="margin: 0 0 20px 0" class="fake-space"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ from rhodecode.lib.exceptions import AttachedForksError
|
|||
from rhodecode.lib.utils import make_db_config
|
||||
from rhodecode.model.db import Repository
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.repo import RepoModel, ForksAction
|
||||
from rhodecode.model.scm import ScmModel
|
||||
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ class TestRepoModel(object):
|
|||
fork_of_fork = backend.create_fork()
|
||||
Session().commit()
|
||||
|
||||
RepoModel().delete(repo=repo, forks=RepoModel.ForkAction.DELETE)
|
||||
RepoModel().delete(repo=repo, forks_action=ForksAction.DELETE)
|
||||
Session().commit()
|
||||
|
||||
assert Repository.get_by_repo_name(repo_name=repo.repo_name) is None
|
||||
|
|
@ -78,7 +78,7 @@ class TestRepoModel(object):
|
|||
fork_of_fork = backend.create_fork()
|
||||
Session().commit()
|
||||
|
||||
RepoModel().delete(repo=repo, forks=RepoModel.ForkAction.DETACH)
|
||||
RepoModel().delete(repo=repo, forks_action=ForksAction.DETACH)
|
||||
Session().commit()
|
||||
|
||||
assert Repository.get_by_repo_name(repo_name=repo.repo_name) is None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue