From 30d1889a914b43d44992ac8405ce5db3baa356c7 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 6 Oct 2024 17:06:57 -0500 Subject: [PATCH 01/14] refactor!(pytest plugin[git]) Session-scoped, cached VCS fixtures --- src/libvcs/pytest_plugin.py | 147 +++++++++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 19 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index 817a083f..71614d7e 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -180,7 +180,7 @@ def clean() -> None: return path -@pytest.fixture +@pytest.fixture(scope="session") def remote_repos_path( user_path: pathlib.Path, request: pytest.FixtureRequest, @@ -255,10 +255,111 @@ def _create_git_remote_repo( return remote_repo_path -@pytest.fixture +def _create_git_remote_repo_full_path( + remote_repo_path: pathlib.Path, + remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, + init_cmd_args: InitCmdArgs = DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, +) -> pathlib.Path: + if init_cmd_args is None: + init_cmd_args = [] + run( + ["git", "init", remote_repo_path.stem, *init_cmd_args], + cwd=remote_repo_path.parent, + ) + + if remote_repo_post_init is not None and callable(remote_repo_post_init): + remote_repo_post_init(remote_repo_path=remote_repo_path) + + return remote_repo_path + + +@pytest.fixture(scope="session") +def libvcs_test_cache_path(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path: + """Return temporary directory to use as cache path for libvcs tests.""" + return tmp_path_factory.mktemp("libvcs-test-cache") + + +@pytest.fixture(scope="session") +def empty_git_repo_path(libvcs_test_cache_path: pathlib.Path) -> pathlib.Path: + """Return temporary directory to use for master-copy of a git repo.""" + return libvcs_test_cache_path / "empty_git_repo" + + +@pytest.fixture(scope="session") +def empty_git_bare_repo_path(libvcs_test_cache_path: pathlib.Path) -> pathlib.Path: + """Return temporary directory to use for master-copy of a bare git repo.""" + return libvcs_test_cache_path / "empty_git_bare_repo" + + +@pytest.fixture(scope="session") +@skip_if_git_missing +def empty_git_bare_repo( + empty_git_bare_repo_path: pathlib.Path, +) -> pathlib.Path: + """Return factory to create git remote repo to for clone / push purposes.""" + if ( + empty_git_bare_repo_path.exists() + and (empty_git_bare_repo_path / ".git").exists() + ): + return empty_git_bare_repo_path + + return _create_git_remote_repo_full_path( + remote_repo_path=empty_git_bare_repo_path, + remote_repo_post_init=None, + init_cmd_args=DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, # --bare + ) + + +@pytest.fixture(scope="session") +@skip_if_git_missing +def empty_git_repo( + empty_git_repo_path: pathlib.Path, +) -> pathlib.Path: + """Return factory to create git remote repo to for clone / push purposes.""" + if empty_git_repo_path.exists() and (empty_git_repo_path / ".git").exists(): + return empty_git_repo_path + + return _create_git_remote_repo_full_path( + remote_repo_path=empty_git_repo_path, + remote_repo_post_init=None, + init_cmd_args=None, + ) + + +@pytest.fixture(scope="session") +@skip_if_git_missing +def create_git_remote_bare_repo( + remote_repos_path: pathlib.Path, + empty_git_bare_repo: pathlib.Path, +) -> CreateRepoPytestFixtureFn: + """Return factory to create git remote repo to for clone / push purposes.""" + + def fn( + remote_repos_path: pathlib.Path = remote_repos_path, + remote_repo_name: Optional[str] = None, + remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, + init_cmd_args: InitCmdArgs = DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, + ) -> pathlib.Path: + if remote_repo_name is None: + remote_repo_name = unique_repo_name(remote_repos_path=remote_repos_path) + remote_repo_path = remote_repos_path / remote_repo_name + + shutil.copytree(empty_git_bare_repo, remote_repo_path) + + assert empty_git_bare_repo.exists() + + assert remote_repo_path.exists() + + return remote_repo_path + + return fn + + +@pytest.fixture(scope="session") @skip_if_git_missing def create_git_remote_repo( remote_repos_path: pathlib.Path, + empty_git_repo: pathlib.Path, ) -> CreateRepoPytestFixtureFn: """Return factory to create git remote repo to for clone / push purposes.""" @@ -268,14 +369,22 @@ def fn( remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, init_cmd_args: InitCmdArgs = DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, ) -> pathlib.Path: - return _create_git_remote_repo( - remote_repos_path=remote_repos_path, - remote_repo_name=remote_repo_name - if remote_repo_name is not None - else unique_repo_name(remote_repos_path=remote_repos_path), - remote_repo_post_init=remote_repo_post_init, - init_cmd_args=init_cmd_args, - ) + if remote_repo_name is None: + remote_repo_name = unique_repo_name(remote_repos_path=remote_repos_path) + remote_repo_path = remote_repos_path / remote_repo_name + + shutil.copytree(empty_git_repo, remote_repo_path) + + if remote_repo_post_init is not None and callable(remote_repo_post_init): + remote_repo_post_init(remote_repo_path=remote_repo_path) + + assert empty_git_repo.exists() + assert (empty_git_repo / ".git").exists() + + assert remote_repo_path.exists() + assert (remote_repo_path / ".git").exists() + + return remote_repo_path return fn @@ -288,16 +397,16 @@ def git_remote_repo_single_commit_post_init(remote_repo_path: pathlib.Path) -> N run(["git", "commit", "-m", "test file for dummyrepo"], cwd=remote_repo_path) -@pytest.fixture +@pytest.fixture(scope="session") @skip_if_git_missing -def git_remote_repo(remote_repos_path: pathlib.Path) -> pathlib.Path: - """Pre-made git repo w/ 1 commit, used as a file:// remote to clone and push to.""" - return _create_git_remote_repo( - remote_repos_path=remote_repos_path, - remote_repo_name="dummyrepo", - remote_repo_post_init=git_remote_repo_single_commit_post_init, - init_cmd_args=None, # Don't do --bare - ) +def git_remote_repo( + create_git_remote_repo: CreateRepoPytestFixtureFn, +) -> pathlib.Path: + """Copy the session-scoped Git repository to a temporary directory.""" + # TODO: Cache the effect of of this in a session-based repo + repo_path = create_git_remote_repo() + git_remote_repo_single_commit_post_init(remote_repo_path=repo_path) + return repo_path def _create_svn_remote_repo( From 10bf5c105ec1aed82d342f7ddd58996ca402c36d Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Fri, 11 Oct 2024 18:46:04 -0500 Subject: [PATCH 02/14] tests(sync[git]) Use bare git repo --- tests/sync/test_git.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/sync/test_git.py b/tests/sync/test_git.py index 4265f771..62659861 100644 --- a/tests/sync/test_git.py +++ b/tests/sync/test_git.py @@ -172,17 +172,17 @@ def test_repo_update_handle_cases( ) def test_repo_update_stash_cases( tmp_path: pathlib.Path, - create_git_remote_repo: CreateRepoPytestFixtureFn, + create_git_remote_bare_repo: CreateRepoPytestFixtureFn, mocker: MockerFixture, has_untracked_files: bool, needs_stash: bool, has_remote_changes: bool, ) -> None: """Test GitSync.update_repo() stash cases.""" - git_remote_repo = create_git_remote_repo() + git_bare_repo = create_git_remote_bare_repo() git_repo: GitSync = GitSync( - url=git_remote_repo.as_uri(), + url=git_bare_repo.as_uri(), path=tmp_path / "myrepo", vcs="git", ) From 90128dc22351d19c3fae177a260a28db7887d6a8 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 03:52:03 -0500 Subject: [PATCH 03/14] refactor!(pytest plugin[svn]) Session-scoped, cached VCS fixtures --- src/libvcs/pytest_plugin.py | 72 ++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index 71614d7e..2e315aac 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -449,10 +449,34 @@ def svn_remote_repo_single_commit_post_init(remote_repo_path: pathlib.Path) -> N ) -@pytest.fixture +@pytest.fixture(scope="session") +def empty_svn_repo_path(libvcs_test_cache_path: pathlib.Path) -> pathlib.Path: + """Return temporary directory to use for master-copy of a svn repo.""" + return libvcs_test_cache_path / "empty_svn_repo" + + +@pytest.fixture(scope="session") +@skip_if_svn_missing +def empty_svn_repo( + empty_svn_repo_path: pathlib.Path, +) -> pathlib.Path: + """Return factory to create svn remote repo to for clone / push purposes.""" + if empty_svn_repo_path.exists() and (empty_svn_repo_path / "conf").exists(): + return empty_svn_repo_path + + return _create_svn_remote_repo( + remote_repos_path=empty_svn_repo_path.parent, + remote_repo_name=empty_svn_repo_path.stem, + remote_repo_post_init=None, + init_cmd_args=None, + ) + + +@pytest.fixture(scope="session") @skip_if_svn_missing def create_svn_remote_repo( remote_repos_path: pathlib.Path, + empty_svn_repo: pathlib.Path, ) -> CreateRepoPytestFixtureFn: """Pre-made svn repo, bare, used as a file:// remote to checkout and commit to.""" @@ -462,27 +486,43 @@ def fn( remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, init_cmd_args: InitCmdArgs = None, ) -> pathlib.Path: - return _create_svn_remote_repo( - remote_repos_path=remote_repos_path, - remote_repo_name=remote_repo_name - if remote_repo_name is not None - else unique_repo_name(remote_repos_path=remote_repos_path), - remote_repo_post_init=remote_repo_post_init, - init_cmd_args=init_cmd_args, - ) + if remote_repo_name is None: + remote_repo_name = unique_repo_name(remote_repos_path=remote_repos_path) + remote_repo_path = remote_repos_path / remote_repo_name + + shutil.copytree(empty_svn_repo, remote_repo_path) + + if remote_repo_post_init is not None and callable(remote_repo_post_init): + remote_repo_post_init(remote_repo_path=remote_repo_path) + + assert empty_svn_repo.exists() + + assert remote_repo_path.exists() + + return remote_repo_path return fn -@pytest.fixture +@pytest.fixture(scope="session") @skip_if_svn_missing -def svn_remote_repo(remote_repos_path: pathlib.Path) -> pathlib.Path: +def svn_remote_repo( + create_svn_remote_repo: CreateRepoPytestFixtureFn, +) -> pathlib.Path: """Pre-made. Local file:// based SVN server.""" - return _create_svn_remote_repo( - remote_repos_path=remote_repos_path, - remote_repo_name="svn_server_dir", - remote_repo_post_init=None, - ) + repo_path = create_svn_remote_repo() + return repo_path + + +@pytest.fixture(scope="session") +@skip_if_svn_missing +def svn_remote_repo_with_files( + create_svn_remote_repo: CreateRepoPytestFixtureFn, +) -> pathlib.Path: + """Pre-made. Local file:// based SVN server.""" + repo_path = create_svn_remote_repo() + svn_remote_repo_single_commit_post_init(remote_repo_path=repo_path) + return repo_path def _create_hg_remote_repo( From 628afaca53e4220f12156fee3710ffe2c5c386c9 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 04:29:18 -0500 Subject: [PATCH 04/14] test(sync[svn]) Add example for non-empty repo checkout --- tests/sync/test_svn.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/sync/test_svn.py b/tests/sync/test_svn.py index 4a68aea2..4b2fbee1 100644 --- a/tests/sync/test_svn.py +++ b/tests/sync/test_svn.py @@ -30,6 +30,26 @@ def test_svn_sync(tmp_path: pathlib.Path, svn_remote_repo: pathlib.Path) -> None assert (tmp_path / repo_name).exists() +def test_svn_sync_with_files( + tmp_path: pathlib.Path, svn_remote_repo_with_files: pathlib.Path +) -> None: + """Tests for SvnSync.""" + repo_name = "my_svn_project" + + svn_repo = SvnSync( + url=f"file://{svn_remote_repo_with_files}", + path=str(tmp_path / repo_name), + ) + + svn_repo.obtain() + svn_repo.update_repo() + + assert svn_repo.get_revision() == 0 + assert svn_repo.get_revision_file("./") == 3 + + assert (tmp_path / repo_name).exists() + + def test_repo_svn_remote_checkout( create_svn_remote_repo: CreateRepoPytestFixtureFn, tmp_path: pathlib.Path, From 70a0fd997dbd055d2186fd02ab05f3a333c9526e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 04:17:22 -0500 Subject: [PATCH 05/14] refactor!(pytest plugin[hg]) Session-scoped, cached VCS fixtures --- src/libvcs/pytest_plugin.py | 64 ++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index 2e315aac..e578c1d0 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -552,12 +552,34 @@ def hg_remote_repo_single_commit_post_init(remote_repo_path: pathlib.Path) -> No run(["hg", "commit", "-m", "test file for hg repo"], cwd=remote_repo_path) -@pytest.fixture +@pytest.fixture(scope="session") +def empty_hg_repo_path(libvcs_test_cache_path: pathlib.Path) -> pathlib.Path: + """Return temporary directory to use for master-copy of a hg repo.""" + return libvcs_test_cache_path / "empty_hg_repo" + + +@pytest.fixture(scope="session") +@skip_if_hg_missing +def empty_hg_repo( + empty_hg_repo_path: pathlib.Path, +) -> pathlib.Path: + """Return factory to create hg remote repo to for clone / push purposes.""" + if empty_hg_repo_path.exists() and (empty_hg_repo_path / ".hg").exists(): + return empty_hg_repo_path + + return _create_hg_remote_repo( + remote_repos_path=empty_hg_repo_path.parent, + remote_repo_name=empty_hg_repo_path.stem, + remote_repo_post_init=None, + init_cmd_args=None, + ) + + +@pytest.fixture(scope="session") @skip_if_hg_missing def create_hg_remote_repo( remote_repos_path: pathlib.Path, - hgconfig: pathlib.Path, - set_home: pathlib.Path, + empty_hg_repo: pathlib.Path, ) -> CreateRepoPytestFixtureFn: """Pre-made hg repo, bare, used as a file:// remote to checkout and commit to.""" @@ -567,30 +589,34 @@ def fn( remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, init_cmd_args: InitCmdArgs = None, ) -> pathlib.Path: - return _create_hg_remote_repo( - remote_repos_path=remote_repos_path, - remote_repo_name=remote_repo_name - if remote_repo_name is not None - else unique_repo_name(remote_repos_path=remote_repos_path), - remote_repo_post_init=remote_repo_post_init, - init_cmd_args=init_cmd_args, - ) + if remote_repo_name is None: + remote_repo_name = unique_repo_name(remote_repos_path=remote_repos_path) + remote_repo_path = remote_repos_path / remote_repo_name + + shutil.copytree(empty_hg_repo, remote_repo_path) + + if remote_repo_post_init is not None and callable(remote_repo_post_init): + remote_repo_post_init(remote_repo_path=remote_repo_path) + + assert empty_hg_repo.exists() + + assert remote_repo_path.exists() + + return remote_repo_path return fn -@pytest.fixture +@pytest.fixture(scope="session") @skip_if_hg_missing def hg_remote_repo( remote_repos_path: pathlib.Path, - hgconfig: pathlib.Path, + create_hg_remote_repo: CreateRepoPytestFixtureFn, ) -> pathlib.Path: """Pre-made, file-based repo for push and pull.""" - return _create_hg_remote_repo( - remote_repos_path=remote_repos_path, - remote_repo_name="dummyrepo", - remote_repo_post_init=hg_remote_repo_single_commit_post_init, - ) + repo_path = create_hg_remote_repo() + hg_remote_repo_single_commit_post_init(remote_repo_path=repo_path) + return repo_path @pytest.fixture @@ -640,6 +666,7 @@ def add_doctest_fixtures( tmp_path: pathlib.Path, set_home: pathlib.Path, gitconfig: pathlib.Path, + hgconfig: pathlib.Path, create_git_remote_repo: CreateRepoPytestFixtureFn, create_svn_remote_repo: CreateRepoPytestFixtureFn, create_hg_remote_repo: CreateRepoPytestFixtureFn, @@ -667,6 +694,7 @@ def add_doctest_fixtures( remote_repo_post_init=svn_remote_repo_single_commit_post_init, ) if shutil.which("hg"): + doctest_namespace["hgconfig"] = hgconfig doctest_namespace["create_hg_remote_repo_bare"] = create_hg_remote_repo doctest_namespace["create_hg_remote_repo"] = functools.partial( create_hg_remote_repo, From a70eb87296ef27ab8250b6b2474d2c99ab2cd2a0 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 04:18:13 -0500 Subject: [PATCH 06/14] test(sync[hg]) Remote repository fixture --- tests/sync/test_hg.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/sync/test_hg.py b/tests/sync/test_hg.py index b36d95b2..7f32abee 100644 --- a/tests/sync/test_hg.py +++ b/tests/sync/test_hg.py @@ -8,12 +8,24 @@ from libvcs import exc from libvcs._internal.run import run from libvcs._internal.shortcuts import create_project +from libvcs.pytest_plugin import CreateRepoPytestFixtureFn from libvcs.sync.hg import HgSync if not shutil.which("hg"): pytestmark = pytest.mark.skip(reason="hg is not available") +@pytest.fixture +def hg_remote_repo( + set_home: pathlib.Path, + hgconfig: pathlib.Path, + create_hg_remote_repo: CreateRepoPytestFixtureFn, +) -> pathlib.Path: + """Create a remote hg repository.""" + return create_hg_remote_repo() + + +@pytest.mark.usefixtures("set_home", "hgconfig") def test_hg_sync( tmp_path: pathlib.Path, projects_path: pathlib.Path, From d769e0a2c8809d627c064391fe008b03175cad4d Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 05:01:40 -0500 Subject: [PATCH 07/14] refactor!(pytest plugin[git]) Cache `git_repo` --- src/libvcs/pytest_plugin.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index e578c1d0..ca4eee71 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -620,11 +620,26 @@ def hg_remote_repo( @pytest.fixture -def git_repo(projects_path: pathlib.Path, git_remote_repo: pathlib.Path) -> GitSync: +def git_repo( + remote_repos_path: pathlib.Path, + projects_path: pathlib.Path, + git_remote_repo: pathlib.Path, +) -> GitSync: """Pre-made git clone of remote repo checked out to user's projects dir.""" + remote_repo_name = unique_repo_name(remote_repos_path=projects_path) + new_checkout_path = projects_path / remote_repo_name + master_copy = remote_repos_path / "git_repo" + + if master_copy.exists(): + shutil.copytree(master_copy, new_checkout_path) + return GitSync( + url=f"file://{git_remote_repo}", + path=str(new_checkout_path), + ) + git_repo = GitSync( url=f"file://{git_remote_repo}", - path=str(projects_path / "git_repo"), + path=master_copy, remotes={ "origin": GitRemote( name="origin", From 9a3c318028594f12595f08904c6850ce9dff7394 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 05:05:02 -0500 Subject: [PATCH 08/14] refactor!(pytest plugin[hg]) Cache `hg_repo` --- src/libvcs/pytest_plugin.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index ca4eee71..b947855f 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -653,11 +653,26 @@ def git_repo( @pytest.fixture -def hg_repo(projects_path: pathlib.Path, hg_remote_repo: pathlib.Path) -> HgSync: +def hg_repo( + remote_repos_path: pathlib.Path, + projects_path: pathlib.Path, + hg_remote_repo: pathlib.Path, +) -> HgSync: """Pre-made hg clone of remote repo checked out to user's projects dir.""" + remote_repo_name = unique_repo_name(remote_repos_path=projects_path) + new_checkout_path = projects_path / remote_repo_name + master_copy = remote_repos_path / "hg_repo" + + if master_copy.exists(): + shutil.copytree(master_copy, new_checkout_path) + return HgSync( + url=f"file://{hg_remote_repo}", + path=str(new_checkout_path), + ) + hg_repo = HgSync( url=f"file://{hg_remote_repo}", - path=str(projects_path / "hg_repo"), + path=master_copy, ) hg_repo.obtain() return hg_repo From 8a05acec59dadd876cb03001d9c6a69b47b4db14 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 05:06:39 -0500 Subject: [PATCH 09/14] refactor!(pytest plugin[svn]) Cache `svn_repo` --- src/libvcs/pytest_plugin.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index b947855f..c1da0fae 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -679,8 +679,23 @@ def hg_repo( @pytest.fixture -def svn_repo(projects_path: pathlib.Path, svn_remote_repo: pathlib.Path) -> SvnSync: +def svn_repo( + remote_repos_path: pathlib.Path, + projects_path: pathlib.Path, + svn_remote_repo: pathlib.Path, +) -> SvnSync: """Pre-made svn clone of remote repo checked out to user's projects dir.""" + remote_repo_name = unique_repo_name(remote_repos_path=projects_path) + new_checkout_path = projects_path / remote_repo_name + master_copy = remote_repos_path / "svn_repo" + + if master_copy.exists(): + shutil.copytree(master_copy, new_checkout_path) + return SvnSync( + url=f"file://{svn_remote_repo}", + path=str(new_checkout_path), + ) + svn_repo = SvnSync( url=f"file://{svn_remote_repo}", path=str(projects_path / "svn_repo"), From e1db75d9d9d1ab6bad63c38bf0b8a355c88f4491 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 06:16:23 -0500 Subject: [PATCH 10/14] test(sync[hg]) Use test fixture --- tests/url/test_hg.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/url/test_hg.py b/tests/url/test_hg.py index ac29df22..7d31dde6 100644 --- a/tests/url/test_hg.py +++ b/tests/url/test_hg.py @@ -1,9 +1,11 @@ """Tests for mercurial URL module.""" +import pathlib import typing import pytest +from libvcs.pytest_plugin import CreateRepoPytestFixtureFn from libvcs.sync.hg import HgSync from libvcs.url.base import RuleMap from libvcs.url.hg import DEFAULT_RULES, PIP_DEFAULT_RULES, HgBaseURL, HgURL @@ -17,6 +19,16 @@ class HgURLFixture(typing.NamedTuple): hg_url: HgURL +@pytest.fixture +def hg_repo( + set_home: pathlib.Path, + hgconfig: pathlib.Path, + create_hg_remote_repo: CreateRepoPytestFixtureFn, +) -> pathlib.Path: + """Create a remote hg repository.""" + return create_hg_remote_repo() + + TEST_FIXTURES: list[HgURLFixture] = [ HgURLFixture( url="https://bitbucket.com/vcs-python/libvcs", @@ -52,8 +64,8 @@ def test_hg_url( hg_repo: HgSync, ) -> None: """Test HgURL.""" - url = url.format(local_repo=hg_repo.path) - hg_url.url = hg_url.url.format(local_repo=hg_repo.path) + url = url.format(local_repo=hg_repo) + hg_url.url = hg_url.url.format(local_repo=hg_repo) assert HgURL.is_valid(url) == is_valid, f"{url} compatibility should be {is_valid}" assert HgURL(url) == hg_url @@ -121,10 +133,10 @@ class HgURLWithPip(HgURL): _rule_map={m.label: m for m in [*DEFAULT_RULES, *PIP_DEFAULT_RULES]}, ) - hg_url_kwargs["url"] = hg_url_kwargs["url"].format(local_repo=hg_repo.path) - url = url.format(local_repo=hg_repo.path) + hg_url_kwargs["url"] = hg_url_kwargs["url"].format(local_repo=hg_repo) + url = url.format(local_repo=hg_repo) hg_url = HgURLWithPip(**hg_url_kwargs) - hg_url.url = hg_url.url.format(local_repo=hg_repo.path) + hg_url.url = hg_url.url.format(local_repo=hg_repo) assert ( HgBaseURL.is_valid(url) != is_valid @@ -186,6 +198,6 @@ def test_hg_to_url( hg_repo: HgSync, ) -> None: """Test HgURL.to_url().""" - hg_url.url = hg_url.url.format(local_repo=hg_repo.path) + hg_url.url = hg_url.url.format(local_repo=hg_repo) assert hg_url.to_url() == expected From faaba05e71737af3b6e0ddbc08eaa24229808ed9 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 04:35:15 -0500 Subject: [PATCH 11/14] docs(CHANGES) Note pytest plugin cache improvements --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 1d8bdaa5..0fd704ce 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,11 @@ $ pip install --user --upgrade --pre libvcs ### Breaking changes +#### pytest plugin: Improve performacne via session-based scoping (#472) + +Improved test execution speed by over 54% by eliminated repetitive repository reinitialization between test runs. +Git, Subversion, and Mercurial repositories are now cached from an initial starter repository + #### pytest fixtures: `git_local_clone` renamed to `example_git_repo` (#468) Renamed `git_local_clone` to `example_git_repo` for better understandability in From d3918866c85e26a46d62e069b8407173d9bedb10 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 11:18:53 -0500 Subject: [PATCH 12/14] refactor!(pytest plugin[git]) Consolidate repo creation function --- src/libvcs/pytest_plugin.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index c1da0fae..728a9e73 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -239,23 +239,6 @@ def __call__( def _create_git_remote_repo( - remote_repos_path: pathlib.Path, - remote_repo_name: str, - remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, - init_cmd_args: InitCmdArgs = DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, -) -> pathlib.Path: - if init_cmd_args is None: - init_cmd_args = [] - remote_repo_path = remote_repos_path / remote_repo_name - run(["git", "init", remote_repo_name, *init_cmd_args], cwd=remote_repos_path) - - if remote_repo_post_init is not None and callable(remote_repo_post_init): - remote_repo_post_init(remote_repo_path=remote_repo_path) - - return remote_repo_path - - -def _create_git_remote_repo_full_path( remote_repo_path: pathlib.Path, remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, init_cmd_args: InitCmdArgs = DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, @@ -303,7 +286,7 @@ def empty_git_bare_repo( ): return empty_git_bare_repo_path - return _create_git_remote_repo_full_path( + return _create_git_remote_repo( remote_repo_path=empty_git_bare_repo_path, remote_repo_post_init=None, init_cmd_args=DEFAULT_GIT_REMOTE_REPO_CMD_ARGS, # --bare @@ -319,7 +302,7 @@ def empty_git_repo( if empty_git_repo_path.exists() and (empty_git_repo_path / ".git").exists(): return empty_git_repo_path - return _create_git_remote_repo_full_path( + return _create_git_remote_repo( remote_repo_path=empty_git_repo_path, remote_repo_post_init=None, init_cmd_args=None, From 475b31a6f4c8e233d6b5bc7b7b295ae2ac1ad77b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 11:20:03 -0500 Subject: [PATCH 13/14] refactor!(pytest plugin[svn]) Consolidate repo creation function --- src/libvcs/pytest_plugin.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index 728a9e73..98962e1e 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -393,8 +393,7 @@ def git_remote_repo( def _create_svn_remote_repo( - remote_repos_path: pathlib.Path, - remote_repo_name: str, + remote_repo_path: pathlib.Path, remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, init_cmd_args: InitCmdArgs = None, ) -> pathlib.Path: @@ -402,7 +401,6 @@ def _create_svn_remote_repo( if init_cmd_args is None: init_cmd_args = [] - remote_repo_path = remote_repos_path / remote_repo_name run(["svnadmin", "create", str(remote_repo_path), *init_cmd_args]) assert remote_repo_path.exists() @@ -448,8 +446,7 @@ def empty_svn_repo( return empty_svn_repo_path return _create_svn_remote_repo( - remote_repos_path=empty_svn_repo_path.parent, - remote_repo_name=empty_svn_repo_path.stem, + remote_repo_path=empty_svn_repo_path, remote_repo_post_init=None, init_cmd_args=None, ) From a658c43ccac611c7c512b8cde18889fccbf9a2d1 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 12 Oct 2024 11:21:41 -0500 Subject: [PATCH 14/14] refactor!(pytest plugin[hg]) Consolidate repo creation function --- src/libvcs/pytest_plugin.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libvcs/pytest_plugin.py b/src/libvcs/pytest_plugin.py index 98962e1e..fc626677 100644 --- a/src/libvcs/pytest_plugin.py +++ b/src/libvcs/pytest_plugin.py @@ -506,8 +506,7 @@ def svn_remote_repo_with_files( def _create_hg_remote_repo( - remote_repos_path: pathlib.Path, - remote_repo_name: str, + remote_repo_path: pathlib.Path, remote_repo_post_init: Optional[CreateRepoPostInitFn] = None, init_cmd_args: InitCmdArgs = None, ) -> pathlib.Path: @@ -515,8 +514,10 @@ def _create_hg_remote_repo( if init_cmd_args is None: init_cmd_args = [] - remote_repo_path = remote_repos_path / remote_repo_name - run(["hg", "init", remote_repo_name, *init_cmd_args], cwd=remote_repos_path) + run( + ["hg", "init", remote_repo_path.stem, *init_cmd_args], + cwd=remote_repo_path.parent, + ) if remote_repo_post_init is not None and callable(remote_repo_post_init): remote_repo_post_init(remote_repo_path=remote_repo_path) @@ -548,8 +549,7 @@ def empty_hg_repo( return empty_hg_repo_path return _create_hg_remote_repo( - remote_repos_path=empty_hg_repo_path.parent, - remote_repo_name=empty_hg_repo_path.stem, + remote_repo_path=empty_hg_repo_path, remote_repo_post_init=None, init_cmd_args=None, )