diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -116,19 +116,21 @@ def make_map(config): #settings actions m.connect('repo_stats', "/repos_stats/{repo_name:.*}", - action="repo_stats", conditions=dict(method=["DELETE"], - function=check_repo)) + action="repo_stats", conditions=dict(method=["DELETE"], + function=check_repo)) m.connect('repo_cache', "/repos_cache/{repo_name:.*}", - action="repo_cache", conditions=dict(method=["DELETE"], + action="repo_cache", conditions=dict(method=["DELETE"], + function=check_repo)) + m.connect('repo_public_journal',"/repos_public_journal/{repo_name:.*}", + action="repo_public_journal", conditions=dict(method=["PUT"], function=check_repo)) - m.connect('repo_public_journal', - "/repos_public_journal/{repo_name:.*}", - action="repo_public_journal", conditions=dict(method=["PUT"], - function=check_repo)) m.connect('repo_pull', "/repo_pull/{repo_name:.*}", - action="repo_pull", conditions=dict(method=["PUT"], - function=check_repo)) - + action="repo_pull", conditions=dict(method=["PUT"], + function=check_repo)) + m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}", + action="repo_as_fork", conditions=dict(method=["PUT"], + function=check_repo)) + with rmap.submapper(path_prefix=ADMIN_PREFIX, controller='admin/repos_groups') as m: m.connect("repos_groups", "/repos_groups", 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 @@ -111,6 +111,10 @@ class ReposController(BaseController): c.repo_last_rev) * 100) defaults = RepoModel()._get_defaults(repo_name) + + c.repos_list = [('', _('--REMOVE FORK--'))] + c.repos_list += [(x.repo_id, x.repo_name) for x in + Repository.query().order_by(Repository.repo_name).all()] return defaults @HasPermissionAllDecorator('hg.admin') @@ -380,6 +384,28 @@ class ReposController(BaseController): return redirect(url('edit_repo', repo_name=repo_name)) @HasPermissionAllDecorator('hg.admin') + def repo_as_fork(self, repo_name): + """ + Mark given repository as a fork of another + + :param repo_name: + """ + try: + fork_id = request.POST.get('id_fork_of') + repo = ScmModel().mark_as_fork(repo_name, fork_id, + self.rhodecode_user.username) + fork = repo.fork.repo_name if repo.fork else _('Nothing') + Session.commit() + h.flash(_('Marked repo %s as fork of %s' % (repo_name,fork)), + category='success') + except Exception, e: + raise + h.flash(_('An error occurred during this operation'), + category='error') + + return redirect(url('edit_repo', repo_name=repo_name)) + + @HasPermissionAllDecorator('hg.admin') def show(self, repo_name, format='html'): """GET /repos/repo_name: Show a specific item""" # url('repo', repo_name=ID) diff --git a/rhodecode/model/__init__.py b/rhodecode/model/__init__.py --- a/rhodecode/model/__init__.py +++ b/rhodecode/model/__init__.py @@ -89,5 +89,4 @@ class BaseModel(object): else: if instance: raise Exception('given object must be int or Instance' - ' of %s got %s' % (type(cls), - type(instance))) + ' of %s got %s' % (type(cls), type(instance))) diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py --- a/rhodecode/model/scm.py +++ b/rhodecode/model/scm.py @@ -117,6 +117,18 @@ class ScmModel(BaseModel): Generic Scm Model """ + def __get_repo(self, instance): + cls = Repository + if isinstance(instance, cls): + return instance + elif isinstance(instance, int) or str(instance).isdigit(): + return cls.get(instance) + elif isinstance(instance, basestring): + return cls.get_by_repo_name(instance) + elif instance: + raise Exception('given object must be int, basestr or Instance' + ' of %s got %s' % (type(cls), type(instance))) + @LazyProperty def repos_path(self): """ @@ -279,6 +291,13 @@ class ScmModel(BaseModel): return self.sa.query(Repository)\ .filter(Repository.fork_id == repo_id).count() + def mark_as_fork(self, repo, fork, user): + repo = self.__get_repo(repo) + fork = self.__get_repo(fork) + repo.fork = fork + self.sa.add(repo) + return repo + def pull_changes(self, repo_name, username): dbrepo = Repository.get_by_repo_name(repo_name) clone_uri = dbrepo.clone_uri diff --git a/rhodecode/templates/admin/repos/repo_edit.html b/rhodecode/templates/admin/repos/repo_edit.html --- a/rhodecode/templates/admin/repos/repo_edit.html +++ b/rhodecode/templates/admin/repos/repo_edit.html @@ -131,14 +131,13 @@ ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
- ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")} -
+ ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")} +
  • ${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}
  • ${_('Percentage of stats gathered')}: ${c.stats_percentage} %
-
${h.end_form()} @@ -148,7 +147,7 @@ ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
- ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="pull_icon action_button",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")} + ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
  • ${c.repo_info.clone_uri}
  • @@ -163,7 +162,7 @@ ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
    - ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="refresh_icon action_button",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")} + ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
    ${h.end_form()} @@ -171,14 +170,20 @@

    ${_('Public journal')}

    ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
    -
    ${h.hidden('auth_token',str(h.get_token()))} +
    %if c.in_public_journal: - ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="stop_following_icon action_button")} + ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")} %else: - ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="start_following_icon action_button")} + ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")} %endif -
    +
    +
    +
      +
    • ${_('''All actions made on this repository will be accessible to everyone in public journal''')} +
    • +
    +
    ${h.end_form()} @@ -186,8 +191,30 @@ ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
    - ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository')+"');")} + ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
    +
    +
      +
    • ${_('''This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems. + If you need fully delete it from filesystem please do it manually''')} +
    • +
    +
    +
    + ${h.end_form()} + +

    ${_('Set as fork')}

    + ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')} +
    +
    + ${h.select('id_fork_of','',c.repos_list,class_="medium")} + ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)} +
    +
    +
      +
    • ${_('''Manually set this repository as a fork of another''')}
    • +
    +
    ${h.end_form()}