# HG changeset patch # User Marcin Kuzminski # Date 2012-11-18 22:17:02 # Node ID 16af24982e307640051c53af4be761208416b686 # Parent 02bbd574fa1448995acba0eee56c0953cb7d1297 Multiple changes for compare system - count number of changed lines and files - add combined compare button into the old per changeset compare - fixed some logic for remote & bundle compare system - added few tests for git compare diff --git a/rhodecode/controllers/compare.py b/rhodecode/controllers/compare.py --- a/rhodecode/controllers/compare.py +++ b/rhodecode/controllers/compare.py @@ -88,14 +88,14 @@ class CompareController(BaseRepoControll org_ref = (org_ref_type, org_ref) other_ref = (other_ref_type, other_ref) other_repo = request.GET.get('repo', org_repo) - bundle_compare = str2bool(request.GET.get('bundle', True)) + remote_compare = str2bool(request.GET.get('bundle', True)) c.fulldiff = fulldiff = request.GET.get('fulldiff') c.swap_url = h.url('compare_url', repo_name=other_repo, org_ref_type=other_ref[0], org_ref=other_ref[1], other_ref_type=org_ref[0], other_ref=org_ref[1], repo=org_repo, as_form=request.GET.get('as_form'), - bundle=bundle_compare) + bundle=remote_compare) c.org_repo = org_repo = Repository.get_by_repo_name(org_repo) c.other_repo = other_repo = Repository.get_by_repo_name(other_repo) @@ -128,20 +128,21 @@ class CompareController(BaseRepoControll if partial: return render('compare/compare_cs.html') - if not bundle_compare and c.cs_ranges: + c.org_ref = org_ref[1] + c.other_ref = other_ref[1] + + if not remote_compare and c.cs_ranges: # case we want a simple diff without incoming changesets, just # for review purposes. Make the diff on the forked repo, with # revision that is common ancestor other_ref = ('rev', c.cs_ranges[-1].parents[0].raw_id) other_repo = org_repo - c.org_ref = org_ref[1] - c.other_ref = other_ref[1] + diff_limit = self.cut_off_limit if not fulldiff else None + _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref, + discovery_data, remote_compare=remote_compare) - _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref, - discovery_data, bundle_compare=bundle_compare) - diff_limit = self.cut_off_limit if not fulldiff else None - diff_processor = diffs.DiffProcessor(_diff, format='gitdiff', + diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff', diff_limit=diff_limit) _parsed = diff_processor.prepare() @@ -151,8 +152,13 @@ class CompareController(BaseRepoControll c.files = [] c.changes = {} - + c.lines_added = 0 + c.lines_deleted = 0 for f in _parsed: + st = f['stats'] + if st[0] != 'b': + c.lines_added += st[0] + c.lines_deleted += st[1] fid = h.FID('', f['filename']) c.files.append([fid, f['operation'], f['filename'], f['stats']]) diff = diff_processor.as_html(enable_comments=False, parsed_lines=[f]) diff --git a/rhodecode/controllers/pullrequests.py b/rhodecode/controllers/pullrequests.py --- a/rhodecode/controllers/pullrequests.py +++ b/rhodecode/controllers/pullrequests.py @@ -51,6 +51,7 @@ from rhodecode.model.comment import Chan from rhodecode.model.changeset_status import ChangesetStatusModel from rhodecode.model.forms import PullRequestForm from rhodecode.lib.vcs.exceptions import EmptyRepositoryError +from rhodecode.lib.vcs.backends.base import EmptyChangeset log = logging.getLogger(__name__) @@ -277,7 +278,9 @@ class PullrequestsController(BaseRepoCon # case we want a simple diff without incoming changesets, just # for review purposes. Make the diff on the forked repo, with # revision that is common ancestor - other_ref = ('rev', c.cs_ranges[-1].parents[0].raw_id) + other_ref = ('rev', getattr(c.cs_ranges[-1].parents[0] + if c.cs_ranges[-1].parents + else EmptyChangeset(), 'raw_id')) other_repo = org_repo c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges]) @@ -286,9 +289,9 @@ class PullrequestsController(BaseRepoCon c.org_ref = org_ref[1] c.other_ref = other_ref[1] - # diff needs to have swapped org with other to generate proper diff - _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref, + _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref, discovery_data) + diff_processor = diffs.DiffProcessor(_diff, format='gitdiff') _parsed = diff_processor.prepare() diff --git a/rhodecode/lib/diffs.py b/rhodecode/lib/diffs.py --- a/rhodecode/lib/diffs.py +++ b/rhodecode/lib/diffs.py @@ -702,52 +702,48 @@ class InMemoryBundleRepo(bundlerepositor def differ(org_repo, org_ref, other_repo, other_ref, discovery_data=None, - bundle_compare=False, context=3, ignore_whitespace=False): + remote_compare=False, context=3, ignore_whitespace=False): """ - General differ between branches, bookmarks, revisions of two remote related - repositories + General differ between branches, bookmarks, revisions of two remote or + local but related repositories :param org_repo: - :type org_repo: :param org_ref: - :type org_ref: :param other_repo: :type other_repo: - :param other_ref: :type other_ref: """ - bundlerepo = None - ignore_whitespace = ignore_whitespace - context = context org_repo_scm = org_repo.scm_instance + other_repo_scm = other_repo.scm_instance + org_repo = org_repo_scm._repo - other_repo = other_repo.scm_instance._repo - opts = diffopts(git=True, ignorews=ignore_whitespace, context=context) + other_repo = other_repo_scm._repo + org_ref = org_ref[1] other_ref = other_ref[1] if org_repo == other_repo: log.debug('running diff between %s@%s and %s@%s' % (org_repo, org_ref, other_repo, other_ref)) - _diff = org_repo_scm.get_diff(rev1=other_ref, rev2=org_ref, + _diff = org_repo_scm.get_diff(rev1=org_ref, rev2=other_ref, ignore_whitespace=ignore_whitespace, context=context) return _diff - elif bundle_compare: - + elif remote_compare: + opts = diffopts(git=True, ignorews=ignore_whitespace, context=context) common, incoming, rheads = discovery_data - other_repo_peer = localrepo.locallegacypeer(other_repo.local()) + org_repo_peer = localrepo.locallegacypeer(org_repo.local()) # create a bundle (uncompressed if other repo is not local) - if other_repo_peer.capable('getbundle') and incoming: + if org_repo_peer.capable('getbundle'): # disable repo hooks here since it's just bundle ! # patch and reset hooks section of UI config to not run any # hooks on fetching archives with subrepos - for k, _ in other_repo.ui.configitems('hooks'): - other_repo.ui.setconfig('hooks', k, None) + for k, _ in org_repo.ui.configitems('hooks'): + org_repo.ui.setconfig('hooks', k, None) - unbundle = other_repo.getbundle('incoming', common=common, - heads=None) + unbundle = org_repo.getbundle('incoming', common=common, + heads=None) buf = BytesIO() while True: @@ -764,8 +760,9 @@ def differ(org_repo, org_ref, other_repo bundlerepo = InMemoryBundleRepo(ui, path=org_repo.root, bundlestream=unbundle) - return ''.join(patch.diff(bundlerepo or org_repo, - node1=org_repo[org_ref].node(), - node2=other_repo[other_ref].node(), - opts=opts)) + return ''.join(patch.diff(bundlerepo, + node1=other_repo[other_ref].node(), + node2=org_repo[org_ref].node(), + opts=opts)) + return '' \ No newline at end of file diff --git a/rhodecode/model/pull_request.py b/rhodecode/model/pull_request.py --- a/rhodecode/model/pull_request.py +++ b/rhodecode/model/pull_request.py @@ -185,21 +185,21 @@ class PullRequestModel(BaseModel): revs = [ "ancestors(%s('%s')) and not ancestors(%s('%s'))" % ( + _revset_predicates[other_ref[0]], other_ref[1], _revset_predicates[org_ref[0]], org_ref[1], - _revset_predicates[other_ref[0]], other_ref[1] ) ] out = scmutil.revrange(org_repo._repo, revs) - for cs in reversed(out): + for cs in (out): changesets.append(org_repo.get_changeset(cs)) elif alias == 'git': so, se = org_repo.run_git_command( - 'log --pretty="format: %%H" -s -p %s..%s' % (org_ref[1], + 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1], other_ref[1]) ) ids = re.findall(r'[0-9a-fA-F]{40}', so) - for cs in reversed(ids): + for cs in (ids): changesets.append(org_repo.get_changeset(cs)) return changesets diff --git a/rhodecode/templates/changeset/changeset_range.html b/rhodecode/templates/changeset/changeset_range.html --- a/rhodecode/templates/changeset/changeset_range.html +++ b/rhodecode/templates/changeset/changeset_range.html @@ -26,7 +26,7 @@
-

