##// END OF EJS Templates
fix(tests): on jenkins ensure re-creation of the path
super-admin -
r5609:cccd61c3 default
parent child Browse files
Show More
@@ -1,1242 +1,1244 b''
1 # Copyright (C) 2010-2024 RhodeCode GmbH
1 # Copyright (C) 2010-2024 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import datetime
19 import datetime
20 import mock
20 import mock
21 import os
21 import os
22 import sys
22 import sys
23 import shutil
23 import shutil
24
24
25 import pytest
25 import pytest
26
26
27 from rhodecode.lib.utils import make_db_config
27 from rhodecode.lib.utils import make_db_config
28 from rhodecode.lib.vcs.backends.base import Reference
28 from rhodecode.lib.vcs.backends.base import Reference
29 from rhodecode.lib.vcs.backends.git import GitRepository, GitCommit, discover_git_version
29 from rhodecode.lib.vcs.backends.git import GitRepository, GitCommit, discover_git_version
30 from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
30 from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
31 from rhodecode.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState, SubModuleNode
31 from rhodecode.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState, SubModuleNode
32 from rhodecode.tests import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
32 from rhodecode.tests import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
33 from rhodecode.tests.vcs.conftest import BackendTestMixin
33 from rhodecode.tests.vcs.conftest import BackendTestMixin
34
34
35
35
36 pytestmark = pytest.mark.backends("git")
36 pytestmark = pytest.mark.backends("git")
37
37
38
38
39 DIFF_FROM_REMOTE = rb"""diff --git a/foobar b/foobar
39 DIFF_FROM_REMOTE = rb"""diff --git a/foobar b/foobar
40 new file mode 100644
40 new file mode 100644
41 index 0000000..f6ea049
41 index 0000000..f6ea049
42 --- /dev/null
42 --- /dev/null
43 +++ b/foobar
43 +++ b/foobar
44 @@ -0,0 +1 @@
44 @@ -0,0 +1 @@
45 +foobar
45 +foobar
46 \ No newline at end of file
46 \ No newline at end of file
47 diff --git a/foobar2 b/foobar2
47 diff --git a/foobar2 b/foobar2
48 new file mode 100644
48 new file mode 100644
49 index 0000000..e8c9d6b
49 index 0000000..e8c9d6b
50 --- /dev/null
50 --- /dev/null
51 +++ b/foobar2
51 +++ b/foobar2
52 @@ -0,0 +1 @@
52 @@ -0,0 +1 @@
53 +foobar2
53 +foobar2
54 \ No newline at end of file
54 \ No newline at end of file
55 """
55 """
56
56
57
57
58 def callable_get_diff(*args, **kwargs):
58 def callable_get_diff(*args, **kwargs):
59 return DIFF_FROM_REMOTE
59 return DIFF_FROM_REMOTE
60
60
61
61
62 class TestGitRepository(object):
62 class TestGitRepository(object):
63 @pytest.fixture(autouse=True)
63 @pytest.fixture(autouse=True)
64 def prepare(self, request, baseapp):
64 def prepare(self, request, baseapp):
65 self.repo = GitRepository(TEST_GIT_REPO, bare=True)
65 self.repo = GitRepository(TEST_GIT_REPO, bare=True)
66 self.repo.count()
66 self.repo.count()
67
67
68 def get_clone_repo(self, tmpdir):
68 def get_clone_repo(self, tmpdir):
69 """
69 """
70 Return a non bare clone of the base repo.
70 Return a non bare clone of the base repo.
71 """
71 """
72 clone_path = str(tmpdir.join("clone-repo"))
72 clone_path = str(tmpdir.join("clone-repo"))
73 repo_clone = GitRepository(clone_path, create=True, src_url=self.repo.path, bare=False)
73 repo_clone = GitRepository(clone_path, create=True, src_url=self.repo.path, bare=False)
74
74
75 return repo_clone
75 return repo_clone
76
76
77 def get_empty_repo(self, tmpdir, bare=False):
77 def get_empty_repo(self, tmpdir, bare=False):
78 """
78 """
79 Return a non bare empty repo.
79 Return a non bare empty repo.
80 """
80 """
81 clone_path = str(tmpdir.join("empty-repo"))
81 clone_path = str(tmpdir.join("empty-repo"))
82 return GitRepository(clone_path, create=True, bare=bare)
82 return GitRepository(clone_path, create=True, bare=bare)
83
83
84 def test_wrong_repo_path(self):
84 def test_wrong_repo_path(self):
85 wrong_repo_path = "/tmp/errorrepo_git"
85 wrong_repo_path = "/tmp/errorrepo_git"
86 with pytest.raises(RepositoryError):
86 with pytest.raises(RepositoryError):
87 GitRepository(wrong_repo_path)
87 GitRepository(wrong_repo_path)
88
88
89 def test_repo_clone(self, tmp_path_factory):
89 def test_repo_clone(self, tmp_path_factory):
90 repo = GitRepository(TEST_GIT_REPO)
90 repo = GitRepository(TEST_GIT_REPO)
91 clone_path = f"{tmp_path_factory.mktemp('_')}_{TEST_GIT_REPO_CLONE}"
91 clone_path = f"{tmp_path_factory.mktemp('_')}_{TEST_GIT_REPO_CLONE}"
92 repo_clone = GitRepository(clone_path, src_url=TEST_GIT_REPO, create=True, do_workspace_checkout=True)
92 repo_clone = GitRepository(clone_path, src_url=TEST_GIT_REPO, create=True, do_workspace_checkout=True)
93
93
94 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
94 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
95 # Checking hashes of commits should be enough
95 # Checking hashes of commits should be enough
96 for commit in repo.get_commits():
96 for commit in repo.get_commits():
97 raw_id = commit.raw_id
97 raw_id = commit.raw_id
98 assert raw_id == repo_clone.get_commit(raw_id).raw_id
98 assert raw_id == repo_clone.get_commit(raw_id).raw_id
99
99
100 def test_repo_clone_without_create(self):
100 def test_repo_clone_without_create(self):
101 with pytest.raises(RepositoryError):
101 with pytest.raises(RepositoryError):
102 GitRepository(TEST_GIT_REPO_CLONE + "_wo_create", src_url=TEST_GIT_REPO)
102 GitRepository(TEST_GIT_REPO_CLONE + "_wo_create", src_url=TEST_GIT_REPO)
103
103
104 def test_repo_clone_with_update(self, tmp_path_factory):
104 def test_repo_clone_with_update(self, tmp_path_factory):
105 repo = GitRepository(TEST_GIT_REPO)
105 repo = GitRepository(TEST_GIT_REPO)
106 clone_path = "{}_{}_update".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
106 clone_path = "{}_{}_update".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
107
107
108 repo_clone = GitRepository(clone_path, create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=True)
108 repo_clone = GitRepository(clone_path, create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=True)
109 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
109 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
110
110
111 # check if current workdir was updated
111 # check if current workdir was updated
112 fpath = os.path.join(clone_path, "MANIFEST.in")
112 fpath = os.path.join(clone_path, "MANIFEST.in")
113 assert os.path.isfile(fpath)
113 assert os.path.isfile(fpath)
114
114
115 def test_repo_clone_without_update(self, tmp_path_factory):
115 def test_repo_clone_without_update(self, tmp_path_factory):
116 repo = GitRepository(TEST_GIT_REPO)
116 repo = GitRepository(TEST_GIT_REPO)
117 clone_path = "{}_{}_without_update".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
117 clone_path = "{}_{}_without_update".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
118 repo_clone = GitRepository(clone_path, create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=False)
118 repo_clone = GitRepository(clone_path, create=True, src_url=TEST_GIT_REPO, do_workspace_checkout=False)
119 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
119 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
120 # check if current workdir was *NOT* updated
120 # check if current workdir was *NOT* updated
121 fpath = os.path.join(clone_path, "MANIFEST.in")
121 fpath = os.path.join(clone_path, "MANIFEST.in")
122 # Make sure it's not bare repo
122 # Make sure it's not bare repo
123 assert not repo_clone.bare
123 assert not repo_clone.bare
124 assert not os.path.isfile(fpath)
124 assert not os.path.isfile(fpath)
125
125
126 def test_repo_clone_into_bare_repo(self, tmp_path_factory):
126 def test_repo_clone_into_bare_repo(self, tmp_path_factory):
127 repo = GitRepository(TEST_GIT_REPO)
127 repo = GitRepository(TEST_GIT_REPO)
128 clone_path = "{}_{}_bare.git".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
128 clone_path = "{}_{}_bare.git".format(tmp_path_factory.mktemp("_"), TEST_GIT_REPO_CLONE)
129 repo_clone = GitRepository(clone_path, create=True, src_url=repo.path, bare=True)
129 repo_clone = GitRepository(clone_path, create=True, src_url=repo.path, bare=True)
130 assert repo_clone.bare
130 assert repo_clone.bare
131
131
132 def test_create_repo_is_not_bare_by_default(self):
132 def test_create_repo_is_not_bare_by_default(self):
133 repo = GitRepository(get_new_dir("not-bare-by-default"), create=True)
133 repo = GitRepository(get_new_dir("not-bare-by-default"), create=True)
134 assert not repo.bare
134 assert not repo.bare
135
135
136 def test_create_bare_repo(self):
136 def test_create_bare_repo(self):
137 repo = GitRepository(get_new_dir("bare-repo"), create=True, bare=True)
137 repo = GitRepository(get_new_dir("bare-repo"), create=True, bare=True)
138 assert repo.bare
138 assert repo.bare
139
139
140 def test_update_server_info(self):
140 def test_update_server_info(self):
141 self.repo._update_server_info()
141 self.repo._update_server_info()
142
142
143 def test_fetch(self, vcsbackend_git):
143 def test_fetch(self, vcsbackend_git):
144 # Note: This is a git specific part of the API, it's only implemented
144 # Note: This is a git specific part of the API, it's only implemented
145 # by the git backend.
145 # by the git backend.
146 source_repo = vcsbackend_git.repo
146 source_repo = vcsbackend_git.repo
147 target_repo = vcsbackend_git.create_repo(bare=True)
147 target_repo = vcsbackend_git.create_repo(bare=True)
148 target_repo.fetch(source_repo.path)
148 target_repo.fetch(source_repo.path)
149 # Note: Get a fresh instance, avoids caching trouble
149 # Note: Get a fresh instance, avoids caching trouble
150 target_repo = vcsbackend_git.backend(target_repo.path)
150 target_repo = vcsbackend_git.backend(target_repo.path)
151 assert len(source_repo.commit_ids) == len(target_repo.commit_ids)
151 assert len(source_repo.commit_ids) == len(target_repo.commit_ids)
152
152
153 def test_commit_ids(self):
153 def test_commit_ids(self):
154 # there are 112 commits (by now)
154 # there are 112 commits (by now)
155 # so we can assume they would be available from now on
155 # so we can assume they would be available from now on
156 subset = {
156 subset = {
157 "c1214f7e79e02fc37156ff215cd71275450cffc3",
157 "c1214f7e79e02fc37156ff215cd71275450cffc3",
158 "38b5fe81f109cb111f549bfe9bb6b267e10bc557",
158 "38b5fe81f109cb111f549bfe9bb6b267e10bc557",
159 "fa6600f6848800641328adbf7811fd2372c02ab2",
159 "fa6600f6848800641328adbf7811fd2372c02ab2",
160 "102607b09cdd60e2793929c4f90478be29f85a17",
160 "102607b09cdd60e2793929c4f90478be29f85a17",
161 "49d3fd156b6f7db46313fac355dca1a0b94a0017",
161 "49d3fd156b6f7db46313fac355dca1a0b94a0017",
162 "2d1028c054665b962fa3d307adfc923ddd528038",
162 "2d1028c054665b962fa3d307adfc923ddd528038",
163 "d7e0d30fbcae12c90680eb095a4f5f02505ce501",
163 "d7e0d30fbcae12c90680eb095a4f5f02505ce501",
164 "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
164 "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
165 "dd80b0f6cf5052f17cc738c2951c4f2070200d7f",
165 "dd80b0f6cf5052f17cc738c2951c4f2070200d7f",
166 "8430a588b43b5d6da365400117c89400326e7992",
166 "8430a588b43b5d6da365400117c89400326e7992",
167 "d955cd312c17b02143c04fa1099a352b04368118",
167 "d955cd312c17b02143c04fa1099a352b04368118",
168 "f67b87e5c629c2ee0ba58f85197e423ff28d735b",
168 "f67b87e5c629c2ee0ba58f85197e423ff28d735b",
169 "add63e382e4aabc9e1afdc4bdc24506c269b7618",
169 "add63e382e4aabc9e1afdc4bdc24506c269b7618",
170 "f298fe1189f1b69779a4423f40b48edf92a703fc",
170 "f298fe1189f1b69779a4423f40b48edf92a703fc",
171 "bd9b619eb41994cac43d67cf4ccc8399c1125808",
171 "bd9b619eb41994cac43d67cf4ccc8399c1125808",
172 "6e125e7c890379446e98980d8ed60fba87d0f6d1",
172 "6e125e7c890379446e98980d8ed60fba87d0f6d1",
173 "d4a54db9f745dfeba6933bf5b1e79e15d0af20bd",
173 "d4a54db9f745dfeba6933bf5b1e79e15d0af20bd",
174 "0b05e4ed56c802098dfc813cbe779b2f49e92500",
174 "0b05e4ed56c802098dfc813cbe779b2f49e92500",
175 "191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e",
175 "191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e",
176 "45223f8f114c64bf4d6f853e3c35a369a6305520",
176 "45223f8f114c64bf4d6f853e3c35a369a6305520",
177 "ca1eb7957a54bce53b12d1a51b13452f95bc7c7e",
177 "ca1eb7957a54bce53b12d1a51b13452f95bc7c7e",
178 "f5ea29fc42ef67a2a5a7aecff10e1566699acd68",
178 "f5ea29fc42ef67a2a5a7aecff10e1566699acd68",
179 "27d48942240f5b91dfda77accd2caac94708cc7d",
179 "27d48942240f5b91dfda77accd2caac94708cc7d",
180 "622f0eb0bafd619d2560c26f80f09e3b0b0d78af",
180 "622f0eb0bafd619d2560c26f80f09e3b0b0d78af",
181 "e686b958768ee96af8029fe19c6050b1a8dd3b2b",
181 "e686b958768ee96af8029fe19c6050b1a8dd3b2b",
182 }
182 }
183 assert subset.issubset(set(self.repo.commit_ids))
183 assert subset.issubset(set(self.repo.commit_ids))
184
184
185 def test_slicing(self):
185 def test_slicing(self):
186 # 4 1 5 10 95
186 # 4 1 5 10 95
187 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5), (10, 20, 10), (5, 100, 95)]:
187 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5), (10, 20, 10), (5, 100, 95)]:
188 commit_ids = list(self.repo[sfrom:sto])
188 commit_ids = list(self.repo[sfrom:sto])
189 assert len(commit_ids) == size
189 assert len(commit_ids) == size
190 assert commit_ids[0] == self.repo.get_commit(commit_idx=sfrom)
190 assert commit_ids[0] == self.repo.get_commit(commit_idx=sfrom)
191 assert commit_ids[-1] == self.repo.get_commit(commit_idx=sto - 1)
191 assert commit_ids[-1] == self.repo.get_commit(commit_idx=sto - 1)
192
192
193 def test_branches(self):
193 def test_branches(self):
194 # TODO: Need more tests here
194 # TODO: Need more tests here
195 # Removed (those are 'remotes' branches for cloned repo)
195 # Removed (those are 'remotes' branches for cloned repo)
196 # assert 'master' in self.repo.branches
196 # assert 'master' in self.repo.branches
197 # assert 'gittree' in self.repo.branches
197 # assert 'gittree' in self.repo.branches
198 # assert 'web-branch' in self.repo.branches
198 # assert 'web-branch' in self.repo.branches
199 for __, commit_id in self.repo.branches.items():
199 for __, commit_id in self.repo.branches.items():
200 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
200 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
201
201
202 def test_tags(self):
202 def test_tags(self):
203 # TODO: Need more tests here
203 # TODO: Need more tests here
204 assert "v0.1.1" in self.repo.tags
204 assert "v0.1.1" in self.repo.tags
205 assert "v0.1.2" in self.repo.tags
205 assert "v0.1.2" in self.repo.tags
206 for __, commit_id in self.repo.tags.items():
206 for __, commit_id in self.repo.tags.items():
207 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
207 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
208
208
209 def _test_single_commit_cache(self, commit_id):
209 def _test_single_commit_cache(self, commit_id):
210 commit = self.repo.get_commit(commit_id)
210 commit = self.repo.get_commit(commit_id)
211 assert commit_id in self.repo.commits
211 assert commit_id in self.repo.commits
212 assert commit is self.repo.commits[commit_id]
212 assert commit is self.repo.commits[commit_id]
213
213
214 def test_initial_commit(self):
214 def test_initial_commit(self):
215 commit_id = self.repo.commit_ids[0]
215 commit_id = self.repo.commit_ids[0]
216 init_commit = self.repo.get_commit(commit_id)
216 init_commit = self.repo.get_commit(commit_id)
217 init_author = init_commit.author
217 init_author = init_commit.author
218
218
219 assert init_commit.message == "initial import\n"
219 assert init_commit.message == "initial import\n"
220 assert init_author == "Marcin Kuzminski <marcin@python-blog.com>"
220 assert init_author == "Marcin Kuzminski <marcin@python-blog.com>"
221 assert init_author == init_commit.committer
221 assert init_author == init_commit.committer
222 for path in ("vcs/__init__.py", "vcs/backends/BaseRepository.py", "vcs/backends/__init__.py"):
222 for path in ("vcs/__init__.py", "vcs/backends/BaseRepository.py", "vcs/backends/__init__.py"):
223 assert isinstance(init_commit.get_node(path), FileNode)
223 assert isinstance(init_commit.get_node(path), FileNode)
224 for path in ("", "vcs", "vcs/backends"):
224 for path in ("", "vcs", "vcs/backends"):
225 assert isinstance(init_commit.get_node(path), DirNode)
225 assert isinstance(init_commit.get_node(path), DirNode)
226
226
227 with pytest.raises(NodeDoesNotExistError):
227 with pytest.raises(NodeDoesNotExistError):
228 init_commit.get_node(path="foobar")
228 init_commit.get_node(path="foobar")
229
229
230 node = init_commit.get_node("vcs/")
230 node = init_commit.get_node("vcs/")
231 assert hasattr(node, "kind")
231 assert hasattr(node, "kind")
232 assert node.kind == NodeKind.DIR
232 assert node.kind == NodeKind.DIR
233
233
234 node = init_commit.get_node("vcs")
234 node = init_commit.get_node("vcs")
235 assert hasattr(node, "kind")
235 assert hasattr(node, "kind")
236 assert node.kind == NodeKind.DIR
236 assert node.kind == NodeKind.DIR
237
237
238 node = init_commit.get_node("vcs/__init__.py")
238 node = init_commit.get_node("vcs/__init__.py")
239 assert hasattr(node, "kind")
239 assert hasattr(node, "kind")
240 assert node.kind == NodeKind.FILE
240 assert node.kind == NodeKind.FILE
241
241
242 def test_not_existing_commit(self):
242 def test_not_existing_commit(self):
243 with pytest.raises(RepositoryError):
243 with pytest.raises(RepositoryError):
244 self.repo.get_commit("f" * 40)
244 self.repo.get_commit("f" * 40)
245
245
246 def test_commit10(self):
246 def test_commit10(self):
247 commit10 = self.repo.get_commit(self.repo.commit_ids[9])
247 commit10 = self.repo.get_commit(self.repo.commit_ids[9])
248 README = """===
248 README = """===
249 VCS
249 VCS
250 ===
250 ===
251
251
252 Various Version Control System management abstraction layer for Python.
252 Various Version Control System management abstraction layer for Python.
253
253
254 Introduction
254 Introduction
255 ------------
255 ------------
256
256
257 TODO: To be written...
257 TODO: To be written...
258
258
259 """
259 """
260 node = commit10.get_node("README.rst")
260 node = commit10.get_node("README.rst")
261 assert node.kind == NodeKind.FILE
261 assert node.kind == NodeKind.FILE
262 assert node.str_content == README
262 assert node.str_content == README
263
263
264 def test_head(self):
264 def test_head(self):
265 assert self.repo.head == self.repo.get_commit().raw_id
265 assert self.repo.head == self.repo.get_commit().raw_id
266
266
267 def test_checkout_with_create(self, tmpdir):
267 def test_checkout_with_create(self, tmpdir):
268 repo_clone = self.get_clone_repo(tmpdir)
268 repo_clone = self.get_clone_repo(tmpdir)
269
269
270 new_branch = "new_branch"
270 new_branch = "new_branch"
271 assert repo_clone._current_branch() == "master"
271 assert repo_clone._current_branch() == "master"
272 assert set(repo_clone.branches) == {"master"}
272 assert set(repo_clone.branches) == {"master"}
273 repo_clone._checkout(new_branch, create=True)
273 repo_clone._checkout(new_branch, create=True)
274
274
275 # Branches is a lazy property so we need to recrete the Repo object.
275 # Branches is a lazy property so we need to recrete the Repo object.
276 repo_clone = GitRepository(repo_clone.path)
276 repo_clone = GitRepository(repo_clone.path)
277 assert set(repo_clone.branches) == {"master", new_branch}
277 assert set(repo_clone.branches) == {"master", new_branch}
278 assert repo_clone._current_branch() == new_branch
278 assert repo_clone._current_branch() == new_branch
279
279
280 def test_checkout(self, tmpdir):
280 def test_checkout(self, tmpdir):
281 repo_clone = self.get_clone_repo(tmpdir)
281 repo_clone = self.get_clone_repo(tmpdir)
282
282
283 repo_clone._checkout("new_branch", create=True)
283 repo_clone._checkout("new_branch", create=True)
284 repo_clone._checkout("master")
284 repo_clone._checkout("master")
285
285
286 assert repo_clone._current_branch() == "master"
286 assert repo_clone._current_branch() == "master"
287
287
288 def test_checkout_same_branch(self, tmpdir):
288 def test_checkout_same_branch(self, tmpdir):
289 repo_clone = self.get_clone_repo(tmpdir)
289 repo_clone = self.get_clone_repo(tmpdir)
290
290
291 repo_clone._checkout("master")
291 repo_clone._checkout("master")
292 assert repo_clone._current_branch() == "master"
292 assert repo_clone._current_branch() == "master"
293
293
294 def test_checkout_branch_already_exists(self, tmpdir):
294 def test_checkout_branch_already_exists(self, tmpdir):
295 repo_clone = self.get_clone_repo(tmpdir)
295 repo_clone = self.get_clone_repo(tmpdir)
296
296
297 with pytest.raises(RepositoryError):
297 with pytest.raises(RepositoryError):
298 repo_clone._checkout("master", create=True)
298 repo_clone._checkout("master", create=True)
299
299
300 def test_checkout_bare_repo(self):
300 def test_checkout_bare_repo(self):
301 with pytest.raises(RepositoryError):
301 with pytest.raises(RepositoryError):
302 self.repo._checkout("master")
302 self.repo._checkout("master")
303
303
304 def test_current_branch_bare_repo(self):
304 def test_current_branch_bare_repo(self):
305 with pytest.raises(RepositoryError):
305 with pytest.raises(RepositoryError):
306 self.repo._current_branch()
306 self.repo._current_branch()
307
307
308 def test_current_branch_empty_repo(self, tmpdir):
308 def test_current_branch_empty_repo(self, tmpdir):
309 repo = self.get_empty_repo(tmpdir)
309 repo = self.get_empty_repo(tmpdir)
310 assert repo._current_branch() is None
310 assert repo._current_branch() is None
311
311
312 def test_local_clone(self, tmp_path_factory):
312 def test_local_clone(self, tmp_path_factory):
313 clone_path = str(tmp_path_factory.mktemp("test-local-clone"))
313 clone_path = str(tmp_path_factory.mktemp("test-local-clone"))
314 self.repo._local_clone(clone_path, "master")
314 self.repo._local_clone(clone_path, "master")
315 repo_clone = GitRepository(clone_path)
315 repo_clone = GitRepository(clone_path)
316
316
317 assert self.repo.commit_ids == repo_clone.commit_ids
317 assert self.repo.commit_ids == repo_clone.commit_ids
318
318
319 def test_local_clone_with_specific_branch(self, tmpdir):
319 def test_local_clone_with_specific_branch(self, tmpdir):
320 source_repo = self.get_clone_repo(tmpdir)
320 source_repo = self.get_clone_repo(tmpdir)
321
321
322 # Create a new branch in source repo
322 # Create a new branch in source repo
323 new_branch_commit = source_repo.commit_ids[-3]
323 new_branch_commit = source_repo.commit_ids[-3]
324 source_repo._checkout(new_branch_commit)
324 source_repo._checkout(new_branch_commit)
325 source_repo._checkout("new_branch", create=True)
325 source_repo._checkout("new_branch", create=True)
326
326
327 clone_path = str(tmpdir.join("git-clone-path-1"))
327 clone_path = str(tmpdir.join("git-clone-path-1"))
328 source_repo._local_clone(clone_path, "new_branch")
328 source_repo._local_clone(clone_path, "new_branch")
329 repo_clone = GitRepository(clone_path)
329 repo_clone = GitRepository(clone_path)
330
330
331 assert source_repo.commit_ids[: -3 + 1] == repo_clone.commit_ids
331 assert source_repo.commit_ids[: -3 + 1] == repo_clone.commit_ids
332
332
333 clone_path = str(tmpdir.join("git-clone-path-2"))
333 clone_path = str(tmpdir.join("git-clone-path-2"))
334 source_repo._local_clone(clone_path, "master")
334 source_repo._local_clone(clone_path, "master")
335 repo_clone = GitRepository(clone_path)
335 repo_clone = GitRepository(clone_path)
336
336
337 assert source_repo.commit_ids == repo_clone.commit_ids
337 assert source_repo.commit_ids == repo_clone.commit_ids
338
338
339 def test_local_clone_fails_if_target_exists(self):
339 def test_local_clone_fails_if_target_exists(self):
340 with pytest.raises(RepositoryError):
340 with pytest.raises(RepositoryError):
341 self.repo._local_clone(self.repo.path, "master")
341 self.repo._local_clone(self.repo.path, "master")
342
342
343 def test_local_fetch(self, tmpdir):
343 def test_local_fetch(self, tmpdir):
344 target_repo = self.get_empty_repo(tmpdir)
344 target_repo = self.get_empty_repo(tmpdir)
345 source_repo = self.get_clone_repo(tmpdir)
345 source_repo = self.get_clone_repo(tmpdir)
346
346
347 # Create a new branch in source repo
347 # Create a new branch in source repo
348 master_commit = source_repo.commit_ids[-1]
348 master_commit = source_repo.commit_ids[-1]
349 new_branch_commit = source_repo.commit_ids[-3]
349 new_branch_commit = source_repo.commit_ids[-3]
350 source_repo._checkout(new_branch_commit)
350 source_repo._checkout(new_branch_commit)
351 source_repo._checkout("new_branch", create=True)
351 source_repo._checkout("new_branch", create=True)
352
352
353 target_repo._local_fetch(source_repo.path, "new_branch")
353 target_repo._local_fetch(source_repo.path, "new_branch")
354 assert target_repo._last_fetch_heads() == [new_branch_commit]
354 assert target_repo._last_fetch_heads() == [new_branch_commit]
355
355
356 target_repo._local_fetch(source_repo.path, "master")
356 target_repo._local_fetch(source_repo.path, "master")
357 assert target_repo._last_fetch_heads() == [master_commit]
357 assert target_repo._last_fetch_heads() == [master_commit]
358
358
359 def test_local_fetch_from_bare_repo(self, tmpdir):
359 def test_local_fetch_from_bare_repo(self, tmpdir):
360 target_repo = self.get_empty_repo(tmpdir)
360 target_repo = self.get_empty_repo(tmpdir)
361 target_repo._local_fetch(self.repo.path, "master")
361 target_repo._local_fetch(self.repo.path, "master")
362
362
363 master_commit = self.repo.commit_ids[-1]
363 master_commit = self.repo.commit_ids[-1]
364 assert target_repo._last_fetch_heads() == [master_commit]
364 assert target_repo._last_fetch_heads() == [master_commit]
365
365
366 def test_local_fetch_from_same_repo(self):
366 def test_local_fetch_from_same_repo(self):
367 with pytest.raises(ValueError):
367 with pytest.raises(ValueError):
368 self.repo._local_fetch(self.repo.path, "master")
368 self.repo._local_fetch(self.repo.path, "master")
369
369
370 def test_local_fetch_branch_does_not_exist(self, tmpdir):
370 def test_local_fetch_branch_does_not_exist(self, tmpdir):
371 target_repo = self.get_empty_repo(tmpdir)
371 target_repo = self.get_empty_repo(tmpdir)
372
372
373 with pytest.raises(RepositoryError):
373 with pytest.raises(RepositoryError):
374 target_repo._local_fetch(self.repo.path, "new_branch")
374 target_repo._local_fetch(self.repo.path, "new_branch")
375
375
376 def test_local_pull(self, tmpdir):
376 def test_local_pull(self, tmpdir):
377 target_repo = self.get_empty_repo(tmpdir)
377 target_repo = self.get_empty_repo(tmpdir)
378 source_repo = self.get_clone_repo(tmpdir)
378 source_repo = self.get_clone_repo(tmpdir)
379
379
380 # Create a new branch in source repo
380 # Create a new branch in source repo
381 master_commit = source_repo.commit_ids[-1]
381 master_commit = source_repo.commit_ids[-1]
382 new_branch_commit = source_repo.commit_ids[-3]
382 new_branch_commit = source_repo.commit_ids[-3]
383 source_repo._checkout(new_branch_commit)
383 source_repo._checkout(new_branch_commit)
384 source_repo._checkout("new_branch", create=True)
384 source_repo._checkout("new_branch", create=True)
385
385
386 target_repo._local_pull(source_repo.path, "new_branch")
386 target_repo._local_pull(source_repo.path, "new_branch")
387 target_repo = GitRepository(target_repo.path)
387 target_repo = GitRepository(target_repo.path)
388 assert target_repo.head == new_branch_commit
388 assert target_repo.head == new_branch_commit
389
389
390 target_repo._local_pull(source_repo.path, "master")
390 target_repo._local_pull(source_repo.path, "master")
391 target_repo = GitRepository(target_repo.path)
391 target_repo = GitRepository(target_repo.path)
392 assert target_repo.head == master_commit
392 assert target_repo.head == master_commit
393
393
394 def test_local_pull_in_bare_repo(self):
394 def test_local_pull_in_bare_repo(self):
395 with pytest.raises(RepositoryError):
395 with pytest.raises(RepositoryError):
396 self.repo._local_pull(self.repo.path, "master")
396 self.repo._local_pull(self.repo.path, "master")
397
397
398 def test_local_merge(self, tmpdir):
398 def test_local_merge(self, tmpdir):
399 target_repo = self.get_empty_repo(tmpdir)
399 target_repo = self.get_empty_repo(tmpdir)
400 source_repo = self.get_clone_repo(tmpdir)
400 source_repo = self.get_clone_repo(tmpdir)
401
401
402 # Create a new branch in source repo
402 # Create a new branch in source repo
403 master_commit = source_repo.commit_ids[-1]
403 master_commit = source_repo.commit_ids[-1]
404 new_branch_commit = source_repo.commit_ids[-3]
404 new_branch_commit = source_repo.commit_ids[-3]
405 source_repo._checkout(new_branch_commit)
405 source_repo._checkout(new_branch_commit)
406 source_repo._checkout("new_branch", create=True)
406 source_repo._checkout("new_branch", create=True)
407
407
408 # This is required as one cannot do a -ff-only merge in an empty repo.
408 # This is required as one cannot do a -ff-only merge in an empty repo.
409 target_repo._local_pull(source_repo.path, "new_branch")
409 target_repo._local_pull(source_repo.path, "new_branch")
410
410
411 target_repo._local_fetch(source_repo.path, "master")
411 target_repo._local_fetch(source_repo.path, "master")
412 merge_message = "Merge message\n\nDescription:..."
412 merge_message = "Merge message\n\nDescription:..."
413 user_name = "Albert Einstein"
413 user_name = "Albert Einstein"
414 user_email = "albert@einstein.com"
414 user_email = "albert@einstein.com"
415 target_repo._local_merge(merge_message, user_name, user_email, target_repo._last_fetch_heads())
415 target_repo._local_merge(merge_message, user_name, user_email, target_repo._last_fetch_heads())
416
416
417 target_repo = GitRepository(target_repo.path)
417 target_repo = GitRepository(target_repo.path)
418 assert target_repo.commit_ids[-2] == master_commit
418 assert target_repo.commit_ids[-2] == master_commit
419 last_commit = target_repo.get_commit(target_repo.head)
419 last_commit = target_repo.get_commit(target_repo.head)
420 assert last_commit.message.strip() == merge_message
420 assert last_commit.message.strip() == merge_message
421 assert last_commit.author == "%s <%s>" % (user_name, user_email)
421 assert last_commit.author == "%s <%s>" % (user_name, user_email)
422
422
423 assert not os.path.exists(os.path.join(target_repo.path, ".git", "MERGE_HEAD"))
423 assert not os.path.exists(os.path.join(target_repo.path, ".git", "MERGE_HEAD"))
424
424
425 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_git):
425 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_git):
426 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
426 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
427 vcsbackend_git.ensure_file(b"README", b"I will conflict with you!!!")
427 vcsbackend_git.ensure_file(b"README", b"I will conflict with you!!!")
428
428
429 target_repo._local_fetch(self.repo.path, "master")
429 target_repo._local_fetch(self.repo.path, "master")
430 with pytest.raises(RepositoryError):
430 with pytest.raises(RepositoryError):
431 target_repo._local_merge("merge_message", "user name", "user@name.com", target_repo._last_fetch_heads())
431 target_repo._local_merge("merge_message", "user name", "user@name.com", target_repo._last_fetch_heads())
432
432
433 # Check we are not left in an intermediate merge state
433 # Check we are not left in an intermediate merge state
434 assert not os.path.exists(os.path.join(target_repo.path, ".git", "MERGE_HEAD"))
434 assert not os.path.exists(os.path.join(target_repo.path, ".git", "MERGE_HEAD"))
435
435
436 def test_local_merge_into_empty_repo(self, tmpdir):
436 def test_local_merge_into_empty_repo(self, tmpdir):
437 target_repo = self.get_empty_repo(tmpdir)
437 target_repo = self.get_empty_repo(tmpdir)
438
438
439 # This is required as one cannot do a -ff-only merge in an empty repo.
439 # This is required as one cannot do a -ff-only merge in an empty repo.
440 target_repo._local_fetch(self.repo.path, "master")
440 target_repo._local_fetch(self.repo.path, "master")
441 with pytest.raises(RepositoryError):
441 with pytest.raises(RepositoryError):
442 target_repo._local_merge("merge_message", "user name", "user@name.com", target_repo._last_fetch_heads())
442 target_repo._local_merge("merge_message", "user name", "user@name.com", target_repo._last_fetch_heads())
443
443
444 def test_local_merge_in_bare_repo(self):
444 def test_local_merge_in_bare_repo(self):
445 with pytest.raises(RepositoryError):
445 with pytest.raises(RepositoryError):
446 self.repo._local_merge("merge_message", "user name", "user@name.com", None)
446 self.repo._local_merge("merge_message", "user name", "user@name.com", None)
447
447
448 def test_local_push_non_bare(self, tmpdir):
448 def test_local_push_non_bare(self, tmpdir):
449 target_repo = self.get_empty_repo(tmpdir)
449 target_repo = self.get_empty_repo(tmpdir)
450
450
451 pushed_branch = "pushed_branch"
451 pushed_branch = "pushed_branch"
452 self.repo._local_push("master", target_repo.path, pushed_branch)
452 self.repo._local_push("master", target_repo.path, pushed_branch)
453 # Fix the HEAD of the target repo, or otherwise GitRepository won't
453 # Fix the HEAD of the target repo, or otherwise GitRepository won't
454 # report any branches.
454 # report any branches.
455 with open(os.path.join(target_repo.path, ".git", "HEAD"), "w") as f:
455 with open(os.path.join(target_repo.path, ".git", "HEAD"), "w") as f:
456 f.write("ref: refs/heads/%s" % pushed_branch)
456 f.write("ref: refs/heads/%s" % pushed_branch)
457
457
458 target_repo = GitRepository(target_repo.path)
458 target_repo = GitRepository(target_repo.path)
459
459
460 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
460 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
461
461
462 def test_local_push_bare(self, tmpdir):
462 def test_local_push_bare(self, tmpdir):
463 target_repo = self.get_empty_repo(tmpdir, bare=True)
463 target_repo = self.get_empty_repo(tmpdir, bare=True)
464
464
465 pushed_branch = "pushed_branch"
465 pushed_branch = "pushed_branch"
466 self.repo._local_push("master", target_repo.path, pushed_branch)
466 self.repo._local_push("master", target_repo.path, pushed_branch)
467 # Fix the HEAD of the target repo, or otherwise GitRepository won't
467 # Fix the HEAD of the target repo, or otherwise GitRepository won't
468 # report any branches.
468 # report any branches.
469 with open(os.path.join(target_repo.path, "HEAD"), "w") as f:
469 with open(os.path.join(target_repo.path, "HEAD"), "w") as f:
470 f.write("ref: refs/heads/%s" % pushed_branch)
470 f.write("ref: refs/heads/%s" % pushed_branch)
471
471
472 target_repo = GitRepository(target_repo.path)
472 target_repo = GitRepository(target_repo.path)
473
473
474 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
474 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
475
475
476 def test_local_push_non_bare_target_branch_is_checked_out(self, tmpdir):
476 def test_local_push_non_bare_target_branch_is_checked_out(self, tmpdir):
477 target_repo = self.get_clone_repo(tmpdir)
477 target_repo = self.get_clone_repo(tmpdir)
478
478
479 pushed_branch = "pushed_branch"
479 pushed_branch = "pushed_branch"
480 # Create a new branch in source repo
480 # Create a new branch in source repo
481 new_branch_commit = target_repo.commit_ids[-3]
481 new_branch_commit = target_repo.commit_ids[-3]
482 target_repo._checkout(new_branch_commit)
482 target_repo._checkout(new_branch_commit)
483 target_repo._checkout(pushed_branch, create=True)
483 target_repo._checkout(pushed_branch, create=True)
484
484
485 self.repo._local_push("master", target_repo.path, pushed_branch)
485 self.repo._local_push("master", target_repo.path, pushed_branch)
486
486
487 target_repo = GitRepository(target_repo.path)
487 target_repo = GitRepository(target_repo.path)
488
488
489 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
489 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
490
490
491 def test_local_push_raises_exception_on_conflict(self, vcsbackend_git):
491 def test_local_push_raises_exception_on_conflict(self, vcsbackend_git):
492 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
492 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
493 with pytest.raises(RepositoryError):
493 with pytest.raises(RepositoryError):
494 self.repo._local_push("master", target_repo.path, "master")
494 self.repo._local_push("master", target_repo.path, "master")
495
495
496 def test_hooks_can_be_enabled_via_env_variable_for_local_push(self, tmpdir):
496 def test_hooks_can_be_enabled_via_env_variable_for_local_push(self, tmpdir):
497 target_repo = self.get_empty_repo(tmpdir, bare=True)
497 target_repo = self.get_empty_repo(tmpdir, bare=True)
498
498
499 with mock.patch.object(self.repo, "run_git_command") as run_mock:
499 with mock.patch.object(self.repo, "run_git_command") as run_mock:
500 self.repo._local_push("master", target_repo.path, "master", enable_hooks=True)
500 self.repo._local_push("master", target_repo.path, "master", enable_hooks=True)
501 env = run_mock.call_args[1]["extra_env"]
501 env = run_mock.call_args[1]["extra_env"]
502 assert "RC_SKIP_HOOKS" not in env
502 assert "RC_SKIP_HOOKS" not in env
503
503
504 def _add_failing_hook(self, repo_path, hook_name, bare=False):
504 def _add_failing_hook(self, repo_path, hook_name, bare=False):
505 path_components = ["hooks", hook_name] if bare else [".git", "hooks", hook_name]
505 path_components = ["hooks", hook_name] if bare else [".git", "hooks", hook_name]
506 hook_path = os.path.join(repo_path, *path_components)
506 hook_path = os.path.join(repo_path, *path_components)
507 with open(hook_path, "w") as f:
507 with open(hook_path, "w") as f:
508 script_lines = [
508 script_lines = [
509 "#!%s" % sys.executable,
509 "#!%s" % sys.executable,
510 "import os",
510 "import os",
511 "import sys",
511 "import sys",
512 'if os.environ.get("RC_SKIP_HOOKS"):',
512 'if os.environ.get("RC_SKIP_HOOKS"):',
513 " sys.exit(0)",
513 " sys.exit(0)",
514 "sys.exit(1)",
514 "sys.exit(1)",
515 ]
515 ]
516 f.write("\n".join(script_lines))
516 f.write("\n".join(script_lines))
517 os.chmod(hook_path, 0o755)
517 os.chmod(hook_path, 0o755)
518
518
519 def test_local_push_does_not_execute_hook(self, tmpdir):
519 def test_local_push_does_not_execute_hook(self, tmpdir):
520 target_repo = self.get_empty_repo(tmpdir)
520 target_repo = self.get_empty_repo(tmpdir)
521
521
522 pushed_branch = "pushed_branch"
522 pushed_branch = "pushed_branch"
523 self._add_failing_hook(target_repo.path, "pre-receive")
523 self._add_failing_hook(target_repo.path, "pre-receive")
524 self.repo._local_push("master", target_repo.path, pushed_branch)
524 self.repo._local_push("master", target_repo.path, pushed_branch)
525 # Fix the HEAD of the target repo, or otherwise GitRepository won't
525 # Fix the HEAD of the target repo, or otherwise GitRepository won't
526 # report any branches.
526 # report any branches.
527 with open(os.path.join(target_repo.path, ".git", "HEAD"), "w") as f:
527 with open(os.path.join(target_repo.path, ".git", "HEAD"), "w") as f:
528 f.write("ref: refs/heads/%s" % pushed_branch)
528 f.write("ref: refs/heads/%s" % pushed_branch)
529
529
530 target_repo = GitRepository(target_repo.path)
530 target_repo = GitRepository(target_repo.path)
531
531
532 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
532 assert target_repo.branches[pushed_branch] == self.repo.branches["master"]
533
533
534 def test_local_push_executes_hook(self, tmpdir):
534 def test_local_push_executes_hook(self, tmpdir):
535 target_repo = self.get_empty_repo(tmpdir, bare=True)
535 target_repo = self.get_empty_repo(tmpdir, bare=True)
536 self._add_failing_hook(target_repo.path, "pre-receive", bare=True)
536 self._add_failing_hook(target_repo.path, "pre-receive", bare=True)
537 with pytest.raises(RepositoryError):
537 with pytest.raises(RepositoryError):
538 self.repo._local_push("master", target_repo.path, "master", enable_hooks=True)
538 self.repo._local_push("master", target_repo.path, "master", enable_hooks=True)
539
539
540 def test_maybe_prepare_merge_workspace(self):
540 def test_maybe_prepare_merge_workspace(self):
541 workspace = self.repo._maybe_prepare_merge_workspace(
541 workspace = self.repo._maybe_prepare_merge_workspace(
542 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
542 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
543 )
543 )
544
544
545 assert os.path.isdir(workspace)
545 assert os.path.isdir(workspace)
546 workspace_repo = GitRepository(workspace)
546 workspace_repo = GitRepository(workspace)
547 assert workspace_repo.branches == self.repo.branches
547 assert workspace_repo.branches == self.repo.branches
548
548
549 # Calling it a second time should also succeed
549 # Calling it a second time should also succeed
550 workspace = self.repo._maybe_prepare_merge_workspace(
550 workspace = self.repo._maybe_prepare_merge_workspace(
551 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
551 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
552 )
552 )
553 assert os.path.isdir(workspace)
553 assert os.path.isdir(workspace)
554
554
555 def test_maybe_prepare_merge_workspace_different_refs(self):
555 def test_maybe_prepare_merge_workspace_different_refs(self):
556 workspace = self.repo._maybe_prepare_merge_workspace(
556 workspace = self.repo._maybe_prepare_merge_workspace(
557 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "develop", "unused")
557 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "develop", "unused")
558 )
558 )
559
559
560 assert os.path.isdir(workspace)
560 assert os.path.isdir(workspace)
561 workspace_repo = GitRepository(workspace)
561 workspace_repo = GitRepository(workspace)
562 assert workspace_repo.branches == self.repo.branches
562 assert workspace_repo.branches == self.repo.branches
563
563
564 # Calling it a second time should also succeed
564 # Calling it a second time should also succeed
565 workspace = self.repo._maybe_prepare_merge_workspace(
565 workspace = self.repo._maybe_prepare_merge_workspace(
566 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "develop", "unused")
566 2, "pr2", Reference("branch", "master", "unused"), Reference("branch", "develop", "unused")
567 )
567 )
568 assert os.path.isdir(workspace)
568 assert os.path.isdir(workspace)
569
569
570 def test_cleanup_merge_workspace(self):
570 def test_cleanup_merge_workspace(self):
571 workspace = self.repo._maybe_prepare_merge_workspace(
571 workspace = self.repo._maybe_prepare_merge_workspace(
572 2, "pr3", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
572 2, "pr3", Reference("branch", "master", "unused"), Reference("branch", "master", "unused")
573 )
573 )
574 self.repo.cleanup_merge_workspace(2, "pr3")
574 self.repo.cleanup_merge_workspace(2, "pr3")
575
575
576 assert not os.path.exists(workspace)
576 assert not os.path.exists(workspace)
577
577
578 def test_cleanup_merge_workspace_invalid_workspace_id(self):
578 def test_cleanup_merge_workspace_invalid_workspace_id(self):
579 # No assert: because in case of an inexistent workspace this function
579 # No assert: because in case of an inexistent workspace this function
580 # should still succeed.
580 # should still succeed.
581 self.repo.cleanup_merge_workspace(1, "pr4")
581 self.repo.cleanup_merge_workspace(1, "pr4")
582
582
583 def test_set_refs(self):
583 def test_set_refs(self):
584 test_ref = "refs/test-refs/abcde"
584 test_ref = "refs/test-refs/abcde"
585 test_commit_id = "ecb86e1f424f2608262b130db174a7dfd25a6623"
585 test_commit_id = "ecb86e1f424f2608262b130db174a7dfd25a6623"
586
586
587 self.repo.set_refs(test_ref, test_commit_id)
587 self.repo.set_refs(test_ref, test_commit_id)
588 stdout, _ = self.repo.run_git_command(["show-ref"])
588 stdout, _ = self.repo.run_git_command(["show-ref"])
589 assert test_ref in stdout
589 assert test_ref in stdout
590 assert test_commit_id in stdout
590 assert test_commit_id in stdout
591
591
592 def test_remove_ref(self):
592 def test_remove_ref(self):
593 test_ref = "refs/test-refs/abcde"
593 test_ref = "refs/test-refs/abcde"
594 test_commit_id = "ecb86e1f424f2608262b130db174a7dfd25a6623"
594 test_commit_id = "ecb86e1f424f2608262b130db174a7dfd25a6623"
595 self.repo.set_refs(test_ref, test_commit_id)
595 self.repo.set_refs(test_ref, test_commit_id)
596 stdout, _ = self.repo.run_git_command(["show-ref"])
596 stdout, _ = self.repo.run_git_command(["show-ref"])
597 assert test_ref in stdout
597 assert test_ref in stdout
598 assert test_commit_id in stdout
598 assert test_commit_id in stdout
599
599
600 self.repo.remove_ref(test_ref)
600 self.repo.remove_ref(test_ref)
601 stdout, _ = self.repo.run_git_command(["show-ref"])
601 stdout, _ = self.repo.run_git_command(["show-ref"])
602 assert test_ref not in stdout
602 assert test_ref not in stdout
603 assert test_commit_id not in stdout
603 assert test_commit_id not in stdout
604
604
605
605
606 class TestGitCommit(object):
606 class TestGitCommit(object):
607 @pytest.fixture(autouse=True)
607 @pytest.fixture(autouse=True)
608 def prepare(self):
608 def prepare(self):
609 self.repo = GitRepository(TEST_GIT_REPO)
609 self.repo = GitRepository(TEST_GIT_REPO)
610
610
611 def test_default_commit(self):
611 def test_default_commit(self):
612 tip = self.repo.get_commit()
612 tip = self.repo.get_commit()
613 assert tip == self.repo.get_commit(None)
613 assert tip == self.repo.get_commit(None)
614 assert tip == self.repo.get_commit("tip")
614 assert tip == self.repo.get_commit("tip")
615
615
616 def test_root_node(self):
616 def test_root_node(self):
617 tip = self.repo.get_commit()
617 tip = self.repo.get_commit()
618 assert tip.root is tip.get_node("")
618 assert tip.root is tip.get_node("")
619
619
620 def test_lazy_fetch(self):
620 def test_lazy_fetch(self):
621 """
621 """
622 Test if commit's nodes expands and are cached as we walk through
622 Test if commit's nodes expands and are cached as we walk through
623 the commit. This test is somewhat hard to write as order of tests
623 the commit. This test is somewhat hard to write as order of tests
624 is a key here. Written by running command after command in a shell.
624 is a key here. Written by running command after command in a shell.
625 """
625 """
626 commit_id = "2a13f185e4525f9d4b59882791a2d397b90d5ddc"
626 commit_id = "2a13f185e4525f9d4b59882791a2d397b90d5ddc"
627 assert commit_id in self.repo.commit_ids
627 assert commit_id in self.repo.commit_ids
628 commit = self.repo.get_commit(commit_id)
628 commit = self.repo.get_commit(commit_id)
629 assert len(commit.nodes) == 0
629 assert len(commit.nodes) == 0
630 root = commit.root
630 root = commit.root
631 assert len(commit.nodes) == 1
631 assert len(commit.nodes) == 1
632 assert len(root.nodes) == 8
632 assert len(root.nodes) == 8
633 # accessing root.nodes updates commit.nodes
633 # accessing root.nodes updates commit.nodes
634 assert len(commit.nodes) == 9
634 assert len(commit.nodes) == 9
635
635
636 docs = root.get_node("docs")
636 docs = root.get_node("docs")
637 # we haven't yet accessed anything new as docs dir was already cached
637 # we haven't yet accessed anything new as docs dir was already cached
638 assert len(commit.nodes) == 9
638 assert len(commit.nodes) == 9
639 assert len(docs.nodes) == 8
639 assert len(docs.nodes) == 8
640 # accessing docs.nodes updates commit.nodes
640 # accessing docs.nodes updates commit.nodes
641 assert len(commit.nodes) == 17
641 assert len(commit.nodes) == 17
642
642
643 assert docs is commit.get_node("docs")
643 assert docs is commit.get_node("docs")
644 assert docs is root.nodes[0]
644 assert docs is root.nodes[0]
645 assert docs is root.dirs[0]
645 assert docs is root.dirs[0]
646 assert docs is commit.get_node("docs")
646 assert docs is commit.get_node("docs")
647
647
648 def test_nodes_with_commit(self):
648 def test_nodes_with_commit(self):
649 commit_id = "2a13f185e4525f9d4b59882791a2d397b90d5ddc"
649 commit_id = "2a13f185e4525f9d4b59882791a2d397b90d5ddc"
650 commit = self.repo.get_commit(commit_id)
650 commit = self.repo.get_commit(commit_id)
651 root = commit.root
651 root = commit.root
652 docs = root.get_node("docs")
652 docs = root.get_node("docs")
653 assert docs is commit.get_node("docs")
653 assert docs is commit.get_node("docs")
654 api = docs.get_node("api")
654 api = docs.get_node("api")
655 assert api is commit.get_node("docs/api")
655 assert api is commit.get_node("docs/api")
656 index = api.get_node("index.rst")
656 index = api.get_node("index.rst")
657 assert index is commit.get_node("docs/api/index.rst")
657 assert index is commit.get_node("docs/api/index.rst")
658 assert index is commit.get_node("docs").get_node("api").get_node("index.rst")
658 assert index is commit.get_node("docs").get_node("api").get_node("index.rst")
659
659
660 def test_branch_and_tags(self):
660 def test_branch_and_tags(self):
661 """
661 """
662 rev0 = self.repo.commit_ids[0]
662 rev0 = self.repo.commit_ids[0]
663 commit0 = self.repo.get_commit(rev0)
663 commit0 = self.repo.get_commit(rev0)
664 assert commit0.branch == 'master'
664 assert commit0.branch == 'master'
665 assert commit0.tags == []
665 assert commit0.tags == []
666
666
667 rev10 = self.repo.commit_ids[10]
667 rev10 = self.repo.commit_ids[10]
668 commit10 = self.repo.get_commit(rev10)
668 commit10 = self.repo.get_commit(rev10)
669 assert commit10.branch == 'master'
669 assert commit10.branch == 'master'
670 assert commit10.tags == []
670 assert commit10.tags == []
671
671
672 rev44 = self.repo.commit_ids[44]
672 rev44 = self.repo.commit_ids[44]
673 commit44 = self.repo.get_commit(rev44)
673 commit44 = self.repo.get_commit(rev44)
674 assert commit44.branch == 'web-branch'
674 assert commit44.branch == 'web-branch'
675
675
676 tip = self.repo.get_commit('tip')
676 tip = self.repo.get_commit('tip')
677 assert 'tip' in tip.tags
677 assert 'tip' in tip.tags
678 """
678 """
679 # Those tests would fail - branches are now going
679 # Those tests would fail - branches are now going
680 # to be changed at main API in order to support git backend
680 # to be changed at main API in order to support git backend
681 pass
681 pass
682
682
683 def test_file_size(self):
683 def test_file_size(self):
684 to_check = (
684 to_check = (
685 ("c1214f7e79e02fc37156ff215cd71275450cffc3", "vcs/backends/BaseRepository.py", 502),
685 ("c1214f7e79e02fc37156ff215cd71275450cffc3", "vcs/backends/BaseRepository.py", 502),
686 ("d7e0d30fbcae12c90680eb095a4f5f02505ce501", "vcs/backends/hg.py", 854),
686 ("d7e0d30fbcae12c90680eb095a4f5f02505ce501", "vcs/backends/hg.py", 854),
687 ("6e125e7c890379446e98980d8ed60fba87d0f6d1", "setup.py", 1068),
687 ("6e125e7c890379446e98980d8ed60fba87d0f6d1", "setup.py", 1068),
688 ("d955cd312c17b02143c04fa1099a352b04368118", "vcs/backends/base.py", 2921),
688 ("d955cd312c17b02143c04fa1099a352b04368118", "vcs/backends/base.py", 2921),
689 ("ca1eb7957a54bce53b12d1a51b13452f95bc7c7e", "vcs/backends/base.py", 3936),
689 ("ca1eb7957a54bce53b12d1a51b13452f95bc7c7e", "vcs/backends/base.py", 3936),
690 ("f50f42baeed5af6518ef4b0cb2f1423f3851a941", "vcs/backends/base.py", 6189),
690 ("f50f42baeed5af6518ef4b0cb2f1423f3851a941", "vcs/backends/base.py", 6189),
691 )
691 )
692 for commit_id, path, size in to_check:
692 for commit_id, path, size in to_check:
693 node = self.repo.get_commit(commit_id).get_node(path)
693 node = self.repo.get_commit(commit_id).get_node(path)
694 assert node.is_file()
694 assert node.is_file()
695 assert node.size == size
695 assert node.size == size
696
696
697 def test_file_history_from_commits(self):
697 def test_file_history_from_commits(self):
698 node = self.repo[10].get_node("setup.py")
698 node = self.repo[10].get_node("setup.py")
699 commit_ids = [commit.raw_id for commit in node.history]
699 commit_ids = [commit.raw_id for commit in node.history]
700 assert ["ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == commit_ids
700 assert ["ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == commit_ids
701
701
702 node = self.repo[20].get_node("setup.py")
702 node = self.repo[20].get_node("setup.py")
703 node_ids = [commit.raw_id for commit in node.history]
703 node_ids = [commit.raw_id for commit in node.history]
704 assert ["191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == node_ids
704 assert ["191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == node_ids
705
705
706 # special case we check history from commit that has this particular
706 # special case we check history from commit that has this particular
707 # file changed this means we check if it's included as well
707 # file changed this means we check if it's included as well
708 node = self.repo.get_commit("191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e").get_node("setup.py")
708 node = self.repo.get_commit("191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e").get_node("setup.py")
709 node_ids = [commit.raw_id for commit in node.history]
709 node_ids = [commit.raw_id for commit in node.history]
710 assert ["191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == node_ids
710 assert ["191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"] == node_ids
711
711
712 def test_file_history(self):
712 def test_file_history(self):
713 # we can only check if those commits are present in the history
713 # we can only check if those commits are present in the history
714 # as we cannot update this test every time file is changed
714 # as we cannot update this test every time file is changed
715 files = {
715 files = {
716 "setup.py": [
716 "setup.py": [
717 "54386793436c938cff89326944d4c2702340037d",
717 "54386793436c938cff89326944d4c2702340037d",
718 "51d254f0ecf5df2ce50c0b115741f4cf13985dab",
718 "51d254f0ecf5df2ce50c0b115741f4cf13985dab",
719 "998ed409c795fec2012b1c0ca054d99888b22090",
719 "998ed409c795fec2012b1c0ca054d99888b22090",
720 "5e0eb4c47f56564395f76333f319d26c79e2fb09",
720 "5e0eb4c47f56564395f76333f319d26c79e2fb09",
721 "0115510b70c7229dbc5dc49036b32e7d91d23acd",
721 "0115510b70c7229dbc5dc49036b32e7d91d23acd",
722 "7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e",
722 "7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e",
723 "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
723 "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
724 "191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e",
724 "191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e",
725 "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
725 "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
726 ],
726 ],
727 "vcs/nodes.py": [
727 "vcs/nodes.py": [
728 "33fa3223355104431402a888fa77a4e9956feb3e",
728 "33fa3223355104431402a888fa77a4e9956feb3e",
729 "fa014c12c26d10ba682fadb78f2a11c24c8118e1",
729 "fa014c12c26d10ba682fadb78f2a11c24c8118e1",
730 "e686b958768ee96af8029fe19c6050b1a8dd3b2b",
730 "e686b958768ee96af8029fe19c6050b1a8dd3b2b",
731 "ab5721ca0a081f26bf43d9051e615af2cc99952f",
731 "ab5721ca0a081f26bf43d9051e615af2cc99952f",
732 "c877b68d18e792a66b7f4c529ea02c8f80801542",
732 "c877b68d18e792a66b7f4c529ea02c8f80801542",
733 "4313566d2e417cb382948f8d9d7c765330356054",
733 "4313566d2e417cb382948f8d9d7c765330356054",
734 "6c2303a793671e807d1cfc70134c9ca0767d98c2",
734 "6c2303a793671e807d1cfc70134c9ca0767d98c2",
735 "54386793436c938cff89326944d4c2702340037d",
735 "54386793436c938cff89326944d4c2702340037d",
736 "54000345d2e78b03a99d561399e8e548de3f3203",
736 "54000345d2e78b03a99d561399e8e548de3f3203",
737 "1c6b3677b37ea064cb4b51714d8f7498f93f4b2b",
737 "1c6b3677b37ea064cb4b51714d8f7498f93f4b2b",
738 "2d03ca750a44440fb5ea8b751176d1f36f8e8f46",
738 "2d03ca750a44440fb5ea8b751176d1f36f8e8f46",
739 "2a08b128c206db48c2f0b8f70df060e6db0ae4f8",
739 "2a08b128c206db48c2f0b8f70df060e6db0ae4f8",
740 "30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b",
740 "30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b",
741 "ac71e9503c2ca95542839af0ce7b64011b72ea7c",
741 "ac71e9503c2ca95542839af0ce7b64011b72ea7c",
742 "12669288fd13adba2a9b7dd5b870cc23ffab92d2",
742 "12669288fd13adba2a9b7dd5b870cc23ffab92d2",
743 "5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382",
743 "5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382",
744 "12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5",
744 "12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5",
745 "5eab1222a7cd4bfcbabc218ca6d04276d4e27378",
745 "5eab1222a7cd4bfcbabc218ca6d04276d4e27378",
746 "f50f42baeed5af6518ef4b0cb2f1423f3851a941",
746 "f50f42baeed5af6518ef4b0cb2f1423f3851a941",
747 "d7e390a45f6aa96f04f5e7f583ad4f867431aa25",
747 "d7e390a45f6aa96f04f5e7f583ad4f867431aa25",
748 "f15c21f97864b4f071cddfbf2750ec2e23859414",
748 "f15c21f97864b4f071cddfbf2750ec2e23859414",
749 "e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade",
749 "e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade",
750 "ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b",
750 "ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b",
751 "84dec09632a4458f79f50ddbbd155506c460b4f9",
751 "84dec09632a4458f79f50ddbbd155506c460b4f9",
752 "0115510b70c7229dbc5dc49036b32e7d91d23acd",
752 "0115510b70c7229dbc5dc49036b32e7d91d23acd",
753 "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
753 "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
754 "3bf1c5868e570e39569d094f922d33ced2fa3b2b",
754 "3bf1c5868e570e39569d094f922d33ced2fa3b2b",
755 "b8d04012574729d2c29886e53b1a43ef16dd00a1",
755 "b8d04012574729d2c29886e53b1a43ef16dd00a1",
756 "6970b057cffe4aab0a792aa634c89f4bebf01441",
756 "6970b057cffe4aab0a792aa634c89f4bebf01441",
757 "dd80b0f6cf5052f17cc738c2951c4f2070200d7f",
757 "dd80b0f6cf5052f17cc738c2951c4f2070200d7f",
758 "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
758 "ff7ca51e58c505fec0dd2491de52c622bb7a806b",
759 ],
759 ],
760 "vcs/backends/git.py": [
760 "vcs/backends/git.py": [
761 "4cf116ad5a457530381135e2f4c453e68a1b0105",
761 "4cf116ad5a457530381135e2f4c453e68a1b0105",
762 "9a751d84d8e9408e736329767387f41b36935153",
762 "9a751d84d8e9408e736329767387f41b36935153",
763 "cb681fb539c3faaedbcdf5ca71ca413425c18f01",
763 "cb681fb539c3faaedbcdf5ca71ca413425c18f01",
764 "428f81bb652bcba8d631bce926e8834ff49bdcc6",
764 "428f81bb652bcba8d631bce926e8834ff49bdcc6",
765 "180ab15aebf26f98f714d8c68715e0f05fa6e1c7",
765 "180ab15aebf26f98f714d8c68715e0f05fa6e1c7",
766 "2b8e07312a2e89e92b90426ab97f349f4bce2a3a",
766 "2b8e07312a2e89e92b90426ab97f349f4bce2a3a",
767 "50e08c506174d8645a4bb517dd122ac946a0f3bf",
767 "50e08c506174d8645a4bb517dd122ac946a0f3bf",
768 "54000345d2e78b03a99d561399e8e548de3f3203",
768 "54000345d2e78b03a99d561399e8e548de3f3203",
769 ],
769 ],
770 }
770 }
771 for path, commit_ids in files.items():
771 for path, commit_ids in files.items():
772 node = self.repo.get_commit(commit_ids[0]).get_node(path)
772 node = self.repo.get_commit(commit_ids[0]).get_node(path)
773 node_ids = [commit.raw_id for commit in node.history]
773 node_ids = [commit.raw_id for commit in node.history]
774 assert set(commit_ids).issubset(set(node_ids)), (
774 assert set(commit_ids).issubset(set(node_ids)), (
775 "We assumed that %s is subset of commit_ids for which file %s "
775 "We assumed that %s is subset of commit_ids for which file %s "
776 "has been changed, and history of that node returned: %s" % (commit_ids, path, node_ids)
776 "has been changed, and history of that node returned: %s" % (commit_ids, path, node_ids)
777 )
777 )
778
778
779 def test_file_annotate(self):
779 def test_file_annotate(self):
780 files = {
780 files = {
781 "vcs/backends/__init__.py": {
781 "vcs/backends/__init__.py": {
782 "c1214f7e79e02fc37156ff215cd71275450cffc3": {
782 "c1214f7e79e02fc37156ff215cd71275450cffc3": {
783 "lines_no": 1,
783 "lines_no": 1,
784 "commits": [
784 "commits": [
785 "c1214f7e79e02fc37156ff215cd71275450cffc3",
785 "c1214f7e79e02fc37156ff215cd71275450cffc3",
786 ],
786 ],
787 },
787 },
788 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647": {
788 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647": {
789 "lines_no": 21,
789 "lines_no": 21,
790 "commits": [
790 "commits": [
791 "49d3fd156b6f7db46313fac355dca1a0b94a0017",
791 "49d3fd156b6f7db46313fac355dca1a0b94a0017",
792 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
792 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
793 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
793 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
794 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
794 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
795 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
795 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
796 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
796 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
797 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
797 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
798 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
798 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
799 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
799 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
800 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
800 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
801 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
801 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
802 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
802 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
803 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
803 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
804 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
804 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
805 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
805 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
806 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
806 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
807 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
807 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
808 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
808 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
809 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
809 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
810 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
810 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
811 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
811 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
812 ],
812 ],
813 },
813 },
814 "e29b67bd158580fc90fc5e9111240b90e6e86064": {
814 "e29b67bd158580fc90fc5e9111240b90e6e86064": {
815 "lines_no": 32,
815 "lines_no": 32,
816 "commits": [
816 "commits": [
817 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
817 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
818 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
818 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
819 "5eab1222a7cd4bfcbabc218ca6d04276d4e27378",
819 "5eab1222a7cd4bfcbabc218ca6d04276d4e27378",
820 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
820 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
821 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
821 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
822 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
822 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
823 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
823 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
824 "54000345d2e78b03a99d561399e8e548de3f3203",
824 "54000345d2e78b03a99d561399e8e548de3f3203",
825 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
825 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
826 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
826 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
827 "78c3f0c23b7ee935ec276acb8b8212444c33c396",
827 "78c3f0c23b7ee935ec276acb8b8212444c33c396",
828 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
828 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
829 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
829 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
830 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
830 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
831 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
831 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
832 "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
832 "2a13f185e4525f9d4b59882791a2d397b90d5ddc",
833 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
833 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
834 "78c3f0c23b7ee935ec276acb8b8212444c33c396",
834 "78c3f0c23b7ee935ec276acb8b8212444c33c396",
835 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
835 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
836 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
836 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
837 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
837 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
838 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
838 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
839 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
839 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
840 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
840 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
841 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
841 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
842 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
842 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
843 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
843 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
844 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
844 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
845 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
845 "992f38217b979d0b0987d0bae3cc26dac85d9b19",
846 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
846 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
847 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
847 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
848 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
848 "16fba1ae9334d79b66d7afed2c2dfbfa2ae53647",
849 ],
849 ],
850 },
850 },
851 },
851 },
852 }
852 }
853
853
854 for fname, commit_dict in files.items():
854 for fname, commit_dict in files.items():
855 for commit_id, __ in commit_dict.items():
855 for commit_id, __ in commit_dict.items():
856 commit = self.repo.get_commit(commit_id)
856 commit = self.repo.get_commit(commit_id)
857
857
858 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
858 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
859 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
859 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
860 assert l1_1 == l1_2
860 assert l1_1 == l1_2
861 l1 = l1_1
861 l1 = l1_1
862 l2 = files[fname][commit_id]["commits"]
862 l2 = files[fname][commit_id]["commits"]
863 assert l1 == l2, (
863 assert l1 == l2, (
864 "The lists of commit_ids for %s@commit_id %s"
864 "The lists of commit_ids for %s@commit_id %s"
865 "from annotation list should match each other, "
865 "from annotation list should match each other, "
866 "got \n%s \nvs \n%s " % (fname, commit_id, l1, l2)
866 "got \n%s \nvs \n%s " % (fname, commit_id, l1, l2)
867 )
867 )
868
868
869 def test_files_state(self):
869 def test_files_state(self):
870 """
870 """
871 Tests state of FileNodes.
871 Tests state of FileNodes.
872 """
872 """
873 node = self.repo.get_commit("e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0").get_node("vcs/utils/diffs.py")
873 node = self.repo.get_commit("e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0").get_node("vcs/utils/diffs.py")
874 assert node.state, NodeState.ADDED
874 assert node.state, NodeState.ADDED
875 assert node.added
875 assert node.added
876 assert not node.changed
876 assert not node.changed
877 assert not node.not_changed
877 assert not node.not_changed
878 assert not node.removed
878 assert not node.removed
879
879
880 node = self.repo.get_commit("33fa3223355104431402a888fa77a4e9956feb3e").get_node(".hgignore")
880 node = self.repo.get_commit("33fa3223355104431402a888fa77a4e9956feb3e").get_node(".hgignore")
881 assert node.state, NodeState.CHANGED
881 assert node.state, NodeState.CHANGED
882 assert not node.added
882 assert not node.added
883 assert node.changed
883 assert node.changed
884 assert not node.not_changed
884 assert not node.not_changed
885 assert not node.removed
885 assert not node.removed
886
886
887 node = self.repo.get_commit("e29b67bd158580fc90fc5e9111240b90e6e86064").get_node("setup.py")
887 node = self.repo.get_commit("e29b67bd158580fc90fc5e9111240b90e6e86064").get_node("setup.py")
888 assert node.state, NodeState.NOT_CHANGED
888 assert node.state, NodeState.NOT_CHANGED
889 assert not node.added
889 assert not node.added
890 assert not node.changed
890 assert not node.changed
891 assert node.not_changed
891 assert node.not_changed
892 assert not node.removed
892 assert not node.removed
893
893
894 # If node has REMOVED state then trying to fetch it would raise
894 # If node has REMOVED state then trying to fetch it would raise
895 # CommitError exception
895 # CommitError exception
896 commit = self.repo.get_commit("fa6600f6848800641328adbf7811fd2372c02ab2")
896 commit = self.repo.get_commit("fa6600f6848800641328adbf7811fd2372c02ab2")
897 path = "vcs/backends/BaseRepository.py"
897 path = "vcs/backends/BaseRepository.py"
898 with pytest.raises(NodeDoesNotExistError):
898 with pytest.raises(NodeDoesNotExistError):
899 commit.get_node(path)
899 commit.get_node(path)
900 # but it would be one of ``removed`` (commit's attribute)
900 # but it would be one of ``removed`` (commit's attribute)
901 assert path in [rf.path for rf in commit.removed]
901 assert path in [rf.path for rf in commit.removed]
902
902
903 commit = self.repo.get_commit("54386793436c938cff89326944d4c2702340037d")
903 commit = self.repo.get_commit("54386793436c938cff89326944d4c2702340037d")
904 changed = ["setup.py", "tests/test_nodes.py", "vcs/backends/hg.py", "vcs/nodes.py"]
904 changed = ["setup.py", "tests/test_nodes.py", "vcs/backends/hg.py", "vcs/nodes.py"]
905 assert set(changed) == set([f.path for f in commit.changed])
905 assert set(changed) == set([f.path for f in commit.changed])
906
906
907 def test_unicode_branch_refs(self):
907 def test_unicode_branch_refs(self):
908 unicode_branches = {
908 unicode_branches = {
909 "refs/heads/unicode": "6c0ce52b229aa978889e91b38777f800e85f330b",
909 "refs/heads/unicode": "6c0ce52b229aa978889e91b38777f800e85f330b",
910 "refs/heads/uniΓ§ΓΆβˆ‚e": "ΓΌrl",
910 "refs/heads/uniΓ§ΓΆβˆ‚e": "ΓΌrl",
911 }
911 }
912 with mock.patch(("rhodecode.lib.vcs.backends.git.repository" ".GitRepository._refs"), unicode_branches):
912 with mock.patch(("rhodecode.lib.vcs.backends.git.repository" ".GitRepository._refs"), unicode_branches):
913 branches = self.repo.branches
913 branches = self.repo.branches
914
914
915 assert "unicode" in branches
915 assert "unicode" in branches
916 assert "uniΓ§ΓΆβˆ‚e" in branches
916 assert "uniΓ§ΓΆβˆ‚e" in branches
917
917
918 def test_unicode_tag_refs(self):
918 def test_unicode_tag_refs(self):
919 unicode_tags = {
919 unicode_tags = {
920 "refs/tags/unicode": "6c0ce52b229aa978889e91b38777f800e85f330b",
920 "refs/tags/unicode": "6c0ce52b229aa978889e91b38777f800e85f330b",
921 "refs/tags/uniΓ§ΓΆβˆ‚e": "6c0ce52b229aa978889e91b38777f800e85f330b",
921 "refs/tags/uniΓ§ΓΆβˆ‚e": "6c0ce52b229aa978889e91b38777f800e85f330b",
922 }
922 }
923 with mock.patch(("rhodecode.lib.vcs.backends.git.repository" ".GitRepository._refs"), unicode_tags):
923 with mock.patch(("rhodecode.lib.vcs.backends.git.repository" ".GitRepository._refs"), unicode_tags):
924 tags = self.repo.tags
924 tags = self.repo.tags
925
925
926 assert "unicode" in tags
926 assert "unicode" in tags
927 assert "uniΓ§ΓΆβˆ‚e" in tags
927 assert "uniΓ§ΓΆβˆ‚e" in tags
928
928
929 def test_commit_message_is_unicode(self):
929 def test_commit_message_is_unicode(self):
930 for commit in self.repo:
930 for commit in self.repo:
931 assert type(commit.message) == str
931 assert type(commit.message) == str
932
932
933 def test_commit_author_is_unicode(self):
933 def test_commit_author_is_unicode(self):
934 for commit in self.repo:
934 for commit in self.repo:
935 assert type(commit.author) == str
935 assert type(commit.author) == str
936
936
937 def test_repo_files_content_types(self):
937 def test_repo_files_content_types(self):
938 commit = self.repo.get_commit()
938 commit = self.repo.get_commit()
939 for node in commit.get_node("/"):
939 for node in commit.get_node("/"):
940 if node.is_file():
940 if node.is_file():
941 assert type(node.content) == bytes
941 assert type(node.content) == bytes
942 assert type(node.str_content) == str
942 assert type(node.str_content) == str
943
943
944 def test_wrong_path(self):
944 def test_wrong_path(self):
945 # There is 'setup.py' in the root dir but not there:
945 # There is 'setup.py' in the root dir but not there:
946 path = "foo/bar/setup.py"
946 path = "foo/bar/setup.py"
947 tip = self.repo.get_commit()
947 tip = self.repo.get_commit()
948 with pytest.raises(VCSError):
948 with pytest.raises(VCSError):
949 tip.get_node(path)
949 tip.get_node(path)
950
950
951 @pytest.mark.parametrize(
951 @pytest.mark.parametrize(
952 "author_email, commit_id",
952 "author_email, commit_id",
953 [
953 [
954 ("marcin@python-blog.com", "c1214f7e79e02fc37156ff215cd71275450cffc3"),
954 ("marcin@python-blog.com", "c1214f7e79e02fc37156ff215cd71275450cffc3"),
955 ("lukasz.balcerzak@python-center.pl", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"),
955 ("lukasz.balcerzak@python-center.pl", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"),
956 ("none@none", "8430a588b43b5d6da365400117c89400326e7992"),
956 ("none@none", "8430a588b43b5d6da365400117c89400326e7992"),
957 ],
957 ],
958 )
958 )
959 def test_author_email(self, author_email, commit_id):
959 def test_author_email(self, author_email, commit_id):
960 commit = self.repo.get_commit(commit_id)
960 commit = self.repo.get_commit(commit_id)
961 assert author_email == commit.author_email
961 assert author_email == commit.author_email
962
962
963 @pytest.mark.parametrize(
963 @pytest.mark.parametrize(
964 "author, commit_id",
964 "author, commit_id",
965 [
965 [
966 ("Marcin Kuzminski", "c1214f7e79e02fc37156ff215cd71275450cffc3"),
966 ("Marcin Kuzminski", "c1214f7e79e02fc37156ff215cd71275450cffc3"),
967 ("Lukasz Balcerzak", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"),
967 ("Lukasz Balcerzak", "ff7ca51e58c505fec0dd2491de52c622bb7a806b"),
968 ("marcink", "8430a588b43b5d6da365400117c89400326e7992"),
968 ("marcink", "8430a588b43b5d6da365400117c89400326e7992"),
969 ],
969 ],
970 )
970 )
971 def test_author_username(self, author, commit_id):
971 def test_author_username(self, author, commit_id):
972 commit = self.repo.get_commit(commit_id)
972 commit = self.repo.get_commit(commit_id)
973 assert author == commit.author_name
973 assert author == commit.author_name
974
974
975
975
976 class TestLargeFileRepo(object):
976 class TestLargeFileRepo(object):
977 def test_large_file(self, backend_git):
977 def test_large_file(self, backend_git):
978 conf = make_db_config()
978 conf = make_db_config()
979 git_largefiles_store = conf.get("vcs_git_lfs", "store_location")
979 git_largefiles_store = conf.get("vcs_git_lfs", "store_location")
980
980
981 repo = backend_git.create_test_repo("largefiles", conf)
981 repo = backend_git.create_test_repo("largefiles", conf)
982
982
983 tip = repo.scm_instance().get_commit()
983 tip = repo.scm_instance().get_commit()
984 node = tip.get_node("1MB.zip")
984 node = tip.get_node("1MB.zip")
985
985
986
986
987 # extract stored LF node into the origin cache
987 # extract stored LF node into the origin cache
988 repo_lfs_store: str = os.path.join(repo.repo_path, repo.repo_name, "lfs_store")
988 repo_lfs_store: str = os.path.join(repo.repo_path, repo.repo_name, "lfs_store")
989
989
990 oid: str = "7b331c02e313c7599d5a90212e17e6d3cb729bd2e1c9b873c302a63c95a2f9bf"
990 oid: str = "7b331c02e313c7599d5a90212e17e6d3cb729bd2e1c9b873c302a63c95a2f9bf"
991 # where the OID actually is INSIDE the repo...
991 # where the OID actually is INSIDE the repo...
992 oid_path = os.path.join(repo_lfs_store, oid)
992 oid_path = os.path.join(repo_lfs_store, oid)
993
993
994 # Note: oid path depends on LFSOidStore.store_suffix. Once it will be changed update below line accordingly
994 # Note: oid path depends on LFSOidStore.store_suffix. Once it will be changed update below line accordingly
995 oid_destination = os.path.join(git_largefiles_store, f"objects/{oid[:2]}/{oid[2:4]}/{oid}")
995 oid_destination = os.path.join(git_largefiles_store, f"objects/{oid[:2]}/{oid[2:4]}/{oid}")
996
996
997 spec_path = os.path.dirname(oid_destination)
998 os.makedirs(spec_path, exist_ok=True)
997 shutil.copy(oid_path, oid_destination)
999 shutil.copy(oid_path, oid_destination)
998
1000
999 lf_node = node.get_largefile_node()
1001 lf_node = node.get_largefile_node()
1000
1002
1001 assert lf_node.is_largefile() is True
1003 assert lf_node.is_largefile() is True
1002 assert lf_node.size == 1024000
1004 assert lf_node.size == 1024000
1003 assert lf_node.name == "1MB.zip"
1005 assert lf_node.name == "1MB.zip"
1004
1006
1005
1007
1006 @pytest.mark.usefixtures("vcs_repository_support")
1008 @pytest.mark.usefixtures("vcs_repository_support")
1007 class TestGitSpecificWithRepo(BackendTestMixin):
1009 class TestGitSpecificWithRepo(BackendTestMixin):
1008 @classmethod
1010 @classmethod
1009 def _get_commits(cls):
1011 def _get_commits(cls):
1010 return [
1012 return [
1011 {
1013 {
1012 "message": "Initial",
1014 "message": "Initial",
1013 "author": "Joe Doe <joe.doe@example.com>",
1015 "author": "Joe Doe <joe.doe@example.com>",
1014 "date": datetime.datetime(2010, 1, 1, 20),
1016 "date": datetime.datetime(2010, 1, 1, 20),
1015 "added": [
1017 "added": [
1016 FileNode(b"foobar/static/js/admin/base.js", content=b"base"),
1018 FileNode(b"foobar/static/js/admin/base.js", content=b"base"),
1017 FileNode(b"foobar/static/admin", content=b"admin", mode=0o120000), # this is a link
1019 FileNode(b"foobar/static/admin", content=b"admin", mode=0o120000), # this is a link
1018 FileNode(b"foo", content=b"foo"),
1020 FileNode(b"foo", content=b"foo"),
1019 ],
1021 ],
1020 },
1022 },
1021 {
1023 {
1022 "message": "Second",
1024 "message": "Second",
1023 "author": "Joe Doe <joe.doe@example.com>",
1025 "author": "Joe Doe <joe.doe@example.com>",
1024 "date": datetime.datetime(2010, 1, 1, 22),
1026 "date": datetime.datetime(2010, 1, 1, 22),
1025 "added": [
1027 "added": [
1026 FileNode(b"foo2", content=b"foo2"),
1028 FileNode(b"foo2", content=b"foo2"),
1027 ],
1029 ],
1028 },
1030 },
1029 ]
1031 ]
1030
1032
1031 def test_paths_slow_traversing(self):
1033 def test_paths_slow_traversing(self):
1032 commit = self.repo.get_commit()
1034 commit = self.repo.get_commit()
1033 assert (
1035 assert (
1034 commit.get_node("foobar").get_node("static").get_node("js").get_node("admin").get_node("base.js").content
1036 commit.get_node("foobar").get_node("static").get_node("js").get_node("admin").get_node("base.js").content
1035 == b"base"
1037 == b"base"
1036 )
1038 )
1037
1039
1038 def test_paths_fast_traversing(self):
1040 def test_paths_fast_traversing(self):
1039 commit = self.repo.get_commit()
1041 commit = self.repo.get_commit()
1040 assert commit.get_node("foobar/static/js/admin/base.js").content == b"base"
1042 assert commit.get_node("foobar/static/js/admin/base.js").content == b"base"
1041
1043
1042 def test_get_diff_runs_git_command_with_hashes(self):
1044 def test_get_diff_runs_git_command_with_hashes(self):
1043 comm1 = self.repo[0]
1045 comm1 = self.repo[0]
1044 comm2 = self.repo[1]
1046 comm2 = self.repo[1]
1045
1047
1046 with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
1048 with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
1047 remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
1049 remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
1048 self.repo.get_diff(comm1, comm2)
1050 self.repo.get_diff(comm1, comm2)
1049
1051
1050 remote_mock.diff.assert_called_once_with(
1052 remote_mock.diff.assert_called_once_with(
1051 comm1.raw_id, comm2.raw_id, file_filter=None, opt_ignorews=False, context=3
1053 comm1.raw_id, comm2.raw_id, file_filter=None, opt_ignorews=False, context=3
1052 )
1054 )
1053
1055
1054 def test_get_diff_runs_git_command_with_str_hashes(self):
1056 def test_get_diff_runs_git_command_with_str_hashes(self):
1055 comm2 = self.repo[1]
1057 comm2 = self.repo[1]
1056
1058
1057 with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
1059 with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
1058 remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
1060 remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
1059 self.repo.get_diff(self.repo.EMPTY_COMMIT, comm2)
1061 self.repo.get_diff(self.repo.EMPTY_COMMIT, comm2)
1060
1062
1061 remote_mock.diff.assert_called_once_with(
1063 remote_mock.diff.assert_called_once_with(
1062 self.repo.EMPTY_COMMIT.raw_id, comm2.raw_id, file_filter=None, opt_ignorews=False, context=3
1064 self.repo.EMPTY_COMMIT.raw_id, comm2.raw_id, file_filter=None, opt_ignorews=False, context=3
1063 )
1065 )
1064
1066
1065 def test_get_diff_runs_git_command_with_path_if_its_given(self):
1067 def test_get_diff_runs_git_command_with_path_if_its_given(self):
1066 comm1 = self.repo[0]
1068 comm1 = self.repo[0]
1067 comm2 = self.repo[1]
1069 comm2 = self.repo[1]
1068
1070
1069 with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
1071 with mock.patch.object(self.repo, "_remote", return_value=mock.Mock()) as remote_mock:
1070 remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
1072 remote_mock.diff = mock.MagicMock(side_effect=callable_get_diff)
1071 self.repo.get_diff(comm1, comm2, "foo")
1073 self.repo.get_diff(comm1, comm2, "foo")
1072
1074
1073 remote_mock.diff.assert_called_once_with(
1075 remote_mock.diff.assert_called_once_with(
1074 self.repo._lookup_commit(0), comm2.raw_id, file_filter="foo", opt_ignorews=False, context=3
1076 self.repo._lookup_commit(0), comm2.raw_id, file_filter="foo", opt_ignorews=False, context=3
1075 )
1077 )
1076
1078
1077
1079
1078 @pytest.mark.usefixtures("vcs_repository_support")
1080 @pytest.mark.usefixtures("vcs_repository_support")
1079 class TestGitRegression(BackendTestMixin):
1081 class TestGitRegression(BackendTestMixin):
1080 @classmethod
1082 @classmethod
1081 def _get_commits(cls):
1083 def _get_commits(cls):
1082 return [
1084 return [
1083 {
1085 {
1084 "message": "Initial",
1086 "message": "Initial",
1085 "author": "Joe Doe <joe.doe@example.com>",
1087 "author": "Joe Doe <joe.doe@example.com>",
1086 "date": datetime.datetime(2010, 1, 1, 20),
1088 "date": datetime.datetime(2010, 1, 1, 20),
1087 "added": [
1089 "added": [
1088 FileNode(b"bot/__init__.py", content=b"base"),
1090 FileNode(b"bot/__init__.py", content=b"base"),
1089 FileNode(b"bot/templates/404.html", content=b"base"),
1091 FileNode(b"bot/templates/404.html", content=b"base"),
1090 FileNode(b"bot/templates/500.html", content=b"base"),
1092 FileNode(b"bot/templates/500.html", content=b"base"),
1091 ],
1093 ],
1092 },
1094 },
1093 {
1095 {
1094 "message": "Second",
1096 "message": "Second",
1095 "author": "Joe Doe <joe.doe@example.com>",
1097 "author": "Joe Doe <joe.doe@example.com>",
1096 "date": datetime.datetime(2010, 1, 1, 22),
1098 "date": datetime.datetime(2010, 1, 1, 22),
1097 "added": [
1099 "added": [
1098 FileNode(b"bot/build/migrations/1.py", content=b"foo2"),
1100 FileNode(b"bot/build/migrations/1.py", content=b"foo2"),
1099 FileNode(b"bot/build/migrations/2.py", content=b"foo2"),
1101 FileNode(b"bot/build/migrations/2.py", content=b"foo2"),
1100 FileNode(b"bot/build/static/templates/f.html", content=b"foo2"),
1102 FileNode(b"bot/build/static/templates/f.html", content=b"foo2"),
1101 FileNode(b"bot/build/static/templates/f1.html", content=b"foo2"),
1103 FileNode(b"bot/build/static/templates/f1.html", content=b"foo2"),
1102 FileNode(b"bot/build/templates/err.html", content=b"foo2"),
1104 FileNode(b"bot/build/templates/err.html", content=b"foo2"),
1103 FileNode(b"bot/build/templates/err2.html", content=b"foo2"),
1105 FileNode(b"bot/build/templates/err2.html", content=b"foo2"),
1104 ],
1106 ],
1105 },
1107 },
1106 ]
1108 ]
1107
1109
1108 @pytest.mark.parametrize(
1110 @pytest.mark.parametrize(
1109 "path, expected_paths",
1111 "path, expected_paths",
1110 [
1112 [
1111 ("bot", ["bot/build", "bot/templates", "bot/__init__.py"]),
1113 ("bot", ["bot/build", "bot/templates", "bot/__init__.py"]),
1112 ("bot/build", ["bot/build/migrations", "bot/build/static", "bot/build/templates"]),
1114 ("bot/build", ["bot/build/migrations", "bot/build/static", "bot/build/templates"]),
1113 ("bot/build/static", ["bot/build/static/templates"]),
1115 ("bot/build/static", ["bot/build/static/templates"]),
1114 ("bot/build/static/templates", ["bot/build/static/templates/f.html", "bot/build/static/templates/f1.html"]),
1116 ("bot/build/static/templates", ["bot/build/static/templates/f.html", "bot/build/static/templates/f1.html"]),
1115 ("bot/build/templates", ["bot/build/templates/err.html", "bot/build/templates/err2.html"]),
1117 ("bot/build/templates", ["bot/build/templates/err.html", "bot/build/templates/err2.html"]),
1116 ("bot/templates/", ["bot/templates/404.html", "bot/templates/500.html"]),
1118 ("bot/templates/", ["bot/templates/404.html", "bot/templates/500.html"]),
1117 ],
1119 ],
1118 )
1120 )
1119 def test_similar_paths(self, path, expected_paths):
1121 def test_similar_paths(self, path, expected_paths):
1120 commit = self.repo.get_commit()
1122 commit = self.repo.get_commit()
1121 paths = [n.path for n in commit.get_nodes(path)]
1123 paths = [n.path for n in commit.get_nodes(path)]
1122 assert paths == expected_paths
1124 assert paths == expected_paths
1123
1125
1124
1126
1125 class TestDiscoverGitVersion(object):
1127 class TestDiscoverGitVersion(object):
1126 def test_returns_git_version(self, baseapp):
1128 def test_returns_git_version(self, baseapp):
1127 version = discover_git_version()
1129 version = discover_git_version()
1128 assert version
1130 assert version
1129
1131
1130 def test_returns_empty_string_without_vcsserver(self):
1132 def test_returns_empty_string_without_vcsserver(self):
1131 mock_connection = mock.Mock()
1133 mock_connection = mock.Mock()
1132 mock_connection.discover_git_version = mock.Mock(side_effect=Exception)
1134 mock_connection.discover_git_version = mock.Mock(side_effect=Exception)
1133 with mock.patch("rhodecode.lib.vcs.connection.Git", mock_connection):
1135 with mock.patch("rhodecode.lib.vcs.connection.Git", mock_connection):
1134 version = discover_git_version()
1136 version = discover_git_version()
1135 assert version == ""
1137 assert version == ""
1136
1138
1137
1139
1138 class TestGetSubmoduleUrl(object):
1140 class TestGetSubmoduleUrl(object):
1139 def test_submodules_file_found(self):
1141 def test_submodules_file_found(self):
1140 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1142 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1141 node = mock.Mock()
1143 node = mock.Mock()
1142
1144
1143 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1145 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1144 node.str_content = (
1146 node.str_content = (
1145 '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
1147 '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
1146 )
1148 )
1147 result = commit._get_submodule_url("subrepo1")
1149 result = commit._get_submodule_url("subrepo1")
1148 get_node_mock.assert_called_once_with(".gitmodules")
1150 get_node_mock.assert_called_once_with(".gitmodules")
1149 assert result == "https://code.rhodecode.com/dulwich"
1151 assert result == "https://code.rhodecode.com/dulwich"
1150
1152
1151 def test_complex_submodule_path(self):
1153 def test_complex_submodule_path(self):
1152 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1154 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1153 node = mock.Mock()
1155 node = mock.Mock()
1154
1156
1155 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1157 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1156 node.str_content = (
1158 node.str_content = (
1157 '[submodule "complex/subrepo/path"]\n'
1159 '[submodule "complex/subrepo/path"]\n'
1158 "\tpath = complex/subrepo/path\n"
1160 "\tpath = complex/subrepo/path\n"
1159 "\turl = https://code.rhodecode.com/dulwich\n"
1161 "\turl = https://code.rhodecode.com/dulwich\n"
1160 )
1162 )
1161 result = commit._get_submodule_url("complex/subrepo/path")
1163 result = commit._get_submodule_url("complex/subrepo/path")
1162 get_node_mock.assert_called_once_with(".gitmodules")
1164 get_node_mock.assert_called_once_with(".gitmodules")
1163 assert result == "https://code.rhodecode.com/dulwich"
1165 assert result == "https://code.rhodecode.com/dulwich"
1164
1166
1165 def test_submodules_file_not_found(self):
1167 def test_submodules_file_not_found(self):
1166 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1168 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1167 with mock.patch.object(commit, "get_node", side_effect=NodeDoesNotExistError):
1169 with mock.patch.object(commit, "get_node", side_effect=NodeDoesNotExistError):
1168 result = commit._get_submodule_url("complex/subrepo/path")
1170 result = commit._get_submodule_url("complex/subrepo/path")
1169 assert result is None
1171 assert result is None
1170
1172
1171 def test_path_not_found(self):
1173 def test_path_not_found(self):
1172 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1174 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1173 node = mock.Mock()
1175 node = mock.Mock()
1174
1176
1175 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1177 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1176 node.str_content = (
1178 node.str_content = (
1177 '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
1179 '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
1178 )
1180 )
1179 result = commit._get_submodule_url("subrepo2")
1181 result = commit._get_submodule_url("subrepo2")
1180 get_node_mock.assert_called_once_with(".gitmodules")
1182 get_node_mock.assert_called_once_with(".gitmodules")
1181 assert result is None
1183 assert result is None
1182
1184
1183 def test_returns_cached_values(self):
1185 def test_returns_cached_values(self):
1184 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1186 commit = GitCommit(repository=mock.Mock(), raw_id="abcdef12", idx=1)
1185 node = mock.Mock()
1187 node = mock.Mock()
1186
1188
1187 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1189 with mock.patch.object(commit, "get_node", return_value=node) as get_node_mock:
1188 node.str_content = (
1190 node.str_content = (
1189 '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
1191 '[submodule "subrepo1"]\n' "\tpath = subrepo1\n" "\turl = https://code.rhodecode.com/dulwich\n"
1190 )
1192 )
1191 for _ in range(3):
1193 for _ in range(3):
1192 commit._get_submodule_url("subrepo1")
1194 commit._get_submodule_url("subrepo1")
1193 get_node_mock.assert_called_once_with(".gitmodules")
1195 get_node_mock.assert_called_once_with(".gitmodules")
1194
1196
1195 def test_get_node_returns_a_link(self):
1197 def test_get_node_returns_a_link(self):
1196 repository = mock.Mock()
1198 repository = mock.Mock()
1197 repository.alias = "git"
1199 repository.alias = "git"
1198 commit = GitCommit(repository=repository, raw_id="abcdef12", idx=1)
1200 commit = GitCommit(repository=repository, raw_id="abcdef12", idx=1)
1199 submodule_url = "https://code.rhodecode.com/dulwich"
1201 submodule_url = "https://code.rhodecode.com/dulwich"
1200 get_id_patch = mock.patch.object(commit, "_get_tree_id_for_path", return_value=(1, "link"))
1202 get_id_patch = mock.patch.object(commit, "_get_tree_id_for_path", return_value=(1, "link"))
1201 get_submodule_patch = mock.patch.object(commit, "_get_submodule_url", return_value=submodule_url)
1203 get_submodule_patch = mock.patch.object(commit, "_get_submodule_url", return_value=submodule_url)
1202
1204
1203 with get_id_patch, get_submodule_patch as submodule_mock:
1205 with get_id_patch, get_submodule_patch as submodule_mock:
1204 node = commit.get_node("/abcde")
1206 node = commit.get_node("/abcde")
1205
1207
1206 submodule_mock.assert_called_once_with("/abcde")
1208 submodule_mock.assert_called_once_with("/abcde")
1207 assert type(node) == SubModuleNode
1209 assert type(node) == SubModuleNode
1208 assert node.url == submodule_url
1210 assert node.url == submodule_url
1209
1211
1210 def test_get_nodes_returns_links(self):
1212 def test_get_nodes_returns_links(self):
1211 repository = mock.MagicMock()
1213 repository = mock.MagicMock()
1212 repository.alias = "git"
1214 repository.alias = "git"
1213 repository._remote.tree_items.return_value = [("subrepo", "stat", 1, "link")]
1215 repository._remote.tree_items.return_value = [("subrepo", "stat", 1, "link")]
1214 commit = GitCommit(repository=repository, raw_id="abcdef12", idx=1)
1216 commit = GitCommit(repository=repository, raw_id="abcdef12", idx=1)
1215 submodule_url = "https://code.rhodecode.com/dulwich"
1217 submodule_url = "https://code.rhodecode.com/dulwich"
1216 get_id_patch = mock.patch.object(commit, "_get_tree_id_for_path", return_value=(1, "tree"))
1218 get_id_patch = mock.patch.object(commit, "_get_tree_id_for_path", return_value=(1, "tree"))
1217 get_submodule_patch = mock.patch.object(commit, "_get_submodule_url", return_value=submodule_url)
1219 get_submodule_patch = mock.patch.object(commit, "_get_submodule_url", return_value=submodule_url)
1218
1220
1219 with get_id_patch, get_submodule_patch as submodule_mock:
1221 with get_id_patch, get_submodule_patch as submodule_mock:
1220 nodes = commit.get_nodes("/abcde")
1222 nodes = commit.get_nodes("/abcde")
1221
1223
1222 submodule_mock.assert_called_once_with("/abcde/subrepo")
1224 submodule_mock.assert_called_once_with("/abcde/subrepo")
1223 assert len(nodes) == 1
1225 assert len(nodes) == 1
1224 assert type(nodes[0]) == SubModuleNode
1226 assert type(nodes[0]) == SubModuleNode
1225 assert nodes[0].url == submodule_url
1227 assert nodes[0].url == submodule_url
1226
1228
1227
1229
1228 class TestGetShadowInstance(object):
1230 class TestGetShadowInstance(object):
1229
1231
1230 @pytest.fixture()
1232 @pytest.fixture()
1231 def repo(self, vcsbackend_git):
1233 def repo(self, vcsbackend_git):
1232 _git_repo = vcsbackend_git.repo
1234 _git_repo = vcsbackend_git.repo
1233
1235
1234 mock.patch.object(_git_repo, "config", mock.Mock())
1236 mock.patch.object(_git_repo, "config", mock.Mock())
1235 connection_mock = mock.Mock(unsafe=True, name="connection.Hg")
1237 connection_mock = mock.Mock(unsafe=True, name="connection.Hg")
1236
1238
1237 mock.patch("rhodecode.lib.vcs.connection.Git", connection_mock)
1239 mock.patch("rhodecode.lib.vcs.connection.Git", connection_mock)
1238 return _git_repo
1240 return _git_repo
1239
1241
1240 def test_getting_shadow_instance_copies_config(self, repo):
1242 def test_getting_shadow_instance_copies_config(self, repo):
1241 shadow = repo.get_shadow_instance(repo.path)
1243 shadow = repo.get_shadow_instance(repo.path)
1242 assert shadow.config.serialize() == repo.config.serialize()
1244 assert shadow.config.serialize() == repo.config.serialize()
General Comments 0
You need to be logged in to leave comments. Login now