Show More
@@ -40,7 +40,7 b' from rhodecode.lib.vcs.nodes import File' | |||
|
40 | 40 | import rhodecode.lib.helpers as h |
|
41 | 41 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
42 | 42 | from rhodecode.lib.base import BaseRepoController, render |
|
43 |
from rhodecode.lib.utils import |
|
|
43 | from rhodecode.lib.utils import action_logger | |
|
44 | 44 | from rhodecode.lib.compat import OrderedDict |
|
45 | 45 | from rhodecode.lib import diffs |
|
46 | 46 | from rhodecode.model.db import ChangesetComment, ChangesetStatus |
@@ -50,6 +50,7 b' from rhodecode.model.meta import Session' | |||
|
50 | 50 | from rhodecode.lib.diffs import wrapped_diff |
|
51 | 51 | from rhodecode.model.repo import RepoModel |
|
52 | 52 | from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError |
|
53 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
53 | 54 | |
|
54 | 55 | log = logging.getLogger(__name__) |
|
55 | 56 |
@@ -71,6 +71,7 b' class CompareController(BaseRepoControll' | |||
|
71 | 71 | redirect(url('summary_home', repo_name=repo.repo_name)) |
|
72 | 72 | |
|
73 | 73 | except RepositoryError, e: |
|
74 | log.error(traceback.format_exc()) | |
|
74 | 75 | h.flash(str(e), category='warning') |
|
75 | 76 | redirect(h.url('summary_home', repo_name=repo.repo_name)) |
|
76 | 77 |
@@ -40,7 +40,7 b' from rhodecode.lib.compat import Ordered' | |||
|
40 | 40 | from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str |
|
41 | 41 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
42 | 42 | from rhodecode.lib.base import BaseRepoController, render |
|
43 |
from rhodecode.lib. |
|
|
43 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
44 | 44 | from rhodecode.lib.vcs.conf import settings |
|
45 | 45 | from rhodecode.lib.vcs.exceptions import RepositoryError, \ |
|
46 | 46 | ChangesetDoesNotExistError, EmptyRepositoryError, \ |
@@ -45,7 +45,7 b' from rhodecode.model.db import Statistic' | |||
|
45 | 45 | from rhodecode.lib.utils2 import safe_unicode |
|
46 | 46 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
47 | 47 | from rhodecode.lib.base import BaseRepoController, render |
|
48 |
from rhodecode.lib. |
|
|
48 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
49 | 49 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
50 | 50 | from rhodecode.lib.celerylib import run_task |
|
51 | 51 | from rhodecode.lib.celerylib.tasks import get_commits_stats |
@@ -34,15 +34,16 b' from itertools import tee, imap' | |||
|
34 | 34 | from mercurial import patch |
|
35 | 35 | from mercurial.mdiff import diffopts |
|
36 | 36 | from mercurial.bundlerepo import bundlerepository |
|
37 | from mercurial import localrepo | |
|
38 | 37 | |
|
39 | 38 | from pylons.i18n.translation import _ |
|
40 | 39 | |
|
41 | 40 | from rhodecode.lib.compat import BytesIO |
|
41 | from rhodecode.lib.vcs.utils.hgcompat import localrepo | |
|
42 | 42 | from rhodecode.lib.vcs.exceptions import VCSError |
|
43 | 43 | from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode |
|
44 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
44 | 45 | from rhodecode.lib.helpers import escape |
|
45 |
from rhodecode.lib.utils import |
|
|
46 | from rhodecode.lib.utils import make_ui | |
|
46 | 47 | |
|
47 | 48 | |
|
48 | 49 | def wrap_to_table(str_): |
@@ -599,9 +600,9 b' def differ(org_repo, org_ref, other_repo' | |||
|
599 | 600 | if org_repo != other_repo: |
|
600 | 601 | |
|
601 | 602 | common, incoming, rheads = discovery_data |
|
602 | ||
|
603 | other_repo_peer = localrepo.locallegacypeer(other_repo.local()) | |
|
603 | 604 | # create a bundle (uncompressed if other repo is not local) |
|
604 | if other_repo.capable('getbundle') and incoming: | |
|
605 | if other_repo_peer.capable('getbundle') and incoming: | |
|
605 | 606 | # disable repo hooks here since it's just bundle ! |
|
606 | 607 | # patch and reset hooks section of UI config to not run any |
|
607 | 608 | # hooks on fetching archives with subrepos |
@@ -346,50 +346,6 b' def invalidate_cache(cache_key, *args):' | |||
|
346 | 346 | ScmModel().mark_for_invalidation(name) |
|
347 | 347 | |
|
348 | 348 | |
|
349 | class EmptyChangeset(BaseChangeset): | |
|
350 | """ | |
|
351 | An dummy empty changeset. It's possible to pass hash when creating | |
|
352 | an EmptyChangeset | |
|
353 | """ | |
|
354 | ||
|
355 | def __init__(self, cs='0' * 40, repo=None, requested_revision=None, | |
|
356 | alias=None): | |
|
357 | self._empty_cs = cs | |
|
358 | self.revision = -1 | |
|
359 | self.message = '' | |
|
360 | self.author = '' | |
|
361 | self.date = '' | |
|
362 | self.repository = repo | |
|
363 | self.requested_revision = requested_revision | |
|
364 | self.alias = alias | |
|
365 | ||
|
366 | @LazyProperty | |
|
367 | def raw_id(self): | |
|
368 | """ | |
|
369 | Returns raw string identifying this changeset, useful for web | |
|
370 | representation. | |
|
371 | """ | |
|
372 | ||
|
373 | return self._empty_cs | |
|
374 | ||
|
375 | @LazyProperty | |
|
376 | def branch(self): | |
|
377 | return get_backend(self.alias).DEFAULT_BRANCH_NAME | |
|
378 | ||
|
379 | @LazyProperty | |
|
380 | def short_id(self): | |
|
381 | return self.raw_id[:12] | |
|
382 | ||
|
383 | def get_file_changeset(self, path): | |
|
384 | return self | |
|
385 | ||
|
386 | def get_file_content(self, path): | |
|
387 | return u'' | |
|
388 | ||
|
389 | def get_file_size(self, path): | |
|
390 | return 0 | |
|
391 | ||
|
392 | ||
|
393 | 349 | def map_groups(path): |
|
394 | 350 | """ |
|
395 | 351 | Given a full path to a repository, create all nested groups that this |
@@ -417,6 +417,7 b' def get_changeset_safe(repo, rev):' | |||
|
417 | 417 | """ |
|
418 | 418 | from rhodecode.lib.vcs.backends.base import BaseRepository |
|
419 | 419 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
420 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
420 | 421 | if not isinstance(repo, BaseRepository): |
|
421 | 422 | raise Exception('You must pass an Repository ' |
|
422 | 423 | 'object as first argument got %s', type(repo)) |
@@ -424,7 +425,6 b' def get_changeset_safe(repo, rev):' | |||
|
424 | 425 | try: |
|
425 | 426 | cs = repo.get_changeset(rev) |
|
426 | 427 | except RepositoryError: |
|
427 | from rhodecode.lib.utils import EmptyChangeset | |
|
428 | 428 | cs = EmptyChangeset(requested_revision=rev) |
|
429 | 429 | return cs |
|
430 | 430 |
@@ -13,3 +13,5 b' from mercurial.mdiff import diffopts' | |||
|
13 | 13 | from mercurial.node import hex |
|
14 | 14 | from mercurial.encoding import tolocal |
|
15 | 15 | from mercurial import discovery |
|
16 | from mercurial import localrepo | |
|
17 | from mercurial import scmutil No newline at end of file |
@@ -36,7 +36,7 b' from rhodecode.model.db import PullReque' | |||
|
36 | 36 | from rhodecode.model.notification import NotificationModel |
|
37 | 37 | from rhodecode.lib.utils2 import safe_unicode |
|
38 | 38 | |
|
39 | from rhodecode.lib.vcs.utils.hgcompat import discovery | |
|
39 | from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil | |
|
40 | 40 | |
|
41 | 41 | log = logging.getLogger(__name__) |
|
42 | 42 | |
@@ -150,13 +150,9 b' class PullRequestModel(BaseModel):' | |||
|
150 | 150 | """ |
|
151 | 151 | changesets = [] |
|
152 | 152 | #case two independent repos |
|
153 | if org_repo != other_repo: | |
|
154 | common, incoming, rheads = discovery_data | |
|
155 | ||
|
156 | if not incoming: | |
|
157 | revs = [] | |
|
158 | else: | |
|
159 | revs = org_repo._repo.changelog.findmissing(common, rheads) | |
|
153 | common, incoming, rheads = discovery_data | |
|
154 | if org_repo != other_repo and incoming: | |
|
155 | revs = org_repo._repo.changelog.findmissing(common, rheads) | |
|
160 | 156 | |
|
161 | 157 | for cs in reversed(map(binascii.hexlify, revs)): |
|
162 | 158 | changesets.append(org_repo.get_changeset(cs)) |
@@ -175,7 +171,6 b' class PullRequestModel(BaseModel):' | |||
|
175 | 171 | ) |
|
176 | 172 | ] |
|
177 | 173 | |
|
178 | from mercurial import scmutil | |
|
179 | 174 | out = scmutil.revrange(org_repo._repo, revs) |
|
180 | 175 | for cs in reversed(out): |
|
181 | 176 | changesets.append(org_repo.get_changeset(cs)) |
@@ -197,17 +192,22 b' class PullRequestModel(BaseModel):' | |||
|
197 | 192 | :type other_ref: |
|
198 | 193 | """ |
|
199 | 194 | |
|
200 |
o |
|
|
201 | repo = other_repo._repo | |
|
202 | tip = other[org_ref[1]] | |
|
195 | _org_repo = org_repo._repo | |
|
196 | org_rev_type, org_rev = org_ref | |
|
197 | ||
|
198 | _other_repo = other_repo._repo | |
|
199 | other_rev_type, other_rev = other_ref | |
|
200 | ||
|
203 | 201 | log.debug('Doing discovery for %s@%s vs %s@%s' % ( |
|
204 | 202 | org_repo, org_ref, other_repo, other_ref) |
|
205 | 203 | ) |
|
206 |
log.debug('Filter heads are %s[%s]' % ( |
|
|
204 | #log.debug('Filter heads are %s[%s]' % ('', org_ref[1])) | |
|
205 | org_peer = localrepo.locallegacypeer(_org_repo.local()) | |
|
207 | 206 | tmp = discovery.findcommonincoming( |
|
208 | repo=repo, # other_repo we check for incoming | |
|
209 |
remote=o |
|
|
210 |
heads=[ |
|
|
207 | repo=_other_repo, # other_repo we check for incoming | |
|
208 | remote=org_peer, # org_repo source for incoming | |
|
209 | heads=[_other_repo[other_rev].node(), | |
|
210 | _org_repo[org_rev].node()], | |
|
211 | 211 | force=False |
|
212 | 212 | ) |
|
213 | 213 | return tmp |
@@ -237,8 +237,9 b' class PullRequestModel(BaseModel):' | |||
|
237 | 237 | other_repo.scm_instance, |
|
238 | 238 | other_ref) |
|
239 | 239 | cs_ranges = self._get_changesets(org_repo.scm_instance, |
|
240 |
|
|
|
241 |
|
|
|
242 |
|
|
|
243 |
|
|
|
240 | org_ref, | |
|
241 | other_repo.scm_instance, | |
|
242 | other_ref, | |
|
243 | discovery_data) | |
|
244 | ||
|
244 | 245 | return cs_ranges, discovery_data |
@@ -40,13 +40,14 b' from rhodecode.lib.vcs import get_backen' | |||
|
40 | 40 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
41 | 41 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
42 | 42 | from rhodecode.lib.vcs.nodes import FileNode |
|
43 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
43 | 44 | |
|
44 | 45 | from rhodecode import BACKENDS |
|
45 | 46 | from rhodecode.lib import helpers as h |
|
46 | 47 | from rhodecode.lib.utils2 import safe_str, safe_unicode |
|
47 | 48 | from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny |
|
48 | 49 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ |
|
49 |
action_logger, |
|
|
50 | action_logger, REMOVED_REPO_PAT | |
|
50 | 51 | from rhodecode.model import BaseModel |
|
51 | 52 | from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \ |
|
52 | 53 | UserFollowing, UserLog, User, RepoGroup, PullRequest |
@@ -414,6 +415,12 b' class ScmModel(BaseModel):' | |||
|
414 | 415 | |
|
415 | 416 | def commit_change(self, repo, repo_name, cs, user, author, message, |
|
416 | 417 | content, f_path): |
|
418 | """ | |
|
419 | Commits changes | |
|
420 | ||
|
421 | :param repo: SCM instance | |
|
422 | ||
|
423 | """ | |
|
417 | 424 | |
|
418 | 425 | if repo.alias == 'hg': |
|
419 | 426 | from rhodecode.lib.vcs.backends.hg import \ |
@@ -439,6 +446,7 b' class ScmModel(BaseModel):' | |||
|
439 | 446 | action = 'push_local:%s' % tip.raw_id |
|
440 | 447 | action_logger(user, action, repo_name) |
|
441 | 448 | self.mark_for_invalidation(repo_name) |
|
449 | return tip | |
|
442 | 450 | |
|
443 | 451 | def create_node(self, repo, repo_name, cs, user, author, message, content, |
|
444 | 452 | f_path): |
@@ -477,6 +485,7 b' class ScmModel(BaseModel):' | |||
|
477 | 485 | action = 'push_local:%s' % tip.raw_id |
|
478 | 486 | action_logger(user, action, repo_name) |
|
479 | 487 | self.mark_for_invalidation(repo_name) |
|
488 | return tip | |
|
480 | 489 | |
|
481 | 490 | def get_nodes(self, repo_name, revision, root_path='/', flat=True): |
|
482 | 491 | """ |
@@ -1,12 +1,17 b'' | |||
|
1 | 1 | from rhodecode.tests import * |
|
2 | from rhodecode.model.repo import RepoModel | |
|
3 | from rhodecode.model.meta import Session | |
|
4 | from rhodecode.model.db import Repository | |
|
5 | from rhodecode.model.scm import ScmModel | |
|
6 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
|
2 | 7 | |
|
3 | 8 | |
|
4 | 9 | class TestCompareController(TestController): |
|
5 | 10 | |
|
6 | 11 | def test_index_tag(self): |
|
7 | 12 | self.log_user() |
|
8 | tag1='0.1.3' | |
|
9 | tag2='0.1.2' | |
|
13 | tag1 = '0.1.3' | |
|
14 | tag2 = '0.1.2' | |
|
10 | 15 | response = self.app.get(url(controller='compare', action='index', |
|
11 | 16 | repo_name=HG_REPO, |
|
12 | 17 | org_ref_type="tag", |
@@ -50,3 +55,135 b' class TestCompareController(TestControll' | |||
|
50 | 55 | response.mustcontain('%s@default -> %s@default' % (HG_REPO, HG_REPO)) |
|
51 | 56 | # branch are equal |
|
52 | 57 | response.mustcontain('<tr><td>No changesets</td></tr>') |
|
58 | ||
|
59 | def test_compare_revisions(self): | |
|
60 | self.log_user() | |
|
61 | rev1 = '3d8f361e72ab' | |
|
62 | rev2 = 'b986218ba1c9' | |
|
63 | response = self.app.get(url(controller='compare', action='index', | |
|
64 | repo_name=HG_REPO, | |
|
65 | org_ref_type="rev", | |
|
66 | org_ref=rev1, | |
|
67 | other_ref_type="rev", | |
|
68 | other_ref=rev2, | |
|
69 | )) | |
|
70 | response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_REPO, rev2)) | |
|
71 | ## outgoing changesets between those revisions | |
|
72 | response.mustcontain("""<a href="/%s/changeset/3d8f361e72ab303da48d799ff1ac40d5ac37c67e">r1:%s</a>""" % (HG_REPO, rev1)) | |
|
73 | ||
|
74 | ## files | |
|
75 | response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--c8e92ef85cd1">.hgignore</a>""" % (HG_REPO, rev1, rev2)) | |
|
76 | ||
|
77 | def test_compare_remote_repos(self): | |
|
78 | self.log_user() | |
|
79 | ||
|
80 | form_data = dict( | |
|
81 | repo_name=HG_FORK, | |
|
82 | repo_name_full=HG_FORK, | |
|
83 | repo_group=None, | |
|
84 | repo_type='hg', | |
|
85 | description='', | |
|
86 | private=False, | |
|
87 | copy_permissions=False, | |
|
88 | landing_rev='tip', | |
|
89 | update_after_clone=False, | |
|
90 | fork_parent_id=Repository.get_by_repo_name(HG_REPO), | |
|
91 | ) | |
|
92 | RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN) | |
|
93 | ||
|
94 | Session().commit() | |
|
95 | ||
|
96 | rev1 = '7d4bc8ec6be5' | |
|
97 | rev2 = '56349e29c2af' | |
|
98 | ||
|
99 | response = self.app.get(url(controller='compare', action='index', | |
|
100 | repo_name=HG_REPO, | |
|
101 | org_ref_type="rev", | |
|
102 | org_ref=rev1, | |
|
103 | other_ref_type="rev", | |
|
104 | other_ref=rev2, | |
|
105 | repo=HG_FORK | |
|
106 | )) | |
|
107 | ||
|
108 | try: | |
|
109 | response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_FORK, rev2)) | |
|
110 | ## outgoing changesets between those revisions | |
|
111 | ||
|
112 | response.mustcontain("""<a href="/%s/changeset/7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7">r6:%s</a>""" % (HG_REPO, rev1)) | |
|
113 | response.mustcontain("""<a href="/%s/changeset/6fff84722075f1607a30f436523403845f84cd9e">r5:6fff84722075</a>""" % (HG_REPO)) | |
|
114 | response.mustcontain("""<a href="/%s/changeset/2dda4e345facb0ccff1a191052dd1606dba6781d">r4:2dda4e345fac</a>""" % (HG_REPO)) | |
|
115 | ||
|
116 | ## files | |
|
117 | response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2)) | |
|
118 | response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2)) | |
|
119 | response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2)) | |
|
120 | finally: | |
|
121 | RepoModel().delete(HG_FORK) | |
|
122 | ||
|
123 | def test_compare_extra_commits(self): | |
|
124 | self.log_user() | |
|
125 | ||
|
126 | repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg', | |
|
127 | description='diff-test', | |
|
128 | owner=TEST_USER_ADMIN_LOGIN) | |
|
129 | ||
|
130 | repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg', | |
|
131 | description='diff-test', | |
|
132 | owner=TEST_USER_ADMIN_LOGIN) | |
|
133 | ||
|
134 | Session().commit() | |
|
135 | r1_id = repo1.repo_id | |
|
136 | r1_name = repo1.repo_name | |
|
137 | r2_id = repo2.repo_id | |
|
138 | r2_name = repo2.repo_name | |
|
139 | ||
|
140 | #commit something ! | |
|
141 | cs0 = ScmModel().create_node( | |
|
142 | repo=repo1.scm_instance, repo_name=r1_name, | |
|
143 | cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN, | |
|
144 | author=TEST_USER_ADMIN_LOGIN, | |
|
145 | message='commit1', | |
|
146 | content='line1', | |
|
147 | f_path='file1' | |
|
148 | ) | |
|
149 | ||
|
150 | cs0_prim = ScmModel().create_node( | |
|
151 | repo=repo2.scm_instance, repo_name=r2_name, | |
|
152 | cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN, | |
|
153 | author=TEST_USER_ADMIN_LOGIN, | |
|
154 | message='commit1', | |
|
155 | content='line1', | |
|
156 | f_path='file1' | |
|
157 | ) | |
|
158 | ||
|
159 | cs1 = ScmModel().commit_change( | |
|
160 | repo=repo2.scm_instance, repo_name=r2_name, | |
|
161 | cs=cs0_prim, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN, | |
|
162 | message='commit2', | |
|
163 | content='line1\nline2', | |
|
164 | f_path='file1' | |
|
165 | ) | |
|
166 | ||
|
167 | rev1 = 'default' | |
|
168 | rev2 = 'default' | |
|
169 | response = self.app.get(url(controller='compare', action='index', | |
|
170 | repo_name=r2_name, | |
|
171 | org_ref_type="branch", | |
|
172 | org_ref=rev1, | |
|
173 | other_ref_type="branch", | |
|
174 | other_ref=rev2, | |
|
175 | repo=r1_name | |
|
176 | )) | |
|
177 | ||
|
178 | try: | |
|
179 | response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2)) | |
|
180 | ||
|
181 | response.mustcontain("""<div class="message">commit2</div>""") | |
|
182 | response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (r2_name, cs1.raw_id, cs1.short_id)) | |
|
183 | ## files | |
|
184 | response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2)) | |
|
185 | ||
|
186 | ||
|
187 | finally: | |
|
188 | RepoModel().delete(r1_id) | |
|
189 | RepoModel().delete(r2_id) |
General Comments 0
You need to be logged in to leave comments.
Login now