##// END OF EJS Templates
settings: Remove obsolete VCS config value HG_USE_REBASE_FOR_MERGING
Martin Bornhold -
r363:78788d34 default
parent child Browse files
Show More
@@ -1,103 +1,101 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import shlex
22 import shlex
23 import Pyro4
23 import Pyro4
24 import platform
24 import platform
25
25
26 from rhodecode.model import init_model
26 from rhodecode.model import init_model
27
27
28
28
29 def configure_pyro4(config):
29 def configure_pyro4(config):
30 """
30 """
31 Configure Pyro4 based on `config`.
31 Configure Pyro4 based on `config`.
32
32
33 This will mainly set the different configuration parameters of the Pyro4
33 This will mainly set the different configuration parameters of the Pyro4
34 library based on the settings in our INI files. The Pyro4 documentation
34 library based on the settings in our INI files. The Pyro4 documentation
35 lists more details about the specific settings and their meaning.
35 lists more details about the specific settings and their meaning.
36 """
36 """
37 Pyro4.config.COMMTIMEOUT = float(config['vcs.connection_timeout'])
37 Pyro4.config.COMMTIMEOUT = float(config['vcs.connection_timeout'])
38 Pyro4.config.SERIALIZER = 'pickle'
38 Pyro4.config.SERIALIZER = 'pickle'
39 Pyro4.config.SERIALIZERS_ACCEPTED.add('pickle')
39 Pyro4.config.SERIALIZERS_ACCEPTED.add('pickle')
40
40
41 # Note: We need server configuration in the WSGI processes
41 # Note: We need server configuration in the WSGI processes
42 # because we provide a callback server in certain vcs operations.
42 # because we provide a callback server in certain vcs operations.
43 Pyro4.config.SERVERTYPE = "multiplex"
43 Pyro4.config.SERVERTYPE = "multiplex"
44 Pyro4.config.POLLTIMEOUT = 0.01
44 Pyro4.config.POLLTIMEOUT = 0.01
45
45
46
46
47 def configure_vcs(config):
47 def configure_vcs(config):
48 """
48 """
49 Patch VCS config with some RhodeCode specific stuff
49 Patch VCS config with some RhodeCode specific stuff
50 """
50 """
51 from rhodecode.lib.vcs import conf
51 from rhodecode.lib.vcs import conf
52 from rhodecode.lib.utils2 import aslist
52 from rhodecode.lib.utils2 import aslist
53 conf.settings.BACKENDS = {
53 conf.settings.BACKENDS = {
54 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
54 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
55 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
55 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
56 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository',
56 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository',
57 }
57 }
58
58
59 conf.settings.HG_USE_REBASE_FOR_MERGING = config.get(
60 'rhodecode_hg_use_rebase_for_merging', False)
61 conf.settings.GIT_REV_FILTER = shlex.split(
59 conf.settings.GIT_REV_FILTER = shlex.split(
62 config.get('git_rev_filter', '--all').strip())
60 config.get('git_rev_filter', '--all').strip())
63 conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
61 conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
64 'UTF-8'), sep=',')
62 'UTF-8'), sep=',')
65 conf.settings.ALIASES[:] = config.get('vcs.backends')
63 conf.settings.ALIASES[:] = config.get('vcs.backends')
66 conf.settings.SVN_COMPATIBLE_VERSION = config.get(
64 conf.settings.SVN_COMPATIBLE_VERSION = config.get(
67 'vcs.svn.compatible_version')
65 'vcs.svn.compatible_version')
68
66
69
67
70 def initialize_database(config):
68 def initialize_database(config):
71 from rhodecode.lib.utils2 import engine_from_config, get_encryption_key
69 from rhodecode.lib.utils2 import engine_from_config, get_encryption_key
72 engine = engine_from_config(config, 'sqlalchemy.db1.')
70 engine = engine_from_config(config, 'sqlalchemy.db1.')
73 init_model(engine, encryption_key=get_encryption_key(config))
71 init_model(engine, encryption_key=get_encryption_key(config))
74
72
75
73
76 def initialize_test_environment(settings, test_env=None):
74 def initialize_test_environment(settings, test_env=None):
77 if test_env is None:
75 if test_env is None:
78 test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0))
76 test_env = not int(os.environ.get('RC_NO_TMP_PATH', 0))
79
77
80 from rhodecode.lib.utils import (
78 from rhodecode.lib.utils import (
81 create_test_directory, create_test_database, create_test_repositories,
79 create_test_directory, create_test_database, create_test_repositories,
82 create_test_index)
80 create_test_index)
83 from rhodecode.tests import TESTS_TMP_PATH
81 from rhodecode.tests import TESTS_TMP_PATH
84 # test repos
82 # test repos
85 if test_env:
83 if test_env:
86 create_test_directory(TESTS_TMP_PATH)
84 create_test_directory(TESTS_TMP_PATH)
87 create_test_database(TESTS_TMP_PATH, settings)
85 create_test_database(TESTS_TMP_PATH, settings)
88 create_test_repositories(TESTS_TMP_PATH, settings)
86 create_test_repositories(TESTS_TMP_PATH, settings)
89 create_test_index(TESTS_TMP_PATH, settings)
87 create_test_index(TESTS_TMP_PATH, settings)
90
88
91
89
92 def get_vcs_server_protocol(config):
90 def get_vcs_server_protocol(config):
93 protocol = config.get('vcs.server.protocol', 'pyro4')
91 protocol = config.get('vcs.server.protocol', 'pyro4')
94 return protocol
92 return protocol
95
93
96
94
97 def set_instance_id(config):
95 def set_instance_id(config):
98 """ Sets a dynamic generated config['instance_id'] if missing or '*' """
96 """ Sets a dynamic generated config['instance_id'] if missing or '*' """
99
97
100 config['instance_id'] = config.get('instance_id') or ''
98 config['instance_id'] = config.get('instance_id') or ''
101 if config['instance_id'] == '*' or not config['instance_id']:
99 if config['instance_id'] == '*' or not config['instance_id']:
102 _platform_id = platform.uname()[1] or 'instance'
100 _platform_id = platform.uname()[1] or 'instance'
103 config['instance_id'] = '%s-%s' % (_platform_id, os.getpid())
101 config['instance_id'] = '%s-%s' % (_platform_id, os.getpid())
@@ -1,86 +1,84 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2016 RhodeCode GmbH
3 # Copyright (C) 2014-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Internal settings for vcs-lib
22 Internal settings for vcs-lib
23 """
23 """
24
24
25 # list of default encoding used in safe_unicode/safe_str methods
25 # list of default encoding used in safe_unicode/safe_str methods
26 DEFAULT_ENCODINGS = ['utf8']
26 DEFAULT_ENCODINGS = ['utf8']
27
27
28 # Optional arguments to rev-filter, it has to be a list
28 # Optional arguments to rev-filter, it has to be a list
29 # It can also be ['--branches', '--tags']
29 # It can also be ['--branches', '--tags']
30 GIT_REV_FILTER = ['--all']
30 GIT_REV_FILTER = ['--all']
31
31
32 HG_USE_REBASE_FOR_MERGING = False
33
34 # Compatibility version when creating SVN repositories. None means newest.
32 # Compatibility version when creating SVN repositories. None means newest.
35 # Other available options are: pre-1.4-compatible, pre-1.5-compatible,
33 # Other available options are: pre-1.4-compatible, pre-1.5-compatible,
36 # pre-1.6-compatible, pre-1.8-compatible
34 # pre-1.6-compatible, pre-1.8-compatible
37 SVN_COMPATIBLE_VERSION = None
35 SVN_COMPATIBLE_VERSION = None
38
36
39 ALIASES = ['hg', 'git', 'svn']
37 ALIASES = ['hg', 'git', 'svn']
40
38
41 BACKENDS = {
39 BACKENDS = {
42 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
40 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
43 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
41 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
44 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository',
42 'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository',
45 }
43 }
46
44
47 # TODO: Remove once controllers/files.py is adjusted
45 # TODO: Remove once controllers/files.py is adjusted
48 ARCHIVE_SPECS = {
46 ARCHIVE_SPECS = {
49 'tbz2': ('application/x-bzip2', '.tar.bz2'),
47 'tbz2': ('application/x-bzip2', '.tar.bz2'),
50 'tgz': ('application/x-gzip', '.tar.gz'),
48 'tgz': ('application/x-gzip', '.tar.gz'),
51 'zip': ('application/zip', '.zip'),
49 'zip': ('application/zip', '.zip'),
52 }
50 }
53
51
54 PYRO_PORT = 9900
52 PYRO_PORT = 9900
55
53
56 PYRO_GIT = 'git_remote'
54 PYRO_GIT = 'git_remote'
57 PYRO_HG = 'hg_remote'
55 PYRO_HG = 'hg_remote'
58 PYRO_SVN = 'svn_remote'
56 PYRO_SVN = 'svn_remote'
59 PYRO_VCSSERVER = 'vcs_server'
57 PYRO_VCSSERVER = 'vcs_server'
60 PYRO_GIT_REMOTE_WSGI = 'git_remote_wsgi'
58 PYRO_GIT_REMOTE_WSGI = 'git_remote_wsgi'
61 PYRO_HG_REMOTE_WSGI = 'hg_remote_wsgi'
59 PYRO_HG_REMOTE_WSGI = 'hg_remote_wsgi'
62
60
63 PYRO_RECONNECT_TRIES = 15
61 PYRO_RECONNECT_TRIES = 15
64 """
62 """
65 How many retries to reconnect will be performed if the connection was lost.
63 How many retries to reconnect will be performed if the connection was lost.
66
64
67 Each try takes 2s. Doing 15 means that we will give it up to 30s for a
65 Each try takes 2s. Doing 15 means that we will give it up to 30s for a
68 connection to be re-established.
66 connection to be re-established.
69 """
67 """
70
68
71
69
72 def pyro_remote(object_id, server_and_port):
70 def pyro_remote(object_id, server_and_port):
73 return "PYRO:%s@%s" % (object_id, server_and_port)
71 return "PYRO:%s@%s" % (object_id, server_and_port)
74
72
75
73
76 def available_aliases():
74 def available_aliases():
77 """
75 """
78 Mercurial is required for the system to work, so in case vcs.backends does
76 Mercurial is required for the system to work, so in case vcs.backends does
79 not include it, we make sure it will be available internally
77 not include it, we make sure it will be available internally
80 TODO: anderson: refactor vcs.backends so it won't be necessary, VCS server
78 TODO: anderson: refactor vcs.backends so it won't be necessary, VCS server
81 should be responsible to dictate available backends.
79 should be responsible to dictate available backends.
82 """
80 """
83 aliases = ALIASES[:]
81 aliases = ALIASES[:]
84 if 'hg' not in aliases:
82 if 'hg' not in aliases:
85 aliases += ['hg']
83 aliases += ['hg']
86 return aliases
84 return aliases
@@ -1,1174 +1,1172 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22
22
23 import mock
23 import mock
24 import pytest
24 import pytest
25
25
26 import rhodecode.lib.vcs.conf.settings
26 import rhodecode.lib.vcs.conf.settings
27 from rhodecode.lib.vcs import backends
27 from rhodecode.lib.vcs import backends
28 from rhodecode.lib.vcs.backends.base import (
28 from rhodecode.lib.vcs.backends.base import (
29 Reference, MergeResponse, MergeFailureReason)
29 Reference, MergeResponse, MergeFailureReason)
30 from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialCommit
30 from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialCommit
31 from rhodecode.lib.vcs.exceptions import (
31 from rhodecode.lib.vcs.exceptions import (
32 CommitError, RepositoryError, VCSError, NodeDoesNotExistError,
32 CommitError, RepositoryError, VCSError, NodeDoesNotExistError,
33 CommitDoesNotExistError)
33 CommitDoesNotExistError)
34 from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
34 from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
35 from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
35 from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
36
36
37
37
38 pytestmark = pytest.mark.backends("hg")
38 pytestmark = pytest.mark.backends("hg")
39
39
40
40
41 def repo_path_generator():
41 def repo_path_generator():
42 """
42 """
43 Return a different path to be used for cloning repos.
43 Return a different path to be used for cloning repos.
44 """
44 """
45 i = 0
45 i = 0
46 while True:
46 while True:
47 i += 1
47 i += 1
48 yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
48 yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
49
49
50
50
51 REPO_PATH_GENERATOR = repo_path_generator()
51 REPO_PATH_GENERATOR = repo_path_generator()
52
52
53
53
54 @pytest.fixture(scope='class', autouse=True)
54 @pytest.fixture(scope='class', autouse=True)
55 def repo(request, pylonsapp):
55 def repo(request, pylonsapp):
56 repo = MercurialRepository(TEST_HG_REPO)
56 repo = MercurialRepository(TEST_HG_REPO)
57 if request.cls:
57 if request.cls:
58 request.cls.repo = repo
58 request.cls.repo = repo
59 return repo
59 return repo
60
60
61
61
62 class TestMercurialRepository:
62 class TestMercurialRepository:
63
63
64 # pylint: disable=protected-access
64 # pylint: disable=protected-access
65
65
66 def get_clone_repo(self):
66 def get_clone_repo(self):
67 """
67 """
68 Return a clone of the base repo.
68 Return a clone of the base repo.
69 """
69 """
70 clone_path = next(REPO_PATH_GENERATOR)
70 clone_path = next(REPO_PATH_GENERATOR)
71 repo_clone = MercurialRepository(
71 repo_clone = MercurialRepository(
72 clone_path, create=True, src_url=self.repo.path)
72 clone_path, create=True, src_url=self.repo.path)
73
73
74 return repo_clone
74 return repo_clone
75
75
76 def get_empty_repo(self):
76 def get_empty_repo(self):
77 """
77 """
78 Return an empty repo.
78 Return an empty repo.
79 """
79 """
80 return MercurialRepository(next(REPO_PATH_GENERATOR), create=True)
80 return MercurialRepository(next(REPO_PATH_GENERATOR), create=True)
81
81
82 def test_wrong_repo_path(self):
82 def test_wrong_repo_path(self):
83 wrong_repo_path = '/tmp/errorrepo'
83 wrong_repo_path = '/tmp/errorrepo'
84 with pytest.raises(RepositoryError):
84 with pytest.raises(RepositoryError):
85 MercurialRepository(wrong_repo_path)
85 MercurialRepository(wrong_repo_path)
86
86
87 def test_unicode_path_repo(self):
87 def test_unicode_path_repo(self):
88 with pytest.raises(VCSError):
88 with pytest.raises(VCSError):
89 MercurialRepository(u'iShouldFail')
89 MercurialRepository(u'iShouldFail')
90
90
91 def test_unicode_commit_id(self):
91 def test_unicode_commit_id(self):
92 with pytest.raises(CommitDoesNotExistError):
92 with pytest.raises(CommitDoesNotExistError):
93 self.repo.get_commit(u'unicode-commit-id')
93 self.repo.get_commit(u'unicode-commit-id')
94 with pytest.raises(CommitDoesNotExistError):
94 with pytest.raises(CommitDoesNotExistError):
95 self.repo.get_commit(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-commit-id')
95 self.repo.get_commit(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-commit-id')
96
96
97 def test_unicode_bookmark(self):
97 def test_unicode_bookmark(self):
98 self.repo.bookmark(u'unicode-bookmark')
98 self.repo.bookmark(u'unicode-bookmark')
99 self.repo.bookmark(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-bookmark')
99 self.repo.bookmark(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-bookmark')
100
100
101 def test_unicode_branch(self):
101 def test_unicode_branch(self):
102 with pytest.raises(KeyError):
102 with pytest.raises(KeyError):
103 self.repo.branches[u'unicode-branch']
103 self.repo.branches[u'unicode-branch']
104 with pytest.raises(KeyError):
104 with pytest.raises(KeyError):
105 self.repo.branches[u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-branch']
105 self.repo.branches[u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-branch']
106
106
107 def test_repo_clone(self):
107 def test_repo_clone(self):
108 if os.path.exists(TEST_HG_REPO_CLONE):
108 if os.path.exists(TEST_HG_REPO_CLONE):
109 self.fail(
109 self.fail(
110 'Cannot test mercurial clone repo as location %s already '
110 'Cannot test mercurial clone repo as location %s already '
111 'exists. You should manually remove it first.'
111 'exists. You should manually remove it first.'
112 % TEST_HG_REPO_CLONE)
112 % TEST_HG_REPO_CLONE)
113
113
114 repo = MercurialRepository(TEST_HG_REPO)
114 repo = MercurialRepository(TEST_HG_REPO)
115 repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
115 repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
116 src_url=TEST_HG_REPO)
116 src_url=TEST_HG_REPO)
117 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
117 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
118 # Checking hashes of commits should be enough
118 # Checking hashes of commits should be enough
119 for commit in repo.get_commits():
119 for commit in repo.get_commits():
120 raw_id = commit.raw_id
120 raw_id = commit.raw_id
121 assert raw_id == repo_clone.get_commit(raw_id).raw_id
121 assert raw_id == repo_clone.get_commit(raw_id).raw_id
122
122
123 def test_repo_clone_with_update(self):
123 def test_repo_clone_with_update(self):
124 repo = MercurialRepository(TEST_HG_REPO)
124 repo = MercurialRepository(TEST_HG_REPO)
125 repo_clone = MercurialRepository(
125 repo_clone = MercurialRepository(
126 TEST_HG_REPO_CLONE + '_w_update',
126 TEST_HG_REPO_CLONE + '_w_update',
127 src_url=TEST_HG_REPO, update_after_clone=True)
127 src_url=TEST_HG_REPO, update_after_clone=True)
128 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
128 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
129
129
130 # check if current workdir was updated
130 # check if current workdir was updated
131 assert os.path.isfile(
131 assert os.path.isfile(
132 os.path.join(TEST_HG_REPO_CLONE + '_w_update', 'MANIFEST.in'))
132 os.path.join(TEST_HG_REPO_CLONE + '_w_update', 'MANIFEST.in'))
133
133
134 def test_repo_clone_without_update(self):
134 def test_repo_clone_without_update(self):
135 repo = MercurialRepository(TEST_HG_REPO)
135 repo = MercurialRepository(TEST_HG_REPO)
136 repo_clone = MercurialRepository(
136 repo_clone = MercurialRepository(
137 TEST_HG_REPO_CLONE + '_wo_update',
137 TEST_HG_REPO_CLONE + '_wo_update',
138 src_url=TEST_HG_REPO, update_after_clone=False)
138 src_url=TEST_HG_REPO, update_after_clone=False)
139 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
139 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
140 assert not os.path.isfile(
140 assert not os.path.isfile(
141 os.path.join(TEST_HG_REPO_CLONE + '_wo_update', 'MANIFEST.in'))
141 os.path.join(TEST_HG_REPO_CLONE + '_wo_update', 'MANIFEST.in'))
142
142
143 def test_commit_ids(self):
143 def test_commit_ids(self):
144 # there are 21 commits at bitbucket now
144 # there are 21 commits at bitbucket now
145 # so we can assume they would be available from now on
145 # so we can assume they would be available from now on
146 subset = set([
146 subset = set([
147 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
147 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
148 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
148 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
149 '6cba7170863a2411822803fa77a0a264f1310b35',
149 '6cba7170863a2411822803fa77a0a264f1310b35',
150 '56349e29c2af3ac913b28bde9a2c6154436e615b',
150 '56349e29c2af3ac913b28bde9a2c6154436e615b',
151 '2dda4e345facb0ccff1a191052dd1606dba6781d',
151 '2dda4e345facb0ccff1a191052dd1606dba6781d',
152 '6fff84722075f1607a30f436523403845f84cd9e',
152 '6fff84722075f1607a30f436523403845f84cd9e',
153 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
153 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
154 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
154 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
155 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
155 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
156 'be90031137367893f1c406e0a8683010fd115b79',
156 'be90031137367893f1c406e0a8683010fd115b79',
157 'db8e58be770518cbb2b1cdfa69146e47cd481481',
157 'db8e58be770518cbb2b1cdfa69146e47cd481481',
158 '84478366594b424af694a6c784cb991a16b87c21',
158 '84478366594b424af694a6c784cb991a16b87c21',
159 '17f8e105dddb9f339600389c6dc7175d395a535c',
159 '17f8e105dddb9f339600389c6dc7175d395a535c',
160 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
160 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
161 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
161 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
162 '786facd2c61deb9cf91e9534735124fb8fc11842',
162 '786facd2c61deb9cf91e9534735124fb8fc11842',
163 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
163 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
164 'aa6a0de05b7612707db567078e130a6cd114a9a7',
164 'aa6a0de05b7612707db567078e130a6cd114a9a7',
165 'eada5a770da98ab0dd7325e29d00e0714f228d09'
165 'eada5a770da98ab0dd7325e29d00e0714f228d09'
166 ])
166 ])
167 assert subset.issubset(set(self.repo.commit_ids))
167 assert subset.issubset(set(self.repo.commit_ids))
168
168
169 # check if we have the proper order of commits
169 # check if we have the proper order of commits
170 org = [
170 org = [
171 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
171 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
172 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
172 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
173 '6cba7170863a2411822803fa77a0a264f1310b35',
173 '6cba7170863a2411822803fa77a0a264f1310b35',
174 '56349e29c2af3ac913b28bde9a2c6154436e615b',
174 '56349e29c2af3ac913b28bde9a2c6154436e615b',
175 '2dda4e345facb0ccff1a191052dd1606dba6781d',
175 '2dda4e345facb0ccff1a191052dd1606dba6781d',
176 '6fff84722075f1607a30f436523403845f84cd9e',
176 '6fff84722075f1607a30f436523403845f84cd9e',
177 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
177 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
178 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
178 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
179 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
179 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
180 'be90031137367893f1c406e0a8683010fd115b79',
180 'be90031137367893f1c406e0a8683010fd115b79',
181 'db8e58be770518cbb2b1cdfa69146e47cd481481',
181 'db8e58be770518cbb2b1cdfa69146e47cd481481',
182 '84478366594b424af694a6c784cb991a16b87c21',
182 '84478366594b424af694a6c784cb991a16b87c21',
183 '17f8e105dddb9f339600389c6dc7175d395a535c',
183 '17f8e105dddb9f339600389c6dc7175d395a535c',
184 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
184 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
185 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
185 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
186 '786facd2c61deb9cf91e9534735124fb8fc11842',
186 '786facd2c61deb9cf91e9534735124fb8fc11842',
187 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
187 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
188 'aa6a0de05b7612707db567078e130a6cd114a9a7',
188 'aa6a0de05b7612707db567078e130a6cd114a9a7',
189 'eada5a770da98ab0dd7325e29d00e0714f228d09',
189 'eada5a770da98ab0dd7325e29d00e0714f228d09',
190 '2c1885c735575ca478bf9e17b0029dca68824458',
190 '2c1885c735575ca478bf9e17b0029dca68824458',
191 'd9bcd465040bf869799b09ad732c04e0eea99fe9',
191 'd9bcd465040bf869799b09ad732c04e0eea99fe9',
192 '469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7',
192 '469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7',
193 '4fb8326d78e5120da2c7468dcf7098997be385da',
193 '4fb8326d78e5120da2c7468dcf7098997be385da',
194 '62b4a097164940bd66030c4db51687f3ec035eed',
194 '62b4a097164940bd66030c4db51687f3ec035eed',
195 '536c1a19428381cfea92ac44985304f6a8049569',
195 '536c1a19428381cfea92ac44985304f6a8049569',
196 '965e8ab3c44b070cdaa5bf727ddef0ada980ecc4',
196 '965e8ab3c44b070cdaa5bf727ddef0ada980ecc4',
197 '9bb326a04ae5d98d437dece54be04f830cf1edd9',
197 '9bb326a04ae5d98d437dece54be04f830cf1edd9',
198 'f8940bcb890a98c4702319fbe36db75ea309b475',
198 'f8940bcb890a98c4702319fbe36db75ea309b475',
199 'ff5ab059786ebc7411e559a2cc309dfae3625a3b',
199 'ff5ab059786ebc7411e559a2cc309dfae3625a3b',
200 '6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08',
200 '6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08',
201 'ee87846a61c12153b51543bf860e1026c6d3dcba',
201 'ee87846a61c12153b51543bf860e1026c6d3dcba',
202 ]
202 ]
203 assert org == self.repo.commit_ids[:31]
203 assert org == self.repo.commit_ids[:31]
204
204
205 def test_iter_slice(self):
205 def test_iter_slice(self):
206 sliced = list(self.repo[:10])
206 sliced = list(self.repo[:10])
207 itered = list(self.repo)[:10]
207 itered = list(self.repo)[:10]
208 assert sliced == itered
208 assert sliced == itered
209
209
210 def test_slicing(self):
210 def test_slicing(self):
211 # 4 1 5 10 95
211 # 4 1 5 10 95
212 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
212 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
213 (10, 20, 10), (5, 100, 95)]:
213 (10, 20, 10), (5, 100, 95)]:
214 indexes = list(self.repo[sfrom:sto])
214 indexes = list(self.repo[sfrom:sto])
215 assert len(indexes) == size
215 assert len(indexes) == size
216 assert indexes[0] == self.repo.get_commit(commit_idx=sfrom)
216 assert indexes[0] == self.repo.get_commit(commit_idx=sfrom)
217 assert indexes[-1] == self.repo.get_commit(commit_idx=sto - 1)
217 assert indexes[-1] == self.repo.get_commit(commit_idx=sto - 1)
218
218
219 def test_branches(self):
219 def test_branches(self):
220 # TODO: Need more tests here
220 # TODO: Need more tests here
221
221
222 # active branches
222 # active branches
223 assert 'default' in self.repo.branches
223 assert 'default' in self.repo.branches
224 assert 'stable' in self.repo.branches
224 assert 'stable' in self.repo.branches
225
225
226 # closed
226 # closed
227 assert 'git' in self.repo._get_branches(closed=True)
227 assert 'git' in self.repo._get_branches(closed=True)
228 assert 'web' in self.repo._get_branches(closed=True)
228 assert 'web' in self.repo._get_branches(closed=True)
229
229
230 for name, id in self.repo.branches.items():
230 for name, id in self.repo.branches.items():
231 assert isinstance(self.repo.get_commit(id), MercurialCommit)
231 assert isinstance(self.repo.get_commit(id), MercurialCommit)
232
232
233 def test_tip_in_tags(self):
233 def test_tip_in_tags(self):
234 # tip is always a tag
234 # tip is always a tag
235 assert 'tip' in self.repo.tags
235 assert 'tip' in self.repo.tags
236
236
237 def test_tip_commit_in_tags(self):
237 def test_tip_commit_in_tags(self):
238 tip = self.repo.get_commit()
238 tip = self.repo.get_commit()
239 assert self.repo.tags['tip'] == tip.raw_id
239 assert self.repo.tags['tip'] == tip.raw_id
240
240
241 def test_initial_commit(self):
241 def test_initial_commit(self):
242 init_commit = self.repo.get_commit(commit_idx=0)
242 init_commit = self.repo.get_commit(commit_idx=0)
243 init_author = init_commit.author
243 init_author = init_commit.author
244
244
245 assert init_commit.message == 'initial import'
245 assert init_commit.message == 'initial import'
246 assert init_author == 'Marcin Kuzminski <marcin@python-blog.com>'
246 assert init_author == 'Marcin Kuzminski <marcin@python-blog.com>'
247 assert init_author == init_commit.committer
247 assert init_author == init_commit.committer
248 assert sorted(init_commit._file_paths) == sorted([
248 assert sorted(init_commit._file_paths) == sorted([
249 'vcs/__init__.py',
249 'vcs/__init__.py',
250 'vcs/backends/BaseRepository.py',
250 'vcs/backends/BaseRepository.py',
251 'vcs/backends/__init__.py',
251 'vcs/backends/__init__.py',
252 ])
252 ])
253 assert sorted(init_commit._dir_paths) == sorted(
253 assert sorted(init_commit._dir_paths) == sorted(
254 ['', 'vcs', 'vcs/backends'])
254 ['', 'vcs', 'vcs/backends'])
255
255
256 assert init_commit._dir_paths + init_commit._file_paths == \
256 assert init_commit._dir_paths + init_commit._file_paths == \
257 init_commit._paths
257 init_commit._paths
258
258
259 with pytest.raises(NodeDoesNotExistError):
259 with pytest.raises(NodeDoesNotExistError):
260 init_commit.get_node(path='foobar')
260 init_commit.get_node(path='foobar')
261
261
262 node = init_commit.get_node('vcs/')
262 node = init_commit.get_node('vcs/')
263 assert hasattr(node, 'kind')
263 assert hasattr(node, 'kind')
264 assert node.kind == NodeKind.DIR
264 assert node.kind == NodeKind.DIR
265
265
266 node = init_commit.get_node('vcs')
266 node = init_commit.get_node('vcs')
267 assert hasattr(node, 'kind')
267 assert hasattr(node, 'kind')
268 assert node.kind == NodeKind.DIR
268 assert node.kind == NodeKind.DIR
269
269
270 node = init_commit.get_node('vcs/__init__.py')
270 node = init_commit.get_node('vcs/__init__.py')
271 assert hasattr(node, 'kind')
271 assert hasattr(node, 'kind')
272 assert node.kind == NodeKind.FILE
272 assert node.kind == NodeKind.FILE
273
273
274 def test_not_existing_commit(self):
274 def test_not_existing_commit(self):
275 # rawid
275 # rawid
276 with pytest.raises(RepositoryError):
276 with pytest.raises(RepositoryError):
277 self.repo.get_commit('abcd' * 10)
277 self.repo.get_commit('abcd' * 10)
278 # shortid
278 # shortid
279 with pytest.raises(RepositoryError):
279 with pytest.raises(RepositoryError):
280 self.repo.get_commit('erro' * 4)
280 self.repo.get_commit('erro' * 4)
281 # numeric
281 # numeric
282 with pytest.raises(RepositoryError):
282 with pytest.raises(RepositoryError):
283 self.repo.get_commit(commit_idx=self.repo.count() + 1)
283 self.repo.get_commit(commit_idx=self.repo.count() + 1)
284
284
285 # Small chance we ever get to this one
285 # Small chance we ever get to this one
286 idx = pow(2, 30)
286 idx = pow(2, 30)
287 with pytest.raises(RepositoryError):
287 with pytest.raises(RepositoryError):
288 self.repo.get_commit(commit_idx=idx)
288 self.repo.get_commit(commit_idx=idx)
289
289
290 def test_commit10(self):
290 def test_commit10(self):
291 commit10 = self.repo.get_commit(commit_idx=10)
291 commit10 = self.repo.get_commit(commit_idx=10)
292 README = """===
292 README = """===
293 VCS
293 VCS
294 ===
294 ===
295
295
296 Various Version Control System management abstraction layer for Python.
296 Various Version Control System management abstraction layer for Python.
297
297
298 Introduction
298 Introduction
299 ------------
299 ------------
300
300
301 TODO: To be written...
301 TODO: To be written...
302
302
303 """
303 """
304 node = commit10.get_node('README.rst')
304 node = commit10.get_node('README.rst')
305 assert node.kind == NodeKind.FILE
305 assert node.kind == NodeKind.FILE
306 assert node.content == README
306 assert node.content == README
307
307
308 def test_local_clone(self):
308 def test_local_clone(self):
309 clone_path = next(REPO_PATH_GENERATOR)
309 clone_path = next(REPO_PATH_GENERATOR)
310 self.repo._local_clone(clone_path)
310 self.repo._local_clone(clone_path)
311 repo_clone = MercurialRepository(clone_path)
311 repo_clone = MercurialRepository(clone_path)
312
312
313 assert self.repo.commit_ids == repo_clone.commit_ids
313 assert self.repo.commit_ids == repo_clone.commit_ids
314
314
315 def test_local_clone_fails_if_target_exists(self):
315 def test_local_clone_fails_if_target_exists(self):
316 with pytest.raises(RepositoryError):
316 with pytest.raises(RepositoryError):
317 self.repo._local_clone(self.repo.path)
317 self.repo._local_clone(self.repo.path)
318
318
319 def test_update(self):
319 def test_update(self):
320 repo_clone = self.get_clone_repo()
320 repo_clone = self.get_clone_repo()
321 branches = repo_clone.branches
321 branches = repo_clone.branches
322
322
323 repo_clone._update('default')
323 repo_clone._update('default')
324 assert branches['default'] == repo_clone._identify()
324 assert branches['default'] == repo_clone._identify()
325 repo_clone._update('stable')
325 repo_clone._update('stable')
326 assert branches['stable'] == repo_clone._identify()
326 assert branches['stable'] == repo_clone._identify()
327
327
328 def test_local_pull_branch(self):
328 def test_local_pull_branch(self):
329 target_repo = self.get_empty_repo()
329 target_repo = self.get_empty_repo()
330 source_repo = self.get_clone_repo()
330 source_repo = self.get_clone_repo()
331
331
332 default = Reference(
332 default = Reference(
333 'branch', 'default', source_repo.branches['default'])
333 'branch', 'default', source_repo.branches['default'])
334 target_repo._local_pull(source_repo.path, default)
334 target_repo._local_pull(source_repo.path, default)
335 target_repo = MercurialRepository(target_repo.path)
335 target_repo = MercurialRepository(target_repo.path)
336 assert (target_repo.branches['default'] ==
336 assert (target_repo.branches['default'] ==
337 source_repo.branches['default'])
337 source_repo.branches['default'])
338
338
339 stable = Reference('branch', 'stable', source_repo.branches['stable'])
339 stable = Reference('branch', 'stable', source_repo.branches['stable'])
340 target_repo._local_pull(source_repo.path, stable)
340 target_repo._local_pull(source_repo.path, stable)
341 target_repo = MercurialRepository(target_repo.path)
341 target_repo = MercurialRepository(target_repo.path)
342 assert target_repo.branches['stable'] == source_repo.branches['stable']
342 assert target_repo.branches['stable'] == source_repo.branches['stable']
343
343
344 def test_local_pull_bookmark(self):
344 def test_local_pull_bookmark(self):
345 target_repo = self.get_empty_repo()
345 target_repo = self.get_empty_repo()
346 source_repo = self.get_clone_repo()
346 source_repo = self.get_clone_repo()
347
347
348 commits = list(source_repo.get_commits(branch_name='default'))
348 commits = list(source_repo.get_commits(branch_name='default'))
349 foo1_id = commits[-5].raw_id
349 foo1_id = commits[-5].raw_id
350 foo1 = Reference('book', 'foo1', foo1_id)
350 foo1 = Reference('book', 'foo1', foo1_id)
351 source_repo._update(foo1_id)
351 source_repo._update(foo1_id)
352 source_repo.bookmark('foo1')
352 source_repo.bookmark('foo1')
353
353
354 foo2_id = commits[-3].raw_id
354 foo2_id = commits[-3].raw_id
355 foo2 = Reference('book', 'foo2', foo2_id)
355 foo2 = Reference('book', 'foo2', foo2_id)
356 source_repo._update(foo2_id)
356 source_repo._update(foo2_id)
357 source_repo.bookmark('foo2')
357 source_repo.bookmark('foo2')
358
358
359 target_repo._local_pull(source_repo.path, foo1)
359 target_repo._local_pull(source_repo.path, foo1)
360 target_repo = MercurialRepository(target_repo.path)
360 target_repo = MercurialRepository(target_repo.path)
361 assert target_repo.branches['default'] == commits[-5].raw_id
361 assert target_repo.branches['default'] == commits[-5].raw_id
362
362
363 target_repo._local_pull(source_repo.path, foo2)
363 target_repo._local_pull(source_repo.path, foo2)
364 target_repo = MercurialRepository(target_repo.path)
364 target_repo = MercurialRepository(target_repo.path)
365 assert target_repo.branches['default'] == commits[-3].raw_id
365 assert target_repo.branches['default'] == commits[-3].raw_id
366
366
367 def test_local_pull_commit(self):
367 def test_local_pull_commit(self):
368 target_repo = self.get_empty_repo()
368 target_repo = self.get_empty_repo()
369 source_repo = self.get_clone_repo()
369 source_repo = self.get_clone_repo()
370
370
371 commits = list(source_repo.get_commits(branch_name='default'))
371 commits = list(source_repo.get_commits(branch_name='default'))
372 commit_id = commits[-5].raw_id
372 commit_id = commits[-5].raw_id
373 commit = Reference('rev', commit_id, commit_id)
373 commit = Reference('rev', commit_id, commit_id)
374 target_repo._local_pull(source_repo.path, commit)
374 target_repo._local_pull(source_repo.path, commit)
375 target_repo = MercurialRepository(target_repo.path)
375 target_repo = MercurialRepository(target_repo.path)
376 assert target_repo.branches['default'] == commit_id
376 assert target_repo.branches['default'] == commit_id
377
377
378 commit_id = commits[-3].raw_id
378 commit_id = commits[-3].raw_id
379 commit = Reference('rev', commit_id, commit_id)
379 commit = Reference('rev', commit_id, commit_id)
380 target_repo._local_pull(source_repo.path, commit)
380 target_repo._local_pull(source_repo.path, commit)
381 target_repo = MercurialRepository(target_repo.path)
381 target_repo = MercurialRepository(target_repo.path)
382 assert target_repo.branches['default'] == commit_id
382 assert target_repo.branches['default'] == commit_id
383
383
384 def test_local_pull_from_same_repo(self):
384 def test_local_pull_from_same_repo(self):
385 reference = Reference('branch', 'default', None)
385 reference = Reference('branch', 'default', None)
386 with pytest.raises(ValueError):
386 with pytest.raises(ValueError):
387 self.repo._local_pull(self.repo.path, reference)
387 self.repo._local_pull(self.repo.path, reference)
388
388
389 def test_validate_pull_reference_raises_on_missing_reference(
389 def test_validate_pull_reference_raises_on_missing_reference(
390 self, vcsbackend_hg):
390 self, vcsbackend_hg):
391 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
391 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
392 reference = Reference(
392 reference = Reference(
393 'book', 'invalid_reference', 'a' * 40)
393 'book', 'invalid_reference', 'a' * 40)
394
394
395 with pytest.raises(CommitDoesNotExistError):
395 with pytest.raises(CommitDoesNotExistError):
396 target_repo._validate_pull_reference(reference)
396 target_repo._validate_pull_reference(reference)
397
397
398 def test_heads(self):
398 def test_heads(self):
399 assert set(self.repo._heads()) == set(self.repo.branches.values())
399 assert set(self.repo._heads()) == set(self.repo.branches.values())
400
400
401 def test_ancestor(self):
401 def test_ancestor(self):
402 commits = [
402 commits = [
403 c.raw_id for c in self.repo.get_commits(branch_name='default')]
403 c.raw_id for c in self.repo.get_commits(branch_name='default')]
404 assert self.repo._ancestor(commits[-3], commits[-5]) == commits[-5]
404 assert self.repo._ancestor(commits[-3], commits[-5]) == commits[-5]
405 assert self.repo._ancestor(commits[-5], commits[-3]) == commits[-5]
405 assert self.repo._ancestor(commits[-5], commits[-3]) == commits[-5]
406
406
407 def test_local_push(self):
407 def test_local_push(self):
408 target_repo = self.get_empty_repo()
408 target_repo = self.get_empty_repo()
409
409
410 revisions = list(self.repo.get_commits(branch_name='default'))
410 revisions = list(self.repo.get_commits(branch_name='default'))
411 revision = revisions[-5].raw_id
411 revision = revisions[-5].raw_id
412 self.repo._local_push(revision, target_repo.path)
412 self.repo._local_push(revision, target_repo.path)
413
413
414 target_repo = MercurialRepository(target_repo.path)
414 target_repo = MercurialRepository(target_repo.path)
415
415
416 assert target_repo.branches['default'] == revision
416 assert target_repo.branches['default'] == revision
417
417
418 def test_hooks_can_be_enabled_for_local_push(self):
418 def test_hooks_can_be_enabled_for_local_push(self):
419 revision = 'deadbeef'
419 revision = 'deadbeef'
420 repo_path = 'test_group/test_repo'
420 repo_path = 'test_group/test_repo'
421 with mock.patch.object(self.repo, '_remote') as remote_mock:
421 with mock.patch.object(self.repo, '_remote') as remote_mock:
422 self.repo._local_push(revision, repo_path, enable_hooks=True)
422 self.repo._local_push(revision, repo_path, enable_hooks=True)
423 remote_mock.push.assert_called_once_with(
423 remote_mock.push.assert_called_once_with(
424 [revision], repo_path, hooks=True, push_branches=False)
424 [revision], repo_path, hooks=True, push_branches=False)
425
425
426 def test_local_merge(self, vcsbackend_hg):
426 def test_local_merge(self, vcsbackend_hg):
427 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
427 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
428 source_repo = vcsbackend_hg.clone_repo(target_repo)
428 source_repo = vcsbackend_hg.clone_repo(target_repo)
429 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
429 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
430 target_repo = MercurialRepository(target_repo.path)
430 target_repo = MercurialRepository(target_repo.path)
431 target_rev = target_repo.branches['default']
431 target_rev = target_repo.branches['default']
432 target_ref = Reference(
432 target_ref = Reference(
433 type='branch', name='default', commit_id=target_rev)
433 type='branch', name='default', commit_id=target_rev)
434 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
434 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
435 source_repo = MercurialRepository(source_repo.path)
435 source_repo = MercurialRepository(source_repo.path)
436 source_rev = source_repo.branches['default']
436 source_rev = source_repo.branches['default']
437 source_ref = Reference(
437 source_ref = Reference(
438 type='branch', name='default', commit_id=source_rev)
438 type='branch', name='default', commit_id=source_rev)
439
439
440 target_repo._local_pull(source_repo.path, source_ref)
440 target_repo._local_pull(source_repo.path, source_ref)
441
441
442 merge_message = 'Merge message\n\nDescription:...'
442 merge_message = 'Merge message\n\nDescription:...'
443 user_name = 'Albert Einstein'
443 user_name = 'Albert Einstein'
444 user_email = 'albert@einstein.com'
444 user_email = 'albert@einstein.com'
445 merge_commit_id, needs_push = target_repo._local_merge(
445 merge_commit_id, needs_push = target_repo._local_merge(
446 target_ref, merge_message, user_name, user_email, source_ref)
446 target_ref, merge_message, user_name, user_email, source_ref)
447 assert needs_push
447 assert needs_push
448
448
449 target_repo = MercurialRepository(target_repo.path)
449 target_repo = MercurialRepository(target_repo.path)
450 assert target_repo.commit_ids[-3] == target_rev
450 assert target_repo.commit_ids[-3] == target_rev
451 assert target_repo.commit_ids[-2] == source_rev
451 assert target_repo.commit_ids[-2] == source_rev
452 last_commit = target_repo.get_commit(merge_commit_id)
452 last_commit = target_repo.get_commit(merge_commit_id)
453 assert last_commit.message.strip() == merge_message
453 assert last_commit.message.strip() == merge_message
454 assert last_commit.author == '%s <%s>' % (user_name, user_email)
454 assert last_commit.author == '%s <%s>' % (user_name, user_email)
455
455
456 assert not os.path.exists(
456 assert not os.path.exists(
457 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
457 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
458
458
459 def test_local_merge_source_is_fast_forward(self, vcsbackend_hg):
459 def test_local_merge_source_is_fast_forward(self, vcsbackend_hg):
460 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
460 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
461 source_repo = vcsbackend_hg.clone_repo(target_repo)
461 source_repo = vcsbackend_hg.clone_repo(target_repo)
462 target_rev = target_repo.branches['default']
462 target_rev = target_repo.branches['default']
463 target_ref = Reference(
463 target_ref = Reference(
464 type='branch', name='default', commit_id=target_rev)
464 type='branch', name='default', commit_id=target_rev)
465 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
465 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
466 source_repo = MercurialRepository(source_repo.path)
466 source_repo = MercurialRepository(source_repo.path)
467 source_rev = source_repo.branches['default']
467 source_rev = source_repo.branches['default']
468 source_ref = Reference(
468 source_ref = Reference(
469 type='branch', name='default', commit_id=source_rev)
469 type='branch', name='default', commit_id=source_rev)
470
470
471 target_repo._local_pull(source_repo.path, source_ref)
471 target_repo._local_pull(source_repo.path, source_ref)
472
472
473 merge_message = 'Merge message\n\nDescription:...'
473 merge_message = 'Merge message\n\nDescription:...'
474 user_name = 'Albert Einstein'
474 user_name = 'Albert Einstein'
475 user_email = 'albert@einstein.com'
475 user_email = 'albert@einstein.com'
476 merge_commit_id, needs_push = target_repo._local_merge(
476 merge_commit_id, needs_push = target_repo._local_merge(
477 target_ref, merge_message, user_name, user_email, source_ref)
477 target_ref, merge_message, user_name, user_email, source_ref)
478 assert merge_commit_id == source_rev
478 assert merge_commit_id == source_rev
479 assert needs_push
479 assert needs_push
480
480
481 target_repo = MercurialRepository(target_repo.path)
481 target_repo = MercurialRepository(target_repo.path)
482 assert target_repo.commit_ids[-2] == target_rev
482 assert target_repo.commit_ids[-2] == target_rev
483 assert target_repo.commit_ids[-1] == source_rev
483 assert target_repo.commit_ids[-1] == source_rev
484
484
485 assert not os.path.exists(
485 assert not os.path.exists(
486 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
486 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
487
487
488 def test_local_merge_source_is_integrated(self, vcsbackend_hg):
488 def test_local_merge_source_is_integrated(self, vcsbackend_hg):
489 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
489 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
490 target_rev = target_repo.branches['default']
490 target_rev = target_repo.branches['default']
491 target_ref = Reference(
491 target_ref = Reference(
492 type='branch', name='default', commit_id=target_rev)
492 type='branch', name='default', commit_id=target_rev)
493
493
494 merge_message = 'Merge message\n\nDescription:...'
494 merge_message = 'Merge message\n\nDescription:...'
495 user_name = 'Albert Einstein'
495 user_name = 'Albert Einstein'
496 user_email = 'albert@einstein.com'
496 user_email = 'albert@einstein.com'
497 merge_commit_id, needs_push = target_repo._local_merge(
497 merge_commit_id, needs_push = target_repo._local_merge(
498 target_ref, merge_message, user_name, user_email, target_ref)
498 target_ref, merge_message, user_name, user_email, target_ref)
499 assert merge_commit_id == target_rev
499 assert merge_commit_id == target_rev
500 assert not needs_push
500 assert not needs_push
501
501
502 target_repo = MercurialRepository(target_repo.path)
502 target_repo = MercurialRepository(target_repo.path)
503 assert target_repo.commit_ids[-1] == target_rev
503 assert target_repo.commit_ids[-1] == target_rev
504
504
505 assert not os.path.exists(
505 assert not os.path.exists(
506 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
506 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
507
507
508 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_hg):
508 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_hg):
509 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
509 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
510 source_repo = vcsbackend_hg.clone_repo(target_repo)
510 source_repo = vcsbackend_hg.clone_repo(target_repo)
511 vcsbackend_hg.add_file(target_repo, 'README_MERGE', 'Version 1')
511 vcsbackend_hg.add_file(target_repo, 'README_MERGE', 'Version 1')
512 target_repo = MercurialRepository(target_repo.path)
512 target_repo = MercurialRepository(target_repo.path)
513 target_rev = target_repo.branches['default']
513 target_rev = target_repo.branches['default']
514 target_ref = Reference(
514 target_ref = Reference(
515 type='branch', name='default', commit_id=target_rev)
515 type='branch', name='default', commit_id=target_rev)
516 vcsbackend_hg.add_file(source_repo, 'README_MERGE', 'Version 2')
516 vcsbackend_hg.add_file(source_repo, 'README_MERGE', 'Version 2')
517 source_repo = MercurialRepository(source_repo.path)
517 source_repo = MercurialRepository(source_repo.path)
518 source_rev = source_repo.branches['default']
518 source_rev = source_repo.branches['default']
519 source_ref = Reference(
519 source_ref = Reference(
520 type='branch', name='default', commit_id=source_rev)
520 type='branch', name='default', commit_id=source_rev)
521
521
522 target_repo._local_pull(source_repo.path, source_ref)
522 target_repo._local_pull(source_repo.path, source_ref)
523 with pytest.raises(RepositoryError):
523 with pytest.raises(RepositoryError):
524 target_repo._local_merge(
524 target_repo._local_merge(
525 target_ref, 'merge_message', 'user name', 'user@name.com',
525 target_ref, 'merge_message', 'user name', 'user@name.com',
526 source_ref)
526 source_ref)
527
527
528 # Check we are not left in an intermediate merge state
528 # Check we are not left in an intermediate merge state
529 assert not os.path.exists(
529 assert not os.path.exists(
530 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
530 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
531
531
532 def test_local_merge_of_two_branches_of_the_same_repo(self, backend_hg):
532 def test_local_merge_of_two_branches_of_the_same_repo(self, backend_hg):
533 commits = [
533 commits = [
534 {'message': 'a'},
534 {'message': 'a'},
535 {'message': 'b', 'branch': 'b'},
535 {'message': 'b', 'branch': 'b'},
536 ]
536 ]
537 repo = backend_hg.create_repo(commits)
537 repo = backend_hg.create_repo(commits)
538 commit_ids = backend_hg.commit_ids
538 commit_ids = backend_hg.commit_ids
539 target_ref = Reference(
539 target_ref = Reference(
540 type='branch', name='default', commit_id=commit_ids['a'])
540 type='branch', name='default', commit_id=commit_ids['a'])
541 source_ref = Reference(
541 source_ref = Reference(
542 type='branch', name='b', commit_id=commit_ids['b'])
542 type='branch', name='b', commit_id=commit_ids['b'])
543 merge_message = 'Merge message\n\nDescription:...'
543 merge_message = 'Merge message\n\nDescription:...'
544 user_name = 'Albert Einstein'
544 user_name = 'Albert Einstein'
545 user_email = 'albert@einstein.com'
545 user_email = 'albert@einstein.com'
546 vcs_repo = repo.scm_instance()
546 vcs_repo = repo.scm_instance()
547 merge_commit_id, needs_push = vcs_repo._local_merge(
547 merge_commit_id, needs_push = vcs_repo._local_merge(
548 target_ref, merge_message, user_name, user_email, source_ref)
548 target_ref, merge_message, user_name, user_email, source_ref)
549 assert merge_commit_id != source_ref.commit_id
549 assert merge_commit_id != source_ref.commit_id
550 assert needs_push is True
550 assert needs_push is True
551 commit = vcs_repo.get_commit(merge_commit_id)
551 commit = vcs_repo.get_commit(merge_commit_id)
552 assert commit.merge is True
552 assert commit.merge is True
553 assert commit.message == merge_message
553 assert commit.message == merge_message
554
554
555 def test_maybe_prepare_merge_workspace(self):
555 def test_maybe_prepare_merge_workspace(self):
556 workspace = self.repo._maybe_prepare_merge_workspace('pr2', 'unused')
556 workspace = self.repo._maybe_prepare_merge_workspace('pr2', 'unused')
557
557
558 assert os.path.isdir(workspace)
558 assert os.path.isdir(workspace)
559 workspace_repo = MercurialRepository(workspace)
559 workspace_repo = MercurialRepository(workspace)
560 assert workspace_repo.branches == self.repo.branches
560 assert workspace_repo.branches == self.repo.branches
561
561
562 # Calling it a second time should also succeed
562 # Calling it a second time should also succeed
563 workspace = self.repo._maybe_prepare_merge_workspace('pr2', 'unused')
563 workspace = self.repo._maybe_prepare_merge_workspace('pr2', 'unused')
564 assert os.path.isdir(workspace)
564 assert os.path.isdir(workspace)
565
565
566 def test_cleanup_merge_workspace(self):
566 def test_cleanup_merge_workspace(self):
567 workspace = self.repo._maybe_prepare_merge_workspace('pr3', 'unused')
567 workspace = self.repo._maybe_prepare_merge_workspace('pr3', 'unused')
568 self.repo.cleanup_merge_workspace('pr3')
568 self.repo.cleanup_merge_workspace('pr3')
569
569
570 assert not os.path.exists(workspace)
570 assert not os.path.exists(workspace)
571
571
572 def test_cleanup_merge_workspace_invalid_workspace_id(self):
572 def test_cleanup_merge_workspace_invalid_workspace_id(self):
573 # No assert: because in case of an inexistent workspace this function
573 # No assert: because in case of an inexistent workspace this function
574 # should still succeed.
574 # should still succeed.
575 self.repo.cleanup_merge_workspace('pr4')
575 self.repo.cleanup_merge_workspace('pr4')
576
576
577 def test_merge_target_is_bookmark(self, vcsbackend_hg):
577 def test_merge_target_is_bookmark(self, vcsbackend_hg):
578 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
578 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
579 source_repo = vcsbackend_hg.clone_repo(target_repo)
579 source_repo = vcsbackend_hg.clone_repo(target_repo)
580 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
580 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
581 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
581 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
582 imc = source_repo.in_memory_commit
582 imc = source_repo.in_memory_commit
583 imc.add(FileNode('file_x', content=source_repo.name))
583 imc.add(FileNode('file_x', content=source_repo.name))
584 imc.commit(
584 imc.commit(
585 message=u'Automatic commit from repo merge test',
585 message=u'Automatic commit from repo merge test',
586 author=u'Automatic')
586 author=u'Automatic')
587 target_commit = target_repo.get_commit()
587 target_commit = target_repo.get_commit()
588 source_commit = source_repo.get_commit()
588 source_commit = source_repo.get_commit()
589 default_branch = target_repo.DEFAULT_BRANCH_NAME
589 default_branch = target_repo.DEFAULT_BRANCH_NAME
590 bookmark_name = 'bookmark'
590 bookmark_name = 'bookmark'
591 target_repo._update(default_branch)
591 target_repo._update(default_branch)
592 target_repo.bookmark(bookmark_name)
592 target_repo.bookmark(bookmark_name)
593 target_ref = Reference('book', bookmark_name, target_commit.raw_id)
593 target_ref = Reference('book', bookmark_name, target_commit.raw_id)
594 source_ref = Reference('branch', default_branch, source_commit.raw_id)
594 source_ref = Reference('branch', default_branch, source_commit.raw_id)
595 workspace = 'test-merge'
595 workspace = 'test-merge'
596
596
597 merge_response = target_repo.merge(
597 merge_response = target_repo.merge(
598 target_ref, source_repo, source_ref, workspace,
598 target_ref, source_repo, source_ref, workspace,
599 'test user', 'test@rhodecode.com', 'merge message 1',
599 'test user', 'test@rhodecode.com', 'merge message 1',
600 dry_run=False)
600 dry_run=False)
601 expected_merge_response = MergeResponse(
601 expected_merge_response = MergeResponse(
602 True, True, merge_response.merge_commit_id,
602 True, True, merge_response.merge_commit_id,
603 MergeFailureReason.NONE)
603 MergeFailureReason.NONE)
604 assert merge_response == expected_merge_response
604 assert merge_response == expected_merge_response
605
605
606 target_repo = backends.get_backend(vcsbackend_hg.alias)(
606 target_repo = backends.get_backend(vcsbackend_hg.alias)(
607 target_repo.path)
607 target_repo.path)
608 target_commits = list(target_repo.get_commits())
608 target_commits = list(target_repo.get_commits())
609 commit_ids = [c.raw_id for c in target_commits[:-1]]
609 commit_ids = [c.raw_id for c in target_commits[:-1]]
610 assert source_ref.commit_id in commit_ids
610 assert source_ref.commit_id in commit_ids
611 assert target_ref.commit_id in commit_ids
611 assert target_ref.commit_id in commit_ids
612
612
613 merge_commit = target_commits[-1]
613 merge_commit = target_commits[-1]
614 assert merge_commit.raw_id == merge_response.merge_commit_id
614 assert merge_commit.raw_id == merge_response.merge_commit_id
615 assert merge_commit.message.strip() == 'merge message 1'
615 assert merge_commit.message.strip() == 'merge message 1'
616 assert merge_commit.author == 'test user <test@rhodecode.com>'
616 assert merge_commit.author == 'test user <test@rhodecode.com>'
617
617
618 # Check the bookmark was updated in the target repo
618 # Check the bookmark was updated in the target repo
619 assert (
619 assert (
620 target_repo.bookmarks[bookmark_name] ==
620 target_repo.bookmarks[bookmark_name] ==
621 merge_response.merge_commit_id)
621 merge_response.merge_commit_id)
622
622
623 def test_merge_source_is_bookmark(self, vcsbackend_hg):
623 def test_merge_source_is_bookmark(self, vcsbackend_hg):
624 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
624 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
625 source_repo = vcsbackend_hg.clone_repo(target_repo)
625 source_repo = vcsbackend_hg.clone_repo(target_repo)
626 imc = source_repo.in_memory_commit
626 imc = source_repo.in_memory_commit
627 imc.add(FileNode('file_x', content=source_repo.name))
627 imc.add(FileNode('file_x', content=source_repo.name))
628 imc.commit(
628 imc.commit(
629 message=u'Automatic commit from repo merge test',
629 message=u'Automatic commit from repo merge test',
630 author=u'Automatic')
630 author=u'Automatic')
631 target_commit = target_repo.get_commit()
631 target_commit = target_repo.get_commit()
632 source_commit = source_repo.get_commit()
632 source_commit = source_repo.get_commit()
633 default_branch = target_repo.DEFAULT_BRANCH_NAME
633 default_branch = target_repo.DEFAULT_BRANCH_NAME
634 bookmark_name = 'bookmark'
634 bookmark_name = 'bookmark'
635 target_ref = Reference('branch', default_branch, target_commit.raw_id)
635 target_ref = Reference('branch', default_branch, target_commit.raw_id)
636 source_repo._update(default_branch)
636 source_repo._update(default_branch)
637 source_repo.bookmark(bookmark_name)
637 source_repo.bookmark(bookmark_name)
638 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
638 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
639 workspace = 'test-merge'
639 workspace = 'test-merge'
640
640
641 merge_response = target_repo.merge(
641 merge_response = target_repo.merge(
642 target_ref, source_repo, source_ref, workspace,
642 target_ref, source_repo, source_ref, workspace,
643 'test user', 'test@rhodecode.com', 'merge message 1',
643 'test user', 'test@rhodecode.com', 'merge message 1',
644 dry_run=False)
644 dry_run=False)
645 expected_merge_response = MergeResponse(
645 expected_merge_response = MergeResponse(
646 True, True, merge_response.merge_commit_id,
646 True, True, merge_response.merge_commit_id,
647 MergeFailureReason.NONE)
647 MergeFailureReason.NONE)
648 assert merge_response == expected_merge_response
648 assert merge_response == expected_merge_response
649
649
650 target_repo = backends.get_backend(vcsbackend_hg.alias)(
650 target_repo = backends.get_backend(vcsbackend_hg.alias)(
651 target_repo.path)
651 target_repo.path)
652 target_commits = list(target_repo.get_commits())
652 target_commits = list(target_repo.get_commits())
653 commit_ids = [c.raw_id for c in target_commits]
653 commit_ids = [c.raw_id for c in target_commits]
654 assert source_ref.commit_id == commit_ids[-1]
654 assert source_ref.commit_id == commit_ids[-1]
655 assert target_ref.commit_id == commit_ids[-2]
655 assert target_ref.commit_id == commit_ids[-2]
656
656
657 def test_merge_target_has_multiple_heads(self, vcsbackend_hg):
657 def test_merge_target_has_multiple_heads(self, vcsbackend_hg):
658 target_repo = vcsbackend_hg.create_repo(number_of_commits=2)
658 target_repo = vcsbackend_hg.create_repo(number_of_commits=2)
659 source_repo = vcsbackend_hg.clone_repo(target_repo)
659 source_repo = vcsbackend_hg.clone_repo(target_repo)
660 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
660 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
661 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
661 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
662
662
663 # add an extra head to the target repo
663 # add an extra head to the target repo
664 imc = target_repo.in_memory_commit
664 imc = target_repo.in_memory_commit
665 imc.add(FileNode('file_x', content='foo'))
665 imc.add(FileNode('file_x', content='foo'))
666 commits = list(target_repo.get_commits())
666 commits = list(target_repo.get_commits())
667 imc.commit(
667 imc.commit(
668 message=u'Automatic commit from repo merge test',
668 message=u'Automatic commit from repo merge test',
669 author=u'Automatic', parents=commits[0:1])
669 author=u'Automatic', parents=commits[0:1])
670
670
671 target_commit = target_repo.get_commit()
671 target_commit = target_repo.get_commit()
672 source_commit = source_repo.get_commit()
672 source_commit = source_repo.get_commit()
673 default_branch = target_repo.DEFAULT_BRANCH_NAME
673 default_branch = target_repo.DEFAULT_BRANCH_NAME
674 target_repo._update(default_branch)
674 target_repo._update(default_branch)
675
675
676 target_ref = Reference('branch', default_branch, target_commit.raw_id)
676 target_ref = Reference('branch', default_branch, target_commit.raw_id)
677 source_ref = Reference('branch', default_branch, source_commit.raw_id)
677 source_ref = Reference('branch', default_branch, source_commit.raw_id)
678 workspace = 'test-merge'
678 workspace = 'test-merge'
679
679
680 assert len(target_repo._heads(branch='default')) == 2
680 assert len(target_repo._heads(branch='default')) == 2
681 expected_merge_response = MergeResponse(
681 expected_merge_response = MergeResponse(
682 False, False, None,
682 False, False, None,
683 MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
683 MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
684 merge_response = target_repo.merge(
684 merge_response = target_repo.merge(
685 target_ref, source_repo, source_ref, workspace,
685 target_ref, source_repo, source_ref, workspace,
686 'test user', 'test@rhodecode.com', 'merge message 1',
686 'test user', 'test@rhodecode.com', 'merge message 1',
687 dry_run=False)
687 dry_run=False)
688 assert merge_response == expected_merge_response
688 assert merge_response == expected_merge_response
689
689
690 def test_merge_rebase_source_is_updated_bookmark(self, vcsbackend_hg):
690 def test_merge_rebase_source_is_updated_bookmark(self, vcsbackend_hg):
691 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
691 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
692 source_repo = vcsbackend_hg.clone_repo(target_repo)
692 source_repo = vcsbackend_hg.clone_repo(target_repo)
693 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
693 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
694 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
694 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
695 imc = source_repo.in_memory_commit
695 imc = source_repo.in_memory_commit
696 imc.add(FileNode('file_x', content=source_repo.name))
696 imc.add(FileNode('file_x', content=source_repo.name))
697 imc.commit(
697 imc.commit(
698 message=u'Automatic commit from repo merge test',
698 message=u'Automatic commit from repo merge test',
699 author=u'Automatic')
699 author=u'Automatic')
700 target_commit = target_repo.get_commit()
700 target_commit = target_repo.get_commit()
701 source_commit = source_repo.get_commit()
701 source_commit = source_repo.get_commit()
702
702
703 vcsbackend_hg.add_file(source_repo, 'LICENSE', 'LICENSE Info')
703 vcsbackend_hg.add_file(source_repo, 'LICENSE', 'LICENSE Info')
704
704
705 default_branch = target_repo.DEFAULT_BRANCH_NAME
705 default_branch = target_repo.DEFAULT_BRANCH_NAME
706 bookmark_name = 'bookmark'
706 bookmark_name = 'bookmark'
707 source_repo._update(default_branch)
707 source_repo._update(default_branch)
708 source_repo.bookmark(bookmark_name)
708 source_repo.bookmark(bookmark_name)
709
709
710 target_ref = Reference('branch', default_branch, target_commit.raw_id)
710 target_ref = Reference('branch', default_branch, target_commit.raw_id)
711 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
711 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
712 workspace = 'test-merge'
712 workspace = 'test-merge'
713
713
714 with mock.patch.object(rhodecode.lib.vcs.conf.settings,
714 merge_response = target_repo.merge(
715 'HG_USE_REBASE_FOR_MERGING', return_value=True):
715 target_ref, source_repo, source_ref, workspace,
716 merge_response = target_repo.merge(
716 'test user', 'test@rhodecode.com', 'merge message 1',
717 target_ref, source_repo, source_ref, workspace,
717 dry_run=False, use_rebase=True)
718 'test user', 'test@rhodecode.com', 'merge message 1',
719 dry_run=False)
720
718
721 expected_merge_response = MergeResponse(
719 expected_merge_response = MergeResponse(
722 True, True, merge_response.merge_commit_id,
720 True, True, merge_response.merge_commit_id,
723 MergeFailureReason.NONE)
721 MergeFailureReason.NONE)
724 assert merge_response == expected_merge_response
722 assert merge_response == expected_merge_response
725
723
726 target_repo = backends.get_backend(vcsbackend_hg.alias)(
724 target_repo = backends.get_backend(vcsbackend_hg.alias)(
727 target_repo.path)
725 target_repo.path)
728 last_commit = target_repo.get_commit()
726 last_commit = target_repo.get_commit()
729 assert last_commit.message == source_commit.message
727 assert last_commit.message == source_commit.message
730 assert last_commit.author == source_commit.author
728 assert last_commit.author == source_commit.author
731 # This checks that we effectively did a rebase
729 # This checks that we effectively did a rebase
732 assert last_commit.raw_id != source_commit.raw_id
730 assert last_commit.raw_id != source_commit.raw_id
733
731
734 # Check the target has only 4 commits: 2 were already in target and
732 # Check the target has only 4 commits: 2 were already in target and
735 # only two should have been added
733 # only two should have been added
736 assert len(target_repo.commit_ids) == 2 + 2
734 assert len(target_repo.commit_ids) == 2 + 2
737
735
738
736
739 class TestGetShadowInstance(object):
737 class TestGetShadowInstance(object):
740
738
741 @pytest.fixture
739 @pytest.fixture
742 def repo(self, vcsbackend_hg, monkeypatch):
740 def repo(self, vcsbackend_hg, monkeypatch):
743 repo = vcsbackend_hg.repo
741 repo = vcsbackend_hg.repo
744 monkeypatch.setattr(repo, 'config', mock.Mock())
742 monkeypatch.setattr(repo, 'config', mock.Mock())
745 monkeypatch.setattr('rhodecode.lib.vcs.connection.Hg', mock.Mock())
743 monkeypatch.setattr('rhodecode.lib.vcs.connection.Hg', mock.Mock())
746 return repo
744 return repo
747
745
748 def test_passes_config(self, repo):
746 def test_passes_config(self, repo):
749 shadow = repo._get_shadow_instance(repo.path)
747 shadow = repo._get_shadow_instance(repo.path)
750 assert shadow.config == repo.config.copy()
748 assert shadow.config == repo.config.copy()
751
749
752 def test_disables_hooks(self, repo):
750 def test_disables_hooks(self, repo):
753 shadow = repo._get_shadow_instance(repo.path)
751 shadow = repo._get_shadow_instance(repo.path)
754 shadow.config.clear_section.assert_called_once_with('hooks')
752 shadow.config.clear_section.assert_called_once_with('hooks')
755
753
756 def test_allows_to_keep_hooks(self, repo):
754 def test_allows_to_keep_hooks(self, repo):
757 shadow = repo._get_shadow_instance(repo.path, enable_hooks=True)
755 shadow = repo._get_shadow_instance(repo.path, enable_hooks=True)
758 assert not shadow.config.clear_section.called
756 assert not shadow.config.clear_section.called
759
757
760
758
761 class TestMercurialCommit(object):
759 class TestMercurialCommit(object):
762
760
763 def _test_equality(self, commit):
761 def _test_equality(self, commit):
764 idx = commit.idx
762 idx = commit.idx
765 assert commit == self.repo.get_commit(commit_idx=idx)
763 assert commit == self.repo.get_commit(commit_idx=idx)
766
764
767 def test_equality(self):
765 def test_equality(self):
768 indexes = [0, 10, 20]
766 indexes = [0, 10, 20]
769 commits = [self.repo.get_commit(commit_idx=idx) for idx in indexes]
767 commits = [self.repo.get_commit(commit_idx=idx) for idx in indexes]
770 for commit in commits:
768 for commit in commits:
771 self._test_equality(commit)
769 self._test_equality(commit)
772
770
773 def test_default_commit(self):
771 def test_default_commit(self):
774 tip = self.repo.get_commit('tip')
772 tip = self.repo.get_commit('tip')
775 assert tip == self.repo.get_commit()
773 assert tip == self.repo.get_commit()
776 assert tip == self.repo.get_commit(commit_id=None)
774 assert tip == self.repo.get_commit(commit_id=None)
777 assert tip == self.repo.get_commit(commit_idx=None)
775 assert tip == self.repo.get_commit(commit_idx=None)
778 assert tip == list(self.repo[-1:])[0]
776 assert tip == list(self.repo[-1:])[0]
779
777
780 def test_root_node(self):
778 def test_root_node(self):
781 tip = self.repo.get_commit('tip')
779 tip = self.repo.get_commit('tip')
782 assert tip.root is tip.get_node('')
780 assert tip.root is tip.get_node('')
783
781
784 def test_lazy_fetch(self):
782 def test_lazy_fetch(self):
785 """
783 """
786 Test if commit's nodes expands and are cached as we walk through
784 Test if commit's nodes expands and are cached as we walk through
787 the commit. This test is somewhat hard to write as order of tests
785 the commit. This test is somewhat hard to write as order of tests
788 is a key here. Written by running command after command in a shell.
786 is a key here. Written by running command after command in a shell.
789 """
787 """
790 commit = self.repo.get_commit(commit_idx=45)
788 commit = self.repo.get_commit(commit_idx=45)
791 assert len(commit.nodes) == 0
789 assert len(commit.nodes) == 0
792 root = commit.root
790 root = commit.root
793 assert len(commit.nodes) == 1
791 assert len(commit.nodes) == 1
794 assert len(root.nodes) == 8
792 assert len(root.nodes) == 8
795 # accessing root.nodes updates commit.nodes
793 # accessing root.nodes updates commit.nodes
796 assert len(commit.nodes) == 9
794 assert len(commit.nodes) == 9
797
795
798 docs = root.get_node('docs')
796 docs = root.get_node('docs')
799 # we haven't yet accessed anything new as docs dir was already cached
797 # we haven't yet accessed anything new as docs dir was already cached
800 assert len(commit.nodes) == 9
798 assert len(commit.nodes) == 9
801 assert len(docs.nodes) == 8
799 assert len(docs.nodes) == 8
802 # accessing docs.nodes updates commit.nodes
800 # accessing docs.nodes updates commit.nodes
803 assert len(commit.nodes) == 17
801 assert len(commit.nodes) == 17
804
802
805 assert docs is commit.get_node('docs')
803 assert docs is commit.get_node('docs')
806 assert docs is root.nodes[0]
804 assert docs is root.nodes[0]
807 assert docs is root.dirs[0]
805 assert docs is root.dirs[0]
808 assert docs is commit.get_node('docs')
806 assert docs is commit.get_node('docs')
809
807
810 def test_nodes_with_commit(self):
808 def test_nodes_with_commit(self):
811 commit = self.repo.get_commit(commit_idx=45)
809 commit = self.repo.get_commit(commit_idx=45)
812 root = commit.root
810 root = commit.root
813 docs = root.get_node('docs')
811 docs = root.get_node('docs')
814 assert docs is commit.get_node('docs')
812 assert docs is commit.get_node('docs')
815 api = docs.get_node('api')
813 api = docs.get_node('api')
816 assert api is commit.get_node('docs/api')
814 assert api is commit.get_node('docs/api')
817 index = api.get_node('index.rst')
815 index = api.get_node('index.rst')
818 assert index is commit.get_node('docs/api/index.rst')
816 assert index is commit.get_node('docs/api/index.rst')
819 assert index is commit.get_node(
817 assert index is commit.get_node(
820 'docs').get_node('api').get_node('index.rst')
818 'docs').get_node('api').get_node('index.rst')
821
819
822 def test_branch_and_tags(self):
820 def test_branch_and_tags(self):
823 commit0 = self.repo.get_commit(commit_idx=0)
821 commit0 = self.repo.get_commit(commit_idx=0)
824 assert commit0.branch == 'default'
822 assert commit0.branch == 'default'
825 assert commit0.tags == []
823 assert commit0.tags == []
826
824
827 commit10 = self.repo.get_commit(commit_idx=10)
825 commit10 = self.repo.get_commit(commit_idx=10)
828 assert commit10.branch == 'default'
826 assert commit10.branch == 'default'
829 assert commit10.tags == []
827 assert commit10.tags == []
830
828
831 commit44 = self.repo.get_commit(commit_idx=44)
829 commit44 = self.repo.get_commit(commit_idx=44)
832 assert commit44.branch == 'web'
830 assert commit44.branch == 'web'
833
831
834 tip = self.repo.get_commit('tip')
832 tip = self.repo.get_commit('tip')
835 assert 'tip' in tip.tags
833 assert 'tip' in tip.tags
836
834
837 def test_bookmarks(self):
835 def test_bookmarks(self):
838 commit0 = self.repo.get_commit(commit_idx=0)
836 commit0 = self.repo.get_commit(commit_idx=0)
839 assert commit0.bookmarks == []
837 assert commit0.bookmarks == []
840
838
841 def _test_file_size(self, idx, path, size):
839 def _test_file_size(self, idx, path, size):
842 node = self.repo.get_commit(commit_idx=idx).get_node(path)
840 node = self.repo.get_commit(commit_idx=idx).get_node(path)
843 assert node.is_file()
841 assert node.is_file()
844 assert node.size == size
842 assert node.size == size
845
843
846 def test_file_size(self):
844 def test_file_size(self):
847 to_check = (
845 to_check = (
848 (10, 'setup.py', 1068),
846 (10, 'setup.py', 1068),
849 (20, 'setup.py', 1106),
847 (20, 'setup.py', 1106),
850 (60, 'setup.py', 1074),
848 (60, 'setup.py', 1074),
851
849
852 (10, 'vcs/backends/base.py', 2921),
850 (10, 'vcs/backends/base.py', 2921),
853 (20, 'vcs/backends/base.py', 3936),
851 (20, 'vcs/backends/base.py', 3936),
854 (60, 'vcs/backends/base.py', 6189),
852 (60, 'vcs/backends/base.py', 6189),
855 )
853 )
856 for idx, path, size in to_check:
854 for idx, path, size in to_check:
857 self._test_file_size(idx, path, size)
855 self._test_file_size(idx, path, size)
858
856
859 def test_file_history_from_commits(self):
857 def test_file_history_from_commits(self):
860 node = self.repo[10].get_node('setup.py')
858 node = self.repo[10].get_node('setup.py')
861 commit_ids = [commit.raw_id for commit in node.history]
859 commit_ids = [commit.raw_id for commit in node.history]
862 assert ['3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == commit_ids
860 assert ['3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == commit_ids
863
861
864 node = self.repo[20].get_node('setup.py')
862 node = self.repo[20].get_node('setup.py')
865 node_ids = [commit.raw_id for commit in node.history]
863 node_ids = [commit.raw_id for commit in node.history]
866 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
864 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
867 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
865 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
868
866
869 # special case we check history from commit that has this particular
867 # special case we check history from commit that has this particular
870 # file changed this means we check if it's included as well
868 # file changed this means we check if it's included as well
871 node = self.repo.get_commit('eada5a770da98ab0dd7325e29d00e0714f228d09')\
869 node = self.repo.get_commit('eada5a770da98ab0dd7325e29d00e0714f228d09')\
872 .get_node('setup.py')
870 .get_node('setup.py')
873 node_ids = [commit.raw_id for commit in node.history]
871 node_ids = [commit.raw_id for commit in node.history]
874 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
872 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
875 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
873 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
876
874
877 def test_file_history(self):
875 def test_file_history(self):
878 # we can only check if those commits are present in the history
876 # we can only check if those commits are present in the history
879 # as we cannot update this test every time file is changed
877 # as we cannot update this test every time file is changed
880 files = {
878 files = {
881 'setup.py': [7, 18, 45, 46, 47, 69, 77],
879 'setup.py': [7, 18, 45, 46, 47, 69, 77],
882 'vcs/nodes.py': [
880 'vcs/nodes.py': [
883 7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60, 61, 73, 76],
881 7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60, 61, 73, 76],
884 'vcs/backends/hg.py': [
882 'vcs/backends/hg.py': [
885 4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23, 26, 27, 28, 30,
883 4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23, 26, 27, 28, 30,
886 31, 33, 35, 36, 37, 38, 39, 40, 41, 44, 45, 47, 48, 49, 53, 54,
884 31, 33, 35, 36, 37, 38, 39, 40, 41, 44, 45, 47, 48, 49, 53, 54,
887 55, 58, 60, 61, 67, 68, 69, 70, 73, 77, 78, 79, 82],
885 55, 58, 60, 61, 67, 68, 69, 70, 73, 77, 78, 79, 82],
888 }
886 }
889 for path, indexes in files.items():
887 for path, indexes in files.items():
890 tip = self.repo.get_commit(commit_idx=indexes[-1])
888 tip = self.repo.get_commit(commit_idx=indexes[-1])
891 node = tip.get_node(path)
889 node = tip.get_node(path)
892 node_indexes = [commit.idx for commit in node.history]
890 node_indexes = [commit.idx for commit in node.history]
893 assert set(indexes).issubset(set(node_indexes)), (
891 assert set(indexes).issubset(set(node_indexes)), (
894 "We assumed that %s is subset of commits for which file %s "
892 "We assumed that %s is subset of commits for which file %s "
895 "has been changed, and history of that node returned: %s"
893 "has been changed, and history of that node returned: %s"
896 % (indexes, path, node_indexes))
894 % (indexes, path, node_indexes))
897
895
898 def test_file_annotate(self):
896 def test_file_annotate(self):
899 files = {
897 files = {
900 'vcs/backends/__init__.py': {
898 'vcs/backends/__init__.py': {
901 89: {
899 89: {
902 'lines_no': 31,
900 'lines_no': 31,
903 'commits': [
901 'commits': [
904 32, 32, 61, 32, 32, 37, 32, 32, 32, 44,
902 32, 32, 61, 32, 32, 37, 32, 32, 32, 44,
905 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
903 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
906 32, 32, 32, 32, 37, 32, 37, 37, 32,
904 32, 32, 32, 32, 37, 32, 37, 37, 32,
907 32, 32
905 32, 32
908 ]
906 ]
909 },
907 },
910 20: {
908 20: {
911 'lines_no': 1,
909 'lines_no': 1,
912 'commits': [4]
910 'commits': [4]
913 },
911 },
914 55: {
912 55: {
915 'lines_no': 31,
913 'lines_no': 31,
916 'commits': [
914 'commits': [
917 32, 32, 45, 32, 32, 37, 32, 32, 32, 44,
915 32, 32, 45, 32, 32, 37, 32, 32, 32, 44,
918 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
916 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
919 32, 32, 32, 32, 37, 32, 37, 37, 32,
917 32, 32, 32, 32, 37, 32, 37, 37, 32,
920 32, 32
918 32, 32
921 ]
919 ]
922 }
920 }
923 },
921 },
924 'vcs/exceptions.py': {
922 'vcs/exceptions.py': {
925 89: {
923 89: {
926 'lines_no': 18,
924 'lines_no': 18,
927 'commits': [
925 'commits': [
928 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
926 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
929 16, 16, 17, 16, 16, 18, 18, 18
927 16, 16, 17, 16, 16, 18, 18, 18
930 ]
928 ]
931 },
929 },
932 20: {
930 20: {
933 'lines_no': 18,
931 'lines_no': 18,
934 'commits': [
932 'commits': [
935 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
933 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
936 16, 16, 17, 16, 16, 18, 18, 18
934 16, 16, 17, 16, 16, 18, 18, 18
937 ]
935 ]
938 },
936 },
939 55: {
937 55: {
940 'lines_no': 18,
938 'lines_no': 18,
941 'commits': [
939 'commits': [
942 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
940 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
943 17, 16, 16, 18, 18, 18
941 17, 16, 16, 18, 18, 18
944 ]
942 ]
945 }
943 }
946 },
944 },
947 'MANIFEST.in': {
945 'MANIFEST.in': {
948 89: {
946 89: {
949 'lines_no': 5,
947 'lines_no': 5,
950 'commits': [7, 7, 7, 71, 71]
948 'commits': [7, 7, 7, 71, 71]
951 },
949 },
952 20: {
950 20: {
953 'lines_no': 3,
951 'lines_no': 3,
954 'commits': [7, 7, 7]
952 'commits': [7, 7, 7]
955 },
953 },
956 55: {
954 55: {
957 'lines_no': 3,
955 'lines_no': 3,
958 'commits': [7, 7, 7]
956 'commits': [7, 7, 7]
959 }
957 }
960 }
958 }
961 }
959 }
962
960
963 for fname, commit_dict in files.items():
961 for fname, commit_dict in files.items():
964 for idx, __ in commit_dict.items():
962 for idx, __ in commit_dict.items():
965 commit = self.repo.get_commit(commit_idx=idx)
963 commit = self.repo.get_commit(commit_idx=idx)
966 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
964 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
967 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
965 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
968 assert l1_1 == l1_2
966 assert l1_1 == l1_2
969 l1 = l1_2 = [
967 l1 = l1_2 = [
970 x[2]().idx for x in commit.get_file_annotate(fname)]
968 x[2]().idx for x in commit.get_file_annotate(fname)]
971 l2 = files[fname][idx]['commits']
969 l2 = files[fname][idx]['commits']
972 assert l1 == l2, (
970 assert l1 == l2, (
973 "The lists of commit for %s@commit_id%s"
971 "The lists of commit for %s@commit_id%s"
974 "from annotation list should match each other,"
972 "from annotation list should match each other,"
975 "got \n%s \nvs \n%s " % (fname, idx, l1, l2))
973 "got \n%s \nvs \n%s " % (fname, idx, l1, l2))
976
974
977 def test_commit_state(self):
975 def test_commit_state(self):
978 """
976 """
979 Tests which files have been added/changed/removed at particular commit
977 Tests which files have been added/changed/removed at particular commit
980 """
978 """
981
979
982 # commit_id 46ad32a4f974:
980 # commit_id 46ad32a4f974:
983 # hg st --rev 46ad32a4f974
981 # hg st --rev 46ad32a4f974
984 # changed: 13
982 # changed: 13
985 # added: 20
983 # added: 20
986 # removed: 1
984 # removed: 1
987 changed = set([
985 changed = set([
988 '.hgignore', 'README.rst', 'docs/conf.py', 'docs/index.rst',
986 '.hgignore', 'README.rst', 'docs/conf.py', 'docs/index.rst',
989 'setup.py', 'tests/test_hg.py', 'tests/test_nodes.py',
987 'setup.py', 'tests/test_hg.py', 'tests/test_nodes.py',
990 'vcs/__init__.py', 'vcs/backends/__init__.py',
988 'vcs/__init__.py', 'vcs/backends/__init__.py',
991 'vcs/backends/base.py', 'vcs/backends/hg.py', 'vcs/nodes.py',
989 'vcs/backends/base.py', 'vcs/backends/hg.py', 'vcs/nodes.py',
992 'vcs/utils/__init__.py'])
990 'vcs/utils/__init__.py'])
993
991
994 added = set([
992 added = set([
995 'docs/api/backends/hg.rst', 'docs/api/backends/index.rst',
993 'docs/api/backends/hg.rst', 'docs/api/backends/index.rst',
996 'docs/api/index.rst', 'docs/api/nodes.rst',
994 'docs/api/index.rst', 'docs/api/nodes.rst',
997 'docs/api/web/index.rst', 'docs/api/web/simplevcs.rst',
995 'docs/api/web/index.rst', 'docs/api/web/simplevcs.rst',
998 'docs/installation.rst', 'docs/quickstart.rst', 'setup.cfg',
996 'docs/installation.rst', 'docs/quickstart.rst', 'setup.cfg',
999 'vcs/utils/baseui_config.py', 'vcs/utils/web.py',
997 'vcs/utils/baseui_config.py', 'vcs/utils/web.py',
1000 'vcs/web/__init__.py', 'vcs/web/exceptions.py',
998 'vcs/web/__init__.py', 'vcs/web/exceptions.py',
1001 'vcs/web/simplevcs/__init__.py', 'vcs/web/simplevcs/exceptions.py',
999 'vcs/web/simplevcs/__init__.py', 'vcs/web/simplevcs/exceptions.py',
1002 'vcs/web/simplevcs/middleware.py', 'vcs/web/simplevcs/models.py',
1000 'vcs/web/simplevcs/middleware.py', 'vcs/web/simplevcs/models.py',
1003 'vcs/web/simplevcs/settings.py', 'vcs/web/simplevcs/utils.py',
1001 'vcs/web/simplevcs/settings.py', 'vcs/web/simplevcs/utils.py',
1004 'vcs/web/simplevcs/views.py'])
1002 'vcs/web/simplevcs/views.py'])
1005
1003
1006 removed = set(['docs/api.rst'])
1004 removed = set(['docs/api.rst'])
1007
1005
1008 commit64 = self.repo.get_commit('46ad32a4f974')
1006 commit64 = self.repo.get_commit('46ad32a4f974')
1009 assert set((node.path for node in commit64.added)) == added
1007 assert set((node.path for node in commit64.added)) == added
1010 assert set((node.path for node in commit64.changed)) == changed
1008 assert set((node.path for node in commit64.changed)) == changed
1011 assert set((node.path for node in commit64.removed)) == removed
1009 assert set((node.path for node in commit64.removed)) == removed
1012
1010
1013 # commit_id b090f22d27d6:
1011 # commit_id b090f22d27d6:
1014 # hg st --rev b090f22d27d6
1012 # hg st --rev b090f22d27d6
1015 # changed: 13
1013 # changed: 13
1016 # added: 20
1014 # added: 20
1017 # removed: 1
1015 # removed: 1
1018 commit88 = self.repo.get_commit('b090f22d27d6')
1016 commit88 = self.repo.get_commit('b090f22d27d6')
1019 assert set((node.path for node in commit88.added)) == set()
1017 assert set((node.path for node in commit88.added)) == set()
1020 assert set((node.path for node in commit88.changed)) == \
1018 assert set((node.path for node in commit88.changed)) == \
1021 set(['.hgignore'])
1019 set(['.hgignore'])
1022 assert set((node.path for node in commit88.removed)) == set()
1020 assert set((node.path for node in commit88.removed)) == set()
1023
1021
1024 #
1022 #
1025 # 85:
1023 # 85:
1026 # added: 2 [
1024 # added: 2 [
1027 # 'vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
1025 # 'vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
1028 # changed: 4 ['vcs/web/simplevcs/models.py', ...]
1026 # changed: 4 ['vcs/web/simplevcs/models.py', ...]
1029 # removed: 1 ['vcs/utils/web.py']
1027 # removed: 1 ['vcs/utils/web.py']
1030 commit85 = self.repo.get_commit(commit_idx=85)
1028 commit85 = self.repo.get_commit(commit_idx=85)
1031 assert set((node.path for node in commit85.added)) == set([
1029 assert set((node.path for node in commit85.added)) == set([
1032 'vcs/utils/diffs.py',
1030 'vcs/utils/diffs.py',
1033 'vcs/web/simplevcs/views/diffs.py'])
1031 'vcs/web/simplevcs/views/diffs.py'])
1034 assert set((node.path for node in commit85.changed)) == set([
1032 assert set((node.path for node in commit85.changed)) == set([
1035 'vcs/web/simplevcs/models.py',
1033 'vcs/web/simplevcs/models.py',
1036 'vcs/web/simplevcs/utils.py',
1034 'vcs/web/simplevcs/utils.py',
1037 'vcs/web/simplevcs/views/__init__.py',
1035 'vcs/web/simplevcs/views/__init__.py',
1038 'vcs/web/simplevcs/views/repository.py',
1036 'vcs/web/simplevcs/views/repository.py',
1039 ])
1037 ])
1040 assert set((node.path for node in commit85.removed)) == \
1038 assert set((node.path for node in commit85.removed)) == \
1041 set(['vcs/utils/web.py'])
1039 set(['vcs/utils/web.py'])
1042
1040
1043 def test_files_state(self):
1041 def test_files_state(self):
1044 """
1042 """
1045 Tests state of FileNodes.
1043 Tests state of FileNodes.
1046 """
1044 """
1047 commit = self.repo.get_commit(commit_idx=85)
1045 commit = self.repo.get_commit(commit_idx=85)
1048 node = commit.get_node('vcs/utils/diffs.py')
1046 node = commit.get_node('vcs/utils/diffs.py')
1049 assert node.state, NodeState.ADDED
1047 assert node.state, NodeState.ADDED
1050 assert node.added
1048 assert node.added
1051 assert not node.changed
1049 assert not node.changed
1052 assert not node.not_changed
1050 assert not node.not_changed
1053 assert not node.removed
1051 assert not node.removed
1054
1052
1055 commit = self.repo.get_commit(commit_idx=88)
1053 commit = self.repo.get_commit(commit_idx=88)
1056 node = commit.get_node('.hgignore')
1054 node = commit.get_node('.hgignore')
1057 assert node.state, NodeState.CHANGED
1055 assert node.state, NodeState.CHANGED
1058 assert not node.added
1056 assert not node.added
1059 assert node.changed
1057 assert node.changed
1060 assert not node.not_changed
1058 assert not node.not_changed
1061 assert not node.removed
1059 assert not node.removed
1062
1060
1063 commit = self.repo.get_commit(commit_idx=85)
1061 commit = self.repo.get_commit(commit_idx=85)
1064 node = commit.get_node('setup.py')
1062 node = commit.get_node('setup.py')
1065 assert node.state, NodeState.NOT_CHANGED
1063 assert node.state, NodeState.NOT_CHANGED
1066 assert not node.added
1064 assert not node.added
1067 assert not node.changed
1065 assert not node.changed
1068 assert node.not_changed
1066 assert node.not_changed
1069 assert not node.removed
1067 assert not node.removed
1070
1068
1071 # If node has REMOVED state then trying to fetch it would raise
1069 # If node has REMOVED state then trying to fetch it would raise
1072 # CommitError exception
1070 # CommitError exception
1073 commit = self.repo.get_commit(commit_idx=2)
1071 commit = self.repo.get_commit(commit_idx=2)
1074 path = 'vcs/backends/BaseRepository.py'
1072 path = 'vcs/backends/BaseRepository.py'
1075 with pytest.raises(NodeDoesNotExistError):
1073 with pytest.raises(NodeDoesNotExistError):
1076 commit.get_node(path)
1074 commit.get_node(path)
1077 # but it would be one of ``removed`` (commit's attribute)
1075 # but it would be one of ``removed`` (commit's attribute)
1078 assert path in [rf.path for rf in commit.removed]
1076 assert path in [rf.path for rf in commit.removed]
1079
1077
1080 def test_commit_message_is_unicode(self):
1078 def test_commit_message_is_unicode(self):
1081 for cm in self.repo:
1079 for cm in self.repo:
1082 assert type(cm.message) == unicode
1080 assert type(cm.message) == unicode
1083
1081
1084 def test_commit_author_is_unicode(self):
1082 def test_commit_author_is_unicode(self):
1085 for cm in self.repo:
1083 for cm in self.repo:
1086 assert type(cm.author) == unicode
1084 assert type(cm.author) == unicode
1087
1085
1088 def test_repo_files_content_is_unicode(self):
1086 def test_repo_files_content_is_unicode(self):
1089 test_commit = self.repo.get_commit(commit_idx=100)
1087 test_commit = self.repo.get_commit(commit_idx=100)
1090 for node in test_commit.get_node('/'):
1088 for node in test_commit.get_node('/'):
1091 if node.is_file():
1089 if node.is_file():
1092 assert type(node.content) == unicode
1090 assert type(node.content) == unicode
1093
1091
1094 def test_wrong_path(self):
1092 def test_wrong_path(self):
1095 # There is 'setup.py' in the root dir but not there:
1093 # There is 'setup.py' in the root dir but not there:
1096 path = 'foo/bar/setup.py'
1094 path = 'foo/bar/setup.py'
1097 with pytest.raises(VCSError):
1095 with pytest.raises(VCSError):
1098 self.repo.get_commit().get_node(path)
1096 self.repo.get_commit().get_node(path)
1099
1097
1100 def test_large_file(self):
1098 def test_large_file(self):
1101 # TODO: valid large file
1099 # TODO: valid large file
1102 tip = self.repo.get_commit()
1100 tip = self.repo.get_commit()
1103 with pytest.raises(CommitError):
1101 with pytest.raises(CommitError):
1104 tip.get_largefile_node("invalid")
1102 tip.get_largefile_node("invalid")
1105
1103
1106 def test_author_email(self):
1104 def test_author_email(self):
1107 assert 'marcin@python-blog.com' == \
1105 assert 'marcin@python-blog.com' == \
1108 self.repo.get_commit('b986218ba1c9').author_email
1106 self.repo.get_commit('b986218ba1c9').author_email
1109 assert 'lukasz.balcerzak@python-center.pl' == \
1107 assert 'lukasz.balcerzak@python-center.pl' == \
1110 self.repo.get_commit('3803844fdbd3').author_email
1108 self.repo.get_commit('3803844fdbd3').author_email
1111 assert '' == self.repo.get_commit('84478366594b').author_email
1109 assert '' == self.repo.get_commit('84478366594b').author_email
1112
1110
1113 def test_author_username(self):
1111 def test_author_username(self):
1114 assert 'Marcin Kuzminski' == \
1112 assert 'Marcin Kuzminski' == \
1115 self.repo.get_commit('b986218ba1c9').author_name
1113 self.repo.get_commit('b986218ba1c9').author_name
1116 assert 'Lukasz Balcerzak' == \
1114 assert 'Lukasz Balcerzak' == \
1117 self.repo.get_commit('3803844fdbd3').author_name
1115 self.repo.get_commit('3803844fdbd3').author_name
1118 assert 'marcink' == \
1116 assert 'marcink' == \
1119 self.repo.get_commit('84478366594b').author_name
1117 self.repo.get_commit('84478366594b').author_name
1120
1118
1121
1119
1122 class TestGetBranchName(object):
1120 class TestGetBranchName(object):
1123 def test_returns_ref_name_when_type_is_branch(self):
1121 def test_returns_ref_name_when_type_is_branch(self):
1124 ref = self._create_ref('branch', 'fake-name')
1122 ref = self._create_ref('branch', 'fake-name')
1125 result = self.repo._get_branch_name(ref)
1123 result = self.repo._get_branch_name(ref)
1126 assert result == ref.name
1124 assert result == ref.name
1127
1125
1128 @pytest.mark.parametrize("type_", ("book", "tag"))
1126 @pytest.mark.parametrize("type_", ("book", "tag"))
1129 def test_queries_remote_when_type_is_not_branch(self, type_):
1127 def test_queries_remote_when_type_is_not_branch(self, type_):
1130 ref = self._create_ref(type_, 'wrong-fake-name')
1128 ref = self._create_ref(type_, 'wrong-fake-name')
1131 with mock.patch.object(self.repo, "_remote") as remote_mock:
1129 with mock.patch.object(self.repo, "_remote") as remote_mock:
1132 remote_mock.ctx_branch.return_value = "fake-name"
1130 remote_mock.ctx_branch.return_value = "fake-name"
1133 result = self.repo._get_branch_name(ref)
1131 result = self.repo._get_branch_name(ref)
1134 assert result == "fake-name"
1132 assert result == "fake-name"
1135 remote_mock.ctx_branch.assert_called_once_with(ref.commit_id)
1133 remote_mock.ctx_branch.assert_called_once_with(ref.commit_id)
1136
1134
1137 def _create_ref(self, type_, name):
1135 def _create_ref(self, type_, name):
1138 ref = mock.Mock()
1136 ref = mock.Mock()
1139 ref.type = type_
1137 ref.type = type_
1140 ref.name = 'wrong-fake-name'
1138 ref.name = 'wrong-fake-name'
1141 ref.commit_id = "deadbeef"
1139 ref.commit_id = "deadbeef"
1142 return ref
1140 return ref
1143
1141
1144
1142
1145 class TestIsTheSameBranch(object):
1143 class TestIsTheSameBranch(object):
1146 def test_returns_true_when_branches_are_equal(self):
1144 def test_returns_true_when_branches_are_equal(self):
1147 source_ref = mock.Mock(name="source-ref")
1145 source_ref = mock.Mock(name="source-ref")
1148 target_ref = mock.Mock(name="target-ref")
1146 target_ref = mock.Mock(name="target-ref")
1149 branch_name_patcher = mock.patch.object(
1147 branch_name_patcher = mock.patch.object(
1150 self.repo, "_get_branch_name", return_value="default")
1148 self.repo, "_get_branch_name", return_value="default")
1151 with branch_name_patcher as branch_name_mock:
1149 with branch_name_patcher as branch_name_mock:
1152 result = self.repo._is_the_same_branch(source_ref, target_ref)
1150 result = self.repo._is_the_same_branch(source_ref, target_ref)
1153
1151
1154 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1152 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1155 assert branch_name_mock.call_args_list == expected_calls
1153 assert branch_name_mock.call_args_list == expected_calls
1156 assert result is True
1154 assert result is True
1157
1155
1158 def test_returns_false_when_branches_are_not_equal(self):
1156 def test_returns_false_when_branches_are_not_equal(self):
1159 source_ref = mock.Mock(name="source-ref")
1157 source_ref = mock.Mock(name="source-ref")
1160 source_ref.name = "source-branch"
1158 source_ref.name = "source-branch"
1161 target_ref = mock.Mock(name="target-ref")
1159 target_ref = mock.Mock(name="target-ref")
1162 source_ref.name = "target-branch"
1160 source_ref.name = "target-branch"
1163
1161
1164 def side_effect(ref):
1162 def side_effect(ref):
1165 return ref.name
1163 return ref.name
1166
1164
1167 branch_name_patcher = mock.patch.object(
1165 branch_name_patcher = mock.patch.object(
1168 self.repo, "_get_branch_name", side_effect=side_effect)
1166 self.repo, "_get_branch_name", side_effect=side_effect)
1169 with branch_name_patcher as branch_name_mock:
1167 with branch_name_patcher as branch_name_mock:
1170 result = self.repo._is_the_same_branch(source_ref, target_ref)
1168 result = self.repo._is_the_same_branch(source_ref, target_ref)
1171
1169
1172 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1170 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1173 assert branch_name_mock.call_args_list == expected_calls
1171 assert branch_name_mock.call_args_list == expected_calls
1174 assert result is False
1172 assert result is False
General Comments 0
You need to be logged in to leave comments. Login now