def test_local_merge_of_two_branches_of_the_same_repo(self, backend_hg):
     commits = [
         {
             'message': 'a'
         },
         {
             'message': 'b',
             'branch': 'b'
         },
     ]
     repo = backend_hg.create_repo(commits)
     commit_ids = backend_hg.commit_ids
     target_ref = Reference(type='branch',
                            name='default',
                            commit_id=commit_ids['a'])
     source_ref = Reference(type='branch',
                            name='b',
                            commit_id=commit_ids['b'])
     merge_message = 'Merge message\n\nDescription:...'
     user_name = 'Albert Einstein'
     user_email = '*****@*****.**'
     vcs_repo = repo.scm_instance()
     merge_commit_id, needs_push = vcs_repo._local_merge(
         target_ref, merge_message, user_name, user_email, source_ref)
     assert merge_commit_id != source_ref.commit_id
     assert needs_push is True
     commit = vcs_repo.get_commit(merge_commit_id)
     assert commit.merge is True
     assert commit.message == merge_message
    def test_local_merge_source_is_fast_forward(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        source_repo = vcsbackend_hg.clone_repo(target_repo)
        target_rev = target_repo.branches['default']
        target_ref = Reference(type='branch',
                               name='default',
                               commit_id=target_rev)
        vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
        source_repo = MercurialRepository(source_repo.path)
        source_rev = source_repo.branches['default']
        source_ref = Reference(type='branch',
                               name='default',
                               commit_id=source_rev)

        target_repo._local_pull(source_repo.path, source_ref)

        merge_message = 'Merge message\n\nDescription:...'
        user_name = 'Albert Einstein'
        user_email = '*****@*****.**'
        merge_commit_id, needs_push = target_repo._local_merge(
            target_ref, merge_message, user_name, user_email, source_ref)
        assert merge_commit_id == source_rev
        assert needs_push

        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.commit_ids[-2] == target_rev
        assert target_repo.commit_ids[-1] == source_rev

        assert not os.path.exists(
            os.path.join(target_repo.path, '.hg', 'merge', 'state'))
    def test_maybe_prepare_merge_workspace(self):
        workspace = self.repo._maybe_prepare_merge_workspace(
            'pr2', Reference('branch', 'master', 'unused'))

        assert os.path.isdir(workspace)
        workspace_repo = GitRepository(workspace)
        assert workspace_repo.branches == self.repo.branches

        # Calling it a second time should also succeed
        workspace = self.repo._maybe_prepare_merge_workspace(
            'pr2', Reference('branch', 'master', 'unused'))
        assert os.path.isdir(workspace)
    def test_merge_rebase_source_is_updated_bookmark(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        source_repo = vcsbackend_hg.clone_repo(target_repo)
        vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
        vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
        imc = source_repo.in_memory_commit
        imc.add(FileNode('file_x', content=source_repo.name))
        imc.commit(message=u'Automatic commit from repo merge test',
                   author=u'Automatic')
        target_commit = target_repo.get_commit()
        source_commit = source_repo.get_commit()

        vcsbackend_hg.add_file(source_repo, 'LICENSE', 'LICENSE Info')

        default_branch = target_repo.DEFAULT_BRANCH_NAME
        bookmark_name = 'bookmark'
        source_repo._update(default_branch)
        source_repo.bookmark(bookmark_name)

        target_ref = Reference('branch', default_branch, target_commit.raw_id)
        source_ref = Reference('book', bookmark_name, source_commit.raw_id)
        workspace = 'test-merge'

        with mock.patch.object(rhodecode.lib.vcs.conf.settings,
                               'HG_USE_REBASE_FOR_MERGING',
                               return_value=True):
            merge_response = target_repo.merge(target_ref,
                                               source_repo,
                                               source_ref,
                                               workspace,
                                               'test user',
                                               '*****@*****.**',
                                               'merge message 1',
                                               dry_run=False)

        expected_merge_response = MergeResponse(True, True,
                                                merge_response.merge_commit_id,
                                                MergeFailureReason.NONE)
        assert merge_response == expected_merge_response

        target_repo = backends.get_backend(vcsbackend_hg.alias)(
            target_repo.path)
        last_commit = target_repo.get_commit()
        assert last_commit.message == source_commit.message
        assert last_commit.author == source_commit.author
        # This checks that we effectively did a rebase
        assert last_commit.raw_id != source_commit.raw_id

        # Check the target has only 4 commits: 2 were already in target and
        # only two should have been added
        assert len(target_repo.commit_ids) == 2 + 2
 def prepare_for_conflict(self, vcsbackend):
     self.target_repo = vcsbackend.create_repo(number_of_commits=1)
     self.source_repo = vcsbackend.clone_repo(self.target_repo)
     vcsbackend.add_file(self.target_repo, 'README_MERGE', 'Version 1')
     vcsbackend.add_file(self.source_repo, 'README_MERGE', 'Version 2')
     self.target_commit = self.target_repo.get_commit()
     self.source_commit = self.source_repo.get_commit()
     # This only works for Git and Mercurial
     default_branch = self.target_repo.DEFAULT_BRANCH_NAME
     self.target_ref = Reference('branch', default_branch,
                                 self.target_commit.raw_id)
     self.source_ref = Reference('branch', default_branch,
                                 self.source_commit.raw_id)
     self.workspace = 'test-merge'
    def test_local_pull_branch(self):
        target_repo = self.get_empty_repo()
        source_repo = self.get_clone_repo()

        default = Reference('branch', 'default',
                            source_repo.branches['default'])
        target_repo._local_pull(source_repo.path, default)
        target_repo = MercurialRepository(target_repo.path)
        assert (
            target_repo.branches['default'] == source_repo.branches['default'])

        stable = Reference('branch', 'stable', source_repo.branches['stable'])
        target_repo._local_pull(source_repo.path, stable)
        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.branches['stable'] == source_repo.branches['stable']
    def test_validate_pull_reference_raises_on_missing_reference(
            self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        reference = Reference('book', 'invalid_reference', 'a' * 40)

        with pytest.raises(CommitDoesNotExistError):
            target_repo._validate_pull_reference(reference)
    def test_local_pull_commit(self):
        target_repo = self.get_empty_repo()
        source_repo = self.get_clone_repo()

        commits = list(source_repo.get_commits(branch_name='default'))
        commit_id = commits[-5].raw_id
        commit = Reference('rev', commit_id, commit_id)
        target_repo._local_pull(source_repo.path, commit)
        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.branches['default'] == commit_id

        commit_id = commits[-3].raw_id
        commit = Reference('rev', commit_id, commit_id)
        target_repo._local_pull(source_repo.path, commit)
        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.branches['default'] == commit_id
    def test_merge_target_is_bookmark(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        source_repo = vcsbackend_hg.clone_repo(target_repo)
        vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
        vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
        imc = source_repo.in_memory_commit
        imc.add(FileNode('file_x', content=source_repo.name))
        imc.commit(message=u'Automatic commit from repo merge test',
                   author=u'Automatic')
        target_commit = target_repo.get_commit()
        source_commit = source_repo.get_commit()
        default_branch = target_repo.DEFAULT_BRANCH_NAME
        bookmark_name = 'bookmark'
        target_repo._update(default_branch)
        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'

        merge_response = target_repo.merge(target_ref,
                                           source_repo,
                                           source_ref,
                                           workspace,
                                           'test user',
                                           '*****@*****.**',
                                           'merge message 1',
                                           dry_run=False)
        expected_merge_response = MergeResponse(True, True,
                                                merge_response.merge_commit_id,
                                                MergeFailureReason.NONE)
        assert merge_response == expected_merge_response

        target_repo = backends.get_backend(vcsbackend_hg.alias)(
            target_repo.path)
        target_commits = list(target_repo.get_commits())
        commit_ids = [c.raw_id for c in target_commits[:-1]]
        assert source_ref.commit_id in commit_ids
        assert target_ref.commit_id in commit_ids

        merge_commit = target_commits[-1]
        assert merge_commit.raw_id == merge_response.merge_commit_id
        assert merge_commit.message.strip() == 'merge message 1'
        assert merge_commit.author == 'test user <*****@*****.**>'

        # Check the bookmark was updated in the target repo
        assert (target_repo.bookmarks[bookmark_name] ==
                merge_response.merge_commit_id)
 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)
     vcsbackend.add_file(self.target_repo, 'README_MERGE1', 'Version 1')
     vcsbackend.add_file(self.source_repo, 'README_MERGE2', 'Version 2')
     imc = self.source_repo.in_memory_commit
     imc.add(FileNode('file_x', content=self.source_repo.name))
     imc.commit(message=u'Automatic commit from repo merge test',
                author=u'Automatic')
     self.target_commit = self.target_repo.get_commit()
     self.source_commit = self.source_repo.get_commit()
     # This only works for Git and Mercurial
     default_branch = self.target_repo.DEFAULT_BRANCH_NAME
     self.target_ref = Reference('branch', default_branch,
                                 self.target_commit.raw_id)
     self.source_ref = Reference('branch', default_branch,
                                 self.source_commit.raw_id)
     self.workspace = 'test-merge'
 def _refresh_reference(self, reference, vcs_repository):
     if reference.type in ('branch', 'book'):
         name_or_id = reference.name
     else:
         name_or_id = reference.commit_id
     refreshed_commit = vcs_repository.get_commit(name_or_id)
     refreshed_reference = Reference(reference.type, reference.name,
                                     refreshed_commit.raw_id)
     return refreshed_reference
    def test_local_pull_bookmark(self):
        target_repo = self.get_empty_repo()
        source_repo = self.get_clone_repo()

        commits = list(source_repo.get_commits(branch_name='default'))
        foo1_id = commits[-5].raw_id
        foo1 = Reference('book', 'foo1', foo1_id)
        source_repo._update(foo1_id)
        source_repo.bookmark('foo1')

        foo2_id = commits[-3].raw_id
        foo2 = Reference('book', 'foo2', foo2_id)
        source_repo._update(foo2_id)
        source_repo.bookmark('foo2')

        target_repo._local_pull(source_repo.path, foo1)
        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.branches['default'] == commits[-5].raw_id

        target_repo._local_pull(source_repo.path, foo2)
        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.branches['default'] == commits[-3].raw_id
    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,
                                                'test user',
                                                '*****@*****.**',
                                                'merge message 1',
                                                dry_run=False)
        expected_merge_response = MergeResponse(True, True,
                                                merge_response.merge_commit_id,
                                                MergeFailureReason.NONE)
        assert merge_response == expected_merge_response

        target_repo = backends.get_backend(vcsbackend.alias)(
            self.target_repo.path)
        target_commits = list(target_repo.get_commits())
        commit_ids = [c.raw_id for c in target_commits[:-1]]
        assert self.source_ref.commit_id in commit_ids
        assert self.target_ref.commit_id in commit_ids

        merge_commit = target_commits[-1]
        assert merge_commit.raw_id == merge_response.merge_commit_id
        assert merge_commit.message.strip() == 'merge message 1'
        assert merge_commit.author == 'test user <*****@*****.**>'

        # We call it twice so to make sure we can handle updates
        target_ref = Reference(self.target_ref.type, self.target_ref.name,
                               merge_response.merge_commit_id)

        merge_response = target_repo.merge(target_ref,
                                           self.source_repo,
                                           self.source_ref,
                                           self.workspace,
                                           'test user',
                                           '*****@*****.**',
                                           'merge message 2',
                                           dry_run=False)
        expected_merge_response = MergeResponse(True, True,
                                                merge_response.merge_commit_id,
                                                MergeFailureReason.NONE)
        assert merge_response == expected_merge_response

        target_repo = backends.get_backend(vcsbackend.alias)(
            self.target_repo.path)
        merge_commit = target_repo.get_commit(merge_response.merge_commit_id)
        assert merge_commit.message.strip() == 'merge message 1'
        assert merge_commit.author == 'test user <*****@*****.**>'
    def test_merge_target_has_multiple_heads(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=2)
        source_repo = vcsbackend_hg.clone_repo(target_repo)
        vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
        vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')

        # add an extra head to the target repo
        imc = target_repo.in_memory_commit
        imc.add(FileNode('file_x', content='foo'))
        commits = list(target_repo.get_commits())
        imc.commit(message=u'Automatic commit from repo merge test',
                   author=u'Automatic',
                   parents=commits[0:1])

        target_commit = target_repo.get_commit()
        source_commit = source_repo.get_commit()
        default_branch = target_repo.DEFAULT_BRANCH_NAME
        target_repo._update(default_branch)

        target_ref = Reference('branch', default_branch, target_commit.raw_id)
        source_ref = Reference('branch', default_branch, source_commit.raw_id)
        workspace = 'test-merge'

        assert len(target_repo._heads(branch='default')) == 2
        expected_merge_response = MergeResponse(
            False, False, None,
            MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
        merge_response = target_repo.merge(target_ref,
                                           source_repo,
                                           source_ref,
                                           workspace,
                                           'test user',
                                           '*****@*****.**',
                                           'merge message 1',
                                           dry_run=False)
        assert merge_response == expected_merge_response
    def test_local_merge_raises_exception_on_conflict(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        source_repo = vcsbackend_hg.clone_repo(target_repo)
        vcsbackend_hg.add_file(target_repo, 'README_MERGE', 'Version 1')
        target_repo = MercurialRepository(target_repo.path)
        target_rev = target_repo.branches['default']
        target_ref = Reference(type='branch',
                               name='default',
                               commit_id=target_rev)
        vcsbackend_hg.add_file(source_repo, 'README_MERGE', 'Version 2')
        source_repo = MercurialRepository(source_repo.path)
        source_rev = source_repo.branches['default']
        source_ref = Reference(type='branch',
                               name='default',
                               commit_id=source_rev)

        target_repo._local_pull(source_repo.path, source_ref)
        with pytest.raises(RepositoryError):
            target_repo._local_merge(target_ref, 'merge_message', 'user name',
                                     '*****@*****.**', source_ref)

        # Check we are not left in an intermediate merge state
        assert not os.path.exists(
            os.path.join(target_repo.path, '.hg', 'merge', 'state'))
    def test_merge_source_is_bookmark(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        source_repo = vcsbackend_hg.clone_repo(target_repo)
        imc = source_repo.in_memory_commit
        imc.add(FileNode('file_x', content=source_repo.name))
        imc.commit(message=u'Automatic commit from repo merge test',
                   author=u'Automatic')
        target_commit = target_repo.get_commit()
        source_commit = source_repo.get_commit()
        default_branch = target_repo.DEFAULT_BRANCH_NAME
        bookmark_name = 'bookmark'
        target_ref = Reference('branch', default_branch, target_commit.raw_id)
        source_repo._update(default_branch)
        source_repo.bookmark(bookmark_name)
        source_ref = Reference('book', bookmark_name, source_commit.raw_id)
        workspace = 'test-merge'

        merge_response = target_repo.merge(target_ref,
                                           source_repo,
                                           source_ref,
                                           workspace,
                                           'test user',
                                           '*****@*****.**',
                                           'merge message 1',
                                           dry_run=False)
        expected_merge_response = MergeResponse(True, True,
                                                merge_response.merge_commit_id,
                                                MergeFailureReason.NONE)
        assert merge_response == expected_merge_response

        target_repo = backends.get_backend(vcsbackend_hg.alias)(
            target_repo.path)
        target_commits = list(target_repo.get_commits())
        commit_ids = [c.raw_id for c in target_commits]
        assert source_ref.commit_id == commit_ids[-1]
        assert target_ref.commit_id == commit_ids[-2]
    def test_merge_missing_commit(self, vcsbackend):
        self.prepare_for_success(vcsbackend)
        expected_merge_response = MergeResponse(
            False, False, None, MergeFailureReason.MISSING_COMMIT)

        source_ref = Reference(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,
                                                dry_run=True)

        assert merge_response == expected_merge_response
    def test_merge_target_is_not_head(self, vcsbackend):
        self.prepare_for_success(vcsbackend)
        expected_merge_response = MergeResponse(
            False, False, None, MergeFailureReason.TARGET_IS_NOT_HEAD)

        target_ref = Reference(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)

        assert merge_response == expected_merge_response
    def test_local_merge_source_is_integrated(self, vcsbackend_hg):
        target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
        target_rev = target_repo.branches['default']
        target_ref = Reference(type='branch',
                               name='default',
                               commit_id=target_rev)

        merge_message = 'Merge message\n\nDescription:...'
        user_name = 'Albert Einstein'
        user_email = '*****@*****.**'
        merge_commit_id, needs_push = target_repo._local_merge(
            target_ref, merge_message, user_name, user_email, target_ref)
        assert merge_commit_id == target_rev
        assert not needs_push

        target_repo = MercurialRepository(target_repo.path)
        assert target_repo.commit_ids[-1] == target_rev

        assert not os.path.exists(
            os.path.join(target_repo.path, '.hg', 'merge', 'state'))
    def test_cleanup_merge_workspace(self):
        workspace = self.repo._maybe_prepare_merge_workspace(
            'pr3', Reference('branch', 'master', 'unused'))
        self.repo.cleanup_merge_workspace('pr3')

        assert not os.path.exists(workspace)
 def test_local_pull_from_same_repo(self):
     reference = Reference('branch', 'default', None)
     with pytest.raises(ValueError):
         self.repo._local_pull(self.repo.path, reference)
 def test_merge_invalid_message(self, vcsbackend):
     repo = vcsbackend.create_repo(number_of_commits=1)
     ref = Reference('branch', 'master', 'not_used')
     with pytest.raises(ValueError):
         repo.merge(ref, self, ref, 'workspace_id', 'user name',
                    '*****@*****.**')