##// END OF EJS Templates
fork: 'Update after clone' only makes sense if the update hook will maintain it
Mads Kiilerich -
r3571:6c88624c beta
parent child Browse files
Show More
@@ -1,185 +1,192 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.forks
3 rhodecode.controllers.forks
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 forks controller for rhodecode
6 forks controller for rhodecode
7
7
8 :created_on: Apr 23, 2011
8 :created_on: Apr 23, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
25 import logging
26 import formencode
26 import formencode
27 import traceback
27 import traceback
28 from formencode import htmlfill
28 from formencode import htmlfill
29
29
30 from pylons import tmpl_context as c, request, url
30 from pylons import tmpl_context as c, request, url
31 from pylons.controllers.util import redirect
31 from pylons.controllers.util import redirect
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33
33
34 import rhodecode.lib.helpers as h
34 import rhodecode.lib.helpers as h
35
35
36 from rhodecode.lib.helpers import Page
36 from rhodecode.lib.helpers import Page
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
38 NotAnonymous, HasRepoPermissionAny, HasPermissionAllDecorator,\
38 NotAnonymous, HasRepoPermissionAny, HasPermissionAllDecorator,\
39 HasPermissionAnyDecorator
39 HasPermissionAnyDecorator
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User
41 from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User,\
42 RhodeCodeUi
42 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.forms import RepoForkForm
44 from rhodecode.model.forms import RepoForkForm
44 from rhodecode.model.scm import ScmModel, GroupList
45 from rhodecode.model.scm import ScmModel, GroupList
45 from rhodecode.lib.utils2 import safe_int
46 from rhodecode.lib.utils2 import safe_int
46
47
47 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
48
49
49
50
50 class ForksController(BaseRepoController):
51 class ForksController(BaseRepoController):
51
52
52 @LoginRequired()
53 @LoginRequired()
53 def __before__(self):
54 def __before__(self):
54 super(ForksController, self).__before__()
55 super(ForksController, self).__before__()
55
56
56 def __load_defaults(self):
57 def __load_defaults(self):
57 acl_groups = GroupList(RepoGroup.query().all(),
58 acl_groups = GroupList(RepoGroup.query().all(),
58 perm_set=['group.write', 'group.admin'])
59 perm_set=['group.write', 'group.admin'])
59 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
60 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
60 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
61 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
61 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
62 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
62 c.landing_revs_choices = choices
63 c.landing_revs_choices = choices
63
64
64 def __load_data(self, repo_name=None):
65 def __load_data(self, repo_name=None):
65 """
66 """
66 Load defaults settings for edit, and update
67 Load defaults settings for edit, and update
67
68
68 :param repo_name:
69 :param repo_name:
69 """
70 """
70 self.__load_defaults()
71 self.__load_defaults()
71
72
72 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
73 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
73 repo = db_repo.scm_instance
74 repo = db_repo.scm_instance
74
75
75 if c.repo_info is None:
76 if c.repo_info is None:
76 h.not_mapped_error(repo_name)
77 h.not_mapped_error(repo_name)
77 return redirect(url('repos'))
78 return redirect(url('repos'))
78
79
79 c.default_user_id = User.get_by_username('default').user_id
80 c.default_user_id = User.get_by_username('default').user_id
80 c.in_public_journal = UserFollowing.query()\
81 c.in_public_journal = UserFollowing.query()\
81 .filter(UserFollowing.user_id == c.default_user_id)\
82 .filter(UserFollowing.user_id == c.default_user_id)\
82 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
83 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
83
84
84 if c.repo_info.stats:
85 if c.repo_info.stats:
85 last_rev = c.repo_info.stats.stat_on_revision+1
86 last_rev = c.repo_info.stats.stat_on_revision+1
86 else:
87 else:
87 last_rev = 0
88 last_rev = 0
88 c.stats_revision = last_rev
89 c.stats_revision = last_rev
89
90
90 c.repo_last_rev = repo.count() if repo.revisions else 0
91 c.repo_last_rev = repo.count() if repo.revisions else 0
91
92
92 if last_rev == 0 or c.repo_last_rev == 0:
93 if last_rev == 0 or c.repo_last_rev == 0:
93 c.stats_percentage = 0
94 c.stats_percentage = 0
94 else:
95 else:
95 c.stats_percentage = '%.2f' % ((float((last_rev)) /
96 c.stats_percentage = '%.2f' % ((float((last_rev)) /
96 c.repo_last_rev) * 100)
97 c.repo_last_rev) * 100)
97
98
99 c.can_update = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE).ui_active
100
98 defaults = RepoModel()._get_defaults(repo_name)
101 defaults = RepoModel()._get_defaults(repo_name)
99 # alter the description to indicate a fork
102 # alter the description to indicate a fork
100 defaults['description'] = ('fork of repository: %s \n%s'
103 defaults['description'] = ('fork of repository: %s \n%s'
101 % (defaults['repo_name'],
104 % (defaults['repo_name'],
102 defaults['description']))
105 defaults['description']))
103 # add suffix to fork
106 # add suffix to fork
104 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
107 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
105
108
106 return defaults
109 return defaults
107
110
108 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
111 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
109 'repository.admin')
112 'repository.admin')
110 def forks(self, repo_name):
113 def forks(self, repo_name):
111 p = safe_int(request.params.get('page', 1), 1)
114 p = safe_int(request.params.get('page', 1), 1)
112 repo_id = c.rhodecode_db_repo.repo_id
115 repo_id = c.rhodecode_db_repo.repo_id
113 d = []
116 d = []
114 for r in Repository.get_repo_forks(repo_id):
117 for r in Repository.get_repo_forks(repo_id):
115 if not HasRepoPermissionAny(
118 if not HasRepoPermissionAny(
116 'repository.read', 'repository.write', 'repository.admin'
119 'repository.read', 'repository.write', 'repository.admin'
117 )(r.repo_name, 'get forks check'):
120 )(r.repo_name, 'get forks check'):
118 continue
121 continue
119 d.append(r)
122 d.append(r)
120 c.forks_pager = Page(d, page=p, items_per_page=20)
123 c.forks_pager = Page(d, page=p, items_per_page=20)
121
124
122 c.forks_data = render('/forks/forks_data.html')
125 c.forks_data = render('/forks/forks_data.html')
123
126
124 if request.environ.get('HTTP_X_PARTIAL_XHR'):
127 if request.environ.get('HTTP_X_PARTIAL_XHR'):
125 return c.forks_data
128 return c.forks_data
126
129
127 return render('/forks/forks.html')
130 return render('/forks/forks.html')
128
131
129 @NotAnonymous()
132 @NotAnonymous()
130 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
133 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
131 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
134 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
132 'repository.admin')
135 'repository.admin')
133 def fork(self, repo_name):
136 def fork(self, repo_name):
134 c.repo_info = Repository.get_by_repo_name(repo_name)
137 c.repo_info = Repository.get_by_repo_name(repo_name)
135 if not c.repo_info:
138 if not c.repo_info:
136 h.not_mapped_error(repo_name)
139 h.not_mapped_error(repo_name)
137 return redirect(url('home'))
140 return redirect(url('home'))
138
141
139 defaults = self.__load_data(repo_name)
142 defaults = self.__load_data(repo_name)
140
143
141 return htmlfill.render(
144 return htmlfill.render(
142 render('forks/fork.html'),
145 render('forks/fork.html'),
143 defaults=defaults,
146 defaults=defaults,
144 encoding="UTF-8",
147 encoding="UTF-8",
145 force_defaults=False
148 force_defaults=False
146 )
149 )
147
150
148 @NotAnonymous()
151 @NotAnonymous()
149 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
152 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
150 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
153 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
151 'repository.admin')
154 'repository.admin')
152 def fork_create(self, repo_name):
155 def fork_create(self, repo_name):
153 self.__load_defaults()
156 self.__load_defaults()
154 c.repo_info = Repository.get_by_repo_name(repo_name)
157 c.repo_info = Repository.get_by_repo_name(repo_name)
155 _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
158 _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
156 repo_groups=c.repo_groups_choices,
159 repo_groups=c.repo_groups_choices,
157 landing_revs=c.landing_revs_choices)()
160 landing_revs=c.landing_revs_choices)()
158 form_result = {}
161 form_result = {}
159 try:
162 try:
160 form_result = _form.to_python(dict(request.POST))
163 form_result = _form.to_python(dict(request.POST))
161
164
165 # an approximation that is better than nothing
166 if not RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE).ui_active:
167 form_result['update_after_clone'] = False
168
162 # create fork is done sometimes async on celery, db transaction
169 # create fork is done sometimes async on celery, db transaction
163 # management is handled there.
170 # management is handled there.
164 RepoModel().create_fork(form_result, self.rhodecode_user.user_id)
171 RepoModel().create_fork(form_result, self.rhodecode_user.user_id)
165 fork_url = h.link_to(form_result['repo_name_full'],
172 fork_url = h.link_to(form_result['repo_name_full'],
166 h.url('summary_home', repo_name=form_result['repo_name_full']))
173 h.url('summary_home', repo_name=form_result['repo_name_full']))
167
174
168 h.flash(h.literal(_('Forked repository %s as %s') \
175 h.flash(h.literal(_('Forked repository %s as %s') \
169 % (repo_name, fork_url)),
176 % (repo_name, fork_url)),
170 category='success')
177 category='success')
171 except formencode.Invalid, errors:
178 except formencode.Invalid, errors:
172 c.new_repo = errors.value['repo_name']
179 c.new_repo = errors.value['repo_name']
173
180
174 return htmlfill.render(
181 return htmlfill.render(
175 render('forks/fork.html'),
182 render('forks/fork.html'),
176 defaults=errors.value,
183 defaults=errors.value,
177 errors=errors.error_dict or {},
184 errors=errors.error_dict or {},
178 prefix_error=False,
185 prefix_error=False,
179 encoding="UTF-8")
186 encoding="UTF-8")
180 except Exception:
187 except Exception:
181 log.error(traceback.format_exc())
188 log.error(traceback.format_exc())
182 h.flash(_('An error occurred during repository forking %s') %
189 h.flash(_('An error occurred during repository forking %s') %
183 repo_name, category='error')
190 repo_name, category='error')
184
191
185 return redirect(h.url('summary_home', repo_name=repo_name))
192 return redirect(h.url('summary_home', repo_name=repo_name))
@@ -1,100 +1,102 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('%s Fork') % c.repo_name} - ${c.rhodecode_name}
5 ${_('%s Fork') % c.repo_name} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_(u'Home'),h.url('/'))}
9 ${h.link_to(_(u'Home'),h.url('/'))}
10 &raquo;
10 &raquo;
11 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
11 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
12 &raquo;
12 &raquo;
13 ${_('fork')}
13 ${_('fork')}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('')}
17 ${self.menu('')}
18 </%def>
18 </%def>
19 <%def name="main()">
19 <%def name="main()">
20 <div class="box">
20 <div class="box">
21 <!-- box / title -->
21 <!-- box / title -->
22 <div class="title">
22 <div class="title">
23 ${self.breadcrumbs()}
23 ${self.breadcrumbs()}
24 </div>
24 </div>
25 ${h.form(url('repo_fork_create_home',repo_name=c.repo_info.repo_name))}
25 ${h.form(url('repo_fork_create_home',repo_name=c.repo_info.repo_name))}
26 <div class="form">
26 <div class="form">
27 <!-- fields -->
27 <!-- fields -->
28 <div class="fields">
28 <div class="fields">
29 <div class="field">
29 <div class="field">
30 <div class="label">
30 <div class="label">
31 <label for="repo_name">${_('Fork name')}:</label>
31 <label for="repo_name">${_('Fork name')}:</label>
32 </div>
32 </div>
33 <div class="input">
33 <div class="input">
34 ${h.text('repo_name',class_="small")}
34 ${h.text('repo_name',class_="small")}
35 ${h.hidden('repo_type',c.repo_info.repo_type)}
35 ${h.hidden('repo_type',c.repo_info.repo_type)}
36 ${h.hidden('fork_parent_id',c.repo_info.repo_id)}
36 ${h.hidden('fork_parent_id',c.repo_info.repo_id)}
37 </div>
37 </div>
38 </div>
38 </div>
39 <div class="field">
39 <div class="field">
40 <div class="label">
40 <div class="label">
41 <label for="landing_rev">${_('Landing revision')}:</label>
41 <label for="landing_rev">${_('Landing revision')}:</label>
42 </div>
42 </div>
43 <div class="input">
43 <div class="input">
44 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
44 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
45 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
45 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
46 </div>
46 </div>
47 </div>
47 </div>
48 <div class="field">
48 <div class="field">
49 <div class="label">
49 <div class="label">
50 <label for="repo_group">${_('Repository group')}:</label>
50 <label for="repo_group">${_('Repository group')}:</label>
51 </div>
51 </div>
52 <div class="input">
52 <div class="input">
53 ${h.select('repo_group','',c.repo_groups,class_="medium")}
53 ${h.select('repo_group','',c.repo_groups,class_="medium")}
54 <span class="help-block">${_('Optionaly select a group to put this repository into.')}</span>
54 <span class="help-block">${_('Optionaly select a group to put this repository into.')}</span>
55 </div>
55 </div>
56 </div>
56 </div>
57 <div class="field">
57 <div class="field">
58 <div class="label label-textarea">
58 <div class="label label-textarea">
59 <label for="description">${_('Description')}:</label>
59 <label for="description">${_('Description')}:</label>
60 </div>
60 </div>
61 <div class="textarea text-area editor">
61 <div class="textarea text-area editor">
62 ${h.textarea('description',cols=23,rows=5)}
62 ${h.textarea('description',cols=23,rows=5)}
63 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
63 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
64 </div>
64 </div>
65 </div>
65 </div>
66 <div class="field">
66 <div class="field">
67 <div class="label label-checkbox">
67 <div class="label label-checkbox">
68 <label for="private">${_('Private')}:</label>
68 <label for="private">${_('Private')}:</label>
69 </div>
69 </div>
70 <div class="checkboxes">
70 <div class="checkboxes">
71 ${h.checkbox('private',value="True")}
71 ${h.checkbox('private',value="True")}
72 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
72 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
73 </div>
73 </div>
74 </div>
74 </div>
75 <div class="field">
75 <div class="field">
76 <div class="label label-checkbox">
76 <div class="label label-checkbox">
77 <label for="private">${_('Copy permissions')}:</label>
77 <label for="private">${_('Copy permissions')}:</label>
78 </div>
78 </div>
79 <div class="checkboxes">
79 <div class="checkboxes">
80 ${h.checkbox('copy_permissions',value="True", checked="checked")}
80 ${h.checkbox('copy_permissions',value="True", checked="checked")}
81 <span class="help-block">${_('Copy permissions from forked repository')}</span>
81 <span class="help-block">${_('Copy permissions from forked repository')}</span>
82 </div>
82 </div>
83 </div>
83 </div>
84 %if c.can_update:
84 <div class="field">
85 <div class="field">
85 <div class="label label-checkbox">
86 <div class="label label-checkbox">
86 <label for="private">${_('Update after clone')}:</label>
87 <label for="private">${_('Update after clone')}:</label>
87 </div>
88 </div>
88 <div class="checkboxes">
89 <div class="checkboxes">
89 ${h.checkbox('update_after_clone',value="True")}
90 ${h.checkbox('update_after_clone',value="True")}
90 <span class="help-block">${_('Checkout source after making a clone')}</span>
91 <span class="help-block">${_('Checkout source after making a clone')}</span>
91 </div>
92 </div>
92 </div>
93 </div>
94 %endif
93 <div class="buttons">
95 <div class="buttons">
94 ${h.submit('',_('Fork this repository'),class_="ui-btn large")}
96 ${h.submit('',_('Fork this repository'),class_="ui-btn large")}
95 </div>
97 </div>
96 </div>
98 </div>
97 </div>
99 </div>
98 ${h.end_form()}
100 ${h.end_form()}
99 </div>
101 </div>
100 </%def>
102 </%def>
General Comments 0
You need to be logged in to leave comments. Login now