Show More
@@ -0,0 +1,368 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2011-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import logging | |
|
22 | import string | |
|
23 | ||
|
24 | from pyramid.view import view_config | |
|
25 | ||
|
26 | from beaker.cache import cache_region | |
|
27 | ||
|
28 | ||
|
29 | from rhodecode.controllers import utils | |
|
30 | ||
|
31 | from rhodecode.apps._base import RepoAppView | |
|
32 | from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP) | |
|
33 | from rhodecode.lib import caches, helpers as h | |
|
34 | from rhodecode.lib.helpers import RepoPage | |
|
35 | from rhodecode.lib.utils2 import safe_str, safe_int | |
|
36 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
|
37 | from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links | |
|
38 | from rhodecode.lib.ext_json import json | |
|
39 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |
|
40 | from rhodecode.lib.vcs.exceptions import CommitError, EmptyRepositoryError | |
|
41 | from rhodecode.model.db import Statistics, CacheKey, User | |
|
42 | from rhodecode.model.meta import Session | |
|
43 | from rhodecode.model.repo import ReadmeFinder | |
|
44 | from rhodecode.model.scm import ScmModel | |
|
45 | ||
|
46 | log = logging.getLogger(__name__) | |
|
47 | ||
|
48 | ||
|
49 | class RepoSummaryView(RepoAppView): | |
|
50 | ||
|
51 | def load_default_context(self): | |
|
52 | c = self._get_local_tmpl_context(include_app_defaults=True) | |
|
53 | ||
|
54 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead | |
|
55 | c.repo_info = self.db_repo | |
|
56 | c.rhodecode_repo = None | |
|
57 | if not c.repository_requirements_missing: | |
|
58 | c.rhodecode_repo = self.rhodecode_vcs_repo | |
|
59 | ||
|
60 | self._register_global_c(c) | |
|
61 | return c | |
|
62 | ||
|
63 | def _get_readme_data(self, db_repo, default_renderer): | |
|
64 | repo_name = db_repo.repo_name | |
|
65 | log.debug('Looking for README file') | |
|
66 | ||
|
67 | @cache_region('long_term') | |
|
68 | def _generate_readme(cache_key): | |
|
69 | readme_data = None | |
|
70 | readme_node = None | |
|
71 | readme_filename = None | |
|
72 | commit = self._get_landing_commit_or_none(db_repo) | |
|
73 | if commit: | |
|
74 | log.debug("Searching for a README file.") | |
|
75 | readme_node = ReadmeFinder(default_renderer).search(commit) | |
|
76 | if readme_node: | |
|
77 | relative_url = h.url('files_raw_home', | |
|
78 | repo_name=repo_name, | |
|
79 | revision=commit.raw_id, | |
|
80 | f_path=readme_node.path) | |
|
81 | readme_data = self._render_readme_or_none( | |
|
82 | commit, readme_node, relative_url) | |
|
83 | readme_filename = readme_node.path | |
|
84 | return readme_data, readme_filename | |
|
85 | ||
|
86 | invalidator_context = CacheKey.repo_context_cache( | |
|
87 | _generate_readme, repo_name, CacheKey.CACHE_TYPE_README) | |
|
88 | ||
|
89 | with invalidator_context as context: | |
|
90 | context.invalidate() | |
|
91 | computed = context.compute() | |
|
92 | ||
|
93 | return computed | |
|
94 | ||
|
95 | def _get_landing_commit_or_none(self, db_repo): | |
|
96 | log.debug("Getting the landing commit.") | |
|
97 | try: | |
|
98 | commit = db_repo.get_landing_commit() | |
|
99 | if not isinstance(commit, EmptyCommit): | |
|
100 | return commit | |
|
101 | else: | |
|
102 | log.debug("Repository is empty, no README to render.") | |
|
103 | except CommitError: | |
|
104 | log.exception( | |
|
105 | "Problem getting commit when trying to render the README.") | |
|
106 | ||
|
107 | def _render_readme_or_none(self, commit, readme_node, relative_url): | |
|
108 | log.debug( | |
|
109 | 'Found README file `%s` rendering...', readme_node.path) | |
|
110 | renderer = MarkupRenderer() | |
|
111 | try: | |
|
112 | html_source = renderer.render( | |
|
113 | readme_node.content, filename=readme_node.path) | |
|
114 | if relative_url: | |
|
115 | return relative_links(html_source, relative_url) | |
|
116 | return html_source | |
|
117 | except Exception: | |
|
118 | log.exception( | |
|
119 | "Exception while trying to render the README") | |
|
120 | ||
|
121 | def _load_commits_context(self, c): | |
|
122 | p = safe_int(self.request.GET.get('page'), 1) | |
|
123 | size = safe_int(self.request.GET.get('size'), 10) | |
|
124 | ||
|
125 | def url_generator(**kw): | |
|
126 | query_params = { | |
|
127 | 'size': size | |
|
128 | } | |
|
129 | query_params.update(kw) | |
|
130 | return h.route_path( | |
|
131 | 'repo_summary_commits', | |
|
132 | repo_name=c.rhodecode_db_repo.repo_name, _query=query_params) | |
|
133 | ||
|
134 | pre_load = ['author', 'branch', 'date', 'message'] | |
|
135 | try: | |
|
136 | collection = self.rhodecode_vcs_repo.get_commits(pre_load=pre_load) | |
|
137 | except EmptyRepositoryError: | |
|
138 | collection = self.rhodecode_vcs_repo | |
|
139 | ||
|
140 | c.repo_commits = RepoPage( | |
|
141 | collection, page=p, items_per_page=size, url=url_generator) | |
|
142 | page_ids = [x.raw_id for x in c.repo_commits] | |
|
143 | c.comments = self.db_repo.get_comments(page_ids) | |
|
144 | c.statuses = self.db_repo.statuses(page_ids) | |
|
145 | ||
|
146 | @LoginRequired() | |
|
147 | @HasRepoPermissionAnyDecorator( | |
|
148 | 'repository.read', 'repository.write', 'repository.admin') | |
|
149 | @view_config( | |
|
150 | route_name='repo_summary_commits', request_method='GET', | |
|
151 | renderer='rhodecode:templates/summary/summary_commits.mako') | |
|
152 | def summary_commits(self): | |
|
153 | c = self.load_default_context() | |
|
154 | self._load_commits_context(c) | |
|
155 | return self._get_template_context(c) | |
|
156 | ||
|
157 | @LoginRequired() | |
|
158 | @HasRepoPermissionAnyDecorator( | |
|
159 | 'repository.read', 'repository.write', 'repository.admin') | |
|
160 | @view_config( | |
|
161 | route_name='repo_summary', request_method='GET', | |
|
162 | renderer='rhodecode:templates/summary/summary.mako') | |
|
163 | @view_config( | |
|
164 | route_name='repo_summary_slash', request_method='GET', | |
|
165 | renderer='rhodecode:templates/summary/summary.mako') | |
|
166 | def summary(self): | |
|
167 | c = self.load_default_context() | |
|
168 | ||
|
169 | # Prepare the clone URL | |
|
170 | username = '' | |
|
171 | if self._rhodecode_user.username != User.DEFAULT_USER: | |
|
172 | username = safe_str(self._rhodecode_user.username) | |
|
173 | ||
|
174 | _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl | |
|
175 | if '{repo}' in _def_clone_uri: | |
|
176 | _def_clone_uri_by_id = _def_clone_uri.replace( | |
|
177 | '{repo}', '_{repoid}') | |
|
178 | elif '{repoid}' in _def_clone_uri: | |
|
179 | _def_clone_uri_by_id = _def_clone_uri.replace( | |
|
180 | '_{repoid}', '{repo}') | |
|
181 | ||
|
182 | c.clone_repo_url = self.db_repo.clone_url( | |
|
183 | user=username, uri_tmpl=_def_clone_uri) | |
|
184 | c.clone_repo_url_id = self.db_repo.clone_url( | |
|
185 | user=username, uri_tmpl=_def_clone_uri_by_id) | |
|
186 | ||
|
187 | # If enabled, get statistics data | |
|
188 | ||
|
189 | c.show_stats = bool(self.db_repo.enable_statistics) | |
|
190 | ||
|
191 | stats = Session().query(Statistics) \ | |
|
192 | .filter(Statistics.repository == self.db_repo) \ | |
|
193 | .scalar() | |
|
194 | ||
|
195 | c.stats_percentage = 0 | |
|
196 | ||
|
197 | if stats and stats.languages: | |
|
198 | c.no_data = False is self.db_repo.enable_statistics | |
|
199 | lang_stats_d = json.loads(stats.languages) | |
|
200 | ||
|
201 | # Sort first by decreasing count and second by the file extension, | |
|
202 | # so we have a consistent output. | |
|
203 | lang_stats_items = sorted(lang_stats_d.iteritems(), | |
|
204 | key=lambda k: (-k[1], k[0]))[:10] | |
|
205 | lang_stats = [(x, {"count": y, | |
|
206 | "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) | |
|
207 | for x, y in lang_stats_items] | |
|
208 | ||
|
209 | c.trending_languages = json.dumps(lang_stats) | |
|
210 | else: | |
|
211 | c.no_data = True | |
|
212 | c.trending_languages = json.dumps({}) | |
|
213 | ||
|
214 | scm_model = ScmModel() | |
|
215 | c.enable_downloads = self.db_repo.enable_downloads | |
|
216 | c.repository_followers = scm_model.get_followers(self.db_repo) | |
|
217 | c.repository_forks = scm_model.get_forks(self.db_repo) | |
|
218 | c.repository_is_user_following = scm_model.is_following_repo( | |
|
219 | self.db_repo_name, self._rhodecode_user.user_id) | |
|
220 | ||
|
221 | # first interaction with the VCS instance after here... | |
|
222 | if c.repository_requirements_missing: | |
|
223 | self.request.override_renderer = \ | |
|
224 | 'rhodecode:templates/summary/missing_requirements.mako' | |
|
225 | return self._get_template_context(c) | |
|
226 | ||
|
227 | c.readme_data, c.readme_file = \ | |
|
228 | self._get_readme_data(self.db_repo, c.visual.default_renderer) | |
|
229 | ||
|
230 | # loads the summary commits template context | |
|
231 | self._load_commits_context(c) | |
|
232 | ||
|
233 | return self._get_template_context(c) | |
|
234 | ||
|
235 | def get_request_commit_id(self): | |
|
236 | return self.request.matchdict['commit_id'] | |
|
237 | ||
|
238 | @LoginRequired() | |
|
239 | @HasRepoPermissionAnyDecorator( | |
|
240 | 'repository.read', 'repository.write', 'repository.admin') | |
|
241 | @view_config( | |
|
242 | route_name='repo_stats', request_method='GET', | |
|
243 | renderer='json_ext') | |
|
244 | def repo_stats(self): | |
|
245 | commit_id = self.get_request_commit_id() | |
|
246 | ||
|
247 | _namespace = caches.get_repo_namespace_key( | |
|
248 | caches.SUMMARY_STATS, self.db_repo_name) | |
|
249 | show_stats = bool(self.db_repo.enable_statistics) | |
|
250 | cache_manager = caches.get_cache_manager( | |
|
251 | 'repo_cache_long', _namespace) | |
|
252 | _cache_key = caches.compute_key_from_params( | |
|
253 | self.db_repo_name, commit_id, show_stats) | |
|
254 | ||
|
255 | def compute_stats(): | |
|
256 | code_stats = {} | |
|
257 | size = 0 | |
|
258 | try: | |
|
259 | scm_instance = self.db_repo.scm_instance() | |
|
260 | commit = scm_instance.get_commit(commit_id) | |
|
261 | ||
|
262 | for node in commit.get_filenodes_generator(): | |
|
263 | size += node.size | |
|
264 | if not show_stats: | |
|
265 | continue | |
|
266 | ext = string.lower(node.extension) | |
|
267 | ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext) | |
|
268 | if ext_info: | |
|
269 | if ext in code_stats: | |
|
270 | code_stats[ext]['count'] += 1 | |
|
271 | else: | |
|
272 | code_stats[ext] = {"count": 1, "desc": ext_info} | |
|
273 | except EmptyRepositoryError: | |
|
274 | pass | |
|
275 | return {'size': h.format_byte_size_binary(size), | |
|
276 | 'code_stats': code_stats} | |
|
277 | ||
|
278 | stats = cache_manager.get(_cache_key, createfunc=compute_stats) | |
|
279 | return stats | |
|
280 | ||
|
281 | @LoginRequired() | |
|
282 | @HasRepoPermissionAnyDecorator( | |
|
283 | 'repository.read', 'repository.write', 'repository.admin') | |
|
284 | @view_config( | |
|
285 | route_name='repo_refs_data', request_method='GET', | |
|
286 | renderer='json_ext') | |
|
287 | def repo_refs_data(self): | |
|
288 | _ = self.request.translate | |
|
289 | self.load_default_context() | |
|
290 | ||
|
291 | repo = self.rhodecode_vcs_repo | |
|
292 | refs_to_create = [ | |
|
293 | (_("Branch"), repo.branches, 'branch'), | |
|
294 | (_("Tag"), repo.tags, 'tag'), | |
|
295 | (_("Bookmark"), repo.bookmarks, 'book'), | |
|
296 | ] | |
|
297 | res = self._create_reference_data( | |
|
298 | repo, self.db_repo_name, refs_to_create) | |
|
299 | data = { | |
|
300 | 'more': False, | |
|
301 | 'results': res | |
|
302 | } | |
|
303 | return data | |
|
304 | ||
|
305 | @LoginRequired() | |
|
306 | @HasRepoPermissionAnyDecorator( | |
|
307 | 'repository.read', 'repository.write', 'repository.admin') | |
|
308 | @view_config( | |
|
309 | route_name='repo_refs_changelog_data', request_method='GET', | |
|
310 | renderer='json_ext') | |
|
311 | def repo_refs_changelog_data(self): | |
|
312 | _ = self.request.translate | |
|
313 | self.load_default_context() | |
|
314 | ||
|
315 | repo = self.rhodecode_vcs_repo | |
|
316 | ||
|
317 | refs_to_create = [ | |
|
318 | (_("Branches"), repo.branches, 'branch'), | |
|
319 | (_("Closed branches"), repo.branches_closed, 'branch_closed'), | |
|
320 | # TODO: enable when vcs can handle bookmarks filters | |
|
321 | # (_("Bookmarks"), repo.bookmarks, "book"), | |
|
322 | ] | |
|
323 | res = self._create_reference_data( | |
|
324 | repo, self.db_repo_name, refs_to_create) | |
|
325 | data = { | |
|
326 | 'more': False, | |
|
327 | 'results': res | |
|
328 | } | |
|
329 | return data | |
|
330 | ||
|
331 | def _create_reference_data(self, repo, full_repo_name, refs_to_create): | |
|
332 | format_ref_id = utils.get_format_ref_id(repo) | |
|
333 | ||
|
334 | result = [] | |
|
335 | for title, refs, ref_type in refs_to_create: | |
|
336 | if refs: | |
|
337 | result.append({ | |
|
338 | 'text': title, | |
|
339 | 'children': self._create_reference_items( | |
|
340 | repo, full_repo_name, refs, ref_type, | |
|
341 | format_ref_id), | |
|
342 | }) | |
|
343 | return result | |
|
344 | ||
|
345 | def _create_reference_items(self, repo, full_repo_name, refs, ref_type, | |
|
346 | format_ref_id): | |
|
347 | result = [] | |
|
348 | is_svn = h.is_svn(repo) | |
|
349 | for ref_name, raw_id in refs.iteritems(): | |
|
350 | files_url = self._create_files_url( | |
|
351 | repo, full_repo_name, ref_name, raw_id, is_svn) | |
|
352 | result.append({ | |
|
353 | 'text': ref_name, | |
|
354 | 'id': format_ref_id(ref_name, raw_id), | |
|
355 | 'raw_id': raw_id, | |
|
356 | 'type': ref_type, | |
|
357 | 'files_url': files_url, | |
|
358 | }) | |
|
359 | return result | |
|
360 | ||
|
361 | def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn): | |
|
362 | use_commit_id = '/' in ref_name or is_svn | |
|
363 | return h.url( | |
|
364 | 'files_home', | |
|
365 | repo_name=full_repo_name, | |
|
366 | f_path=ref_name if is_svn else '', | |
|
367 | revision=raw_id if use_commit_id else ref_name, | |
|
368 | at=ref_name) |
@@ -0,0 +1,136 b'' | |||
|
1 | ## -*- coding: utf-8 -*- | |
|
2 | <%namespace name="base" file="/base/base.mako"/> | |
|
3 | %if c.repo_commits: | |
|
4 | <table class="rctable repo_summary table_disp"> | |
|
5 | <tr> | |
|
6 | ||
|
7 | <th class="status" colspan="2"></th> | |
|
8 | <th>${_('Commit')}</th> | |
|
9 | <th>${_('Commit message')}</th> | |
|
10 | <th>${_('Age')}</th> | |
|
11 | <th>${_('Author')}</th> | |
|
12 | <th>${_('Refs')}</th> | |
|
13 | </tr> | |
|
14 | %for cnt,cs in enumerate(c.repo_commits): | |
|
15 | <tr class="parity${cnt%2}"> | |
|
16 | ||
|
17 | <td class="td-status"> | |
|
18 | %if c.statuses.get(cs.raw_id): | |
|
19 | <div class="changeset-status-ico shortlog"> | |
|
20 | %if c.statuses.get(cs.raw_id)[2]: | |
|
21 | <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (c.statuses.get(cs.raw_id)[0], c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"> | |
|
22 | <div class="${'flag_status %s' % c.statuses.get(cs.raw_id)[0]}"></div> | |
|
23 | </a> | |
|
24 | %else: | |
|
25 | <a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(cs.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}"> | |
|
26 | <div class="${'flag_status %s' % c.statuses.get(cs.raw_id)[0]}"></div> | |
|
27 | </a> | |
|
28 | %endif | |
|
29 | </div> | |
|
30 | %else: | |
|
31 | <div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div> | |
|
32 | %endif | |
|
33 | </td> | |
|
34 | <td class="td-comments"> | |
|
35 | %if c.comments.get(cs.raw_id,[]): | |
|
36 | <a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}"> | |
|
37 | <i class="icon-comment"></i> ${len(c.comments[cs.raw_id])} | |
|
38 | </a> | |
|
39 | %endif | |
|
40 | </td> | |
|
41 | <td class="td-commit"> | |
|
42 | <pre><a href="${h.url('changeset_home', repo_name=c.repo_name, revision=cs.raw_id)}">${h.show_id(cs)}</a></pre> | |
|
43 | </td> | |
|
44 | ||
|
45 | <td class="td-description mid"> | |
|
46 | <div class="log-container truncate-wrap"> | |
|
47 | <div class="message truncate" id="c-${cs.raw_id}">${h.urlify_commit_message(cs.message, c.repo_name)}</div> | |
|
48 | </div> | |
|
49 | </td> | |
|
50 | ||
|
51 | <td class="td-time"> | |
|
52 | ${h.age_component(cs.date)} | |
|
53 | </td> | |
|
54 | <td class="td-user author"> | |
|
55 | ${base.gravatar_with_user(cs.author)} | |
|
56 | </td> | |
|
57 | ||
|
58 | <td class="td-tags"> | |
|
59 | <div class="autoexpand"> | |
|
60 | %if h.is_hg(c.rhodecode_repo): | |
|
61 | %for book in cs.bookmarks: | |
|
62 | <span class="booktag tag" title="${_('Bookmark %s') % book}"> | |
|
63 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a> | |
|
64 | </span> | |
|
65 | %endfor | |
|
66 | %endif | |
|
67 | ## tags | |
|
68 | %for tag in cs.tags: | |
|
69 | <span class="tagtag tag" title="${_('Tag %s') % tag}"> | |
|
70 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}"><i class="icon-tag"></i>${h.shorter(tag)}</a> | |
|
71 | </span> | |
|
72 | %endfor | |
|
73 | ||
|
74 | ## branch | |
|
75 | %if cs.branch: | |
|
76 | <span class="branchtag tag" title="${_('Branch %s') % cs.branch}"> | |
|
77 | <a href="${h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch)}"><i class="icon-code-fork"></i>${h.shorter(cs.branch)}</a> | |
|
78 | </span> | |
|
79 | %endif | |
|
80 | </div> | |
|
81 | </td> | |
|
82 | </tr> | |
|
83 | %endfor | |
|
84 | ||
|
85 | </table> | |
|
86 | ||
|
87 | <script type="text/javascript"> | |
|
88 | $(document).pjax('#shortlog_data .pager_link','#shortlog_data', {timeout: 2000, scrollTo: false }); | |
|
89 | $(document).on('pjax:success', function(){ timeagoActivate(); }); | |
|
90 | </script> | |
|
91 | ||
|
92 | <div class="pagination-wh pagination-left"> | |
|
93 | ${c.repo_commits.pager('$link_previous ~2~ $link_next')} | |
|
94 | </div> | |
|
95 | %else: | |
|
96 | ||
|
97 | %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): | |
|
98 | <div class="quick_start"> | |
|
99 | <div class="fieldset"> | |
|
100 | <div class="left-label">${_('Add or upload files directly via RhodeCode:')}</div> | |
|
101 | <div class="right-content"> | |
|
102 | <div id="add_node_id" class="add_node"> | |
|
103 | <a href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='', anchor='edit')}" class="btn btn-default">${_('Add New File')}</a> | |
|
104 | </div> | |
|
105 | </div> | |
|
106 | %endif | |
|
107 | </div> | |
|
108 | ||
|
109 | %if not h.is_svn(c.rhodecode_repo): | |
|
110 | <div class="fieldset"> | |
|
111 | <div class="left-label">${_('Push new repo:')}</div> | |
|
112 | <div class="right-content"> | |
|
113 | <pre> | |
|
114 | ${c.rhodecode_repo.alias} clone ${c.clone_repo_url} | |
|
115 | ${c.rhodecode_repo.alias} add README # add first file | |
|
116 | ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message | |
|
117 | ${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back | |
|
118 | </pre> | |
|
119 | </div> | |
|
120 | </div> | |
|
121 | <div class="fieldset"> | |
|
122 | <div class="left-label">${_('Existing repository?')}</div> | |
|
123 | <div class="right-content"> | |
|
124 | <pre> | |
|
125 | %if h.is_git(c.rhodecode_repo): | |
|
126 | git remote add origin ${c.clone_repo_url} | |
|
127 | git push -u origin master | |
|
128 | %else: | |
|
129 | hg push ${c.clone_repo_url} | |
|
130 | %endif | |
|
131 | </pre> | |
|
132 | </div> | |
|
133 | </div> | |
|
134 | %endif | |
|
135 | </div> | |
|
136 | %endif |
@@ -105,9 +105,14 b' class BaseAppView(object):' | |||
|
105 | 105 | raise HTTPFound( |
|
106 | 106 | self.request.route_path('my_account_password')) |
|
107 | 107 | |
|
108 | def _get_local_tmpl_context(self): | |
|
108 | def _get_local_tmpl_context(self, include_app_defaults=False): | |
|
109 | 109 | c = TemplateArgs() |
|
110 | 110 | c.auth_user = self.request.user |
|
111 | if include_app_defaults: | |
|
112 | # NOTE(marcink): after full pyramid migration include_app_defaults | |
|
113 | # should be turned on by default | |
|
114 | from rhodecode.lib.base import attach_context_attributes | |
|
115 | attach_context_attributes(c, self.request, self.request.user.user_id) | |
|
111 | 116 | return c |
|
112 | 117 | |
|
113 | 118 | def _register_global_c(self, tmpl_args): |
@@ -154,8 +159,10 b' class RepoAppView(BaseAppView):' | |||
|
154 | 159 | 'Requirements are missing for repository %s: %s', |
|
155 | 160 | self.db_repo_name, error.message) |
|
156 | 161 | |
|
157 | def _get_local_tmpl_context(self): | |
|
158 |
c = super(RepoAppView, self)._get_local_tmpl_context( |
|
|
162 | def _get_local_tmpl_context(self, include_app_defaults=False): | |
|
163 | c = super(RepoAppView, self)._get_local_tmpl_context( | |
|
164 | include_app_defaults=include_app_defaults) | |
|
165 | ||
|
159 | 166 | # register common vars for this type of view |
|
160 | 167 | c.rhodecode_db_repo = self.db_repo |
|
161 | 168 | c.repo_name = self.db_repo_name |
@@ -309,7 +316,7 b' class RepoTypeRoutePredicate(object):' | |||
|
309 | 316 | # _('Action not supported for %s.' % rhodecode_repo.alias)), |
|
310 | 317 | # category='warning') |
|
311 | 318 | # return redirect( |
|
312 |
# |
|
|
319 | # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name)) | |
|
313 | 320 | |
|
314 | 321 | return False |
|
315 | 322 |
@@ -123,7 +123,7 b' class HomeView(BaseAppView):' | |||
|
123 | 123 | 'text': obj['name'], |
|
124 | 124 | 'type': 'repo', |
|
125 | 125 | 'obj': obj['dbrepo'], |
|
126 |
'url': h. |
|
|
126 | 'url': h.route_path('repo_summary', repo_name=obj['name']) | |
|
127 | 127 | } |
|
128 | 128 | for obj in repo_iter] |
|
129 | 129 |
@@ -17,18 +17,33 b'' | |||
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | from rhodecode.apps._base import add_route_with_slash | |
|
20 | 21 | |
|
21 | 22 | |
|
22 | 23 | def includeme(config): |
|
23 | 24 | |
|
24 | 25 | # Summary |
|
25 | config.add_route( | |
|
26 | name='repo_summary', | |
|
27 | pattern='/{repo_name:.*?[^/]}', repo_route=True) | |
|
28 | ||
|
26 | # NOTE(marcink): one additional route is defined in very bottom, catch | |
|
27 | # all pattern | |
|
29 | 28 | config.add_route( |
|
30 | 29 | name='repo_summary_explicit', |
|
31 | 30 | pattern='/{repo_name:.*?[^/]}/summary', repo_route=True) |
|
31 | config.add_route( | |
|
32 | name='repo_summary_commits', | |
|
33 | pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True) | |
|
34 | ||
|
35 | # refs data | |
|
36 | config.add_route( | |
|
37 | name='repo_refs_data', | |
|
38 | pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True) | |
|
39 | ||
|
40 | config.add_route( | |
|
41 | name='repo_refs_changelog_data', | |
|
42 | pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True) | |
|
43 | ||
|
44 | config.add_route( | |
|
45 | name='repo_stats', | |
|
46 | pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True) | |
|
32 | 47 | |
|
33 | 48 | # Tags |
|
34 | 49 | config.add_route( |
@@ -40,7 +55,6 b' def includeme(config):' | |||
|
40 | 55 | name='branches_home', |
|
41 | 56 | pattern='/{repo_name:.*?[^/]}/branches', repo_route=True) |
|
42 | 57 | |
|
43 | # Bookmarks | |
|
44 | 58 | config.add_route( |
|
45 | 59 | name='bookmarks_home', |
|
46 | 60 | pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True) |
@@ -125,9 +139,10 b' def includeme(config):' | |||
|
125 | 139 | pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True) |
|
126 | 140 | |
|
127 | 141 | # NOTE(marcink): needs to be at the end for catch-all |
|
128 | # config.add_route( | |
|
129 | # name='repo_summary', | |
|
130 | # pattern='/{repo_name:.*?[^/]}', repo_route=True) | |
|
142 | add_route_with_slash( | |
|
143 | config, | |
|
144 | name='repo_summary', | |
|
145 | pattern='/{repo_name:.*?[^/]}', repo_route=True) | |
|
131 | 146 | |
|
132 | 147 | # Scan module for configuration decorators. |
|
133 | 148 | config.scan() |
@@ -23,16 +23,16 b' import re' | |||
|
23 | 23 | import mock |
|
24 | 24 | import pytest |
|
25 | 25 | |
|
26 |
from rhodecode. |
|
|
26 | from rhodecode.apps.repository.views.repo_summary import RepoSummaryView | |
|
27 | 27 | from rhodecode.lib import helpers as h |
|
28 | 28 | from rhodecode.lib.compat import OrderedDict |
|
29 | from rhodecode.lib.utils2 import AttributeDict | |
|
29 | 30 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
30 | 31 | from rhodecode.model.db import Repository |
|
31 | 32 | from rhodecode.model.meta import Session |
|
32 | 33 | from rhodecode.model.repo import RepoModel |
|
33 | 34 | from rhodecode.model.scm import ScmModel |
|
34 |
from rhodecode.tests import |
|
|
35 | TestController, url, HG_REPO, assert_session_flash) | |
|
35 | from rhodecode.tests import assert_session_flash | |
|
36 | 36 | from rhodecode.tests.fixture import Fixture |
|
37 | 37 | from rhodecode.tests.utils import AssertResponse, repo_on_filesystem |
|
38 | 38 | |
@@ -40,14 +40,31 b' from rhodecode.tests.utils import Assert' | |||
|
40 | 40 | fixture = Fixture() |
|
41 | 41 | |
|
42 | 42 | |
|
43 | class TestSummaryController(TestController): | |
|
44 | def test_index(self, backend, http_host_only_stub): | |
|
45 | self.log_user() | |
|
43 | def route_path(name, params=None, **kwargs): | |
|
44 | import urllib | |
|
45 | ||
|
46 | base_url = { | |
|
47 | 'repo_summary': '/{repo_name}', | |
|
48 | 'repo_stats': '/{repo_name}/repo_stats/{commit_id}', | |
|
49 | 'repo_refs_data': '/{repo_name}/refs-data', | |
|
50 | 'repo_refs_changelog_data': '/{repo_name}/refs-data-changelog' | |
|
51 | ||
|
52 | }[name].format(**kwargs) | |
|
53 | ||
|
54 | if params: | |
|
55 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |
|
56 | return base_url | |
|
57 | ||
|
58 | ||
|
59 | @pytest.mark.usefixtures('app') | |
|
60 | class TestSummaryView(object): | |
|
61 | def test_index(self, autologin_user, backend, http_host_only_stub): | |
|
46 | 62 | repo_id = backend.repo.repo_id |
|
47 | 63 | repo_name = backend.repo_name |
|
48 | 64 | with mock.patch('rhodecode.lib.helpers.is_svn_without_proxy', |
|
49 | 65 | return_value=False): |
|
50 |
response = self.app.get( |
|
|
66 | response = self.app.get( | |
|
67 | route_path('repo_summary', repo_name=repo_name)) | |
|
51 | 68 | |
|
52 | 69 | # repo type |
|
53 | 70 | response.mustcontain( |
@@ -66,11 +83,11 b' class TestSummaryController(TestControll' | |||
|
66 | 83 | 'id="clone_url_id" readonly="readonly"' |
|
67 | 84 | ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, )) |
|
68 | 85 | |
|
69 |
def test_index_svn_without_proxy( |
|
|
70 | self.log_user() | |
|
86 | def test_index_svn_without_proxy( | |
|
87 | self, autologin_user, backend_svn, http_host_only_stub): | |
|
71 | 88 | repo_id = backend_svn.repo.repo_id |
|
72 | 89 | repo_name = backend_svn.repo_name |
|
73 |
response = self.app.get( |
|
|
90 | response = self.app.get(route_path('repo_summary', repo_name=repo_name)) | |
|
74 | 91 | # clone url... |
|
75 | 92 | response.mustcontain( |
|
76 | 93 | 'id="clone_url" disabled' |
@@ -79,14 +96,15 b' class TestSummaryController(TestControll' | |||
|
79 | 96 | 'id="clone_url_id" disabled' |
|
80 | 97 | ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, )) |
|
81 | 98 | |
|
82 |
def test_index_with_trailing_slash( |
|
|
83 | http_host_only_stub): | |
|
99 | def test_index_with_trailing_slash( | |
|
100 | self, autologin_user, backend, http_host_only_stub): | |
|
101 | ||
|
84 | 102 | repo_id = backend.repo.repo_id |
|
85 | 103 | repo_name = backend.repo_name |
|
86 | 104 | with mock.patch('rhodecode.lib.helpers.is_svn_without_proxy', |
|
87 | 105 | return_value=False): |
|
88 | 106 | response = self.app.get( |
|
89 |
|
|
|
107 | route_path('repo_summary', repo_name=repo_name) + '/', | |
|
90 | 108 | status=200) |
|
91 | 109 | |
|
92 | 110 | # clone url... |
@@ -97,11 +115,10 b' class TestSummaryController(TestControll' | |||
|
97 | 115 | 'id="clone_url_id" readonly="readonly"' |
|
98 | 116 | ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, )) |
|
99 | 117 | |
|
100 | def test_index_by_id(self, backend): | |
|
101 | self.log_user() | |
|
118 | def test_index_by_id(self, autologin_user, backend): | |
|
102 | 119 | repo_id = backend.repo.repo_id |
|
103 |
response = self.app.get( |
|
|
104 |
'summary |
|
|
120 | response = self.app.get( | |
|
121 | route_path('repo_summary', repo_name='_%s' % (repo_id,))) | |
|
105 | 122 | |
|
106 | 123 | # repo type |
|
107 | 124 | response.mustcontain( |
@@ -112,10 +129,9 b' class TestSummaryController(TestControll' | |||
|
112 | 129 | """<i class="icon-unlock-alt">""" |
|
113 | 130 | ) |
|
114 | 131 | |
|
115 | def test_index_by_repo_having_id_path_in_name_hg(self): | |
|
116 | self.log_user() | |
|
132 | def test_index_by_repo_having_id_path_in_name_hg(self, autologin_user): | |
|
117 | 133 | fixture.create_repo(name='repo_1') |
|
118 |
response = self.app.get( |
|
|
134 | response = self.app.get(route_path('repo_summary', repo_name='repo_1')) | |
|
119 | 135 | |
|
120 | 136 | try: |
|
121 | 137 | response.mustcontain("repo_1") |
@@ -123,11 +139,11 b' class TestSummaryController(TestControll' | |||
|
123 | 139 | RepoModel().delete(Repository.get_by_repo_name('repo_1')) |
|
124 | 140 | Session().commit() |
|
125 | 141 | |
|
126 |
def test_index_with_anonymous_access_disabled( |
|
|
127 | with fixture.anon_access(False): | |
|
128 | response = self.app.get(url('summary_home', repo_name=HG_REPO), | |
|
129 | status=302) | |
|
130 |
|
|
|
142 | def test_index_with_anonymous_access_disabled( | |
|
143 | self, backend, disable_anonymous_user): | |
|
144 | response = self.app.get( | |
|
145 | route_path('repo_summary', repo_name=backend.repo_name), status=302) | |
|
146 | assert 'login' in response.location | |
|
131 | 147 | |
|
132 | 148 | def _enable_stats(self, repo): |
|
133 | 149 | r = Repository.get_by_repo_name(repo) |
@@ -174,17 +190,15 b' class TestSummaryController(TestControll' | |||
|
174 | 190 | }, |
|
175 | 191 | } |
|
176 | 192 | |
|
177 | def test_repo_stats(self, backend, xhr_header): | |
|
178 | self.log_user() | |
|
193 | def test_repo_stats(self, autologin_user, backend, xhr_header): | |
|
179 | 194 | response = self.app.get( |
|
180 |
|
|
|
181 | repo_name=backend.repo_name, commit_id='tip'), | |
|
195 | route_path( | |
|
196 | 'repo_stats', repo_name=backend.repo_name, commit_id='tip'), | |
|
182 | 197 | extra_environ=xhr_header, |
|
183 | 198 | status=200) |
|
184 | 199 | assert re.match(r'6[\d\.]+ KiB', response.json['size']) |
|
185 | 200 | |
|
186 | def test_repo_stats_code_stats_enabled(self, backend, xhr_header): | |
|
187 | self.log_user() | |
|
201 | def test_repo_stats_code_stats_enabled(self, autologin_user, backend, xhr_header): | |
|
188 | 202 | repo_name = backend.repo_name |
|
189 | 203 | |
|
190 | 204 | # codes stats |
@@ -192,8 +206,8 b' class TestSummaryController(TestControll' | |||
|
192 | 206 | ScmModel().mark_for_invalidation(repo_name) |
|
193 | 207 | |
|
194 | 208 | response = self.app.get( |
|
195 |
|
|
|
196 | repo_name=backend.repo_name, commit_id='tip'), | |
|
209 | route_path( | |
|
210 | 'repo_stats', repo_name=backend.repo_name, commit_id='tip'), | |
|
197 | 211 | extra_environ=xhr_header, |
|
198 | 212 | status=200) |
|
199 | 213 | |
@@ -204,7 +218,7 b' class TestSummaryController(TestControll' | |||
|
204 | 218 | |
|
205 | 219 | def test_repo_refs_data(self, backend): |
|
206 | 220 | response = self.app.get( |
|
207 |
|
|
|
221 | route_path('repo_refs_data', repo_name=backend.repo_name), | |
|
208 | 222 | status=200) |
|
209 | 223 | |
|
210 | 224 | # Ensure that there is the correct amount of items in the result |
@@ -221,72 +235,68 b' class TestSummaryController(TestControll' | |||
|
221 | 235 | Repository, 'scm_instance', side_effect=RepositoryRequirementError) |
|
222 | 236 | |
|
223 | 237 | with scm_patcher: |
|
224 |
response = self.app.get( |
|
|
238 | response = self.app.get(route_path('repo_summary', repo_name=repo_name)) | |
|
225 | 239 | assert_response = AssertResponse(response) |
|
226 | 240 | assert_response.element_contains( |
|
227 | 241 | '.main .alert-warning strong', 'Missing requirements') |
|
228 | 242 | assert_response.element_contains( |
|
229 | 243 | '.main .alert-warning', |
|
230 |
' |
|
|
231 |
' |
|
|
244 | 'Commits cannot be displayed, because this repository ' | |
|
245 | 'uses one or more extensions, which was not enabled.') | |
|
232 | 246 | |
|
233 | 247 | def test_missing_requirements_page_does_not_contains_switch_to( |
|
234 | self, backend): | |
|
235 | self.log_user() | |
|
248 | self, autologin_user, backend): | |
|
236 | 249 | repo_name = backend.repo_name |
|
237 | 250 | scm_patcher = mock.patch.object( |
|
238 | 251 | Repository, 'scm_instance', side_effect=RepositoryRequirementError) |
|
239 | 252 | |
|
240 | 253 | with scm_patcher: |
|
241 |
response = self.app.get( |
|
|
254 | response = self.app.get(route_path('repo_summary', repo_name=repo_name)) | |
|
242 | 255 | response.mustcontain(no='Switch To') |
|
243 | 256 | |
|
244 | 257 | |
|
245 |
@pytest.mark.usefixtures(' |
|
|
246 | class TestSwitcherReferenceData: | |
|
258 | @pytest.mark.usefixtures('app') | |
|
259 | class TestRepoLocation(object): | |
|
247 | 260 | |
|
248 | def test_creates_reference_urls_based_on_name(self): | |
|
249 | references = { | |
|
250 | 'name': 'commit_id', | |
|
251 | } | |
|
252 | controller = summary.SummaryController() | |
|
253 | is_svn = False | |
|
254 | result = controller._switcher_reference_data( | |
|
255 | 'repo_name', references, is_svn) | |
|
256 | expected_url = h.url( | |
|
257 | 'files_home', repo_name='repo_name', revision='name', | |
|
258 | at='name') | |
|
259 | assert result[0]['files_url'] == expected_url | |
|
261 | @pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii']) | |
|
262 | def test_manual_delete(self, autologin_user, backend, suffix, csrf_token): | |
|
263 | repo = backend.create_repo(name_suffix=suffix) | |
|
264 | repo_name = repo.repo_name | |
|
265 | ||
|
266 | # delete from file system | |
|
267 | RepoModel()._delete_filesystem_repo(repo) | |
|
260 | 268 | |
|
261 | def test_urls_contain_commit_id_if_slash_in_name(self): | |
|
262 | references = { | |
|
263 | 'name/with/slash': 'commit_id', | |
|
264 | } | |
|
265 | controller = summary.SummaryController() | |
|
266 | is_svn = False | |
|
267 | result = controller._switcher_reference_data( | |
|
268 | 'repo_name', references, is_svn) | |
|
269 | expected_url = h.url( | |
|
270 | 'files_home', repo_name='repo_name', revision='commit_id', | |
|
271 | at='name/with/slash') | |
|
272 | assert result[0]['files_url'] == expected_url | |
|
269 | # test if the repo is still in the database | |
|
270 | new_repo = RepoModel().get_by_repo_name(repo_name) | |
|
271 | assert new_repo.repo_name == repo_name | |
|
273 | 272 | |
|
274 | def test_adds_reference_to_path_for_svn(self): | |
|
275 | references = { | |
|
276 | 'name/with/slash': 'commit_id', | |
|
277 | } | |
|
278 | controller = summary.SummaryController() | |
|
279 | is_svn = True | |
|
280 | result = controller._switcher_reference_data( | |
|
281 | 'repo_name', references, is_svn) | |
|
282 | expected_url = h.url( | |
|
283 | 'files_home', repo_name='repo_name', f_path='name/with/slash', | |
|
284 | revision='commit_id', at='name/with/slash') | |
|
285 | assert result[0]['files_url'] == expected_url | |
|
273 | # check if repo is not in the filesystem | |
|
274 | assert not repo_on_filesystem(repo_name) | |
|
275 | self.assert_repo_not_found_redirect(repo_name) | |
|
276 | ||
|
277 | def assert_repo_not_found_redirect(self, repo_name): | |
|
278 | # run the check page that triggers the other flash message | |
|
279 | response = self.app.get(h.url('repo_check_home', repo_name=repo_name)) | |
|
280 | assert_session_flash( | |
|
281 | response, 'The repository at %s cannot be located.' % repo_name) | |
|
286 | 282 | |
|
287 | 283 | |
|
288 |
@pytest. |
|
|
289 | class TestCreateReferenceData: | |
|
284 | @pytest.fixture() | |
|
285 | def summary_view(context_stub, request_stub, user_util): | |
|
286 | """ | |
|
287 | Bootstrap view to test the view functions | |
|
288 | """ | |
|
289 | request_stub.matched_route = AttributeDict(name='test_view') | |
|
290 | ||
|
291 | request_stub.user = user_util.create_user().AuthUser | |
|
292 | request_stub.db_repo = user_util.create_repo() | |
|
293 | ||
|
294 | view = RepoSummaryView(context=context_stub, request=request_stub) | |
|
295 | return view | |
|
296 | ||
|
297 | ||
|
298 | @pytest.mark.usefixtures('app') | |
|
299 | class TestCreateReferenceData(object): | |
|
290 | 300 | |
|
291 | 301 | @pytest.fixture |
|
292 | 302 | def example_refs(self): |
@@ -297,14 +307,13 b' class TestCreateReferenceData:' | |||
|
297 | 307 | ] |
|
298 | 308 | return example_refs |
|
299 | 309 | |
|
300 | def test_generates_refs_based_on_commit_ids(self, example_refs): | |
|
310 | def test_generates_refs_based_on_commit_ids(self, example_refs, summary_view): | |
|
301 | 311 | repo = mock.Mock() |
|
302 | 312 | repo.name = 'test-repo' |
|
303 | 313 | repo.alias = 'git' |
|
304 | 314 | full_repo_name = 'pytest-repo-group/' + repo.name |
|
305 | controller = summary.SummaryController() | |
|
306 | 315 | |
|
307 |
result = |
|
|
316 | result = summary_view._create_reference_data( | |
|
308 | 317 | repo, full_repo_name, example_refs) |
|
309 | 318 | |
|
310 | 319 | expected_files_url = '/{}/files/'.format(full_repo_name) |
@@ -333,13 +342,13 b' class TestCreateReferenceData:' | |||
|
333 | 342 | }] |
|
334 | 343 | assert result == expected_result |
|
335 | 344 | |
|
336 | def test_generates_refs_with_path_for_svn(self, example_refs): | |
|
345 | def test_generates_refs_with_path_for_svn(self, example_refs, summary_view): | |
|
337 | 346 | repo = mock.Mock() |
|
338 | 347 | repo.name = 'test-repo' |
|
339 | 348 | repo.alias = 'svn' |
|
340 | 349 | full_repo_name = 'pytest-repo-group/' + repo.name |
|
341 | controller = summary.SummaryController() | |
|
342 |
result = |
|
|
350 | ||
|
351 | result = summary_view._create_reference_data( | |
|
343 | 352 | repo, full_repo_name, example_refs) |
|
344 | 353 | |
|
345 | 354 | expected_files_url = '/{}/files/'.format(full_repo_name) |
@@ -373,35 +382,9 b' class TestCreateReferenceData:' | |||
|
373 | 382 | assert result == expected_result |
|
374 | 383 | |
|
375 | 384 | |
|
376 | @pytest.mark.usefixtures("app") | |
|
377 | class TestRepoLocation: | |
|
378 | ||
|
379 | @pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii']) | |
|
380 | def test_manual_delete(self, autologin_user, backend, suffix, csrf_token): | |
|
381 | repo = backend.create_repo(name_suffix=suffix) | |
|
382 | repo_name = repo.repo_name | |
|
383 | ||
|
384 | # delete from file system | |
|
385 | RepoModel()._delete_filesystem_repo(repo) | |
|
386 | ||
|
387 | # test if the repo is still in the database | |
|
388 | new_repo = RepoModel().get_by_repo_name(repo_name) | |
|
389 | assert new_repo.repo_name == repo_name | |
|
385 | class TestCreateFilesUrl(object): | |
|
390 | 386 | |
|
391 | # check if repo is not in the filesystem | |
|
392 | assert not repo_on_filesystem(repo_name) | |
|
393 | self.assert_repo_not_found_redirect(repo_name) | |
|
394 | ||
|
395 | def assert_repo_not_found_redirect(self, repo_name): | |
|
396 | # run the check page that triggers the other flash message | |
|
397 | response = self.app.get(url('repo_check_home', repo_name=repo_name)) | |
|
398 | assert_session_flash( | |
|
399 | response, 'The repository at %s cannot be located.' % repo_name) | |
|
400 | ||
|
401 | ||
|
402 | class TestCreateFilesUrl(object): | |
|
403 | def test_creates_non_svn_url(self): | |
|
404 | controller = summary.SummaryController() | |
|
387 | def test_creates_non_svn_url(self, summary_view): | |
|
405 | 388 | repo = mock.Mock() |
|
406 | 389 | repo.name = 'abcde' |
|
407 | 390 | full_repo_name = 'test-repo-group/' + repo.name |
@@ -409,16 +392,15 b' class TestCreateFilesUrl(object):' | |||
|
409 | 392 | raw_id = 'deadbeef0123456789' |
|
410 | 393 | is_svn = False |
|
411 | 394 | |
|
412 |
with mock.patch |
|
|
413 |
result = |
|
|
395 | with mock.patch('rhodecode.lib.helpers.url') as url_mock: | |
|
396 | result = summary_view._create_files_url( | |
|
414 | 397 | repo, full_repo_name, ref_name, raw_id, is_svn) |
|
415 | 398 | url_mock.assert_called_once_with( |
|
416 | 399 | 'files_home', repo_name=full_repo_name, f_path='', |
|
417 | 400 | revision=ref_name, at=ref_name) |
|
418 | 401 | assert result == url_mock.return_value |
|
419 | 402 | |
|
420 | def test_creates_svn_url(self): | |
|
421 | controller = summary.SummaryController() | |
|
403 | def test_creates_svn_url(self, summary_view): | |
|
422 | 404 | repo = mock.Mock() |
|
423 | 405 | repo.name = 'abcde' |
|
424 | 406 | full_repo_name = 'test-repo-group/' + repo.name |
@@ -426,16 +408,15 b' class TestCreateFilesUrl(object):' | |||
|
426 | 408 | raw_id = 'deadbeef0123456789' |
|
427 | 409 | is_svn = True |
|
428 | 410 | |
|
429 |
with mock.patch |
|
|
430 |
result = |
|
|
411 | with mock.patch('rhodecode.lib.helpers.url') as url_mock: | |
|
412 | result = summary_view._create_files_url( | |
|
431 | 413 | repo, full_repo_name, ref_name, raw_id, is_svn) |
|
432 | 414 | url_mock.assert_called_once_with( |
|
433 | 415 | 'files_home', repo_name=full_repo_name, f_path=ref_name, |
|
434 | 416 | revision=raw_id, at=ref_name) |
|
435 | 417 | assert result == url_mock.return_value |
|
436 | 418 | |
|
437 | def test_name_has_slashes(self): | |
|
438 | controller = summary.SummaryController() | |
|
419 | def test_name_has_slashes(self, summary_view): | |
|
439 | 420 | repo = mock.Mock() |
|
440 | 421 | repo.name = 'abcde' |
|
441 | 422 | full_repo_name = 'test-repo-group/' + repo.name |
@@ -443,8 +424,8 b' class TestCreateFilesUrl(object):' | |||
|
443 | 424 | raw_id = 'deadbeef0123456789' |
|
444 | 425 | is_svn = False |
|
445 | 426 | |
|
446 |
with mock.patch |
|
|
447 |
result = |
|
|
427 | with mock.patch('rhodecode.lib.helpers.url') as url_mock: | |
|
428 | result = summary_view._create_files_url( | |
|
448 | 429 | repo, full_repo_name, ref_name, raw_id, is_svn) |
|
449 | 430 | url_mock.assert_called_once_with( |
|
450 | 431 | 'files_home', repo_name=full_repo_name, f_path='', revision=raw_id, |
@@ -463,42 +444,39 b' class TestReferenceItems(object):' | |||
|
463 | 444 | def _format_function(name, id_): |
|
464 | 445 | return 'format_function_{}_{}'.format(name, id_) |
|
465 | 446 | |
|
466 | def test_creates_required_amount_of_items(self): | |
|
447 | def test_creates_required_amount_of_items(self, summary_view): | |
|
467 | 448 | amount = 100 |
|
468 | 449 | refs = { |
|
469 | 450 | 'ref{}'.format(i): '{0:040d}'.format(i) |
|
470 | 451 | for i in range(amount) |
|
471 | 452 | } |
|
472 | 453 | |
|
473 | controller = summary.SummaryController() | |
|
474 | ||
|
475 | url_patcher = mock.patch.object( | |
|
476 | controller, '_create_files_url') | |
|
477 | svn_patcher = mock.patch.object( | |
|
478 | summary.h, 'is_svn', return_value=False) | |
|
454 | url_patcher = mock.patch.object(summary_view, '_create_files_url') | |
|
455 | svn_patcher = mock.patch('rhodecode.lib.helpers.is_svn', | |
|
456 | return_value=False) | |
|
479 | 457 | |
|
480 | 458 | with url_patcher as url_mock, svn_patcher: |
|
481 |
result = |
|
|
459 | result = summary_view._create_reference_items( | |
|
482 | 460 | self.repo, self.repo_full_name, refs, self.ref_type, |
|
483 | 461 | self._format_function) |
|
484 | 462 | assert len(result) == amount |
|
485 | 463 | assert url_mock.call_count == amount |
|
486 | 464 | |
|
487 | def test_single_item_details(self): | |
|
465 | def test_single_item_details(self, summary_view): | |
|
488 | 466 | ref_name = 'ref1' |
|
489 | 467 | ref_id = 'deadbeef' |
|
490 | 468 | refs = { |
|
491 | 469 | ref_name: ref_id |
|
492 | 470 | } |
|
493 | 471 | |
|
494 | controller = summary.SummaryController() | |
|
472 | svn_patcher = mock.patch('rhodecode.lib.helpers.is_svn', | |
|
473 | return_value=False) | |
|
474 | ||
|
495 | 475 | url_patcher = mock.patch.object( |
|
496 |
|
|
|
497 | svn_patcher = mock.patch.object( | |
|
498 | summary.h, 'is_svn', return_value=False) | |
|
476 | summary_view, '_create_files_url', return_value=self.fake_url) | |
|
499 | 477 | |
|
500 | 478 | with url_patcher as url_mock, svn_patcher: |
|
501 |
result = |
|
|
479 | result = summary_view._create_reference_items( | |
|
502 | 480 | self.repo, self.repo_full_name, refs, self.ref_type, |
|
503 | 481 | self._format_function) |
|
504 | 482 |
@@ -39,11 +39,15 b' from routes.middleware import RoutesMidd' | |||
|
39 | 39 | import routes.util |
|
40 | 40 | |
|
41 | 41 | import rhodecode |
|
42 | ||
|
42 | 43 | from rhodecode.model import meta |
|
43 | 44 | from rhodecode.config import patches |
|
44 | 45 | from rhodecode.config.routing import STATIC_FILE_PREFIX |
|
45 | 46 | from rhodecode.config.environment import ( |
|
46 | 47 | load_environment, load_pyramid_environment) |
|
48 | ||
|
49 | from rhodecode.lib.vcs import VCSCommunicationError | |
|
50 | from rhodecode.lib.exceptions import VCSServerUnavailable | |
|
47 | 51 | from rhodecode.lib.middleware import csrf |
|
48 | 52 | from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled |
|
49 | 53 | from rhodecode.lib.middleware.error_handling import ( |
@@ -51,7 +55,7 b' from rhodecode.lib.middleware.error_hand' | |||
|
51 | 55 | from rhodecode.lib.middleware.https_fixup import HttpsFixup |
|
52 | 56 | from rhodecode.lib.middleware.vcs import VCSMiddleware |
|
53 | 57 | from rhodecode.lib.plugins.utils import register_rhodecode_plugin |
|
54 | from rhodecode.lib.utils2 import aslist as rhodecode_aslist | |
|
58 | from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict | |
|
55 | 59 | from rhodecode.subscribers import ( |
|
56 | 60 | scan_repositories_if_enabled, write_js_routes_if_enabled, |
|
57 | 61 | write_metadata_if_needed) |
@@ -221,7 +225,6 b' def add_pylons_compat_data(registry, glo' | |||
|
221 | 225 | |
|
222 | 226 | def error_handler(exception, request): |
|
223 | 227 | import rhodecode |
|
224 | from rhodecode.lib.utils2 import AttributeDict | |
|
225 | 228 | from rhodecode.lib import helpers |
|
226 | 229 | |
|
227 | 230 | rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode' |
@@ -230,6 +233,8 b' def error_handler(exception, request):' | |||
|
230 | 233 | # prefer original exception for the response since it may have headers set |
|
231 | 234 | if isinstance(exception, HTTPException): |
|
232 | 235 | base_response = exception |
|
236 | elif isinstance(exception, VCSCommunicationError): | |
|
237 | base_response = VCSServerUnavailable() | |
|
233 | 238 | |
|
234 | 239 | def is_http_error(response): |
|
235 | 240 | # error which should have traceback |
@@ -257,6 +262,7 b' def error_handler(exception, request):' | |||
|
257 | 262 | if hasattr(base_response, 'causes'): |
|
258 | 263 | c.causes = base_response.causes |
|
259 | 264 | c.messages = helpers.flash.pop_messages() |
|
265 | ||
|
260 | 266 | response = render_to_response( |
|
261 | 267 | '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request, |
|
262 | 268 | response=base_response) |
@@ -404,7 +410,6 b' def wrap_app_in_wsgi_middlewares(pyramid' | |||
|
404 | 410 | pool = meta.Base.metadata.bind.engine.pool |
|
405 | 411 | log.debug('sa pool status: %s', pool.status()) |
|
406 | 412 | |
|
407 | ||
|
408 | 413 | return pyramid_app_with_cleanup |
|
409 | 414 | |
|
410 | 415 |
@@ -117,8 +117,9 b' class JSRoutesMapper(Mapper):' | |||
|
117 | 117 | |
|
118 | 118 | def make_map(config): |
|
119 | 119 | """Create, configure and return the routes Mapper""" |
|
120 | rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'], | |
|
121 | always_scan=config['debug']) | |
|
120 | rmap = JSRoutesMapper( | |
|
121 | directory=config['pylons.paths']['controllers'], | |
|
122 | always_scan=config['debug']) | |
|
122 | 123 | rmap.minimization = False |
|
123 | 124 | rmap.explicit = False |
|
124 | 125 | |
@@ -609,18 +610,6 b' def make_map(config):' | |||
|
609 | 610 | controller='admin/repos', action='repo_check', |
|
610 | 611 | requirements=URL_NAME_REQUIREMENTS) |
|
611 | 612 | |
|
612 | rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}', | |
|
613 | controller='summary', action='repo_stats', | |
|
614 | conditions={'function': check_repo}, | |
|
615 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
|
616 | ||
|
617 | rmap.connect('repo_refs_data', '/{repo_name}/refs-data', | |
|
618 | controller='summary', action='repo_refs_data', | |
|
619 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
|
620 | rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog', | |
|
621 | controller='summary', action='repo_refs_changelog_data', | |
|
622 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
|
623 | ||
|
624 | 613 | rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}', |
|
625 | 614 | controller='changeset', revision='tip', |
|
626 | 615 | conditions={'function': check_repo}, |
@@ -834,19 +823,10 b' def make_map(config):' | |||
|
834 | 823 | conditions={'function': check_repo, 'method': ['DELETE']}, |
|
835 | 824 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
836 | 825 | |
|
837 | rmap.connect('summary_home_explicit', '/{repo_name}/summary', | |
|
838 | controller='summary', conditions={'function': check_repo}, | |
|
839 | requirements=URL_NAME_REQUIREMENTS) | |
|
840 | ||
|
841 | 826 | rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True, |
|
842 | 827 | controller='changelog', conditions={'function': check_repo}, |
|
843 | 828 | requirements=URL_NAME_REQUIREMENTS) |
|
844 | 829 | |
|
845 | rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary', | |
|
846 | controller='changelog', action='changelog_summary', | |
|
847 | conditions={'function': check_repo}, | |
|
848 | requirements=URL_NAME_REQUIREMENTS) | |
|
849 | ||
|
850 | 830 | rmap.connect('changelog_file_home', |
|
851 | 831 | '/{repo_name}/changelog/{revision}/{f_path}', |
|
852 | 832 | controller='changelog', f_path=None, |
@@ -999,19 +979,4 b' def make_map(config):' | |||
|
999 | 979 | conditions={'function': check_repo}, |
|
1000 | 980 | requirements=URL_NAME_REQUIREMENTS) |
|
1001 | 981 | |
|
1002 | # catch all, at the end | |
|
1003 | _connect_with_slash( | |
|
1004 | rmap, 'summary_home', '/{repo_name}', jsroute=True, | |
|
1005 | controller='summary', action='index', | |
|
1006 | conditions={'function': check_repo}, | |
|
1007 | requirements=URL_NAME_REQUIREMENTS) | |
|
1008 | ||
|
1009 | 982 | return rmap |
|
1010 | ||
|
1011 | ||
|
1012 | def _connect_with_slash(mapper, name, path, *args, **kwargs): | |
|
1013 | """ | |
|
1014 | Connect a route with an optional trailing slash in `path`. | |
|
1015 | """ | |
|
1016 | mapper.connect(name + '_slash', path + '/', *args, **kwargs) | |
|
1017 | mapper.connect(name, path, *args, **kwargs) |
@@ -274,9 +274,9 b' class ReposController(BaseRepoController' | |||
|
274 | 274 | h.flash(_('Created repository %s from %s') |
|
275 | 275 | % (repo.repo_name, clone_uri), category='success') |
|
276 | 276 | else: |
|
277 |
repo_url = h.link_to( |
|
|
278 | h.url('summary_home', | |
|
279 |
|
|
|
277 | repo_url = h.link_to( | |
|
278 | repo.repo_name, | |
|
279 | h.route_path('repo_summary',repo_name=repo.repo_name)) | |
|
280 | 280 | fork = repo.fork |
|
281 | 281 | if fork: |
|
282 | 282 | fork_name = fork.repo_name |
@@ -366,7 +366,7 b' class ReposController(BaseRepoController' | |||
|
366 | 366 | log.exception("Exception during unlocking") |
|
367 | 367 | h.flash(_('An error occurred during unlocking'), |
|
368 | 368 | category='error') |
|
369 |
return redirect( |
|
|
369 | return redirect(h.route_path('repo_summary', repo_name=repo_name)) | |
|
370 | 370 | |
|
371 | 371 | @HasRepoPermissionAllDecorator('repository.admin') |
|
372 | 372 | @auth.CSRFRequired() |
@@ -46,27 +46,6 b' log = logging.getLogger(__name__)' | |||
|
46 | 46 | DEFAULT_CHANGELOG_SIZE = 20 |
|
47 | 47 | |
|
48 | 48 | |
|
49 | def _load_changelog_summary(): | |
|
50 | p = safe_int(request.GET.get('page'), 1) | |
|
51 | size = safe_int(request.GET.get('size'), 10) | |
|
52 | ||
|
53 | def url_generator(**kw): | |
|
54 | return url('summary_home', | |
|
55 | repo_name=c.rhodecode_db_repo.repo_name, size=size, **kw) | |
|
56 | ||
|
57 | pre_load = ['author', 'branch', 'date', 'message'] | |
|
58 | try: | |
|
59 | collection = c.rhodecode_repo.get_commits(pre_load=pre_load) | |
|
60 | except EmptyRepositoryError: | |
|
61 | collection = c.rhodecode_repo | |
|
62 | ||
|
63 | c.repo_commits = RepoPage( | |
|
64 | collection, page=p, items_per_page=size, url=url_generator) | |
|
65 | page_ids = [x.raw_id for x in c.repo_commits] | |
|
66 | c.comments = c.rhodecode_db_repo.get_comments(page_ids) | |
|
67 | c.statuses = c.rhodecode_db_repo.statuses(page_ids) | |
|
68 | ||
|
69 | ||
|
70 | 49 | class ChangelogController(BaseRepoController): |
|
71 | 50 | |
|
72 | 51 | def __before__(self): |
@@ -211,7 +190,7 b' class ChangelogController(BaseRepoContro' | |||
|
211 | 190 | |
|
212 | 191 | except EmptyRepositoryError as e: |
|
213 | 192 | h.flash(safe_str(e), category='warning') |
|
214 |
return redirect( |
|
|
193 | return redirect(h.route_path('repo_summary', repo_name=repo_name)) | |
|
215 | 194 | except (RepositoryError, CommitDoesNotExistError, Exception) as e: |
|
216 | 195 | msg = safe_str(e) |
|
217 | 196 | log.exception(msg) |
@@ -279,12 +258,3 b' class ChangelogController(BaseRepoContro' | |||
|
279 | 258 | c.rhodecode_repo, c.pagination, |
|
280 | 259 | prev_data=prev_data, next_data=next_data) |
|
281 | 260 | return render('changelog/changelog_elements.mako') |
|
282 | ||
|
283 | @LoginRequired() | |
|
284 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
|
285 | 'repository.admin') | |
|
286 | def changelog_summary(self, repo_name): | |
|
287 | if request.environ.get('HTTP_X_PJAX'): | |
|
288 | _load_changelog_summary() | |
|
289 | return render('changelog/changelog_summary_data.mako') | |
|
290 | raise HTTPNotFound() |
@@ -63,14 +63,14 b' class CompareController(BaseRepoControll' | |||
|
63 | 63 | return repo.scm_instance().EMPTY_COMMIT |
|
64 | 64 | h.flash(h.literal(_('There are no commits yet')), |
|
65 | 65 | category='warning') |
|
66 |
redirect( |
|
|
66 | redirect(h.route_path('repo_summary', repo_name=repo.repo_name)) | |
|
67 | 67 | |
|
68 | 68 | except RepositoryError as e: |
|
69 | 69 | msg = safe_str(e) |
|
70 | 70 | log.exception(msg) |
|
71 | 71 | h.flash(msg, category='warning') |
|
72 | 72 | if not partial: |
|
73 |
redirect(h. |
|
|
73 | redirect(h.route_path('repo_summary', repo_name=repo.repo_name)) | |
|
74 | 74 | raise HTTPBadRequest() |
|
75 | 75 | |
|
76 | 76 | @LoginRequired() |
@@ -113,7 +113,7 b' class FeedController(BaseRepoController)' | |||
|
113 | 113 | def _generate_feed(cache_key): |
|
114 | 114 | feed = Atom1Feed( |
|
115 | 115 | title=self.title % repo_name, |
|
116 |
link=url('summary |
|
|
116 | link=h.route_url('repo_summary', repo_name=repo_name), | |
|
117 | 117 | description=self.description % repo_name, |
|
118 | 118 | language=self.language, |
|
119 | 119 | ttl=self.ttl |
@@ -150,8 +150,7 b' class FeedController(BaseRepoController)' | |||
|
150 | 150 | def _generate_feed(cache_key): |
|
151 | 151 | feed = Rss201rev2Feed( |
|
152 | 152 | title=self.title % repo_name, |
|
153 |
link=url('summary |
|
|
154 | qualified=True), | |
|
153 | link=h.route_url('repo_summary', repo_name=repo_name), | |
|
155 | 154 | description=self.description % repo_name, |
|
156 | 155 | language=self.language, |
|
157 | 156 | ttl=self.ttl |
@@ -101,7 +101,7 b' class FilesController(BaseRepoController' | |||
|
101 | 101 | add_new = "" |
|
102 | 102 | h.flash(h.literal( |
|
103 | 103 | _('There are no files yet. %s') % add_new), category='warning') |
|
104 |
redirect(h. |
|
|
104 | redirect(h.route_path('repo_summary', repo_name=repo_name)) | |
|
105 | 105 | except (CommitDoesNotExistError, LookupError): |
|
106 | 106 | msg = _('No such commit exists for this repository') |
|
107 | 107 | h.flash(msg, category='error') |
@@ -669,14 +669,14 b' class FilesController(BaseRepoController' | |||
|
669 | 669 | |
|
670 | 670 | # If there's no commit, redirect to repo summary |
|
671 | 671 | if type(c.commit) is EmptyCommit: |
|
672 |
redirect_url = |
|
|
672 | redirect_url = h.route_path('repo_summary', repo_name=c.repo_name) | |
|
673 | 673 | else: |
|
674 | redirect_url = "changeset_home" | |
|
674 | redirect_url = url("changeset_home", repo_name=c.repo_name, | |
|
675 | revision='tip') | |
|
675 | 676 | |
|
676 | 677 | if not filename: |
|
677 | 678 | h.flash(_('No filename'), category='warning') |
|
678 |
return redirect( |
|
|
679 | revision='tip')) | |
|
679 | return redirect(redirect_url) | |
|
680 | 680 | |
|
681 | 681 | # extract the location from filename, |
|
682 | 682 | # allows using foo/bar.txt syntax to create subdirectories |
@@ -85,7 +85,7 b' class PullrequestsController(BaseRepoCon' | |||
|
85 | 85 | except EmptyRepositoryError: |
|
86 | 86 | h.flash(h.literal(_('There are no commits yet')), |
|
87 | 87 | category='warning') |
|
88 |
redirect( |
|
|
88 | redirect(h.route_path('repo_summary', repo_name=source_repo.repo_name)) | |
|
89 | 89 | |
|
90 | 90 | commit_id = request.GET.get('commit') |
|
91 | 91 | branch_ref = request.GET.get('branch') |
@@ -161,8 +161,9 b' class ActionParser(object):' | |||
|
161 | 161 | return action_map |
|
162 | 162 | |
|
163 | 163 | def get_fork_name(self): |
|
164 | from rhodecode.lib import helpers as h | |
|
164 | 165 | repo_name = self.action_params |
|
165 |
_url = |
|
|
166 | _url = h.route_path('repo_summary', repo_name=repo_name) | |
|
166 | 167 | return _('fork name %s') % link_to(self.action_params, _url) |
|
167 | 168 | |
|
168 | 169 | def get_user_name(self): |
@@ -1342,7 +1342,7 b' class HasAcceptedRepoType(object):' | |||
|
1342 | 1342 | _('Action not supported for %s.' % rhodecode_repo.alias)), |
|
1343 | 1343 | category='warning') |
|
1344 | 1344 | return redirect( |
|
1345 |
|
|
|
1345 | h.route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name)) | |
|
1346 | 1346 | |
|
1347 | 1347 | |
|
1348 | 1348 | class PermsDecorator(object): |
@@ -580,7 +580,7 b' class BaseRepoController(BaseController)' | |||
|
580 | 580 | 'Requirements are missing for repository %s: %s', |
|
581 | 581 | c.repo_name, error.message) |
|
582 | 582 | |
|
583 |
summary_url = |
|
|
583 | summary_url = h.route_path('repo_summary', repo_name=c.repo_name) | |
|
584 | 584 | statistics_url = url('edit_repo_statistics', repo_name=c.repo_name) |
|
585 | 585 | settings_update_url = url('repo', repo_name=c.repo_name) |
|
586 | 586 | path = request.path |
@@ -1538,7 +1538,7 b' def breadcrumb_repo_link(repo):' | |||
|
1538 | 1538 | link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name)) |
|
1539 | 1539 | for group in repo.groups_with_parents |
|
1540 | 1540 | ] + [ |
|
1541 |
link_to(repo.just_name, |
|
|
1541 | link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name)) | |
|
1542 | 1542 | ] |
|
1543 | 1543 | |
|
1544 | 1544 | return literal(' » '.join(path)) |
@@ -268,8 +268,7 b' class CommentsModel(BaseModel):' | |||
|
268 | 268 | |
|
269 | 269 | target_repo_url = h.link_to( |
|
270 | 270 | repo.repo_name, |
|
271 |
h.url('summary |
|
|
272 | repo_name=repo.repo_name, qualified=True)) | |
|
271 | h.route_url('repo_summary', repo_name=repo.repo_name)) | |
|
273 | 272 | |
|
274 | 273 | # commit specifics |
|
275 | 274 | kwargs.update({ |
@@ -300,13 +299,11 b' class CommentsModel(BaseModel):' | |||
|
300 | 299 | qualified=True,) |
|
301 | 300 | |
|
302 | 301 | # set some variables for email notification |
|
303 | pr_target_repo_url = h.url( | |
|
304 |
'summary |
|
|
305 | qualified=True) | |
|
302 | pr_target_repo_url = h.route_url( | |
|
303 | 'repo_summary', repo_name=pr_target_repo.repo_name) | |
|
306 | 304 | |
|
307 | pr_source_repo_url = h.url( | |
|
308 |
'summary |
|
|
309 | qualified=True) | |
|
305 | pr_source_repo_url = h.route_url( | |
|
306 | 'repo_summary', repo_name=pr_source_repo.repo_name) | |
|
310 | 307 | |
|
311 | 308 | # pull request specifics |
|
312 | 309 | kwargs.update({ |
@@ -1765,6 +1765,7 b' class Repository(Base, BaseModel):' | |||
|
1765 | 1765 | # TODO: mikhail: Here there is an anti-pattern, we probably need to |
|
1766 | 1766 | # move this methods on models level. |
|
1767 | 1767 | from rhodecode.model.settings import SettingsModel |
|
1768 | from rhodecode.model.repo import RepoModel | |
|
1768 | 1769 | |
|
1769 | 1770 | repo = self |
|
1770 | 1771 | _user_id, _time, _reason = self.locked |
@@ -1774,7 +1775,7 b' class Repository(Base, BaseModel):' | |||
|
1774 | 1775 | 'repo_name': repo.repo_name, |
|
1775 | 1776 | 'repo_type': repo.repo_type, |
|
1776 | 1777 | 'clone_uri': repo.clone_uri or '', |
|
1777 |
'url': |
|
|
1778 | 'url': RepoModel().get_url(self), | |
|
1778 | 1779 | 'private': repo.private, |
|
1779 | 1780 | 'created_on': repo.created_on, |
|
1780 | 1781 | 'description': repo.description, |
@@ -1935,10 +1936,6 b' class Repository(Base, BaseModel):' | |||
|
1935 | 1936 | repo_name=self.repo_name, |
|
1936 | 1937 | repo_id=self.repo_id, **override) |
|
1937 | 1938 | |
|
1938 | def home_url(self): | |
|
1939 | request = get_current_request() | |
|
1940 | return request.route_url('repo_summary', repo_name=self.repo_name) | |
|
1941 | ||
|
1942 | 1939 | def set_state(self, state): |
|
1943 | 1940 | self.repo_state = state |
|
1944 | 1941 | Session().add(self) |
@@ -999,15 +999,11 b' class PullRequestModel(BaseModel):' | |||
|
999 | 999 | qualified=True,) |
|
1000 | 1000 | |
|
1001 | 1001 | # set some variables for email notification |
|
1002 | pr_target_repo_url = h.url( | |
|
1003 | 'summary_home', | |
|
1004 | repo_name=pr_target_repo.repo_name, | |
|
1005 | qualified=True) | |
|
1002 | pr_target_repo_url = h.route_url( | |
|
1003 | 'repo_summary', repo_name=pr_target_repo.repo_name) | |
|
1006 | 1004 | |
|
1007 | pr_source_repo_url = h.url( | |
|
1008 | 'summary_home', | |
|
1009 | repo_name=pr_source_repo.repo_name, | |
|
1010 | qualified=True) | |
|
1005 | pr_source_repo_url = h.route_url( | |
|
1006 | 'repo_summary', repo_name=pr_source_repo.repo_name) | |
|
1011 | 1007 | |
|
1012 | 1008 | # pull request specifics |
|
1013 | 1009 | pull_request_commits = [ |
@@ -30,6 +30,7 b' import time' | |||
|
30 | 30 | import traceback |
|
31 | 31 | from datetime import datetime, timedelta |
|
32 | 32 | |
|
33 | from pyramid.threadlocal import get_current_request | |
|
33 | 34 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
34 | 35 | |
|
35 | 36 | from rhodecode import events |
@@ -154,9 +155,10 b' class RepoModel(BaseModel):' | |||
|
154 | 155 | repos = Repository.query().filter(Repository.group == root).all() |
|
155 | 156 | return repos |
|
156 | 157 | |
|
157 | def get_url(self, repo): | |
|
158 | return h.url('summary_home', repo_name=safe_str(repo.repo_name), | |
|
159 | qualified=True) | |
|
158 | def get_url(self, repo, request=None): | |
|
159 | if not request: | |
|
160 | request = get_current_request() | |
|
161 | return request.route_url('repo_summary', repo_name=safe_str(repo.repo_name)) | |
|
160 | 162 | |
|
161 | 163 | @classmethod |
|
162 | 164 | def update_repoinfo(cls, repositories=None): |
@@ -215,6 +215,7 b'' | |||
|
215 | 215 | float: left; |
|
216 | 216 | display: block; |
|
217 | 217 | position: relative; |
|
218 | width: 100%; | |
|
218 | 219 | |
|
219 | 220 | // adds some space to make copy and paste easier |
|
220 | 221 | .left-label, |
@@ -62,7 +62,7 b' function setRCMouseBindings(repoName, re' | |||
|
62 | 62 | // nav in repo context |
|
63 | 63 | Mousetrap.bind(['g s'], function(e) { |
|
64 | 64 | window.location = pyroutes.url( |
|
65 |
'summary |
|
|
65 | 'repo_summary', {'repo_name': repoName}); | |
|
66 | 66 | }); |
|
67 | 67 | Mousetrap.bind(['g c'], function(e) { |
|
68 | 68 | window.location = pyroutes.url( |
@@ -18,9 +18,6 b' function registerRCRoutes() {' | |||
|
18 | 18 | pyroutes.register('gists', '/_admin/gists', []); |
|
19 | 19 | pyroutes.register('new_gist', '/_admin/gists/new', []); |
|
20 | 20 | pyroutes.register('toggle_following', '/_admin/toggle_following', []); |
|
21 | pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); | |
|
22 | pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); | |
|
23 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); | |
|
24 | 21 | pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']); |
|
25 | 22 | pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']); |
|
26 | 23 | pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']); |
@@ -46,8 +43,6 b' function registerRCRoutes() {' | |||
|
46 | 43 | pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); |
|
47 | 44 | pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); |
|
48 | 45 | pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
49 | pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']); | |
|
50 | pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']); | |
|
51 | 46 | pyroutes.register('favicon', '/favicon.ico', []); |
|
52 | 47 | pyroutes.register('robots', '/robots.txt', []); |
|
53 | 48 | pyroutes.register('auth_home', '/_admin/auth*traverse', []); |
@@ -99,8 +94,11 b' function registerRCRoutes() {' | |||
|
99 | 94 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); |
|
100 | 95 | pyroutes.register('repo_list_data', '/_repos', []); |
|
101 | 96 | pyroutes.register('goto_switcher_data', '/_goto_data', []); |
|
102 | pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']); | |
|
103 | 97 | pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']); |
|
98 | pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']); | |
|
99 | pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']); | |
|
100 | pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']); | |
|
101 | pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']); | |
|
104 | 102 | pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']); |
|
105 | 103 | pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']); |
|
106 | 104 | pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']); |
@@ -122,6 +120,8 b' function registerRCRoutes() {' | |||
|
122 | 120 | pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']); |
|
123 | 121 | pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']); |
|
124 | 122 | pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']); |
|
123 | pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']); | |
|
124 | pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']); | |
|
125 | 125 | pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']); |
|
126 | 126 | pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']); |
|
127 | 127 | pyroutes.register('search', '/_admin/search', []); |
@@ -45,7 +45,7 b'' | |||
|
45 | 45 | </td> |
|
46 | 46 | <td class="td-componentname"> |
|
47 | 47 | %if l.repository is not None: |
|
48 |
${h.link_to(l.repository.repo_name,h. |
|
|
48 | ${h.link_to(l.repository.repo_name, h.route_path('repo_summary',repo_name=l.repository.repo_name))} | |
|
49 | 49 | %else: |
|
50 | 50 | ${l.repository_name} |
|
51 | 51 | %endif |
@@ -160,7 +160,7 b'' | |||
|
160 | 160 | </td> |
|
161 | 161 | <td class="td-scope"> |
|
162 | 162 | %if integration.repo: |
|
163 |
<a href="${h. |
|
|
163 | <a href="${h.route_path('repo_summary', repo_name=integration.repo.repo_name)}"> | |
|
164 | 164 | ${_('repo')}:${integration.repo.repo_name} |
|
165 | 165 | </a> |
|
166 | 166 | %elif integration.repo_group: |
@@ -48,12 +48,12 b'' | |||
|
48 | 48 | if (jsonResponse === undefined) { |
|
49 | 49 | setTimeout(function () { |
|
50 | 50 | // we might have a backend problem, try dashboard again |
|
51 |
window.location = "${h. |
|
|
51 | window.location = "${h.route_path('repo_summary', repo_name = c.repo)}"; | |
|
52 | 52 | }, 3000); |
|
53 | 53 | } else { |
|
54 | 54 | if (skipCheck || jsonResponse.result === true) { |
|
55 | 55 | // success, means go to dashboard |
|
56 |
window.location = "${h. |
|
|
56 | window.location = "${h.route_path('repo_summary', repo_name = c.repo)}"; | |
|
57 | 57 | } else { |
|
58 | 58 | // Schedule the next request when the current one's complete |
|
59 | 59 | setTimeout(worker, 1000); |
@@ -27,7 +27,7 b'' | |||
|
27 | 27 | ${h.secure_form(h.route_path('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='POST')} |
|
28 | 28 | |
|
29 | 29 | % if c.repo_info.fork: |
|
30 |
<div class="panel-body-title-text">${h.literal(_('This repository is a fork of %(repo_link)s') % {'repo_link': h.link_to_if(c.has_origin_repo_read_perm,c.repo_info.fork.repo_name, h. |
|
|
30 | <div class="panel-body-title-text">${h.literal(_('This repository is a fork of %(repo_link)s') % {'repo_link': h.link_to_if(c.has_origin_repo_read_perm,c.repo_info.fork.repo_name, h.route_path('repo_summary', repo_name=c.repo_info.fork.repo_name))})} | |
|
31 | 31 | | <button class="btn btn-link btn-danger" type="submit">Remove fork reference</button></div> |
|
32 | 32 | % endif |
|
33 | 33 |
@@ -52,6 +52,6 b'' | |||
|
52 | 52 | <script> |
|
53 | 53 | $('#check_for_update').click(function(e){ |
|
54 | 54 | $('#update_notice').show(); |
|
55 |
$('#update_notice').load("${h.route_path('admin_settings_system_update' |
|
|
55 | $('#update_notice').load("${h.route_path('admin_settings_system_update')}"); | |
|
56 | 56 | }) |
|
57 | 57 | </script> |
@@ -186,7 +186,7 b'' | |||
|
186 | 186 | %if repo_instance.fork: |
|
187 | 187 | <p> |
|
188 | 188 | <i class="icon-code-fork"></i> ${_('Fork of')} |
|
189 |
<a href="${h. |
|
|
189 | <a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a> | |
|
190 | 190 | </p> |
|
191 | 191 | %endif |
|
192 | 192 | |
@@ -225,7 +225,7 b'' | |||
|
225 | 225 | <div id="context-bar"> |
|
226 | 226 | <div class="wrapper"> |
|
227 | 227 | <ul id="context-pages" class="horizontal-list navigation"> |
|
228 |
<li class="${is_active('summary')}"><a class="menulink" href="${h. |
|
|
228 | <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li> | |
|
229 | 229 | <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li> |
|
230 | 230 | <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li> |
|
231 | 231 | <li class="${is_active('compare')}"> |
@@ -124,7 +124,7 b'' | |||
|
124 | 124 | <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}"> |
|
125 | 125 | <td class="td-componentname"> |
|
126 | 126 | %if section == 'repositories': |
|
127 |
<a href="${h. |
|
|
127 | <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a> | |
|
128 | 128 | %elif section == 'repositories_groups': |
|
129 | 129 | <a href="${h.route_path('repo_group_home', repo_group_name=k)}">${k}</a> |
|
130 | 130 | %elif section == 'user_groups': |
@@ -9,7 +9,7 b'' | |||
|
9 | 9 | <div class="menu_items_container hidden"> |
|
10 | 10 | <ul class="menu_items"> |
|
11 | 11 | <li> |
|
12 |
<a title="${_('Summary')}" href="${h. |
|
|
12 | <a title="${_('Summary')}" href="${h.route_path('repo_summary',repo_name=repo_name)}"> | |
|
13 | 13 | <span>${_('Summary')}</span> |
|
14 | 14 | </a> |
|
15 | 15 | </li> |
@@ -42,7 +42,7 b'' | |||
|
42 | 42 | %> |
|
43 | 43 | <div class="${'repo_state_pending' if rstate == 'repo_state_pending' else ''} truncate"> |
|
44 | 44 | ##NAME |
|
45 |
<a href="${h.route_path('edit_repo',repo_name=name) if admin else h. |
|
|
45 | <a href="${h.route_path('edit_repo',repo_name=name) if admin else h.route_path('repo_summary',repo_name=name)}"> | |
|
46 | 46 | |
|
47 | 47 | ##TYPE OF REPO |
|
48 | 48 | %if h.is_hg(rtype): |
@@ -64,7 +64,7 b'' | |||
|
64 | 64 | ${get_name(name)} |
|
65 | 65 | </a> |
|
66 | 66 | %if fork_of: |
|
67 |
<a href="${h. |
|
|
67 | <a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a> | |
|
68 | 68 | %endif |
|
69 | 69 | %if rstate == 'repo_state_pending': |
|
70 | 70 | <i class="icon-cogs" title="${_('Repository creating in progress...')}"></i> |
@@ -282,7 +282,7 b'' | |||
|
282 | 282 | |
|
283 | 283 | <%def name="pullrequest_target_repo(repo_name)"> |
|
284 | 284 | <div class="truncate"> |
|
285 |
${h.link_to(repo_name,h. |
|
|
285 | ${h.link_to(repo_name,h.route_path('repo_summary',repo_name=repo_name))} | |
|
286 | 286 | </div> |
|
287 | 287 | </%def> |
|
288 | 288 | <%def name="pullrequest_status(status)"> |
@@ -16,7 +16,7 b'' | |||
|
16 | 16 | ${base.gravatar_with_user(f.user.email, 16)} |
|
17 | 17 | </td> |
|
18 | 18 | <td class="td-componentname"> |
|
19 |
${h.link_to(f.repo_name,h. |
|
|
19 | ${h.link_to(f.repo_name,h.route_path('repo_summary',repo_name=f.repo_name))} | |
|
20 | 20 | </td> |
|
21 | 21 | <td class="td-description"> |
|
22 | 22 | <div class="truncate">${f.description}</div> |
@@ -20,7 +20,7 b'' | |||
|
20 | 20 | <span class="journal_repo_name"> |
|
21 | 21 | %if entry.repository is not None: |
|
22 | 22 | ${h.link_to(entry.repository.repo_name, |
|
23 |
h. |
|
|
23 | h.route_path('repo_summary',repo_name=entry.repository.repo_name))} | |
|
24 | 24 | %else: |
|
25 | 25 | ${entry.repository_name} |
|
26 | 26 | %endif |
@@ -81,7 +81,7 b'' | |||
|
81 | 81 | %endif |
|
82 | 82 | </span> |
|
83 | 83 | <span class="clone-url"> |
|
84 |
<a href="${h. |
|
|
84 | <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a> | |
|
85 | 85 | </span> |
|
86 | 86 | <br/> |
|
87 | 87 | % if c.ancestor_commit: |
@@ -113,7 +113,7 b'' | |||
|
113 | 113 | %endif |
|
114 | 114 | </span> |
|
115 | 115 | <span class="clone-url"> |
|
116 |
<a href="${h. |
|
|
116 | <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a> | |
|
117 | 117 | </span> |
|
118 | 118 | </div> |
|
119 | 119 | </div> |
@@ -27,7 +27,7 b'' | |||
|
27 | 27 | %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn': |
|
28 | 28 | <i class="icon-svn"></i> |
|
29 | 29 | %endif |
|
30 |
${h.link_to(entry['repository'], h. |
|
|
30 | ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))} | |
|
31 | 31 | </td> |
|
32 | 32 | <td class="td-commit"> |
|
33 | 33 | ${h.link_to(h._shorten_commit_id(entry['commit_id']), |
@@ -49,7 +49,7 b' for line_number in matching_lines:' | |||
|
49 | 49 | %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn': |
|
50 | 50 | <i class="icon-svn"></i> |
|
51 | 51 | %endif |
|
52 |
${h.link_to(entry['repository'], h. |
|
|
52 | ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))} | |
|
53 | 53 | </h2> |
|
54 | 54 | <div class="stats"> |
|
55 | 55 | ${h.link_to(h.literal(entry['f_path']), h.url('files_home',repo_name=entry['repository'],revision=entry.get('commit_id', 'tip'),f_path=entry['f_path']))} |
@@ -16,7 +16,7 b'' | |||
|
16 | 16 | %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn': |
|
17 | 17 | <i class="icon-svn"></i> |
|
18 | 18 | %endif |
|
19 |
${h.link_to(entry['repository'], h. |
|
|
19 | ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))} | |
|
20 | 20 | </td> |
|
21 | 21 | <td class="td-componentname"> |
|
22 | 22 | ${h.link_to(h.literal(entry['f_path']), |
@@ -1,28 +1,28 b'' | |||
|
1 | 1 | <%def name="refs_counters(branches, closed_branches, tags, bookmarks)"> |
|
2 | 2 | <span class="branchtag tag"> |
|
3 | 3 | <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs"> |
|
4 | <i class="icon-branch"></i>${ungettext( | |
|
4 | <i class="icon-branch"></i>${_ungettext( | |
|
5 | 5 | '%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}}</a> |
|
6 | 6 | </span> |
|
7 | 7 | |
|
8 | 8 | %if closed_branches: |
|
9 | 9 | <span class="branchtag tag"> |
|
10 | 10 | <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs"> |
|
11 | <i class="icon-branch"></i>${ungettext( | |
|
11 | <i class="icon-branch"></i>${_ungettext( | |
|
12 | 12 | '%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}}</a> |
|
13 | 13 | </span> |
|
14 | 14 | %endif |
|
15 | 15 | |
|
16 | 16 | <span class="tagtag tag"> |
|
17 | 17 | <a href="${h.route_path('tags_home',repo_name=c.repo_name)}" class="childs"> |
|
18 | <i class="icon-tag"></i>${ungettext( | |
|
18 | <i class="icon-tag"></i>${_ungettext( | |
|
19 | 19 | '%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}}</a> |
|
20 | 20 | </span> |
|
21 | 21 | |
|
22 | 22 | %if bookmarks: |
|
23 | 23 | <span class="booktag tag"> |
|
24 | 24 | <a href="${h.route_path('bookmarks_home',repo_name=c.repo_name)}" class="childs"> |
|
25 | <i class="icon-bookmark"></i>${ungettext( | |
|
25 | <i class="icon-bookmark"></i>${_ungettext( | |
|
26 | 26 | '%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}}</a> |
|
27 | 27 | </span> |
|
28 | 28 | %endif |
@@ -92,15 +92,15 b'' | |||
|
92 | 92 | |
|
93 | 93 | ## commits |
|
94 | 94 | % if commit_rev == -1: |
|
95 | ${ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}}, | |
|
95 | ${_ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}}, | |
|
96 | 96 | % else: |
|
97 | 97 | <a href="${h.url('changelog_home', repo_name=c.repo_name)}"> |
|
98 | ${ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>, | |
|
98 | ${_ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>, | |
|
99 | 99 | % endif |
|
100 | 100 | |
|
101 | 101 | ## forks |
|
102 | 102 | <a title="${_('Number of Repository Forks')}" href="${h.url('repo_forks_home', repo_name=c.repo_name)}"> |
|
103 | ${c.repository_forks} ${ungettext('Fork', 'Forks', c.repository_forks)}</a>, | |
|
103 | ${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)}</a>, | |
|
104 | 104 | |
|
105 | 105 | ## repo size |
|
106 | 106 | % if commit_rev == -1: |
@@ -14,8 +14,14 b'' | |||
|
14 | 14 | |
|
15 | 15 | <div class="alert alert-dismissable alert-warning"> |
|
16 | 16 | <strong>Missing requirements</strong> |
|
17 |
|
|
|
18 |
Please <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">enable |
|
|
17 | Commits cannot be displayed, because this repository uses one or more extensions, which was not enabled. <br/> | |
|
18 | Please <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">enable extension in settings</a>, or contact the repository owner for help. | |
|
19 | Missing extensions could be: | |
|
20 | <pre> | |
|
21 | ||
|
22 | - Mercurial largefiles | |
|
23 | - Git LFS | |
|
24 | </pre> | |
|
19 | 25 | </div> |
|
20 | 26 | |
|
21 | 27 | </%def> |
@@ -36,7 +36,7 b'' | |||
|
36 | 36 | %endif |
|
37 | 37 | <div class="table"> |
|
38 | 38 | <div id="shortlog_data"> |
|
39 |
<%include file=' |
|
|
39 | <%include file='summary_commits.mako'/> | |
|
40 | 40 | </div> |
|
41 | 41 | </div> |
|
42 | 42 | </div> |
@@ -110,8 +110,7 b'' | |||
|
110 | 110 | |
|
111 | 111 | var callback = function (data) { |
|
112 | 112 | % if c.show_stats: |
|
113 | showRepoStats( | |
|
114 | 'lang_stats', data); | |
|
113 | showRepoStats('lang_stats', data); | |
|
115 | 114 | % endif |
|
116 | 115 | }; |
|
117 | 116 |
@@ -56,7 +56,7 b' def scm_extras(user_regular, repo_stub):' | |||
|
56 | 56 | RepoPreCreateEvent, RepoCreateEvent, |
|
57 | 57 | RepoPreDeleteEvent, RepoDeleteEvent, |
|
58 | 58 | ]) |
|
59 | def test_repo_events_serialized(repo_stub, EventClass): | |
|
59 | def test_repo_events_serialized(config_stub, repo_stub, EventClass): | |
|
60 | 60 | event = EventClass(repo_stub) |
|
61 | 61 | data = event.as_dict() |
|
62 | 62 | assert data['name'] == EventClass.name |
@@ -67,7 +67,7 b' def test_repo_events_serialized(repo_stu' | |||
|
67 | 67 | @pytest.mark.parametrize('EventClass', [ |
|
68 | 68 | RepoPrePullEvent, RepoPullEvent, RepoPrePushEvent |
|
69 | 69 | ]) |
|
70 | def test_vcs_repo_events_serialize(repo_stub, scm_extras, EventClass): | |
|
70 | def test_vcs_repo_events_serialize(config_stub, repo_stub, scm_extras, EventClass): | |
|
71 | 71 | event = EventClass(repo_name=repo_stub.repo_name, extras=scm_extras) |
|
72 | 72 | data = event.as_dict() |
|
73 | 73 | assert data['name'] == EventClass.name |
@@ -76,7 +76,7 b' def test_vcs_repo_events_serialize(repo_' | |||
|
76 | 76 | |
|
77 | 77 | |
|
78 | 78 | @pytest.mark.parametrize('EventClass', [RepoPushEvent]) |
|
79 | def test_vcs_repo_push_event_serialize(repo_stub, scm_extras, EventClass): | |
|
79 | def test_vcs_repo_push_event_serialize(config_stub, repo_stub, scm_extras, EventClass): | |
|
80 | 80 | event = EventClass(repo_name=repo_stub.repo_name, |
|
81 | 81 | pushed_commit_ids=scm_extras['commit_ids'], |
|
82 | 82 | extras=scm_extras) |
@@ -24,10 +24,10 b' import mock' | |||
|
24 | 24 | import pytest |
|
25 | 25 | |
|
26 | 26 | from rhodecode.lib import auth |
|
27 |
from rhodecode.lib.utils2 import safe_str, str2bool |
|
|
28 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError | |
|
29 | from rhodecode.model.db import Repository, RepoGroup, UserRepoToPerm, User,\ | |
|
30 | Permission | |
|
27 | from rhodecode.lib.utils2 import safe_str, str2bool | |
|
28 | from rhodecode.lib import helpers as h | |
|
29 | from rhodecode.model.db import ( | |
|
30 | Repository, RepoGroup, UserRepoToPerm, User, Permission) | |
|
31 | 31 | from rhodecode.model.meta import Session |
|
32 | 32 | from rhodecode.model.repo import RepoModel |
|
33 | 33 | from rhodecode.model.repo_group import RepoGroupModel |
@@ -475,7 +475,7 b' class TestAdminRepos(object):' | |||
|
475 | 475 | assert new_repo.description == description |
|
476 | 476 | |
|
477 | 477 | # test if the repository is visible in the list ? |
|
478 |
response = self.app.get( |
|
|
478 | response = self.app.get(h.route_path('repo_summary', repo_name=repo_name)) | |
|
479 | 479 | response.mustcontain(repo_name) |
|
480 | 480 | response.mustcontain(backend.alias) |
|
481 | 481 |
@@ -796,11 +796,12 b' class TestChangingFiles:' | |||
|
796 | 796 | |
|
797 | 797 | # Not allowed, redirect to the summary |
|
798 | 798 | redirected = response.follow() |
|
799 |
summary_url = |
|
|
799 | summary_url = h.route_path('repo_summary', repo_name=repo.repo_name) | |
|
800 | 800 | |
|
801 | 801 | # As there are no commits, displays the summary page with the error of |
|
802 | 802 | # creating a file with no filename |
|
803 | assert redirected.req.path == summary_url | |
|
803 | ||
|
804 | assert redirected.request.path == summary_url | |
|
804 | 805 | |
|
805 | 806 | @pytest.mark.parametrize("location, filename", [ |
|
806 | 807 | ('/abs', 'foo'), |
@@ -22,6 +22,7 b' import pytest' | |||
|
22 | 22 | |
|
23 | 23 | from rhodecode.tests import * |
|
24 | 24 | from rhodecode.tests.fixture import Fixture |
|
25 | from rhodecode.lib import helpers as h | |
|
25 | 26 | |
|
26 | 27 | from rhodecode.model.db import Repository |
|
27 | 28 | from rhodecode.model.repo import RepoModel |
@@ -147,7 +148,7 b' class _BaseTest(TestController):' | |||
|
147 | 148 | assert fork_repo.fork.repo_name == repo_name |
|
148 | 149 | |
|
149 | 150 | # test if the repository is visible in the list ? |
|
150 |
response = self.app.get( |
|
|
151 | response = self.app.get(h.route_path('repo_summary', repo_name=fork_name_full)) | |
|
151 | 152 | response.mustcontain(fork_name_full) |
|
152 | 153 | response.mustcontain(self.REPO_TYPE) |
|
153 | 154 | |
@@ -193,7 +194,7 b' class _BaseTest(TestController):' | |||
|
193 | 194 | assert fork_repo.fork.repo_name == repo_name |
|
194 | 195 | |
|
195 | 196 | # test if the repository is visible in the list ? |
|
196 |
response = self.app.get( |
|
|
197 | response = self.app.get(h.route_path('repo_summary', repo_name=fork_name)) | |
|
197 | 198 | response.mustcontain(fork_name) |
|
198 | 199 | response.mustcontain(self.REPO_TYPE) |
|
199 | 200 | response.mustcontain('Fork of') |
@@ -254,7 +255,7 b' class TestHG(_BaseTest):' | |||
|
254 | 255 | |
|
255 | 256 | @pytest.mark.usefixtures('app', 'autologin_user') |
|
256 | 257 | @pytest.mark.skip_backends('git','hg') |
|
257 | class TestSVNFork: | |
|
258 | class TestSVNFork(object): | |
|
258 | 259 | |
|
259 | 260 | def test_fork_redirects(self, backend): |
|
260 | 261 | denied_actions = ['fork','fork_create'] |
@@ -266,7 +267,7 b' class TestSVNFork:' | |||
|
266 | 267 | |
|
267 | 268 | # Not allowed, redirect to the summary |
|
268 | 269 | redirected = response.follow() |
|
269 |
summary_url = |
|
|
270 | summary_url = h.route_path('repo_summary', repo_name=backend.repo_name) | |
|
270 | 271 | |
|
271 | 272 | # URL adds leading slash and path doesn't have it |
|
272 | assert redirected.req.path == summary_url | |
|
273 | assert redirected.request.path == summary_url |
@@ -29,6 +29,7 b' from rhodecode.tests import (' | |||
|
29 | 29 | no_newline_id_generator) |
|
30 | 30 | from rhodecode.tests.fixture import Fixture |
|
31 | 31 | from rhodecode.lib.auth import check_password |
|
32 | from rhodecode.lib import helpers as h | |
|
32 | 33 | from rhodecode.model.auth_token import AuthTokenModel |
|
33 | 34 | from rhodecode.model import validators |
|
34 | 35 | from rhodecode.model.db import User, Notification, UserApiKeys |
@@ -105,8 +106,9 b' class TestLoginController(object):' | |||
|
105 | 106 | with fixture.anon_access(False): |
|
106 | 107 | kwargs = {'branch': 'stable'} |
|
107 | 108 | response = self.app.get( |
|
108 |
|
|
|
109 | h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs)) | |
|
109 | 110 | assert response.status == '302 Found' |
|
111 | ||
|
110 | 112 | response_query = urlparse.parse_qsl(response.location) |
|
111 | 113 | assert 'branch=stable' in response_query[0][1] |
|
112 | 114 |
@@ -24,13 +24,13 b' from webob.exc import HTTPNotFound' | |||
|
24 | 24 | |
|
25 | 25 | import rhodecode |
|
26 | 26 | from rhodecode.lib.vcs.nodes import FileNode |
|
27 | from rhodecode.lib import helpers as h | |
|
27 | 28 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
28 | 29 | from rhodecode.model.db import ( |
|
29 | 30 | PullRequest, ChangesetStatus, UserLog, Notification) |
|
30 | 31 | from rhodecode.model.meta import Session |
|
31 | 32 | from rhodecode.model.pull_request import PullRequestModel |
|
32 | 33 | from rhodecode.model.user import UserModel |
|
33 | from rhodecode.model.repo import RepoModel | |
|
34 | 34 | from rhodecode.tests import ( |
|
35 | 35 | assert_session_flash, url, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN) |
|
36 | 36 | from rhodecode.tests.utils import AssertResponse |
@@ -38,7 +38,7 b' from rhodecode.tests.utils import Assert' | |||
|
38 | 38 | |
|
39 | 39 | @pytest.mark.usefixtures('app', 'autologin_user') |
|
40 | 40 | @pytest.mark.backends("git", "hg") |
|
41 | class TestPullrequestsController: | |
|
41 | class TestPullrequestsController(object): | |
|
42 | 42 | |
|
43 | 43 | def test_index(self, backend): |
|
44 | 44 | self.app.get(url( |
@@ -47,7 +47,7 b' class TestPullrequestsController:' | |||
|
47 | 47 | |
|
48 | 48 | def test_option_menu_create_pull_request_exists(self, backend): |
|
49 | 49 | repo_name = backend.repo_name |
|
50 |
response = self.app.get( |
|
|
50 | response = self.app.get(h.route_path('repo_summary', repo_name=repo_name)) | |
|
51 | 51 | |
|
52 | 52 | create_pr_link = '<a href="%s">Create Pull Request</a>' % url( |
|
53 | 53 | 'pullrequest', repo_name=repo_name) |
@@ -1074,10 +1074,10 b' def test_redirects_to_repo_summary_for_s' | |||
|
1074 | 1074 | |
|
1075 | 1075 | # Not allowed, redirect to the summary |
|
1076 | 1076 | redirected = response.follow() |
|
1077 |
summary_url = |
|
|
1077 | summary_url = h.route_path('repo_summary', repo_name=backend_svn.repo_name) | |
|
1078 | 1078 | |
|
1079 | 1079 | # URL adds leading slash and path doesn't have it |
|
1080 | assert redirected.req.path == summary_url | |
|
1080 | assert redirected.request.path == summary_url | |
|
1081 | 1081 | |
|
1082 | 1082 | |
|
1083 | 1083 | def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp): |
@@ -20,10 +20,10 b'' | |||
|
20 | 20 | |
|
21 | 21 | import pytest |
|
22 | 22 | from mock import Mock, patch |
|
23 | from pylons import url | |
|
24 | 23 | |
|
25 | 24 | from rhodecode.lib import base |
|
26 | 25 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
26 | from rhodecode.lib import helpers as h | |
|
27 | 27 | from rhodecode.model import db |
|
28 | 28 | |
|
29 | 29 | |
@@ -165,7 +165,7 b' class TestBaseRepoControllerHandleMissin' | |||
|
165 | 165 | context_mock.repo_name = repo_name |
|
166 | 166 | controller._handle_missing_requirements(error) |
|
167 | 167 | |
|
168 |
expected_url = |
|
|
168 | expected_url = h.route_path('repo_summary', repo_name=repo_name) | |
|
169 | 169 | if should_redirect: |
|
170 | 170 | redirect_mock.assert_called_once_with(expected_url) |
|
171 | 171 | else: |
@@ -1683,6 +1683,15 b' def request_stub():' | |||
|
1683 | 1683 | |
|
1684 | 1684 | |
|
1685 | 1685 | @pytest.fixture |
|
1686 | def context_stub(): | |
|
1687 | """ | |
|
1688 | Stub context object. | |
|
1689 | """ | |
|
1690 | context = pyramid.testing.DummyResource() | |
|
1691 | return context | |
|
1692 | ||
|
1693 | ||
|
1694 | @pytest.fixture | |
|
1686 | 1695 | def config_stub(request, request_stub): |
|
1687 | 1696 | """ |
|
1688 | 1697 | Set up pyramid.testing and return the Configurator. |
@@ -123,6 +123,7 b' def set_anonymous_access(enabled):' | |||
|
123 | 123 | user.active = enabled |
|
124 | 124 | Session().add(user) |
|
125 | 125 | Session().commit() |
|
126 | time.sleep(1.5) # must sleep for cache (1s to expire) | |
|
126 | 127 | log.info('anonymous access is now: %s', enabled) |
|
127 | 128 | assert enabled == User.get_default_user().active, ( |
|
128 | 129 | 'Cannot set anonymous access') |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now