${_('Compare View')}

+

${_('Compare View')} / ${h.link_to(_('Show combined compare'),h.url('compare_url',repo_name=c.repo_name,org_ref_type='rev',org_ref=getattr(c.cs_ranges[0].parents[0] if c.cs_ranges[0].parents else h.EmptyChangeset(),'raw_id'),other_ref_type='rev',other_ref=c.cs_ranges[-1].raw_id))}

${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
diff --git a/rhodecode/templates/compare/compare_cs.html b/rhodecode/templates/compare/compare_cs.html --- a/rhodecode/templates/compare/compare_cs.html +++ b/rhodecode/templates/compare/compare_cs.html @@ -2,7 +2,7 @@
%if not c.cs_ranges: - + ${_('No changesets')} %else: %for cnt, cs in enumerate(c.cs_ranges): diff --git a/rhodecode/templates/compare/compare_diff.html b/rhodecode/templates/compare/compare_diff.html --- a/rhodecode/templates/compare/compare_diff.html +++ b/rhodecode/templates/compare/compare_diff.html @@ -34,12 +34,23 @@
##CS -
${_('Outgoing changesets')}
+
${ungettext('Showing %s commit','Showing %s commits', len(c.cs_ranges)) % len(c.cs_ranges)}
<%include file="compare_cs.html" /> ## FILES -
${_('Files affected')}
+
+ + % if c.limited_diff: + ${ungettext('%s file changed', '%s files changed', len(c.files)) % len(c.files)} + % else: + ${ungettext('%s file changed with %s insertions and %s deletions','%s files changed with %s insertions and %s deletions', len(c.files)) % (len(c.files),c.lines_added,c.lines_deleted)}: + %endif + +
+ %if not c.files: + ${_('No files')} + %endif %for fid, change, f, stat in c.files:
${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}
diff --git a/rhodecode/tests/functional/test_compare.py b/rhodecode/tests/functional/test_compare.py --- a/rhodecode/tests/functional/test_compare.py +++ b/rhodecode/tests/functional/test_compare.py @@ -8,10 +8,10 @@ from rhodecode.lib.vcs.backends.base imp class TestCompareController(TestController): - def test_index_tag(self): + def test_compare_tag_hg(self): self.log_user() - tag1 = '0.1.3' - tag2 = '0.1.2' + tag1 = '0.1.2' + tag2 = '0.1.3' response = self.app.get(url(controller='compare', action='index', repo_name=HG_REPO, org_ref_type="tag", @@ -21,13 +21,13 @@ class TestCompareController(TestControll )) response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, tag1, HG_REPO, tag2)) ## outgoing changesets between tags - response.mustcontain('''r120:17544fbfcd33''' % HG_REPO) - response.mustcontain('''r119:36e0fc9d2808''' % HG_REPO) - response.mustcontain('''r118:bb1a3ab98cc4''' % HG_REPO) + response.mustcontain('''r112:c5ddebc06eaa''' % HG_REPO) + response.mustcontain('''r115:70d4cef8a376''' % HG_REPO) + response.mustcontain('''r116:9749bfbfc0d2''' % HG_REPO) response.mustcontain('''r117:41fda979f02f''' % HG_REPO) - response.mustcontain('''r116:9749bfbfc0d2''' % HG_REPO) - response.mustcontain('''r115:70d4cef8a376''' % HG_REPO) - response.mustcontain('''r112:c5ddebc06eaa''' % HG_REPO) + response.mustcontain('''r118:bb1a3ab98cc4''' % HG_REPO) + response.mustcontain('''r119:36e0fc9d2808''' % HG_REPO) + response.mustcontain('''r120:17544fbfcd33''' % HG_REPO) ## files diff response.mustcontain('''''' % (HG_REPO, tag1, tag2)) @@ -42,7 +42,43 @@ class TestCompareController(TestControll response.mustcontain('''''' % (HG_REPO, tag1, tag2)) response.mustcontain('''''' % (HG_REPO, tag1, tag2)) - def test_index_branch(self): + def test_compare_tag_git(self): + self.log_user() + tag1 = 'v0.1.2' + tag2 = 'v0.1.3' + response = self.app.get(url(controller='compare', action='index', + repo_name=GIT_REPO, + org_ref_type="tag", + org_ref=tag1, + other_ref_type="tag", + other_ref=tag2, + bundle=False + )) + response.mustcontain('%s@%s -> %s@%s' % (GIT_REPO, tag1, GIT_REPO, tag2)) + + ## outgoing changesets between tags + response.mustcontain('''r113:794bbdd31545''' % GIT_REPO) + response.mustcontain('''r115:e36d8c502532''' % GIT_REPO) + response.mustcontain('''r116:5c9ff4f6d750''' % GIT_REPO) + response.mustcontain('''r117:b7187fa2b8c1''' % GIT_REPO) + response.mustcontain('''r118:5f3b74262014''' % GIT_REPO) + response.mustcontain('''r119:17438a11f72b''' % GIT_REPO) + response.mustcontain('''r120:5a3a8fb00555''' % GIT_REPO) + + #files + response.mustcontain('''docs/api/utils/index.rst''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''test_and_report.sh''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''.hgignore''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''.hgtags''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''docs/api/index.rst''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''vcs/__init__.py''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''vcs/backends/hg.py''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''vcs/utils/__init__.py''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''vcs/utils/annotate.py''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''vcs/utils/diffs.py''' % (GIT_REPO, tag1, tag2)) + response.mustcontain('''vcs/utils/lazy.py''' % (GIT_REPO, tag1, tag2)) + + def test_index_branch_hg(self): self.log_user() response = self.app.get(url(controller='compare', action='index', repo_name=HG_REPO, @@ -54,12 +90,29 @@ class TestCompareController(TestControll response.mustcontain('%s@default -> %s@default' % (HG_REPO, HG_REPO)) # branch are equal - response.mustcontain('
') + response.mustcontain('No files') + response.mustcontain('No changesets') + + def test_index_branch_git(self): + self.log_user() + response = self.app.get(url(controller='compare', action='index', + repo_name=GIT_REPO, + org_ref_type="branch", + org_ref='master', + other_ref_type="branch", + other_ref='master', + )) + + response.mustcontain('%s@master -> %s@master' % (GIT_REPO, GIT_REPO)) + # branch are equal + response.mustcontain('No files') + response.mustcontain('No changesets') def test_compare_revisions(self): self.log_user() - rev1 = '3d8f361e72ab' - rev2 = 'b986218ba1c9' + rev1 = 'b986218ba1c9' + rev2 = '3d8f361e72ab' + response = self.app.get(url(controller='compare', action='index', repo_name=HG_REPO, org_ref_type="rev", @@ -69,8 +122,7 @@ class TestCompareController(TestControll )) response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_REPO, rev2)) ## outgoing changesets between those revisions - response.mustcontain("""r1:%s""" % (HG_REPO, rev1)) - + response.mustcontain("""r1:%s""" % (HG_REPO, rev2)) ## files response.mustcontain(""".hgignore""" % (HG_REPO, rev1, rev2)) @@ -93,8 +145,54 @@ class TestCompareController(TestControll Session().commit() - rev1 = '7d4bc8ec6be5' - rev2 = '56349e29c2af' + rev1 = '56349e29c2af' + rev2 = '7d4bc8ec6be5' + + response = self.app.get(url(controller='compare', action='index', + repo_name=HG_REPO, + org_ref_type="rev", + org_ref=rev1, + other_ref_type="rev", + other_ref=rev2, + repo=HG_FORK, + )) + + try: + response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_FORK, rev2)) + ## outgoing changesets between those revisions + + response.mustcontain("""r4:2dda4e345fac""" % (HG_REPO)) + response.mustcontain("""r5:6fff84722075""" % (HG_REPO)) + response.mustcontain("""r6:%s""" % (HG_REPO, rev2)) + + ## files + response.mustcontain("""vcs/backends/hg.py""" % (HG_REPO, rev1, rev2)) + response.mustcontain("""vcs/backends/__init__.py""" % (HG_REPO, rev1, rev2)) + response.mustcontain("""vcs/backends/base.py""" % (HG_REPO, rev1, rev2)) + finally: + RepoModel().delete(HG_FORK) + + def test_compare_remote_repos_remote_flag_off(self): + self.log_user() + + form_data = dict( + repo_name=HG_FORK, + repo_name_full=HG_FORK, + repo_group=None, + repo_type='hg', + description='', + private=False, + copy_permissions=False, + landing_rev='tip', + update_after_clone=False, + fork_parent_id=Repository.get_by_repo_name(HG_REPO), + ) + RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN) + + Session().commit() + + rev1 = '56349e29c2af' + rev2 = '7d4bc8ec6be5' response = self.app.get(url(controller='compare', action='index', repo_name=HG_REPO, @@ -102,16 +200,17 @@ class TestCompareController(TestControll org_ref=rev1, other_ref_type="rev", other_ref=rev2, - repo=HG_FORK + repo=HG_FORK, + bundle=False, )) try: response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_FORK, rev2)) ## outgoing changesets between those revisions - response.mustcontain("""r6:%s""" % (HG_REPO, rev1)) + response.mustcontain("""r4:2dda4e345fac""" % (HG_REPO)) response.mustcontain("""r5:6fff84722075""" % (HG_REPO)) - response.mustcontain("""r4:2dda4e345fac""" % (HG_REPO)) + response.mustcontain("""r6:%s""" % (HG_REPO, rev2)) ## files response.mustcontain("""vcs/backends/hg.py""" % (HG_REPO, rev1, rev2)) @@ -120,6 +219,67 @@ class TestCompareController(TestControll finally: RepoModel().delete(HG_FORK) +# def test_compare_origin_ahead_of_fork(self): +# self.log_user() +# +# form_data = dict( +# repo_name=HG_FORK, +# repo_name_full=HG_FORK, +# repo_group=None, +# repo_type='hg', +# description='', +# private=False, +# copy_permissions=False, +# landing_rev='tip', +# update_after_clone=False, +# fork_parent_id=Repository.get_by_repo_name(HG_REPO), +# ) +# RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN) +# +# Session().commit() +# +# repo1 = Repository.get_by_repo_name(HG_REPO) +# r1_name = HG_REPO +# +# #commit something ! +# cs0 = ScmModel().create_node( +# repo=repo1.scm_instance, repo_name=r1_name, +# cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN, +# author=TEST_USER_ADMIN_LOGIN, +# message='extra commit1', +# content='line1', +# f_path='file1' +# ) +# +# +# rev1 = '56349e29c2af' +# rev2 = '7d4bc8ec6be5' +# +# response = self.app.get(url(controller='compare', action='index', +# repo_name=HG_REPO, +# org_ref_type="rev", +# org_ref=rev1, +# other_ref_type="rev", +# other_ref=rev2, +# repo=HG_FORK, +# bundle=False, +# )) +# +# try: +# response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_REPO, rev2)) +# ## outgoing changesets between those revisions +# +# response.mustcontain("""r4:2dda4e345fac""" % (HG_REPO)) +# response.mustcontain("""r5:6fff84722075""" % (HG_REPO)) +# response.mustcontain("""r6:%s""" % (HG_REPO, rev2)) +# +# ## files +# response.mustcontain("""vcs/backends/hg.py""" % (HG_REPO, rev1, rev2)) +# response.mustcontain("""vcs/backends/__init__.py""" % (HG_REPO, rev1, rev2)) +# response.mustcontain("""vcs/backends/base.py""" % (HG_REPO, rev1, rev2)) +# finally: +# RepoModel().delete(HG_FORK) + def test_compare_extra_commits(self): self.log_user() @@ -178,7 +338,7 @@ class TestCompareController(TestControll try: response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2)) - response.mustcontain("""
commit2
""") + response.mustcontain("""
commit2
""") response.mustcontain("""r1:%s""" % (r2_name, cs1.raw_id, cs1.short_id)) ## files response.mustcontain("""file1""" % (r2_name, rev1, rev2)) @@ -391,7 +551,7 @@ class TestCompareController(TestControll repo=r1_name, bundle=False )) - rev2 = cs0.parents[0].raw_id + response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2)) response.mustcontain("""file1-line1-from-fork""") response.mustcontain("""file2-line1-from-fork""")
${_('No changesets')}
No changesets