shadow-repos: use numeric repo id for creation of shadow repos.

- Fixes a problem after rename or move into repository group.
This commit is contained in:
Marcin Kuzminski 2018-06-21 14:04:06 +02:00
parent d28aeae1b2
commit 42c80fe075
16 changed files with 174 additions and 114 deletions

View file

@ -302,7 +302,7 @@ def merge_pull_request(
request.environ, repo_name=target_repo.repo_name,
username=apiuser.username, action='push',
scm=target_repo.repo_type)
merge_response = PullRequestModel().merge(
merge_response = PullRequestModel().merge_repo(
pull_request, apiuser, extras=extras)
if merge_response.executed:
PullRequestModel().close_pull_request(

View file

@ -618,7 +618,7 @@ class TestPullrequestsView(object):
model_patcher = mock.patch.multiple(
PullRequestModel,
merge=mock.Mock(return_value=MergeResponse(
merge_repo=mock.Mock(return_value=MergeResponse(
True, False, 'STUB_COMMIT_ID', MergeFailureReason.PUSH_FAILED)),
merge_status=mock.Mock(return_value=(True, 'WRONG_MESSAGE')))

View file

@ -340,7 +340,8 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
# check merge capabilities
_merge_check = MergeCheck.validate(
pull_request_latest, user=self._rhodecode_user,
translator=self.request.translate, force_shadow_repo_refresh=force_refresh)
translator=self.request.translate,
force_shadow_repo_refresh=force_refresh)
c.pr_merge_errors = _merge_check.error_details
c.pr_merge_possible = not _merge_check.failed
c.pr_merge_message = _merge_check.merge_msg
@ -1063,7 +1064,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
def _merge_pull_request(self, pull_request, user, extras):
_ = self.request.translate
merge_resp = PullRequestModel().merge(pull_request, user, extras=extras)
merge_resp = PullRequestModel().merge_repo(pull_request, user, extras=extras)
if merge_resp.executed:
log.debug("The merge was successful, closing the pull request.")

View file

@ -204,13 +204,14 @@ class SimpleVCS(object):
# Only proceed if we got a pull request and if acl repo name from
# URL equals the target repo name of the pull request.
if pull_request and (acl_repo_name ==
pull_request.target_repo.repo_name):
if pull_request and \
(acl_repo_name == pull_request.target_repo.repo_name):
repo_id = pull_request.target_repo.repo_id
# Get file system path to shadow repository.
workspace_id = PullRequestModel()._workspace_id(pull_request)
target_vcs = pull_request.target_repo.scm_instance()
vcs_repo_name = target_vcs._get_shadow_repository_path(
workspace_id)
repo_id, workspace_id)
# Store names for later usage.
self.vcs_repo_name = vcs_repo_name

View file

@ -451,7 +451,7 @@ class BaseRepository(object):
"""
raise NotImplementedError
def merge(self, target_ref, source_repo, source_ref, workspace_id,
def merge(self, repo_id, workspace_id, target_ref, source_repo, source_ref,
user_name='', user_email='', message='', dry_run=False,
use_rebase=False, close_branch=False):
"""
@ -465,13 +465,14 @@ class BaseRepository(object):
'possible', 'executed', 'source_commit', 'target_commit',
'merge_commit'.
:param repo_id: `repo_id` target repo id.
:param workspace_id: `workspace_id` unique identifier.
:param target_ref: `target_ref` points to the commit on top of which
the `source_ref` should be merged.
:param source_repo: The repository that contains the commits to be
merged.
:param source_ref: `source_ref` points to the topmost commit from
the `source_repo` which should be merged.
:param workspace_id: `workspace_id` unique identifier.
:param user_name: Merge commit `user_name`.
:param user_email: Merge commit `user_email`.
:param message: Merge commit `message`.
@ -492,12 +493,9 @@ class BaseRepository(object):
if not message:
raise ValueError('message cannot be empty')
shadow_repository_path = self._maybe_prepare_merge_workspace(
workspace_id, target_ref, source_ref)
try:
return self._merge_repo(
shadow_repository_path, target_ref, source_repo,
repo_id, workspace_id, target_ref, source_repo,
source_ref, message, user_name, user_email, dry_run=dry_run,
use_rebase=use_rebase, close_branch=close_branch)
except RepositoryError:
@ -507,14 +505,15 @@ class BaseRepository(object):
return MergeResponse(
False, False, None, MergeFailureReason.UNKNOWN)
def _merge_repo(self, shadow_repository_path, target_ref,
def _merge_repo(self, repo_id, workspace_id, target_ref,
source_repo, source_ref, merge_message,
merger_name, merger_email, dry_run=False,
use_rebase=False, close_branch=False):
"""Internal implementation of merge."""
raise NotImplementedError
def _maybe_prepare_merge_workspace(self, workspace_id, target_ref, source_ref):
def _maybe_prepare_merge_workspace(
self, repo_id, workspace_id, target_ref, source_ref):
"""
Create the merge workspace.
@ -522,10 +521,27 @@ class BaseRepository(object):
"""
raise NotImplementedError
def _get_shadow_repository_path(self, workspace_id):
raise NotImplementedError
def _get_legacy_shadow_repository_path(self, workspace_id):
"""
Legacy version that was used before. We still need it for
backward compat
"""
return os.path.join(
os.path.dirname(self.path),
'.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
def cleanup_merge_workspace(self, workspace_id):
def _get_shadow_repository_path(self, repo_id, workspace_id):
# The name of the shadow repository must start with '.', so it is
# skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
legacy_repository_path = self._get_legacy_shadow_repository_path(workspace_id)
if os.path.exists(legacy_repository_path):
return legacy_repository_path
else:
return os.path.join(
os.path.dirname(self.path),
'.__shadow_repo_%s_%s' % (repo_id, workspace_id))
def cleanup_merge_workspace(self, repo_id, workspace_id):
"""
Remove merge workspace.
@ -534,7 +550,7 @@ class BaseRepository(object):
:param workspace_id: `workspace_id` unique identifier.
"""
shadow_repository_path = self._get_shadow_repository_path(workspace_id)
shadow_repository_path = self._get_shadow_repository_path(repo_id, workspace_id)
shadow_repository_path_del = '{}.{}.delete'.format(
shadow_repository_path, time.time())

View file

@ -902,7 +902,19 @@ class GitRepository(BaseRepository):
return '%s%d' % (prefix, branch_id)
def _merge_repo(self, shadow_repository_path, target_ref,
def _maybe_prepare_merge_workspace(
self, repo_id, workspace_id, target_ref, source_ref):
shadow_repository_path = self._get_shadow_repository_path(
repo_id, workspace_id)
if not os.path.exists(shadow_repository_path):
self._local_clone(
shadow_repository_path, target_ref.name, source_ref.name)
log.debug(
'Prepared shadow repository in %s', shadow_repository_path)
return shadow_repository_path
def _merge_repo(self, repo_id, workspace_id, target_ref,
source_repo, source_ref, merge_message,
merger_name, merger_email, dry_run=False,
use_rebase=False, close_branch=False):
@ -912,7 +924,10 @@ class GitRepository(BaseRepository):
return MergeResponse(
False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD)
shadow_repo = GitRepository(shadow_repository_path)
shadow_repository_path = self._maybe_prepare_merge_workspace(
repo_id, workspace_id, target_ref, source_ref)
shadow_repo = self._get_shadow_instance(shadow_repository_path)
# checkout source, if it's different. Otherwise we could not
# fetch proper commits for merge testing
if source_ref.name != target_ref.name:
@ -929,7 +944,7 @@ class GitRepository(BaseRepository):
# Need to reload repo to invalidate the cache, or otherwise we cannot
# retrieve the last target commit.
shadow_repo = GitRepository(shadow_repository_path)
shadow_repo = self._get_shadow_instance(shadow_repository_path)
if target_ref.commit_id != shadow_repo.branches[target_ref.name]:
log.warning('Shadow Target ref %s commit mismatch %s vs %s',
target_ref, target_ref.commit_id,
@ -989,18 +1004,3 @@ class GitRepository(BaseRepository):
return MergeResponse(
merge_possible, merge_succeeded, merge_ref,
merge_failure_reason)
def _get_shadow_repository_path(self, workspace_id):
# The name of the shadow repository must start with '.', so it is
# skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
return os.path.join(
os.path.dirname(self.path),
'.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
def _maybe_prepare_merge_workspace(self, workspace_id, target_ref, source_ref):
shadow_repository_path = self._get_shadow_repository_path(workspace_id)
if not os.path.exists(shadow_repository_path):
self._local_clone(
shadow_repository_path, target_ref.name, source_ref.name)
return shadow_repository_path

View file

@ -681,15 +681,10 @@ class MercurialRepository(BaseRepository):
return ref.name
return self._remote.ctx_branch(ref.commit_id)
def _get_shadow_repository_path(self, workspace_id):
# The name of the shadow repository must start with '.', so it is
# skipped by 'rhodecode.lib.utils.get_filesystem_repos'.
return os.path.join(
os.path.dirname(self.path),
'.__shadow_%s_%s' % (os.path.basename(self.path), workspace_id))
def _maybe_prepare_merge_workspace(self, workspace_id, unused_target_ref, unused_source_ref):
shadow_repository_path = self._get_shadow_repository_path(workspace_id)
def _maybe_prepare_merge_workspace(
self, repo_id, workspace_id, unused_target_ref, unused_source_ref):
shadow_repository_path = self._get_shadow_repository_path(
repo_id, workspace_id)
if not os.path.exists(shadow_repository_path):
self._local_clone(shadow_repository_path)
log.debug(
@ -697,7 +692,7 @@ class MercurialRepository(BaseRepository):
return shadow_repository_path
def _merge_repo(self, shadow_repository_path, target_ref,
def _merge_repo(self, repo_id, workspace_id, target_ref,
source_repo, source_ref, merge_message,
merger_name, merger_email, dry_run=False,
use_rebase=False, close_branch=False):
@ -719,6 +714,8 @@ class MercurialRepository(BaseRepository):
return MergeResponse(
False, False, None, MergeFailureReason.MISSING_TARGET_REF)
shadow_repository_path = self._maybe_prepare_merge_workspace(
repo_id, workspace_id, target_ref, source_ref)
shadow_repo = self._get_shadow_instance(shadow_repository_path)
log.debug('Pulling in target reference %s', target_ref)

View file

@ -1883,6 +1883,12 @@ class Repository(Base, BaseModel):
return os.listdir(diff_cache_dir)
return []
def shadow_repos(self):
shadow_repos_pattern = '.__shadow_repo_{}'.format(self.repo_id)
return [
x for x in os.listdir(os.path.dirname(self.repo_full_path))
if x.startswith(shadow_repos_pattern)]
def get_new_name(self, repo_name):
"""
returns new full repository name based on assigned group and new new
@ -3762,7 +3768,7 @@ class PullRequest(Base, _PullRequestBase):
workspace_id = self.workspace_id
vcs_obj = self.target_repo.scm_instance()
shadow_repository_path = vcs_obj._get_shadow_repository_path(
workspace_id)
self.target_repo.repo_id, workspace_id)
if os.path.isdir(shadow_repository_path):
return vcs_obj._get_shadow_instance(shadow_repository_path)

View file

@ -583,7 +583,7 @@ class PullRequestModel(BaseModel):
return commit_ids
def merge(self, pull_request, user, extras):
def merge_repo(self, pull_request, user, extras):
log.debug("Merging pull request %s", pull_request.pull_request_id)
merge_state = self._merge_pull_request(pull_request, user, extras)
if merge_state.executed:
@ -616,6 +616,7 @@ class PullRequestModel(BaseModel):
}
workspace_id = self._workspace_id(pull_request)
repo_id = pull_request.target_repo.repo_id
use_rebase = self._use_rebase_for_merging(pull_request)
close_branch = self._close_branch_before_merging(pull_request)
@ -629,9 +630,10 @@ class PullRequestModel(BaseModel):
target_vcs.config.set(
'rhodecode', 'RC_SCM_DATA', json.dumps(extras))
merge_state = target_vcs.merge(
target_ref, source_vcs, pull_request.source_ref_parts,
workspace_id, user_name=user.username,
user_email=user.email, message=message, use_rebase=use_rebase,
repo_id, workspace_id, target_ref, source_vcs,
pull_request.source_ref_parts,
user_name=user.username, user_email=user.email,
message=message, use_rebase=use_rebase,
close_branch=close_branch)
return merge_state
@ -1328,11 +1330,13 @@ class PullRequestModel(BaseModel):
def _refresh_merge_state(self, pull_request, target_vcs, target_reference):
workspace_id = self._workspace_id(pull_request)
source_vcs = pull_request.source_repo.scm_instance()
repo_id = pull_request.target_repo.repo_id
use_rebase = self._use_rebase_for_merging(pull_request)
close_branch = self._close_branch_before_merging(pull_request)
merge_state = target_vcs.merge(
repo_id, workspace_id,
target_reference, source_vcs, pull_request.source_ref_parts,
workspace_id, dry_run=True, use_rebase=use_rebase,
dry_run=True, use_rebase=use_rebase,
close_branch=close_branch)
# Do not store the response if there was an unknown error.
@ -1398,11 +1402,12 @@ class PullRequestModel(BaseModel):
def _cleanup_merge_workspace(self, pull_request):
# Merging related cleanup
repo_id = pull_request.target_repo.repo_id
target_scm = pull_request.target_repo.scm_instance()
workspace_id = 'pr-%s' % pull_request.pull_request_id
workspace_id = self._workspace_id(pull_request)
try:
target_scm.cleanup_merge_workspace(workspace_id)
target_scm.cleanup_merge_workspace(repo_id, workspace_id)
except NotImplementedError:
pass

View file

@ -116,6 +116,13 @@ def get_new_dir(title):
return get_normalized_path(path)
def repo_id_generator(name):
numeric_hash = 0
for char in name:
numeric_hash += (ord(char))
return numeric_hash
@pytest.mark.usefixtures('app', 'index_location')
class TestController(object):

View file

@ -333,7 +333,7 @@ class TestShadowRepoExposure(object):
workspace_id = PullRequestModel()._workspace_id(pull_request)
target_vcs = pull_request.target_repo.scm_instance()
vcs_repo_name = target_vcs._get_shadow_repository_path(
workspace_id)
pull_request.target_repo.repo_id, workspace_id)
assert controller.vcs_repo_name == vcs_repo_name
assert controller.url_repo_name == shadow_url

View file

@ -81,6 +81,7 @@ class TestPullRequestModel(object):
self.source_commit = self.pull_request.source_ref_parts.commit_id
self.target_commit = self.pull_request.target_ref_parts.commit_id
self.workspace_id = 'pr-%s' % self.pull_request.pull_request_id
self.repo_id = self.pull_request.target_repo.repo_id
@request.addfinalizer
def cleanup_pull_request():
@ -135,17 +136,19 @@ class TestPullRequestModel(object):
assert pr_count == 1
def test_delete_calls_cleanup_merge(self, pull_request):
repo_id = pull_request.target_repo.repo_id
PullRequestModel().delete(pull_request, pull_request.author)
self.workspace_remove_mock.assert_called_once_with(
self.workspace_id)
repo_id, self.workspace_id)
def test_close_calls_cleanup_and_hook(self, pull_request):
PullRequestModel().close_pull_request(
pull_request, pull_request.author)
repo_id = pull_request.target_repo.repo_id
self.workspace_remove_mock.assert_called_once_with(
self.workspace_id)
repo_id, self.workspace_id)
self.hook_mock.assert_called_with(
self.pull_request, self.pull_request.author, 'close')
@ -161,9 +164,10 @@ class TestPullRequestModel(object):
assert status is True
assert msg.eval() == 'This pull request can be automatically merged.'
self.merge_mock.assert_called_with(
self.repo_id, self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts, self.workspace_id, dry_run=True,
pull_request.source_ref_parts, dry_run=True,
use_rebase=False, close_branch=False)
assert pull_request._last_merge_source_rev == self.source_commit
@ -190,9 +194,10 @@ class TestPullRequestModel(object):
msg.eval() ==
'This pull request cannot be merged because of merge conflicts.')
self.merge_mock.assert_called_with(
self.repo_id, self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts, self.workspace_id, dry_run=True,
pull_request.source_ref_parts, dry_run=True,
use_rebase=False, close_branch=False)
assert pull_request._last_merge_source_rev == self.source_commit
@ -222,9 +227,10 @@ class TestPullRequestModel(object):
'This pull request cannot be merged because of an unhandled'
' exception.')
self.merge_mock.assert_called_with(
self.repo_id, self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts, self.workspace_id, dry_run=True,
pull_request.source_ref_parts, dry_run=True,
use_rebase=False, close_branch=False)
assert pull_request._last_merge_source_rev is None
@ -281,7 +287,7 @@ class TestPullRequestModel(object):
True, True, merge_ref, MergeFailureReason.NONE)
merge_extras['repository'] = pull_request.target_repo.repo_name
PullRequestModel().merge(
PullRequestModel().merge_repo(
pull_request, pull_request.author, extras=merge_extras)
message = (
@ -295,9 +301,10 @@ class TestPullRequestModel(object):
)
)
self.merge_mock.assert_called_with(
self.repo_id, self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts, self.workspace_id,
pull_request.source_ref_parts,
user_name=user.username, user_email=user.email, message=message,
use_rebase=False, close_branch=False
)
@ -320,7 +327,7 @@ class TestPullRequestModel(object):
False, False, merge_ref, MergeFailureReason.MERGE_FAILED)
merge_extras['repository'] = pull_request.target_repo.repo_name
PullRequestModel().merge(
PullRequestModel().merge_repo(
pull_request, pull_request.author, extras=merge_extras)
message = (
@ -334,9 +341,10 @@ class TestPullRequestModel(object):
)
)
self.merge_mock.assert_called_with(
self.repo_id, self.workspace_id,
pull_request.target_ref_parts,
pull_request.source_repo.scm_instance(),
pull_request.source_ref_parts, self.workspace_id,
pull_request.source_ref_parts,
user_name=user.username, user_email=user.email, message=message,
use_rebase=False, close_branch=False
)
@ -392,7 +400,7 @@ class TestIntegrationMerge(object):
Session().commit()
with mock.patch.dict(rhodecode.CONFIG, extra_config, clear=False):
merge_state = PullRequestModel().merge(
merge_state = PullRequestModel().merge_repo(
pull_request, user_admin, extras=merge_extras)
assert merge_state.executed
@ -409,7 +417,7 @@ class TestIntegrationMerge(object):
with mock.patch('rhodecode.EXTENSIONS.PRE_PUSH_HOOK') as pre_pull:
pre_pull.side_effect = RepositoryError("Disallow push!")
merge_status = PullRequestModel().merge(
merge_status = PullRequestModel().merge_repo(
pull_request, user_admin, extras=merge_extras)
assert not merge_status.executed
@ -429,7 +437,7 @@ class TestIntegrationMerge(object):
merge_extras['repository'] = pull_request.target_repo.repo_name
# TODO: johbo: Needed for sqlite, try to find an automatic way for it
Session().commit()
merge_status = PullRequestModel().merge(
merge_status = PullRequestModel().merge_repo(
pull_request, user_regular, extras=merge_extras)
assert not merge_status.executed

View file

@ -566,7 +566,7 @@ TODO: To be written...
def test_maybe_prepare_merge_workspace(self):
workspace = self.repo._maybe_prepare_merge_workspace(
'pr2', Reference('branch', 'master', 'unused'),
2, 'pr2', Reference('branch', 'master', 'unused'),
Reference('branch', 'master', 'unused'))
assert os.path.isdir(workspace)
@ -575,13 +575,13 @@ TODO: To be written...
# Calling it a second time should also succeed
workspace = self.repo._maybe_prepare_merge_workspace(
'pr2', Reference('branch', 'master', 'unused'),
2, 'pr2', Reference('branch', 'master', 'unused'),
Reference('branch', 'master', 'unused'))
assert os.path.isdir(workspace)
def test_maybe_prepare_merge_workspace_different_refs(self):
workspace = self.repo._maybe_prepare_merge_workspace(
'pr2', Reference('branch', 'master', 'unused'),
2, 'pr2', Reference('branch', 'master', 'unused'),
Reference('branch', 'develop', 'unused'))
assert os.path.isdir(workspace)
@ -590,22 +590,22 @@ TODO: To be written...
# Calling it a second time should also succeed
workspace = self.repo._maybe_prepare_merge_workspace(
'pr2', Reference('branch', 'master', 'unused'),
2, 'pr2', Reference('branch', 'master', 'unused'),
Reference('branch', 'develop', 'unused'))
assert os.path.isdir(workspace)
def test_cleanup_merge_workspace(self):
workspace = self.repo._maybe_prepare_merge_workspace(
'pr3', Reference('branch', 'master', 'unused'),
2, 'pr3', Reference('branch', 'master', 'unused'),
Reference('branch', 'master', 'unused'))
self.repo.cleanup_merge_workspace('pr3')
self.repo.cleanup_merge_workspace(2, 'pr3')
assert not os.path.exists(workspace)
def test_cleanup_merge_workspace_invalid_workspace_id(self):
# No assert: because in case of an inexistent workspace this function
# should still succeed.
self.repo.cleanup_merge_workspace('pr4')
self.repo.cleanup_merge_workspace(1, 'pr4')
def test_set_refs(self):
test_ref = 'refs/test-refs/abcde'

View file

@ -31,7 +31,7 @@ from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialCommit
from rhodecode.lib.vcs.exceptions import (
RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError)
from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE, repo_id_generator
pytestmark = pytest.mark.backends("hg")
@ -46,7 +46,6 @@ def repo_path_generator():
i += 1
yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
REPO_PATH_GENERATOR = repo_path_generator()
@ -553,7 +552,7 @@ TODO: To be written...
def test_maybe_prepare_merge_workspace(self):
workspace = self.repo._maybe_prepare_merge_workspace(
'pr2', 'unused', 'unused2')
1, 'pr2', 'unused', 'unused2')
assert os.path.isdir(workspace)
workspace_repo = MercurialRepository(workspace)
@ -561,20 +560,22 @@ TODO: To be written...
# Calling it a second time should also succeed
workspace = self.repo._maybe_prepare_merge_workspace(
'pr2', 'unused', 'unused2')
1, 'pr2', 'unused', 'unused2')
assert os.path.isdir(workspace)
def test_cleanup_merge_workspace(self):
workspace = self.repo._maybe_prepare_merge_workspace(
'pr3', 'unused', 'unused2')
self.repo.cleanup_merge_workspace('pr3')
1, 'pr3', 'unused', 'unused2')
assert os.path.isdir(workspace)
self.repo.cleanup_merge_workspace(1, 'pr3')
assert not os.path.exists(workspace)
def test_cleanup_merge_workspace_invalid_workspace_id(self):
# No assert: because in case of an inexistent workspace this function
# should still succeed.
self.repo.cleanup_merge_workspace('pr4')
self.repo.cleanup_merge_workspace(1, 'pr4')
def test_merge_target_is_bookmark(self, vcsbackend_hg):
target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
@ -594,10 +595,10 @@ TODO: To be written...
target_repo.bookmark(bookmark_name)
target_ref = Reference('book', bookmark_name, target_commit.raw_id)
source_ref = Reference('branch', default_branch, source_commit.raw_id)
workspace = 'test-merge'
workspace_id = 'test-merge'
repo_id = repo_id_generator(target_repo.path)
merge_response = target_repo.merge(
target_ref, source_repo, source_ref, workspace,
repo_id, workspace_id, target_ref, source_repo, source_ref,
'test user', 'test@rhodecode.com', 'merge message 1',
dry_run=False)
expected_merge_response = MergeResponse(
@ -638,10 +639,10 @@ TODO: To be written...
source_repo._update(default_branch)
source_repo.bookmark(bookmark_name)
source_ref = Reference('book', bookmark_name, source_commit.raw_id)
workspace = 'test-merge'
workspace_id = 'test-merge'
repo_id = repo_id_generator(target_repo.path)
merge_response = target_repo.merge(
target_ref, source_repo, source_ref, workspace,
repo_id, workspace_id, target_ref, source_repo, source_ref,
'test user', 'test@rhodecode.com', 'merge message 1',
dry_run=False)
expected_merge_response = MergeResponse(
@ -677,14 +678,15 @@ TODO: To be written...
target_ref = Reference('branch', default_branch, target_commit.raw_id)
source_ref = Reference('branch', default_branch, source_commit.raw_id)
workspace = 'test-merge'
workspace_id = 'test-merge'
assert len(target_repo._heads(branch='default')) == 2
expected_merge_response = MergeResponse(
False, False, None,
MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
repo_id = repo_id_generator(target_repo.path)
merge_response = target_repo.merge(
target_ref, source_repo, source_ref, workspace,
repo_id, workspace_id, target_ref, source_repo, source_ref,
'test user', 'test@rhodecode.com', 'merge message 1',
dry_run=False)
assert merge_response == expected_merge_response
@ -711,10 +713,11 @@ TODO: To be written...
target_ref = Reference('branch', default_branch, target_commit.raw_id)
source_ref = Reference('book', bookmark_name, source_commit.raw_id)
workspace = 'test-merge'
repo_id = repo_id_generator(target_repo.path)
workspace_id = 'test-merge'
merge_response = target_repo.merge(
target_ref, source_repo, source_ref, workspace,
repo_id, workspace_id, target_ref, source_repo, source_ref,
'test user', 'test@rhodecode.com', 'merge message 1',
dry_run=False, use_rebase=True)

View file

@ -95,7 +95,7 @@ class TestMercurialRemoteRepoInvalidation(object):
references.
"""
from rhodecode.model.pull_request import PullRequestModel
repo_id = pull_request.target_repo
target_vcs = pull_request.target_repo.scm_instance()
target_ref = pull_request.target_ref_parts
source_ref = pull_request.source_ref_parts
@ -104,7 +104,7 @@ class TestMercurialRemoteRepoInvalidation(object):
pr = PullRequestModel()
workspace_id = pr._workspace_id(pull_request)
shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
workspace_id, target_ref, source_ref)
repo_id, workspace_id, target_ref, source_ref)
shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
# This will populate the cache of the mercurial repository object

View file

@ -30,6 +30,7 @@ from rhodecode.lib.vcs.backends.base import (
from rhodecode.lib.vcs.exceptions import VCSError, RepositoryError
from rhodecode.lib.vcs.nodes import FileNode
from rhodecode.tests.vcs.conftest import BackendTestMixin
from rhodecode.tests import repo_id_generator
@pytest.mark.usefixtures("vcs_repository_support")
@ -268,7 +269,7 @@ class TestRepositoryGetCommonAncestor:
@pytest.mark.backends("git", "hg")
class TestRepositoryMerge:
class TestRepositoryMerge(object):
def prepare_for_success(self, vcsbackend):
self.target_repo = vcsbackend.create_repo(number_of_commits=1)
self.source_repo = vcsbackend.clone_repo(self.target_repo)
@ -287,7 +288,8 @@ class TestRepositoryMerge:
'branch', default_branch, self.target_commit.raw_id)
self.source_ref = Reference(
'branch', default_branch, self.source_commit.raw_id)
self.workspace = 'test-merge'
self.workspace_id = 'test-merge'
self.repo_id = repo_id_generator(self.target_repo.path)
def prepare_for_conflict(self, vcsbackend):
self.target_repo = vcsbackend.create_repo(number_of_commits=1)
@ -302,13 +304,15 @@ class TestRepositoryMerge:
'branch', default_branch, self.target_commit.raw_id)
self.source_ref = Reference(
'branch', default_branch, self.source_commit.raw_id)
self.workspace = 'test-merge'
self.workspace_id = 'test-merge'
self.repo_id = repo_id_generator(self.target_repo.path)
def test_merge_success(self, vcsbackend):
self.prepare_for_success(vcsbackend)
merge_response = self.target_repo.merge(
self.target_ref, self.source_repo, self.source_ref, self.workspace,
self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
self.source_ref,
'test user', 'test@rhodecode.com', 'merge message 1',
dry_run=False)
expected_merge_response = MergeResponse(
@ -334,7 +338,7 @@ class TestRepositoryMerge:
merge_response.merge_ref.commit_id)
merge_response = target_repo.merge(
target_ref, self.source_repo, self.source_ref, self.workspace,
self.repo_id, self.workspace_id, target_ref, self.source_repo, self.source_ref,
'test user', 'test@rhodecode.com', 'merge message 2',
dry_run=False)
expected_merge_response = MergeResponse(
@ -353,13 +357,13 @@ class TestRepositoryMerge:
self.prepare_for_success(vcsbackend)
merge_response = self.target_repo.merge(
self.target_ref, self.source_repo, self.source_ref, self.workspace,
dry_run=True)
self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
self.source_ref, dry_run=True)
# We call it twice so to make sure we can handle updates
merge_response_update = self.target_repo.merge(
self.target_ref, self.source_repo, self.source_ref, self.workspace,
dry_run=True)
self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
self.source_ref, dry_run=True)
# Multiple merges may differ in their commit id. Therefore we set the
# commit id to `None` before comparing the merge responses.
@ -381,13 +385,15 @@ class TestRepositoryMerge:
False, False, None, MergeFailureReason.MERGE_FAILED)
merge_response = self.target_repo.merge(
self.target_ref, self.source_repo, self.source_ref, self.workspace,
self.repo_id, self.workspace_id, self.target_ref,
self.source_repo, self.source_ref,
'test_user', 'test@rhodecode.com', 'test message', dry_run=dry_run)
assert merge_response == expected_merge_response
# We call it twice so to make sure we can handle updates
merge_response = self.target_repo.merge(
self.target_ref, self.source_repo, self.source_ref, self.workspace,
self.repo_id, self.workspace_id, self.target_ref, self.source_repo,
self.source_ref,
'test_user', 'test@rhodecode.com', 'test message', dry_run=dry_run)
assert merge_response == expected_merge_response
@ -400,8 +406,8 @@ class TestRepositoryMerge:
self.target_ref.type, self.target_ref.name, '0' * 40)
merge_response = self.target_repo.merge(
target_ref, self.source_repo, self.source_ref, self.workspace,
dry_run=True)
self.repo_id, self.workspace_id, target_ref, self.source_repo,
self.source_ref, dry_run=True)
assert merge_response == expected_merge_response
@ -414,7 +420,8 @@ class TestRepositoryMerge:
self.source_ref.type, 'not_existing', self.source_ref.commit_id)
merge_response = self.target_repo.merge(
self.target_ref, self.source_repo, source_ref, self.workspace,
self.repo_id, self.workspace_id, self.target_ref,
self.source_repo, source_ref,
dry_run=True)
assert merge_response == expected_merge_response
@ -427,29 +434,38 @@ class TestRepositoryMerge:
with mock.patch.object(self.target_repo, '_merge_repo',
side_effect=RepositoryError()):
merge_response = self.target_repo.merge(
self.target_ref, self.source_repo, self.source_ref,
self.workspace, dry_run=True)
self.repo_id, self.workspace_id, self.target_ref,
self.source_repo, self.source_ref,
dry_run=True)
assert merge_response == expected_merge_response
def test_merge_invalid_user_name(self, vcsbackend):
repo = vcsbackend.create_repo(number_of_commits=1)
ref = Reference('branch', 'master', 'not_used')
workspace_id = 'test-errors-in-merge'
repo_id = repo_id_generator(workspace_id)
with pytest.raises(ValueError):
repo.merge(ref, self, ref, 'workspace_id')
repo.merge(repo_id, workspace_id, ref, self, ref)
def test_merge_invalid_user_email(self, vcsbackend):
repo = vcsbackend.create_repo(number_of_commits=1)
ref = Reference('branch', 'master', 'not_used')
workspace_id = 'test-errors-in-merge'
repo_id = repo_id_generator(workspace_id)
with pytest.raises(ValueError):
repo.merge(ref, self, ref, 'workspace_id', 'user name')
repo.merge(
repo_id, workspace_id, ref, self, ref, 'user name')
def test_merge_invalid_message(self, vcsbackend):
repo = vcsbackend.create_repo(number_of_commits=1)
ref = Reference('branch', 'master', 'not_used')
workspace_id = 'test-errors-in-merge'
repo_id = repo_id_generator(workspace_id)
with pytest.raises(ValueError):
repo.merge(
ref, self, ref, 'workspace_id', 'user name', 'user@email.com')
repo_id, workspace_id, ref, self, ref,
'user name', 'user@email.com')
@pytest.mark.usefixtures("vcs_repository_support")
@ -505,7 +521,7 @@ class TestRepositoryStrip(BackendTestMixin):
@pytest.mark.backends('hg', 'git')
class TestRepositoryPull:
class TestRepositoryPull(object):
def test_pull(self, vcsbackend):
source_repo = vcsbackend.repo