From 4636d65ae71ad9e3f90453957118fabf0dc25f61 Mon Sep 17 00:00:00 2001 From: "Axel H." Date: Sun, 21 Dec 2025 19:32:26 +0100 Subject: [PATCH 1/2] build(tox): do not use poetry anymore and use the builtin `dependency-group` support --- pyproject.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 120bd2792..214dfb864 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -177,9 +177,7 @@ env_list = ["3.10", "3.11", "3.12", "3.13", "3.14"] [tool.tox.env_run_base] description = "Run tests suite against Python {base_python}" -skip_install = true -deps = ["poetry>=2.0"] -commands_pre = [["poetry", "install", "--only", "main,test"]] +dependency_groups = ["test"] commands = [["pytest", { replace = "posargs", extend = true }]] [tool.ruff] From a2b127a792477eafcc13e7ccd533c89b09c424d2 Mon Sep 17 00:00:00 2001 From: "Axel H." Date: Sun, 28 Dec 2025 03:48:09 +0100 Subject: [PATCH 2/2] test(tox): ensure all tests can run from any directory --- poetry.lock | 15 ++++++ pyproject.toml | 1 + tests/conftest.py | 46 +++++++++--------- tests/{ => data}/CHANGELOG_FOR_TEST.md | 0 tests/test_bump_update_version_in_files.py | 55 ++++++++++------------ tests/test_changelog.py | 7 +-- tests/test_conf.py | 1 + tests/test_git.py | 31 +++++------- 8 files changed, 83 insertions(+), 73 deletions(-) rename tests/{ => data}/CHANGELOG_FOR_TEST.md (100%) diff --git a/poetry.lock b/poetry.lock index 72cafcd56..bc6a9d27f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1414,6 +1414,21 @@ files = [ freezegun = ">=1.1" pytest = ">=3.6" +[[package]] +name = "pytest-gitconfig" +version = "0.9.0" +description = "Provide a Git config sandbox for testing" +optional = false +python-versions = ">=3.10" +groups = ["test"] +files = [ + {file = "pytest_gitconfig-0.9.0-py3-none-any.whl", hash = "sha256:3d855a9dd5fb3906010dbb1f8161366d4d86b34df8c14021fa012f23de3e5354"}, + {file = "pytest_gitconfig-0.9.0.tar.gz", hash = "sha256:5f9e8a29b4a8e55ddd740216ddb0a8a5e97f1c9c7f6bfdac91863473a8c60f9c"}, +] + +[package.dependencies] +pytest = ">=7.1.2" + [[package]] name = "pytest-mock" version = "3.15.1" diff --git a/pyproject.toml b/pyproject.toml index 214dfb864..bf7800996 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,6 +95,7 @@ test = [ "pytest-regressions>=2.4.0", "pytest-freezer>=0.4.6", "pytest-xdist>=3.1.0", + "pytest-gitconfig>=0.9.0", ] linters = [ diff --git a/tests/conftest.py b/tests/conftest.py index 5eaa17440..dc68da555 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ import os import re import tempfile +from pathlib import Path from typing import TYPE_CHECKING import pytest @@ -15,45 +16,46 @@ from commitizen.config import BaseConfig from commitizen.cz import registry from commitizen.cz.base import BaseCommitizen +from tests.utils import create_file_and_commit if TYPE_CHECKING: from collections.abc import Iterator, Mapping - from pathlib import Path from pytest_mock import MockerFixture from commitizen.question import CzQuestion -from tests.utils import create_file_and_commit + SIGNER = "GitHub Action" SIGNER_MAIL = "action@github.com" -@pytest.fixture(autouse=True) -def git_sandbox(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): - """Ensure git commands are executed without the current user settings""" - # Clear any GIT_ prefixed environment variable - for var in os.environ: - if var.startswith("GIT_"): - monkeypatch.delenv(var) +@pytest.fixture +def repo_root() -> Path: + return Path(__file__).parent.parent + - # Define a dedicated temporary git config - gitconfig = tmp_path / ".git" / "config" - if not gitconfig.parent.exists(): - gitconfig.parent.mkdir() +@pytest.fixture +def in_repo_root(repo_root: Path) -> Iterator[Path]: + cwd = os.getcwd() + os.chdir(repo_root) + yield repo_root + os.chdir(cwd) - monkeypatch.setenv("GIT_CONFIG_GLOBAL", str(gitconfig)) - r = cmd.run(f"git config --file {gitconfig} user.name {SIGNER}") - assert r.return_code == 0, r.err - r = cmd.run(f"git config --file {gitconfig} user.email {SIGNER_MAIL}") - assert r.return_code == 0, r.err +@pytest.fixture +def data_dir(repo_root: Path) -> Path: + return repo_root / "tests" / "data" - r = cmd.run(f"git config --file {gitconfig} safe.directory '*'") - assert r.return_code == 0, r.err - r = cmd.run("git config --global init.defaultBranch master") - assert r.return_code == 0, r.err +@pytest.fixture(scope="session") +def set_default_gitconfig() -> dict[str, str]: + return { + "user.name": "SIGNER", + "user.email": SIGNER_MAIL, + "safe.cirectory": "*", + "init.defaultBranch": "master", + } @pytest.fixture diff --git a/tests/CHANGELOG_FOR_TEST.md b/tests/data/CHANGELOG_FOR_TEST.md similarity index 100% rename from tests/CHANGELOG_FOR_TEST.md rename to tests/data/CHANGELOG_FOR_TEST.md diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 9d53a3e81..5fb812f19 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -1,5 +1,7 @@ +from collections.abc import Callable from pathlib import Path from shutil import copyfile +from typing import TypeAlias import pytest from _pytest.fixtures import FixtureRequest @@ -10,53 +12,48 @@ MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 -TESTING_FILE_PREFIX = "tests/data" +SampleFileFixture: TypeAlias = Callable[[str, str], Path] -def _copy_sample_file_to_tmpdir( - tmp_path: Path, source_filename: str, dest_filename: str -) -> Path: - tmp_file = tmp_path / dest_filename - copyfile(f"{TESTING_FILE_PREFIX}/{source_filename}", tmp_file) - return tmp_file + +@pytest.fixture +def sample_file(tmp_path: Path, data_dir: Path) -> SampleFileFixture: + def fixture(source: str, destination: str) -> Path: + tmp_file = tmp_path / destination + copyfile(data_dir / source, tmp_file) + return tmp_file + + return fixture @pytest.fixture(scope="function") -def commitizen_config_file(tmp_path: Path) -> Path: - return _copy_sample_file_to_tmpdir( - tmp_path, "sample_pyproject.toml", "pyproject.toml" - ) +def commitizen_config_file(sample_file: SampleFileFixture) -> Path: + return sample_file("sample_pyproject.toml", "pyproject.toml") @pytest.fixture(scope="function") -def python_version_file(tmp_path: Path, request: FixtureRequest) -> Path: - return _copy_sample_file_to_tmpdir(tmp_path, "sample_version.py", "__version__.py") +def python_version_file(sample_file: SampleFileFixture) -> Path: + return sample_file("sample_version.py", "__version__.py") @pytest.fixture(scope="function") -def inconsistent_python_version_file(tmp_path: Path) -> Path: - return _copy_sample_file_to_tmpdir( - tmp_path, "inconsistent_version.py", "__version__.py" - ) +def inconsistent_python_version_file(sample_file: SampleFileFixture) -> Path: + return sample_file("inconsistent_version.py", "__version__.py") @pytest.fixture(scope="function") -def random_location_version_file(tmp_path: Path) -> Path: - return _copy_sample_file_to_tmpdir(tmp_path, "sample_cargo.lock", "Cargo.lock") +def random_location_version_file(sample_file: SampleFileFixture) -> Path: + return sample_file("sample_cargo.lock", "Cargo.lock") @pytest.fixture(scope="function") -def version_repeated_file(tmp_path: Path) -> Path: - return _copy_sample_file_to_tmpdir( - tmp_path, "repeated_version_number.json", "package.json" - ) +def version_repeated_file(sample_file: SampleFileFixture) -> Path: + return sample_file("repeated_version_number.json", "package.json") @pytest.fixture(scope="function") -def docker_compose_file(tmp_path: Path) -> Path: - return _copy_sample_file_to_tmpdir( - tmp_path, "sample_docker_compose.yaml", "docker-compose.yaml" - ) +def docker_compose_file(sample_file: SampleFileFixture) -> Path: + return sample_file("sample_docker_compose.yaml", "docker-compose.yaml") @pytest.fixture( @@ -68,9 +65,9 @@ def docker_compose_file(tmp_path: Path) -> Path: ids=("with_eol", "without_eol"), ) def multiple_versions_to_update_poetry_lock( - tmp_path: Path, request: FixtureRequest + sample_file: SampleFileFixture, request: FixtureRequest ) -> Path: - return _copy_sample_file_to_tmpdir(tmp_path, request.param, "pyproject.toml") + return sample_file(request.param, "pyproject.toml") @pytest.fixture(scope="function") diff --git a/tests/test_changelog.py b/tests/test_changelog.py index e32a9bcf9..bcf90b11d 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -578,9 +578,9 @@ def tags() -> list[git.GitTag]: @pytest.fixture -def changelog_content() -> str: - changelog_path = "tests/CHANGELOG_FOR_TEST.md" - with open(changelog_path, encoding="utf-8") as f: +def changelog_content(data_dir: Path) -> str: + changelog = data_dir / "CHANGELOG_FOR_TEST.md" + with changelog.open(encoding="utf-8") as f: return f.read() @@ -1657,6 +1657,7 @@ def test_tags_rules_get_version_tags(capsys: pytest.CaptureFixture): assert captured.err.count("not-a-version") == 2 +@pytest.mark.usefixtures("in_repo_root") def test_changelog_file_name_from_args_and_config(): mock_config = Mock(spec=BaseConfig) mock_path = Mock(spec=Path) diff --git a/tests/test_conf.py b/tests/test_conf.py index bbbed41e0..0df0d1864 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -164,6 +164,7 @@ def config_files_manager(request, tmpdir): yield +@pytest.mark.usefixtures("in_repo_root") def test_find_git_project_root(tmpdir): assert git.find_git_project_root() == Path(os.getcwd()) diff --git a/tests/test_git.py b/tests/test_git.py index 45e6028c9..12c0e2ad8 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -3,7 +3,6 @@ import inspect import os import platform -import shutil from typing import TYPE_CHECKING import pytest @@ -19,6 +18,7 @@ ) if TYPE_CHECKING: + from pytest_gitconfig import GitConfig from pytest_mock import MockFixture @@ -260,25 +260,18 @@ def test_get_commits_with_and_without_parents(mocker: MockFixture): assert commits[2].parents == [] -def test_get_commits_with_signature(): - config_file = ".git/config" - config_backup = ".git/config.bak" - shutil.copy(config_file, config_backup) +@pytest.mark.usefixtures("in_repo_root") +def test_get_commits_with_signature(gitconfig: GitConfig): + # temporarily turn on --show-signature + gitconfig.set("log.showsignature", "true") - try: - # temporarily turn on --show-signature - cmd.run("git config log.showsignature true") - - # retrieve a commit that we know has a signature - commit = git.get_commits( - start="bec20ebf433f2281c70f1eb4b0b6a1d0ed83e9b2", - end="9eae518235d051f145807ddf971ceb79ad49953a", - )[0] - - assert commit.title.startswith("fix") - finally: - # restore the repo's original config - shutil.move(config_backup, config_file) + # retrieve a commit that we know has a signature + commit = git.get_commits( + start="bec20ebf433f2281c70f1eb4b0b6a1d0ed83e9b2", + end="9eae518235d051f145807ddf971ceb79ad49953a", + )[0] + + assert commit.title.startswith("fix") def test_get_tag_names_has_correct_arrow_annotation():