Skip to content

Commit ee834e2

Browse files
committed
Fix+test checkout of fetched updates
1 parent d7656e0 commit ee834e2

File tree

3 files changed

+59
-13
lines changed

3 files changed

+59
-13
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ The local copies should not be modified by users.
6060
## To do
6161
* flesh out integration tests
6262
* cater for new repositories being made locally and pushed remotely
63+
* compare (toasted-)marshmallow as a replacement for attr+voluptious - marshmallow uses attr

gitlab_sync/operations.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ def update_local(local):
2828
"""Update master from the remote."""
2929
local.git("fetch")
3030
# get refs/remotes/origin/HEAD
31-
issue = local.git(
31+
result = local.git(
3232
"remote",
3333
"set-head",
3434
"origin",
3535
"--auto",
3636
check=False,
3737
stderr=subprocess.PIPE,
3838
universal_newlines=True,
39-
).stderr.rstrip()
40-
if not issue:
39+
)
40+
issue = result.stderr.rstrip()
41+
if not result.returncode:
4142
# read which branch the remote HEAD points to
4243
remote_head = local.git(
4344
"symbolic-ref",
@@ -46,24 +47,30 @@ def update_local(local):
4647
universal_newlines=True,
4748
).stdout.rstrip()
4849
# checkout and track the branch that the remote HEAD points to
49-
issue = local.git(
50+
result = local.git(
5051
"checkout",
5152
"--track",
5253
remote_head,
5354
check=False,
5455
stderr=subprocess.PIPE,
5556
universal_newlines=True,
56-
).stdout
57-
if issue:
57+
)
58+
if result.returncode:
59+
issue = result.stderr
5860
# if the branch is already tracked, then just check out the tip of it
59-
if issue.startswith("fatal: a branch"):
60-
local.git("checkout", remote_head.rpartition("/")[2])
61+
name = remote_head.rpartition("/")[2]
62+
if issue.startswith(r"fatal: A branch named '%s' already exists." % name):
63+
local.git("reset", "--hard", remote_head)
6164
else:
6265
raise Exception(issue.rstrip())
66+
else:
67+
logger.debug("`git checkout --track %s` worked", remote_head)
6368
elif issue.endswith("error: Cannot determine remote HEAD"):
6469
logger.debug("%s is an empty project", local)
6570
else:
6671
raise Exception(issue)
72+
# mirror only logic
73+
local.git("clean", "-d", "--force")
6774

6875

6976
def delete_local(repo):

tests/test_integration.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ def docker_compose_file(pytestconfig):
2424
return os.path.join(str(pytestconfig.rootdir), "tests", "docker-compose.yml")
2525

2626

27-
@pytest.fixture(scope="session")
28-
def gitlab(docker_ip, docker_services, tmp_path_factory, pytestconfig):
27+
@pytest.fixture(scope="function")
28+
def gitlab(docker_ip, docker_services, tmp_path_factory, pytestconfig, tmpdir):
2929
"""Manage a GitLab instance and return an object which can interact with it."""
3030
http_url = "http://%s:%s/" % (docker_ip, docker_services.port_for("gitlab", 80))
3131
git_url = "git+ssh://git@%s:%s/" % (docker_ip, docker_services.port_for("gitlab", 22))
@@ -154,7 +154,28 @@ def make_project(self, **kwargs):
154154
)
155155
response.raise_for_status()
156156
data = response.json()
157-
return data["id"], self.git_url + data["path_with_namespace"] + ".git"
157+
158+
path = data["path_with_namespace"]
159+
testing_project_path = tmpdir / path
160+
testing_project_path.ensure(dir=True)
161+
162+
class TestRepo:
163+
def __init__(self, path, remote):
164+
self.path = path
165+
self.remote = remote
166+
self.git("init", ".")
167+
self.git("remote", "add", "origin", remote)
168+
self.git("config", "--local", "user.email", "[email protected]")
169+
self.git("config", "--local", "user.name", "Tester")
170+
171+
def git(self, *args, **kwargs):
172+
kwargs.setdefault("check", True)
173+
kwargs.setdefault("universal_newlines", True)
174+
return subprocess.run(["git", "-C", str(self.path), *args], **kwargs)
175+
176+
repo = TestRepo(testing_project_path, self.git_url + data["path_with_namespace"] + ".git")
177+
178+
return data["id"], repo
158179

159180
def delete_project(self, project_id):
160181
"""Make a project and return (id, ssh url)."""
@@ -172,17 +193,34 @@ def delete_project(self, project_id):
172193
yield Info()
173194

174195

175-
def test_mirror(gitlab):
196+
def test_mirror(gitlab, tmp_path_factory):
176197
"""Check that a sync runs first time."""
177198
gitlab_sync = gitlab.make_runner()
178-
project_id, _ = gitlab.make_project(name="lulz")
199+
project_id, repo = gitlab.make_project(name="lulz")
200+
201+
# make sure empty repositories work
179202
gitlab_sync("local-update", check=True)
180203
project_absolute_path = gitlab.sync_root / gitlab.username / "lulz"
181204
assert project_absolute_path.is_dir()
182205

206+
# one file
207+
repo.git("init", ".")
208+
(repo.path / "README.md").write_text("Hello", "UTF8")
209+
repo.git("add", "README.md")
210+
repo.git("commit", "--message=Initial commit")
211+
repo.git("push", "--set-upstream", "origin", "master")
212+
gitlab_sync("local-update", check=True)
213+
assert (project_absolute_path / "README.md").is_file()
214+
215+
# remote the file
216+
repo.git("rm", "README.md")
217+
repo.git("commit", "--message=Remote README.md")
218+
repo.git("push")
183219
gitlab_sync("local-update", check=True)
184220
assert project_absolute_path.is_dir()
221+
assert not (project_absolute_path / "README.md").is_file()
185222

223+
# remote the project
186224
gitlab.delete_project(project_id)
187225
gitlab_sync("local-update", check=True)
188226
assert not project_absolute_path.is_dir()

0 commit comments

Comments
 (0)