diff --git a/src/pytest_codspeed/plugin.py b/src/pytest_codspeed/plugin.py index beb7737..407af07 100644 --- a/src/pytest_codspeed/plugin.py +++ b/src/pytest_codspeed/plugin.py @@ -18,6 +18,8 @@ import pytest from _pytest.fixtures import FixtureManager +from pytest_codspeed.utils import get_git_relative_uri + from . import __version__ from ._wrapper import get_lib @@ -169,7 +171,12 @@ def pytest_collection_modifyitems( def _run_with_instrumentation( - lib: "LibType", nodeId: str, fn: Callable[..., Any], *args, **kwargs + lib: "LibType", + nodeId: str, + config: "pytest.Config", + fn: Callable[..., Any], + *args, + **kwargs, ): is_gc_enabled = gc.isenabled() if is_gc_enabled: @@ -185,12 +192,12 @@ def __codspeed_root_frame__(): if SUPPORTS_PERF_TRAMPOLINE: # Warmup CPython performance map cache __codspeed_root_frame__() - lib.zero_stats() lib.start_instrumentation() __codspeed_root_frame__() lib.stop_instrumentation() - lib.dump_stats_at(f"{nodeId}".encode("ascii")) + uri = get_git_relative_uri(nodeId, config.rootpath) + lib.dump_stats_at(uri.encode("ascii")) if is_gc_enabled: gc.enable() @@ -226,7 +233,9 @@ def pytest_runtest_protocol(item: "pytest.Item", nextitem: Union["pytest.Item", if setup_report.passed and not item.config.getoption("setuponly"): assert plugin.lib is not None runtest_call = pytest.CallInfo.from_call( - lambda: _run_with_instrumentation(plugin.lib, item.nodeid, item.runtest), + lambda: _run_with_instrumentation( + plugin.lib, item.nodeid, item.config, item.runtest + ), "call", ) runtest_report = ihook.pytest_runtest_makereport(item=item, call=runtest_call) diff --git a/src/pytest_codspeed/utils.py b/src/pytest_codspeed/utils.py new file mode 100644 index 0000000..71b7f39 --- /dev/null +++ b/src/pytest_codspeed/utils.py @@ -0,0 +1,35 @@ +from pathlib import Path + + +def get_git_relative_path(abs_path: Path) -> Path: + """Get the path relative to the git root directory. If the path is not + inside a git repository, the original path itself is returned. + """ + git_path = Path(abs_path).resolve() + while ( + git_path != git_path.parent + ): # stops at root since parent of root is root itself + if (git_path / ".git").exists(): + return abs_path.resolve().relative_to(git_path) + git_path = git_path.parent + return abs_path + + +def get_git_relative_uri(uri: str, pytest_rootdir: Path) -> str: + """Get the benchmark uri relative to the git root dir. + + Args: + uri (str): the benchmark uri, for example: + testing/test_excinfo.py::TestFormattedExcinfo::test_repr_source + pytest_rootdir (str): the pytest root dir, for example: + /home/user/gitrepo/folder + + Returns: + str: the benchmark uri relative to the git root dir, for example: + folder/testing/test_excinfo.py::TestFormattedExcinfo::test_repr_source + + """ + file_path, function_path = uri.split("::", 1) + absolute_file_path = pytest_rootdir / Path(file_path) + relative_git_path = get_git_relative_path(absolute_file_path) + return f"{str(relative_git_path)}::{function_path}" diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..5111718 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,30 @@ +from pathlib import Path +from unittest.mock import patch + +from pytest_codspeed.utils import get_git_relative_path, get_git_relative_uri + + +def test_get_git_relative_path_found(): + with patch.object( + Path, "exists", lambda self: str(self) == "/home/user/gitrepo/.git" + ): + path = Path("/home/user/gitrepo/folder/nested_folder") + assert get_git_relative_path(path) == Path("folder/nested_folder") + + +def test_get_git_relative_path_not_found(): + with patch.object(Path, "exists", lambda self: False): + path = Path("/home/user/gitrepo/folder") + assert get_git_relative_path(path) == path + + +def test_get_git_relative_uri(): + with patch.object( + Path, "exists", lambda self: str(self) == "/home/user/gitrepo/.git" + ): + pytest_rootdir = Path("/home/user/gitrepo/pytest_root") + uri = "testing/test_excinfo.py::TestFormattedExcinfo::test_fn" + assert ( + get_git_relative_uri(uri, pytest_rootdir) + == "pytest_root/testing/test_excinfo.py::TestFormattedExcinfo::test_fn" + )