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