##// END OF EJS Templates
compare: migrated code from pylons to pyramid views.
marcink -
r1957:00f3a509 default
parent child Browse files
Show More
@@ -0,0 +1,323 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2012-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
22 import logging
23
24 from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPFound
25 from pyramid.view import view_config
26 from pyramid.renderers import render
27 from pyramid.response import Response
28
29
30 from rhodecode.apps._base import RepoAppView
31 from rhodecode.controllers.utils import parse_path_ref, get_commit_from_ref_name
32 from rhodecode.lib import helpers as h
33 from rhodecode.lib import diffs, codeblocks
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.utils import safe_str
36 from rhodecode.lib.utils2 import safe_unicode, str2bool
37 from rhodecode.lib.vcs.exceptions import (
38 EmptyRepositoryError, RepositoryError, RepositoryRequirementError,
39 NodeDoesNotExistError)
40 from rhodecode.model.db import Repository, ChangesetStatus
41
42 log = logging.getLogger(__name__)
43
44
45 class RepoCompareView(RepoAppView):
46 def load_default_context(self):
47 c = self._get_local_tmpl_context(include_app_defaults=True)
48
49 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
50 c.repo_info = self.db_repo
51 c.rhodecode_repo = self.rhodecode_vcs_repo
52
53 self._register_global_c(c)
54 return c
55
56 def _get_commit_or_redirect(
57 self, ref, ref_type, repo, redirect_after=True, partial=False):
58 """
59 This is a safe way to get a commit. If an error occurs it
60 redirects to a commit with a proper message. If partial is set
61 then it does not do redirect raise and throws an exception instead.
62 """
63 _ = self.request.translate
64 try:
65 return get_commit_from_ref_name(repo, safe_str(ref), ref_type)
66 except EmptyRepositoryError:
67 if not redirect_after:
68 return repo.scm_instance().EMPTY_COMMIT
69 h.flash(h.literal(_('There are no commits yet')),
70 category='warning')
71 raise HTTPFound(
72 h.route_path('repo_summary', repo_name=repo.repo_name))
73
74 except RepositoryError as e:
75 log.exception(safe_str(e))
76 h.flash(safe_str(h.escape(e)), category='warning')
77 if not partial:
78 raise HTTPFound(
79 h.route_path('repo_summary', repo_name=repo.repo_name))
80 raise HTTPBadRequest()
81
82 @LoginRequired()
83 @HasRepoPermissionAnyDecorator(
84 'repository.read', 'repository.write', 'repository.admin')
85 @view_config(
86 route_name='repo_compare_select', request_method='GET',
87 renderer='rhodecode:templates/compare/compare_diff.mako')
88 def compare_select(self):
89 _ = self.request.translate
90 c = self.load_default_context()
91
92 source_repo = self.db_repo_name
93 target_repo = self.request.GET.get('target_repo', source_repo)
94 c.source_repo = Repository.get_by_repo_name(source_repo)
95 c.target_repo = Repository.get_by_repo_name(target_repo)
96
97 if c.source_repo is None or c.target_repo is None:
98 raise HTTPNotFound()
99
100 c.compare_home = True
101 c.commit_ranges = []
102 c.collapse_all_commits = False
103 c.diffset = None
104 c.limited_diff = False
105 c.source_ref = c.target_ref = _('Select commit')
106 c.source_ref_type = ""
107 c.target_ref_type = ""
108 c.commit_statuses = ChangesetStatus.STATUSES
109 c.preview_mode = False
110 c.file_path = None
111
112 return self._get_template_context(c)
113
114 @LoginRequired()
115 @HasRepoPermissionAnyDecorator(
116 'repository.read', 'repository.write', 'repository.admin')
117 @view_config(
118 route_name='repo_compare', request_method='GET',
119 renderer=None)
120 def compare(self):
121 _ = self.request.translate
122 c = self.load_default_context()
123
124 source_ref_type = self.request.matchdict['source_ref_type']
125 source_ref = self.request.matchdict['source_ref']
126 target_ref_type = self.request.matchdict['target_ref_type']
127 target_ref = self.request.matchdict['target_ref']
128
129 # source_ref will be evaluated in source_repo
130 source_repo_name = self.db_repo_name
131 source_path, source_id = parse_path_ref(source_ref)
132
133 # target_ref will be evaluated in target_repo
134 target_repo_name = self.request.GET.get('target_repo', source_repo_name)
135 target_path, target_id = parse_path_ref(
136 target_ref, default_path=self.request.GET.get('f_path', ''))
137
138 # if merge is True
139 # Show what changes since the shared ancestor commit of target/source
140 # the source would get if it was merged with target. Only commits
141 # which are in target but not in source will be shown.
142 merge = str2bool(self.request.GET.get('merge'))
143 # if merge is False
144 # Show a raw diff of source/target refs even if no ancestor exists
145
146 # c.fulldiff disables cut_off_limit
147 c.fulldiff = str2bool(self.request.GET.get('fulldiff'))
148
149 c.file_path = target_path
150 c.commit_statuses = ChangesetStatus.STATUSES
151
152 # if partial, returns just compare_commits.html (commits log)
153 partial = self.request.is_xhr
154
155 # swap url for compare_diff page
156 c.swap_url = h.route_path(
157 'repo_compare',
158 repo_name=target_repo_name,
159 source_ref_type=target_ref_type,
160 source_ref=target_ref,
161 target_repo=source_repo_name,
162 target_ref_type=source_ref_type,
163 target_ref=source_ref,
164 _query=dict(merge=merge and '1' or '', f_path=target_path))
165
166 source_repo = Repository.get_by_repo_name(source_repo_name)
167 target_repo = Repository.get_by_repo_name(target_repo_name)
168
169 if source_repo is None:
170 log.error('Could not find the source repo: {}'
171 .format(source_repo_name))
172 h.flash(_('Could not find the source repo: `{}`')
173 .format(h.escape(source_repo_name)), category='error')
174 raise HTTPFound(
175 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
176
177 if target_repo is None:
178 log.error('Could not find the target repo: {}'
179 .format(source_repo_name))
180 h.flash(_('Could not find the target repo: `{}`')
181 .format(h.escape(target_repo_name)), category='error')
182 raise HTTPFound(
183 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
184
185 source_scm = source_repo.scm_instance()
186 target_scm = target_repo.scm_instance()
187
188 source_alias = source_scm.alias
189 target_alias = target_scm.alias
190 if source_alias != target_alias:
191 msg = _('The comparison of two different kinds of remote repos '
192 'is not available')
193 log.error(msg)
194 h.flash(msg, category='error')
195 raise HTTPFound(
196 h.route_path('repo_compare_select', repo_name=self.db_repo_name))
197
198 source_commit = self._get_commit_or_redirect(
199 ref=source_id, ref_type=source_ref_type, repo=source_repo,
200 partial=partial)
201 target_commit = self._get_commit_or_redirect(
202 ref=target_id, ref_type=target_ref_type, repo=target_repo,
203 partial=partial)
204
205 c.compare_home = False
206 c.source_repo = source_repo
207 c.target_repo = target_repo
208 c.source_ref = source_ref
209 c.target_ref = target_ref
210 c.source_ref_type = source_ref_type
211 c.target_ref_type = target_ref_type
212
213 pre_load = ["author", "branch", "date", "message"]
214 c.ancestor = None
215
216 if c.file_path:
217 if source_commit == target_commit:
218 c.commit_ranges = []
219 else:
220 c.commit_ranges = [target_commit]
221 else:
222 try:
223 c.commit_ranges = source_scm.compare(
224 source_commit.raw_id, target_commit.raw_id,
225 target_scm, merge, pre_load=pre_load)
226 if merge:
227 c.ancestor = source_scm.get_common_ancestor(
228 source_commit.raw_id, target_commit.raw_id, target_scm)
229 except RepositoryRequirementError:
230 msg = _('Could not compare repos with different '
231 'large file settings')
232 log.error(msg)
233 if partial:
234 return Response(msg)
235 h.flash(msg, category='error')
236 raise HTTPFound(
237 h.route_path('repo_compare_select',
238 repo_name=self.db_repo_name))
239
240 c.statuses = self.db_repo.statuses(
241 [x.raw_id for x in c.commit_ranges])
242
243 # auto collapse if we have more than limit
244 collapse_limit = diffs.DiffProcessor._collapse_commits_over
245 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
246
247 if partial: # for PR ajax commits loader
248 if not c.ancestor:
249 return Response('') # cannot merge if there is no ancestor
250
251 html = render(
252 'rhodecode:templates/compare/compare_commits.mako',
253 self._get_template_context(c), self.request)
254 return Response(html)
255
256 if c.ancestor:
257 # case we want a simple diff without incoming commits,
258 # previewing what will be merged.
259 # Make the diff on target repo (which is known to have target_ref)
260 log.debug('Using ancestor %s as source_ref instead of %s'
261 % (c.ancestor, source_ref))
262 source_repo = target_repo
263 source_commit = target_repo.get_commit(commit_id=c.ancestor)
264
265 # diff_limit will cut off the whole diff if the limit is applied
266 # otherwise it will just hide the big files from the front-end
267 diff_limit = c.visual.cut_off_limit_diff
268 file_limit = c.visual.cut_off_limit_file
269
270 log.debug('calculating diff between '
271 'source_ref:%s and target_ref:%s for repo `%s`',
272 source_commit, target_commit,
273 safe_unicode(source_repo.scm_instance().path))
274
275 if source_commit.repository != target_commit.repository:
276 msg = _(
277 "Repositories unrelated. "
278 "Cannot compare commit %(commit1)s from repository %(repo1)s "
279 "with commit %(commit2)s from repository %(repo2)s.") % {
280 'commit1': h.show_id(source_commit),
281 'repo1': source_repo.repo_name,
282 'commit2': h.show_id(target_commit),
283 'repo2': target_repo.repo_name,
284 }
285 h.flash(msg, category='error')
286 raise HTTPFound(
287 h.route_path('repo_compare_select',
288 repo_name=self.db_repo_name))
289
290 txt_diff = source_repo.scm_instance().get_diff(
291 commit1=source_commit, commit2=target_commit,
292 path=target_path, path1=source_path)
293
294 diff_processor = diffs.DiffProcessor(
295 txt_diff, format='newdiff', diff_limit=diff_limit,
296 file_limit=file_limit, show_full_diff=c.fulldiff)
297 _parsed = diff_processor.prepare()
298
299 def _node_getter(commit):
300 """ Returns a function that returns a node for a commit or None """
301 def get_node(fname):
302 try:
303 return commit.get_node(fname)
304 except NodeDoesNotExistError:
305 return None
306 return get_node
307
308 diffset = codeblocks.DiffSet(
309 repo_name=source_repo.repo_name,
310 source_node_getter=_node_getter(source_commit),
311 target_node_getter=_node_getter(target_commit),
312 )
313 c.diffset = diffset.render_patchset(
314 _parsed, source_ref, target_ref)
315
316 c.preview_mode = merge
317 c.source_commit = source_commit
318 c.target_commit = target_commit
319
320 html = render(
321 'rhodecode:templates/compare/compare_diff.mako',
322 self._get_template_context(c), self.request)
323 return Response(html) No newline at end of file
@@ -32,8 +32,7 b' def includeme(config):'
32 32 name='repo_summary_commits',
33 33 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
34 34
35 # repo commits
36
35 # Commits
37 36 config.add_route(
38 37 name='repo_commit',
39 38 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
@@ -46,11 +45,6 b' def includeme(config):'
46 45 name='repo_commit_parents',
47 46 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
48 47
49 # still working url for backward compat.
50 config.add_route(
51 name='repo_commit_raw_deprecated',
52 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
53
54 48 config.add_route(
55 49 name='repo_commit_raw',
56 50 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
@@ -79,7 +73,12 b' def includeme(config):'
79 73 name='repo_commit_comment_delete',
80 74 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
81 75
82 # repo files
76 # still working url for backward compat.
77 config.add_route(
78 name='repo_commit_raw_deprecated',
79 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
80
81 # Files
83 82 config.add_route(
84 83 name='repo_archivefile',
85 84 pattern='/{repo_name:.*?[^/]}/archive/{fname}', repo_route=True)
@@ -168,7 +167,7 b' def includeme(config):'
168 167 pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}',
169 168 repo_route=True)
170 169
171 # refs data
170 # Refs data
172 171 config.add_route(
173 172 name='repo_refs_data',
174 173 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
@@ -192,6 +191,15 b' def includeme(config):'
192 191 name='repo_changelog_elements',
193 192 pattern='/{repo_name:.*?[^/]}/changelog_elements', repo_route=True)
194 193
194 # Compare
195 config.add_route(
196 name='repo_compare_select',
197 pattern='/{repo_name:.*?[^/]}/compare', repo_route=True)
198
199 config.add_route(
200 name='repo_compare',
201 pattern='/{repo_name:.*?[^/]}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', repo_route=True)
202
195 203 # Tags
196 204 config.add_route(
197 205 name='tags_home',
@@ -23,12 +23,30 b' import pytest'
23 23 import lxml.html
24 24
25 25 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
26 from rhodecode.tests import url, assert_session_flash
26 from rhodecode.tests import assert_session_flash
27 27 from rhodecode.tests.utils import AssertResponse, commit_change
28 28
29 29
30 def route_path(name, params=None, **kwargs):
31 import urllib
32
33 base_url = {
34 'repo_compare_select': '/{repo_name}/compare',
35 'repo_compare': '/{repo_name}/compare/{source_ref_type}@{source_ref}...{target_ref_type}@{target_ref}',
36 }[name].format(**kwargs)
37
38 if params:
39 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
40 return base_url
41
42
30 43 @pytest.mark.usefixtures("autologin_user", "app")
31 class TestCompareController(object):
44 class TestCompareView(object):
45
46 def test_compare_index_is_reached_at_least_once(self, backend):
47 repo = backend.repo
48 self.app.get(
49 route_path('repo_compare_select', repo_name=repo.repo_name))
32 50
33 51 @pytest.mark.xfail_backends("svn", reason="Requires pull")
34 52 def test_compare_remote_with_different_commit_indexes(self, backend):
@@ -85,14 +103,14 b' class TestCompareController(object):'
85 103
86 104 # Comparing the revisions
87 105 response = self.app.get(
88 url('compare_url',
106 route_path('repo_compare',
89 107 repo_name=origin.repo_name,
90 108 source_ref_type="rev",
91 109 source_ref=commit3.raw_id,
92 target_repo=fork.repo_name,
93 110 target_ref_type="rev",
94 111 target_ref=commit4.raw_id,
95 merge='1',))
112 params=dict(merge='1', target_repo=fork.repo_name)
113 ))
96 114
97 115 compare_page = ComparePage(response)
98 116 compare_page.contains_commits([commit4])
@@ -123,14 +141,14 b' class TestCompareController(object):'
123 141 commit_id2 = repo2.scm_instance().DEFAULT_BRANCH_NAME
124 142
125 143 response = self.app.get(
126 url('compare_url',
144 route_path('repo_compare',
127 145 repo_name=repo1.repo_name,
128 146 source_ref_type="branch",
129 147 source_ref=commit_id2,
130 target_repo=repo2.repo_name,
131 148 target_ref_type="branch",
132 149 target_ref=commit_id1,
133 merge='1',))
150 params=dict(merge='1', target_repo=repo2.repo_name)
151 ))
134 152
135 153 response.mustcontain('%s@%s' % (repo1.repo_name, commit_id2))
136 154 response.mustcontain('%s@%s' % (repo2.repo_name, commit_id1))
@@ -180,14 +198,14 b' class TestCompareController(object):'
180 198 commit_id2 = repo2.scm_instance().DEFAULT_BRANCH_NAME
181 199
182 200 response = self.app.get(
183 url('compare_url',
201 route_path('repo_compare',
184 202 repo_name=repo1.repo_name,
185 203 source_ref_type="branch",
186 204 source_ref=commit_id2,
187 target_repo=repo2.repo_name,
188 205 target_ref_type="branch",
189 206 target_ref=commit_id1,
190 merge='1'))
207 params=dict(merge='1', target_repo=repo2.repo_name),
208 ))
191 209
192 210 response.mustcontain('%s@%s' % (repo1.repo_name, commit_id2))
193 211 response.mustcontain('%s@%s' % (repo2.repo_name, commit_id1))
@@ -211,17 +229,16 b' class TestCompareController(object):'
211 229 fork = backend.create_repo(number_of_commits=1)
212 230
213 231 response = self.app.get(
214 url('compare_url',
232 route_path('repo_compare',
215 233 repo_name=orig.repo_name,
216 action="compare",
217 234 source_ref_type="rev",
218 235 source_ref="tip",
219 236 target_ref_type="rev",
220 237 target_ref="tip",
221 merge='1',
222 target_repo=fork.repo_name),
223 status=400)
224
238 params=dict(merge='1', target_repo=fork.repo_name),
239 ),
240 status=302)
241 response = response.follow()
225 242 response.mustcontain("Repositories unrelated.")
226 243
227 244 @pytest.mark.xfail_backends("svn")
@@ -271,15 +288,15 b' class TestCompareController(object):'
271 288 message='commit6', vcs_type=backend.alias, parent=commit4)
272 289
273 290 response = self.app.get(
274 url('compare_url',
291 route_path('repo_compare',
275 292 repo_name=repo2.repo_name,
276 293 source_ref_type="rev",
277 294 # parent of commit2, in target repo2
278 295 source_ref=commit1.raw_id,
279 target_repo=repo1.repo_name,
280 296 target_ref_type="rev",
281 297 target_ref=commit4.raw_id,
282 merge='1',))
298 params=dict(merge='1', target_repo=repo1.repo_name),
299 ))
283 300 response.mustcontain('%s@%s' % (repo2.repo_name, commit1.short_id))
284 301 response.mustcontain('%s@%s' % (repo1.repo_name, commit4.short_id))
285 302
@@ -337,14 +354,15 b' class TestCompareController(object):'
337 354 message='commit6', vcs_type=backend.alias, parent=commit4)
338 355
339 356 response = self.app.get(
340 url('compare_url',
357 route_path('repo_compare',
341 358 repo_name=repo1.repo_name,
342 359 source_ref_type="rev",
343 360 # parent of commit3, not in source repo2
344 361 source_ref=commit2.raw_id,
345 362 target_ref_type="rev",
346 363 target_ref=commit5.raw_id,
347 merge='1',))
364 params=dict(merge='1'),
365 ))
348 366
349 367 response.mustcontain('%s@%s' % (repo1.repo_name, commit2.short_id))
350 368 response.mustcontain('%s@%s' % (repo1.repo_name, commit5.short_id))
@@ -367,14 +385,14 b' class TestCompareController(object):'
367 385 commit_id2 = repo1.get_commit(commit_idx=6).raw_id
368 386
369 387 response = self.app.get(
370 url('compare_url',
388 route_path('repo_compare',
371 389 repo_name=repo1.repo_name,
372 390 source_ref_type="rev",
373 391 source_ref=commit_id1,
374 392 target_ref_type="rev",
375 393 target_ref=commit_id2,
376 target_repo=repo2.repo_name,
377 merge='1',))
394 params=dict(merge='1', target_repo=repo2.repo_name),
395 ))
378 396
379 397 response.mustcontain('%s@%s' % (repo1.repo_name, commit_id1))
380 398 response.mustcontain('%s@%s' % (repo2.repo_name, commit_id2))
@@ -432,14 +450,14 b' class TestCompareController(object):'
432 450 commit_id2 = repo2.scm_instance().DEFAULT_BRANCH_NAME
433 451
434 452 response = self.app.get(
435 url('compare_url',
453 route_path('repo_compare',
436 454 repo_name=r2_name,
437 455 source_ref_type="branch",
438 456 source_ref=commit_id1,
439 457 target_ref_type="branch",
440 458 target_ref=commit_id2,
441 target_repo=r1_name,
442 merge='1',))
459 params=dict(merge='1', target_repo=r1_name),
460 ))
443 461
444 462 response.mustcontain('%s@%s' % (r2_name, commit_id1))
445 463 response.mustcontain('%s@%s' % (r1_name, commit_id2))
@@ -453,14 +471,14 b' class TestCompareController(object):'
453 471
454 472 # compare !
455 473 response = self.app.get(
456 url('compare_url',
474 route_path('repo_compare',
457 475 repo_name=r2_name,
458 476 source_ref_type="branch",
459 477 source_ref=commit_id1,
460 478 target_ref_type="branch",
461 479 target_ref=commit_id2,
462 target_repo=r1_name,
463 merge='1',))
480 params=dict(merge='1', target_repo=r1_name),
481 ))
464 482
465 483 response.mustcontain('%s@%s' % (r2_name, commit_id1))
466 484 response.mustcontain('%s@%s' % (r1_name, commit_id2))
@@ -476,13 +494,14 b' class TestCompareController(object):'
476 494 commit1 = backend.repo.get_commit(commit_idx=1)
477 495
478 496 response = self.app.get(
479 url('compare_url',
497 route_path('repo_compare',
480 498 repo_name=backend.repo_name,
481 499 source_ref_type="rev",
482 500 source_ref=commit0.raw_id,
483 501 target_ref_type="rev",
484 502 target_ref=commit1.raw_id,
485 merge='1',),
503 params=dict(merge='1')
504 ),
486 505 extra_environ=xhr_header,)
487 506
488 507 # outgoing commits between those commits
@@ -494,14 +513,14 b' class TestCompareController(object):'
494 513 badrepo = 'badrepo'
495 514
496 515 response = self.app.get(
497 url('compare_url',
516 route_path('repo_compare',
498 517 repo_name=badrepo,
499 518 source_ref_type="rev",
500 519 source_ref='tip',
501 520 target_ref_type="rev",
502 521 target_ref='tip',
503 target_repo=repo.repo_name,
504 merge='1',),
522 params=dict(merge='1', target_repo=repo.repo_name)
523 ),
505 524 status=404)
506 525
507 526 def test_errors_when_comparing_unknown_target_repo(self, backend):
@@ -509,14 +528,14 b' class TestCompareController(object):'
509 528 badrepo = 'badrepo'
510 529
511 530 response = self.app.get(
512 url('compare_url',
531 route_path('repo_compare',
513 532 repo_name=repo.repo_name,
514 533 source_ref_type="rev",
515 534 source_ref='tip',
516 535 target_ref_type="rev",
517 536 target_ref='tip',
518 target_repo=badrepo,
519 merge='1',),
537 params=dict(merge='1', target_repo=badrepo),
538 ),
520 539 status=302)
521 540 redirected = response.follow()
522 541 redirected.mustcontain(
@@ -526,13 +545,14 b' class TestCompareController(object):'
526 545 commit0 = backend_stub.repo.get_commit(commit_idx=0)
527 546 commit1 = backend_stub.repo.get_commit(commit_idx=1)
528 547
529 response = self.app.get(url('compare_url',
548 response = self.app.get(
549 route_path('repo_compare',
530 550 repo_name=backend_stub.repo_name,
531 551 source_ref_type="rev",
532 552 source_ref=commit0.raw_id,
533 553 target_ref_type="rev",
534 554 target_ref=commit1.raw_id,
535 ),)
555 ))
536 556
537 557 # outgoing commits between those commits
538 558 compare_page = ComparePage(response)
@@ -554,15 +574,14 b' class TestCompareController(object):'
554 574 compare_mock.side_effect = RepositoryRequirementError()
555 575
556 576 response = self.app.get(
557 url('compare_url',
577 route_path('repo_compare',
558 578 repo_name=orig.repo_name,
559 action="compare",
560 579 source_ref_type="rev",
561 580 source_ref="tip",
562 581 target_ref_type="rev",
563 582 target_ref="tip",
564 merge='1',
565 target_repo=fork.repo_name),
583 params=dict(merge='1', target_repo=fork.repo_name),
584 ),
566 585 status=302)
567 586
568 587 assert_session_flash(
@@ -577,13 +596,14 b' class TestCompareControllerSvn(object):'
577 596 repo = backend_svn['svn-simple-layout']
578 597 commit_id = repo.get_commit(commit_idx=-1).raw_id
579 598 response = app.get(
580 url('compare_url',
599 route_path('repo_compare',
581 600 repo_name=repo.repo_name,
582 601 source_ref_type="tag",
583 602 source_ref="%s@%s" % ('tags/v0.1', commit_id),
584 603 target_ref_type="tag",
585 604 target_ref="%s@%s" % ('tags/v0.2', commit_id),
586 merge='1',),
605 params=dict(merge='1'),
606 ),
587 607 status=200)
588 608
589 609 # Expecting no commits, since both paths are at the same revision
@@ -599,13 +619,14 b' class TestCompareControllerSvn(object):'
599 619 source_id = repo.get_commit(commit_idx=-6).raw_id
600 620 target_id = repo.get_commit(commit_idx=-1).raw_id
601 621 response = app.get(
602 url('compare_url',
622 route_path('repo_compare',
603 623 repo_name=repo.repo_name,
604 624 source_ref_type="tag",
605 625 source_ref="%s@%s" % ('tags/v0.1', source_id),
606 626 target_ref_type="tag",
607 627 target_ref="%s@%s" % ('tags/v0.2', target_id),
608 merge='1',),
628 params=dict(merge='1')
629 ),
609 630 status=200)
610 631
611 632 # It should show commits
@@ -673,3 +694,4 b' class ComparePage(AssertResponse):'
673 694 def target_source_are_enabled(self):
674 695 response = self.response
675 696 response.mustcontain("var enable_fields = true;")
697
@@ -20,20 +20,32 b''
20 20
21 21 import pytest
22 22
23 from rhodecode.tests import url
24 from rhodecode.tests.functional.test_compare import ComparePage
23 from .test_repo_compare import ComparePage
24
25
26 def route_path(name, params=None, **kwargs):
27 import urllib
28
29 base_url = {
30 'repo_compare_select': '/{repo_name}/compare',
31 'repo_compare': '/{repo_name}/compare/{source_ref_type}@{source_ref}...{target_ref_type}@{target_ref}',
32 }[name].format(**kwargs)
33
34 if params:
35 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
36 return base_url
25 37
26 38
27 39 @pytest.mark.usefixtures("autologin_user", "app")
28 class TestCompareController:
40 class TestCompareView(object):
29 41
30 42 @pytest.mark.xfail_backends("svn", msg="Depends on branch and tag support")
31 43 def test_compare_tag(self, backend):
32 44 tag1 = 'v0.1.2'
33 45 tag2 = 'v0.1.3'
34 46 response = self.app.get(
35 url(
36 'compare_url',
47 route_path(
48 'repo_compare',
37 49 repo_name=backend.repo_name,
38 50 source_ref_type="tag",
39 51 source_ref=tag1,
@@ -90,8 +102,9 b' class TestCompareController:'
90 102 # functional tests.
91 103 data = revisions[backend.alias]
92 104
93 response = self.app.get(url(
94 'compare_url',
105 response = self.app.get(
106 route_path(
107 'repo_compare',
95 108 repo_name=backend.repo_name,
96 109 source_ref_type='branch',
97 110 source_ref=data['branch'],
@@ -106,8 +119,9 b' class TestCompareController:'
106 119
107 120 def test_index_branch(self, backend):
108 121 head_id = backend.default_head_id
109 response = self.app.get(url(
110 'compare_url',
122 response = self.app.get(
123 route_path(
124 'repo_compare',
111 125 repo_name=backend.repo_name,
112 126 source_ref_type="branch",
113 127 source_ref=head_id,
@@ -126,8 +140,9 b' class TestCompareController:'
126 140 commit1 = repo.get_commit(commit_idx=0)
127 141 commit2 = repo.get_commit(commit_idx=1)
128 142
129 response = self.app.get(url(
130 'compare_url',
143 response = self.app.get(
144 route_path(
145 'repo_compare',
131 146 repo_name=backend.repo_name,
132 147 source_ref_type="rev",
133 148 source_ref=commit1.raw_id,
@@ -21,13 +21,25 b''
21 21 import pytest
22 22
23 23 from rhodecode.lib.vcs import nodes
24 from rhodecode.tests import url
25 24 from rhodecode.tests.fixture import Fixture
26 25 from rhodecode.tests.utils import commit_change
27 26
28 27 fixture = Fixture()
29 28
30 29
30 def route_path(name, params=None, **kwargs):
31 import urllib
32
33 base_url = {
34 'repo_compare_select': '/{repo_name}/compare',
35 'repo_compare': '/{repo_name}/compare/{source_ref_type}@{source_ref}...{target_ref_type}@{target_ref}',
36 }[name].format(**kwargs)
37
38 if params:
39 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
40 return base_url
41
42
31 43 @pytest.mark.usefixtures("autologin_user", "app")
32 44 class TestSideBySideDiff(object):
33 45
@@ -45,18 +57,15 b' class TestSideBySideDiff(object):'
45 57 repo.repo_name, filename=f_path, content=commit2_content,
46 58 message='B, child of A', vcs_type=backend.alias, parent=commit1)
47 59
48 compare_url = url(
49 'compare_url',
60 response = self.app.get(route_path(
61 'repo_compare',
50 62 repo_name=repo.repo_name,
51 63 source_ref_type='rev',
52 64 source_ref=commit1.raw_id,
53 target_repo=repo.repo_name,
54 65 target_ref_type='rev',
55 66 target_ref=commit2.raw_id,
56 f_path=f_path,
57 diffmode='sidebyside')
58
59 response = self.app.get(compare_url)
67 params=dict(f_path=f_path, target_repo=repo.repo_name, diffmode='sidebyside')
68 ))
60 69
61 70 response.mustcontain('Expand 1 commit')
62 71 response.mustcontain('1 file changed')
@@ -78,18 +87,15 b' class TestSideBySideDiff(object):'
78 87 commit1 = repo.get_commit(commit_idx=0)
79 88 commit2 = repo.get_commit(commit_idx=1)
80 89
81 compare_url = url(
82 'compare_url',
90 response = self.app.get(route_path(
91 'repo_compare',
83 92 repo_name=repo.repo_name,
84 93 source_ref_type='rev',
85 94 source_ref=commit1.raw_id,
86 target_repo=repo.repo_name,
87 95 target_ref_type='rev',
88 96 target_ref=commit2.raw_id,
89 f_path=f_path,
90 diffmode='sidebyside')
91
92 response = self.app.get(compare_url)
97 params=dict(f_path=f_path, target_repo=repo.repo_name, diffmode='sidebyside')
98 ))
93 99
94 100 response.mustcontain('Expand 1 commit')
95 101 response.mustcontain('1 file changed')
@@ -124,16 +130,16 b' class TestSideBySideDiff(object):'
124 130 commit2, commit1 = commit_info['commits']
125 131 file_changes = commit_info['changes']
126 132
127 compare_url = url(
128 'compare_url',
133 response = self.app.get(route_path(
134 'repo_compare',
129 135 repo_name=backend.repo_name,
130 136 source_ref_type='rev',
131 137 source_ref=commit2,
132 138 target_repo=backend.repo_name,
133 139 target_ref_type='rev',
134 140 target_ref=commit1,
135 diffmode='sidebyside')
136 response = self.app.get(compare_url)
141 params=dict(target_repo=backend.repo_name, diffmode='sidebyside')
142 ))
137 143
138 144 response.mustcontain('Expand 1 commit')
139 145 response.mustcontain(file_changes)
@@ -163,17 +169,15 b' class TestSideBySideDiff(object):'
163 169 commit2, commit1 = commit_info['commits']
164 170 file_changes = commit_info['changes']
165 171
166 compare_url = url(
167 'compare_url',
172 response = self.app.get(route_path(
173 'repo_compare',
168 174 repo_name=backend.repo_name,
169 175 source_ref_type='rev',
170 176 source_ref=commit2,
171 target_repo=backend.repo_name,
172 177 target_ref_type='rev',
173 178 target_ref=commit1,
174 f_path=f_path,
175 diffmode='sidebyside')
176 response = self.app.get(compare_url)
179 params=dict(f_path=f_path, target_repo=backend.repo_name, diffmode='sidebyside')
180 ))
177 181
178 182 response.mustcontain('Expand 1 commit')
179 183 response.mustcontain(file_changes)
@@ -392,14 +392,15 b' class RepoFilesView(RepoAppView):'
392 392
393 393 c.action = self.request.GET.get('diff')
394 394 if c.action not in ['download', 'raw']:
395 compare_url = h.url(
396 'compare_url', repo_name=self.db_repo_name,
395 compare_url = h.route_path(
396 'repo_compare',
397 repo_name=self.db_repo_name,
397 398 source_ref_type='rev',
398 399 source_ref=diff1,
399 400 target_repo=self.db_repo_name,
400 401 target_ref_type='rev',
401 402 target_ref=diff2,
402 f_path=f_path)
403 _query=dict(f_path=f_path))
403 404 # redirect to new view if we render diff
404 405 raise HTTPFound(compare_url)
405 406
@@ -471,15 +472,15 b' class RepoFilesView(RepoAppView):'
471 472 category='error')
472 473 raise HTTPBadRequest()
473 474
474 compare_url = h.url(
475 'compare_url', repo_name=self.db_repo_name,
475 compare_url = h.route_path(
476 'repo_compare',
477 repo_name=self.db_repo_name,
476 478 source_ref_type='rev',
477 479 source_ref=diff1,
478 target_repo=self.db_repo_name,
479 480 target_ref_type='rev',
480 481 target_ref=diff2,
481 f_path=f_path,
482 diffmode='sideside')
482 _query=dict(f_path=f_path, diffmode='sideside',
483 target_repo=self.db_repo_name,))
483 484 raise HTTPFound(compare_url)
484 485
485 486 @LoginRequired()
@@ -502,17 +502,6 b' def make_map(config):'
502 502 conditions={'method': ['GET', 'POST'], 'function': check_repo},
503 503 requirements=URL_NAME_REQUIREMENTS)
504 504
505 rmap.connect('compare_home',
506 '/{repo_name}/compare',
507 controller='compare', action='index',
508 conditions={'function': check_repo},
509 requirements=URL_NAME_REQUIREMENTS)
510
511 rmap.connect('compare_url',
512 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
513 controller='compare', action='compare',
514 conditions={'function': check_repo},
515 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
516 505
517 506 rmap.connect('pullrequest_home',
518 507 '/{repo_name}/pull-request/new', controller='pullrequests',
@@ -15,7 +15,6 b' function registerRCRoutes() {'
15 15 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 16 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
19 18 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
20 19 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
21 20 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
@@ -108,7 +107,6 b' function registerRCRoutes() {'
108 107 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
109 108 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
110 109 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
111 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
112 110 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
113 111 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
114 112 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
@@ -116,6 +114,7 b' function registerRCRoutes() {'
116 114 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
117 115 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
118 116 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
117 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
119 118 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
120 119 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
121 120 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
@@ -145,6 +144,8 b' function registerRCRoutes() {'
145 144 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
146 145 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
147 146 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
147 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
148 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
148 149 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
149 150 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
150 151 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
@@ -58,7 +58,7 b' var compare_radio_buttons = function(rep'
58 58 target_ref_type: compare_ref_type,
59 59 merge: 1
60 60 };
61 window.location = pyroutes.url('compare_url', url_data);
61 window.location = pyroutes.url('repo_compare', url_data);
62 62 }
63 63 });
64 64 $('.compare-radio-button').on('click', function(e){
@@ -228,9 +228,7 b''
228 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.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
230 230 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
231 <li class="${is_active('compare')}">
232 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
233 </li>
231 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
234 232 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
235 233 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
236 234 <li class="${is_active('showpullrequest')}">
@@ -251,8 +249,19 b''
251 249 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
252 250 %endif
253 251 %if c.rhodecode_db_repo.fork:
254 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
255 ${_('Compare fork')}</a></li>
252 <li>
253 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
254 href="${h.route_path('repo_compare',
255 repo_name=c.rhodecode_db_repo.fork.repo_name,
256 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
257 source_ref=c.rhodecode_db_repo.landing_rev[1],
258 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
259 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
260 _query=dict(merge=1))}"
261 >
262 ${_('Compare fork')}
263 </a>
264 </li>
256 265 %endif
257 266
258 267 <li><a href="${h.route_path('search_repo',repo_name=c.repo_name)}">${_('Search')}</a></li>
@@ -39,16 +39,14 b''
39 39 <a id="compare_fork_button"
40 40 title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
41 41 class="btn btn-small"
42 href="${h.url('compare_url',
42 href="${h.route_path('repo_compare',
43 43 repo_name=c.rhodecode_db_repo.fork.repo_name,
44 44 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
45 45 source_ref=c.rhodecode_db_repo.landing_rev[1],
46 target_repo=c.repo_name,
47 46 target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
48 47 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
49 merge=1)}"
48 _query=dict(merge=1, target_repo=c.repo_name))}"
50 49 >
51 <i class="icon-loop"></i>
52 50 ${_('Compare fork with Parent (%s)' % c.rhodecode_db_repo.fork.repo_name)}
53 51 </a>
54 52 </span>
@@ -55,7 +55,13 b''
55 55 </div>
56 56 <div class="right-content">
57 57 <div class="header-buttons">
58 <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}">
58 <a href="${h.route_path('repo_compare',
59 repo_name=c.repo_name,
60 source_ref_type='rev',
61 source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'),
62 target_ref_type='rev',
63 target_ref=c.commit_ranges[-1].raw_id)}"
64 >
59 65 ${_('Show combined compare')}
60 66 </a>
61 67 </div>
@@ -288,7 +288,7 b''
288 288 target_ref: target.id,
289 289 target_ref_type: target.type
290 290 };
291 window.location = pyroutes.url('compare_url', url_data);
291 window.location = pyroutes.url('repo_compare', url_data);
292 292 }
293 293 });
294 294 $('#compare_changeset_status_toggle').on('click', function(e) {
@@ -174,7 +174,7 b''
174 174 merge: 1,
175 175 f_path: state.f_path
176 176 };
177 window.location = pyroutes.url('compare_url', url_data);
177 window.location = pyroutes.url('repo_compare', url_data);
178 178 });
179 179
180 180 $('#show_at_commit').on('click', function(e) {
@@ -26,8 +26,17 b''
26 26 </td>
27 27 <td class="td-compare">
28 28 <a title="${h.tooltip(_('Compare fork with %s' % c.repo_name))}"
29 href="${h.url('compare_url',repo_name=c.repo_name, source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1],target_repo=f.repo_name,target_ref_type=c.rhodecode_db_repo.landing_rev[0],target_ref=c.rhodecode_db_repo.landing_rev[1], merge=1)}"
30 class="btn-link"><i class="icon-loop"></i> ${_('Compare fork')}</a>
29 class="btn-link"
30 href="${h.route_path('repo_compare',
31 repo_name=c.repo_name,
32 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
33 source_ref=c.rhodecode_db_repo.landing_rev[1],
34 target_ref_type=c.rhodecode_db_repo.landing_rev[0],
35 target_ref=c.rhodecode_db_repo.landing_rev[1],
36 _query=dict(merge=1, target_repo=f.repo_name))}"
37 >
38 ${_('Compare fork')}
39 </a>
31 40 </td>
32 41 </tr>
33 42 % endfor
@@ -302,7 +302,7 b''
302 302 prButtonLock(true, "${_('Please select source and target')}");
303 303 return;
304 304 }
305 var url = pyroutes.url('compare_url', url_data);
305 var url = pyroutes.url('repo_compare', url_data);
306 306
307 307 // lock PR button, so we cannot send PR before it's calculated
308 308 prButtonLock(true, "${_('Loading compare ...')}", 'compare');
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