e2e: Update test for worktree adding
This commit is contained in:
@@ -4,92 +4,487 @@ from helpers import *
|
||||
|
||||
import git
|
||||
import pytest
|
||||
import datetime
|
||||
|
||||
import os.path
|
||||
|
||||
|
||||
@pytest.mark.parametrize("config_enabled", [True, False])
|
||||
@pytest.mark.parametrize("config_has_default_remote_prefix", [True, False])
|
||||
@pytest.mark.parametrize("config_has_default_track_enabled", [True, False])
|
||||
@pytest.mark.parametrize("explicit_notrack", [True, False])
|
||||
@pytest.mark.parametrize("explicit_track", [True, False])
|
||||
@pytest.mark.parametrize("local_branch_exists", [True, False])
|
||||
@pytest.mark.parametrize("local_branch_has_tracking_branch", [True, False])
|
||||
@pytest.mark.parametrize("remote_branch_already_exists", [True, False])
|
||||
@pytest.mark.parametrize("has_config", [True, False])
|
||||
@pytest.mark.parametrize("has_default", [True, False])
|
||||
@pytest.mark.parametrize("has_prefix", [True, False])
|
||||
@pytest.mark.parametrize("remote_branch_with_prefix_already_exists", [True, False])
|
||||
@pytest.mark.parametrize(
|
||||
"remote_setup",
|
||||
(
|
||||
(0, "origin", False),
|
||||
(1, "origin", False),
|
||||
(2, "origin", False),
|
||||
(2, "otherremote", False),
|
||||
(2, "origin", True),
|
||||
(2, "otherremote", True),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("track_differs_from_existing_branch_upstream", [True, False])
|
||||
@pytest.mark.parametrize("worktree_with_slash", [True, False])
|
||||
def test_worktree_add(
|
||||
config_enabled,
|
||||
config_has_default_remote_prefix,
|
||||
config_has_default_track_enabled,
|
||||
explicit_notrack,
|
||||
explicit_track,
|
||||
local_branch_exists,
|
||||
local_branch_has_tracking_branch,
|
||||
remote_branch_already_exists,
|
||||
has_config,
|
||||
has_default,
|
||||
has_prefix,
|
||||
remote_branch_with_prefix_already_exists,
|
||||
remote_setup,
|
||||
track_differs_from_existing_branch_upstream,
|
||||
worktree_with_slash,
|
||||
):
|
||||
(remote_count, default_remote, remotes_differ) = remote_setup
|
||||
has_remotes = True if remote_count > 0 else False
|
||||
|
||||
if worktree_with_slash:
|
||||
worktree_name = "dir/test"
|
||||
worktree_name = "dir/nested/test"
|
||||
else:
|
||||
worktree_name = "test"
|
||||
with TempGitRepositoryWorktree() as (base_dir, _commit):
|
||||
if has_config:
|
||||
|
||||
if track_differs_from_existing_branch_upstream:
|
||||
explicit_track_branch_name = f"{default_remote}/somethingelse"
|
||||
else:
|
||||
explicit_track_branch_name = f"{default_remote}/{worktree_name}"
|
||||
|
||||
timestamp = datetime.datetime.now().replace(microsecond=0).isoformat()
|
||||
# GitPython has some weird behaviour here. It is not possible to use kwargs
|
||||
# to set the commit and author date.
|
||||
#
|
||||
# `committer_date=x` (which is documented) does not work, as `git commit`
|
||||
# does not accept --committer-date
|
||||
#
|
||||
# `author_date=x` does not work, as it's now called --date in `git commit`
|
||||
#
|
||||
# `date=x` should work, but is refused by GitPython, as it does not know
|
||||
# about the new behaviour in `git commit`
|
||||
#
|
||||
# Fortunately, there are env variables that control those timestamps.
|
||||
os.environ["GIT_COMMITTER_DATE"] = str(timestamp)
|
||||
os.environ["GIT_AUTHOR_DATE"] = str(timestamp)
|
||||
|
||||
def setup_remote1(directory):
|
||||
if remote_branch_already_exists:
|
||||
with tempfile.TemporaryDirectory() as cloned:
|
||||
repo = git.Repo.clone_from(directory, cloned)
|
||||
newfile = os.path.join(cloned, "change")
|
||||
open(newfile, "w").close()
|
||||
repo.index.add([newfile])
|
||||
repo.index.commit("commit")
|
||||
repo.remotes.origin.push(f"HEAD:{worktree_name}", force=True)
|
||||
|
||||
if remote_branch_with_prefix_already_exists:
|
||||
with tempfile.TemporaryDirectory() as cloned:
|
||||
repo = git.Repo.clone_from(directory, cloned)
|
||||
newfile = os.path.join(cloned, "change2")
|
||||
open(newfile, "w").close()
|
||||
repo.index.add([newfile])
|
||||
repo.index.commit("commit")
|
||||
repo.remotes.origin.push(f"HEAD:myprefix/{worktree_name}", force=True)
|
||||
|
||||
return "_".join(
|
||||
[
|
||||
str(worktree_with_slash),
|
||||
str(remote_branch_already_exists),
|
||||
str(remote_branch_with_prefix_already_exists),
|
||||
str(remotes_differ),
|
||||
]
|
||||
)
|
||||
|
||||
def setup_remote2(directory):
|
||||
if remote_branch_already_exists:
|
||||
with tempfile.TemporaryDirectory() as cloned:
|
||||
repo = git.Repo.clone_from(directory, cloned)
|
||||
newfile = os.path.join(cloned, "change")
|
||||
open(newfile, "w").close()
|
||||
repo.index.add([newfile])
|
||||
repo.index.commit("commit")
|
||||
if remotes_differ:
|
||||
newfile = os.path.join(cloned, "change_on_second_remote")
|
||||
open(newfile, "w").close()
|
||||
repo.index.add([newfile])
|
||||
repo.index.commit("commit_on_second_remote")
|
||||
repo.remotes.origin.push(f"HEAD:{worktree_name}", force=True)
|
||||
|
||||
if remote_branch_with_prefix_already_exists:
|
||||
with tempfile.TemporaryDirectory() as cloned:
|
||||
repo = git.Repo.clone_from(directory, cloned)
|
||||
newfile = os.path.join(cloned, "change2")
|
||||
open(newfile, "w").close()
|
||||
repo.index.add([newfile])
|
||||
repo.index.commit("commit")
|
||||
if remotes_differ:
|
||||
newfile = os.path.join(cloned, "change_on_second_remote2")
|
||||
open(newfile, "w").close()
|
||||
repo.index.add([newfile])
|
||||
repo.index.commit("commit_on_second_remote2")
|
||||
repo.remotes.origin.push(f"HEAD:myprefix/{worktree_name}", force=True)
|
||||
|
||||
return "_".join(
|
||||
[
|
||||
str(worktree_with_slash),
|
||||
str(remote_branch_already_exists),
|
||||
str(remote_branch_with_prefix_already_exists),
|
||||
str(remotes_differ),
|
||||
]
|
||||
)
|
||||
|
||||
cachefn = lambda nr: "_".join(
|
||||
[
|
||||
str(nr),
|
||||
str(default_remote),
|
||||
str(local_branch_exists),
|
||||
str(remote_branch_already_exists),
|
||||
str(remote_branch_with_prefix_already_exists),
|
||||
str(remote_count),
|
||||
str(remotes_differ),
|
||||
str(worktree_name),
|
||||
]
|
||||
)
|
||||
remote1_cache_key = cachefn(1)
|
||||
remote2_cache_key = cachefn(2)
|
||||
|
||||
cachekey = "_".join(
|
||||
[
|
||||
str(local_branch_exists),
|
||||
str(local_branch_has_tracking_branch),
|
||||
str(remote_branch_already_exists),
|
||||
str(remote_branch_with_prefix_already_exists),
|
||||
str(remote_count),
|
||||
str(remotes_differ),
|
||||
str(worktree_name),
|
||||
]
|
||||
)
|
||||
|
||||
with TempGitRepositoryWorktree.get(
|
||||
cachekey=cachekey,
|
||||
branch=worktree_name if local_branch_exists else None,
|
||||
remotes=remote_count,
|
||||
remote_setup=[
|
||||
[remote1_cache_key, setup_remote1],
|
||||
[remote2_cache_key, setup_remote2],
|
||||
],
|
||||
) as (base_dir, initial_commit):
|
||||
repo = git.Repo(os.path.join(base_dir, ".git-main-working-tree"))
|
||||
|
||||
if config_enabled:
|
||||
with open(os.path.join(base_dir, "grm.toml"), "w") as f:
|
||||
f.write(
|
||||
f"""
|
||||
[track]
|
||||
default = {str(has_default).lower()}
|
||||
default_remote = "origin"
|
||||
"""
|
||||
[track]
|
||||
default = {str(config_has_default_track_enabled).lower()}
|
||||
default_remote = "{default_remote}"
|
||||
"""
|
||||
)
|
||||
if has_prefix:
|
||||
|
||||
if config_has_default_remote_prefix:
|
||||
f.write(
|
||||
"""
|
||||
default_remote_prefix = "myprefix"
|
||||
"""
|
||||
)
|
||||
|
||||
if remote_branch_already_exists:
|
||||
shell(
|
||||
f"""
|
||||
cd {base_dir}
|
||||
git --git-dir ./.git-main-working-tree worktree add tmp
|
||||
(
|
||||
cd tmp
|
||||
touch change
|
||||
git add change
|
||||
git commit -m commit
|
||||
git push origin HEAD:{worktree_name}
|
||||
#git reset --hard 'HEAD@{1}'
|
||||
git branch -va
|
||||
)
|
||||
git --git-dir ./.git-main-working-tree worktree remove tmp
|
||||
"""
|
||||
)
|
||||
cmd = grm(["wt", "add", worktree_name], cwd=base_dir)
|
||||
if local_branch_exists:
|
||||
if has_remotes and local_branch_has_tracking_branch:
|
||||
origin = repo.remote(default_remote)
|
||||
if remote_count >= 2:
|
||||
otherremote = repo.remote("otherremote")
|
||||
br = list(filter(lambda x: x.name == worktree_name, repo.branches))[0]
|
||||
assert os.path.exists(base_dir)
|
||||
if track_differs_from_existing_branch_upstream:
|
||||
origin.push(
|
||||
f"{worktree_name}:someothername", force=True, set_upstream=True
|
||||
)
|
||||
if remote_count >= 2:
|
||||
otherremote.push(
|
||||
f"{worktree_name}:someothername",
|
||||
force=True,
|
||||
set_upstream=True,
|
||||
)
|
||||
br.set_tracking_branch(
|
||||
list(
|
||||
filter(
|
||||
lambda x: x.remote_head == "someothername", origin.refs
|
||||
)
|
||||
)[0]
|
||||
)
|
||||
else:
|
||||
origin.push(
|
||||
f"{worktree_name}:{worktree_name}",
|
||||
force=True,
|
||||
set_upstream=True,
|
||||
)
|
||||
if remote_count >= 2:
|
||||
otherremote.push(
|
||||
f"{worktree_name}:{worktree_name}",
|
||||
force=True,
|
||||
set_upstream=True,
|
||||
)
|
||||
br.set_tracking_branch(
|
||||
list(
|
||||
filter(
|
||||
lambda x: x.remote_head == worktree_name, origin.refs
|
||||
)
|
||||
)[0]
|
||||
)
|
||||
|
||||
args = ["wt", "add", worktree_name]
|
||||
if explicit_track:
|
||||
args.extend(["--track", explicit_track_branch_name])
|
||||
if explicit_notrack:
|
||||
args.extend(["--no-track"])
|
||||
cmd = grm(args, cwd=base_dir)
|
||||
if explicit_track and not explicit_notrack and not has_remotes:
|
||||
assert cmd.returncode != 0
|
||||
assert f'remote "{default_remote}" not found' in cmd.stderr.lower()
|
||||
return
|
||||
assert cmd.returncode == 0
|
||||
|
||||
assert len(cmd.stdout.strip().split("\n")) == 1
|
||||
assert f"worktree {worktree_name} created" in cmd.stdout.lower()
|
||||
|
||||
def check_deviation_error(base):
|
||||
if (
|
||||
not local_branch_exists
|
||||
and (explicit_notrack or (not explicit_notrack and not explicit_track))
|
||||
and (
|
||||
remote_branch_already_exists
|
||||
or (
|
||||
config_enabled
|
||||
and config_has_default_remote_prefix
|
||||
and remote_branch_with_prefix_already_exists
|
||||
)
|
||||
)
|
||||
and remote_count >= 2
|
||||
and remotes_differ
|
||||
):
|
||||
assert (
|
||||
f"branch exists on multiple remotes, but they deviate"
|
||||
in cmd.stderr.lower()
|
||||
)
|
||||
assert len(cmd.stderr.strip().split("\n")) == base + 1
|
||||
else:
|
||||
if base == 0:
|
||||
assert len(cmd.stderr) == base
|
||||
else:
|
||||
assert len(cmd.stderr.strip().split("\n")) == base
|
||||
|
||||
if explicit_track and explicit_notrack:
|
||||
assert "--track will be ignored" in cmd.stderr.lower()
|
||||
check_deviation_error(1)
|
||||
else:
|
||||
check_deviation_error(0)
|
||||
|
||||
files = os.listdir(base_dir)
|
||||
if has_config is True:
|
||||
if config_enabled is True:
|
||||
if worktree_with_slash:
|
||||
assert set(files) == {".git-main-working-tree", "grm.toml", "dir"}
|
||||
else:
|
||||
assert set(files) == {".git-main-working-tree", "grm.toml", "test"}
|
||||
assert len(files) == 3
|
||||
if worktree_with_slash:
|
||||
assert set(files) == {".git-main-working-tree", "grm.toml", "dir"}
|
||||
assert set(os.listdir(os.path.join(base_dir, "dir"))) == {"test"}
|
||||
assert set(os.listdir(os.path.join(base_dir, "dir"))) == {"nested"}
|
||||
assert set(os.listdir(os.path.join(base_dir, "dir/nested"))) == {"test"}
|
||||
else:
|
||||
assert set(files) == {".git-main-working-tree", "grm.toml", "test"}
|
||||
else:
|
||||
assert len(files) == 2
|
||||
if worktree_with_slash:
|
||||
assert set(files) == {".git-main-working-tree", "dir"}
|
||||
assert set(os.listdir(os.path.join(base_dir, "dir"))) == {"test"}
|
||||
assert set(os.listdir(os.path.join(base_dir, "dir"))) == {"nested"}
|
||||
assert set(os.listdir(os.path.join(base_dir, "dir/nested"))) == {"test"}
|
||||
else:
|
||||
assert set(files) == {".git-main-working-tree", "test"}
|
||||
|
||||
repo = git.Repo(os.path.join(base_dir, worktree_name))
|
||||
assert not repo.bare
|
||||
assert not repo.is_dirty()
|
||||
if has_config and has_default:
|
||||
if has_prefix and not remote_branch_already_exists:
|
||||
# assert not repo.is_dirty()
|
||||
assert str(repo.head.ref) == worktree_name
|
||||
|
||||
local_commit = repo.head.commit.hexsha
|
||||
|
||||
if not has_remotes:
|
||||
assert local_commit == initial_commit
|
||||
elif local_branch_exists:
|
||||
assert local_commit == initial_commit
|
||||
elif explicit_track and not explicit_notrack:
|
||||
assert local_commit == repo.commit(explicit_track_branch_name).hexsha
|
||||
elif explicit_notrack:
|
||||
if config_enabled and config_has_default_remote_prefix:
|
||||
if remote_branch_with_prefix_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(
|
||||
f"{default_remote}/myprefix/{worktree_name}"
|
||||
).hexsha
|
||||
)
|
||||
elif remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
elif remote_count == 1:
|
||||
if config_enabled and config_has_default_remote_prefix:
|
||||
if remote_branch_with_prefix_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(
|
||||
f"{default_remote}/myprefix/{worktree_name}"
|
||||
).hexsha
|
||||
)
|
||||
elif remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
elif remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
elif remotes_differ:
|
||||
if config_enabled: # we have a default remote
|
||||
if (
|
||||
config_has_default_remote_prefix
|
||||
and remote_branch_with_prefix_already_exists
|
||||
):
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(
|
||||
f"{default_remote}/myprefix/{worktree_name}"
|
||||
).hexsha
|
||||
)
|
||||
elif remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
|
||||
else:
|
||||
if config_enabled and config_has_default_remote_prefix:
|
||||
if remote_branch_with_prefix_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(
|
||||
f"{default_remote}/myprefix/{worktree_name}"
|
||||
).hexsha
|
||||
)
|
||||
elif remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
|
||||
elif config_enabled:
|
||||
if not config_has_default_remote_prefix:
|
||||
if config_has_default_track_enabled:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
if remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
else:
|
||||
if remote_branch_with_prefix_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(
|
||||
f"{default_remote}/myprefix/{worktree_name}"
|
||||
).hexsha
|
||||
)
|
||||
elif remote_branch_already_exists:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
elif config_has_default_track_enabled:
|
||||
assert (
|
||||
local_commit
|
||||
== repo.commit(
|
||||
f"{default_remote}/myprefix/{worktree_name}"
|
||||
).hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
elif remote_branch_already_exists and not remotes_differ:
|
||||
assert (
|
||||
local_commit == repo.commit(f"{default_remote}/{worktree_name}").hexsha
|
||||
)
|
||||
else:
|
||||
assert local_commit == initial_commit
|
||||
|
||||
# Check whether tracking is ok
|
||||
if not has_remotes:
|
||||
assert repo.active_branch.tracking_branch() is None
|
||||
elif explicit_notrack:
|
||||
if local_branch_exists and local_branch_has_tracking_branch:
|
||||
if track_differs_from_existing_branch_upstream:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch())
|
||||
== f"{default_remote}/someothername"
|
||||
)
|
||||
else:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch())
|
||||
== f"{default_remote}/{worktree_name}"
|
||||
)
|
||||
else:
|
||||
assert repo.active_branch.tracking_branch() is None
|
||||
elif explicit_track:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch()) == explicit_track_branch_name
|
||||
)
|
||||
elif config_enabled and config_has_default_track_enabled:
|
||||
if config_has_default_remote_prefix:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch())
|
||||
== f"origin/myprefix/{worktree_name}"
|
||||
== f"{default_remote}/myprefix/{worktree_name}"
|
||||
)
|
||||
else:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch())
|
||||
== f"origin/{worktree_name}"
|
||||
== f"{default_remote}/{worktree_name}"
|
||||
)
|
||||
elif local_branch_exists and local_branch_has_tracking_branch:
|
||||
if track_differs_from_existing_branch_upstream:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch())
|
||||
== f"{default_remote}/someothername"
|
||||
)
|
||||
else:
|
||||
assert (
|
||||
str(repo.active_branch.tracking_branch())
|
||||
== f"{default_remote}/{worktree_name}"
|
||||
)
|
||||
else:
|
||||
assert repo.active_branch.tracking_branch() is None
|
||||
|
||||
Reference in New Issue
Block a user