diff --git a/src/poetry/puzzle/provider.py b/src/poetry/puzzle/provider.py index 523228c9e88..516b6990afc 100644 --- a/src/poetry/puzzle/provider.py +++ b/src/poetry/puzzle/provider.py @@ -581,6 +581,12 @@ def complete_package( # Retrieving constraints for deferred dependencies for r in requires: if r.is_direct_origin(): + locked = self.get_locked(r) + # If lock file contains exactly the same URL and reference + # (commit hash) of dependency as is requested, + # do not analyze it again: nothing could have changed. + if locked is not None and locked.package.is_same_package_as(r): + continue self.search_for_direct_origin_dependency(r) optional_dependencies = [] diff --git a/tests/puzzle/test_solver.py b/tests/puzzle/test_solver.py index 92a39849b81..2bfd4f8313a 100644 --- a/tests/puzzle/test_solver.py +++ b/tests/puzzle/test_solver.py @@ -34,6 +34,8 @@ if TYPE_CHECKING: import httpretty + from pytest_mock import MockerFixture + from poetry.installation.operations.operation import Operation from poetry.puzzle.provider import Provider from poetry.puzzle.transaction import Transaction @@ -3454,6 +3456,97 @@ def test_solver_keeps_multiple_locked_dependencies_for_same_package( ) +@pytest.mark.parametrize("is_locked", [False, True]) +def test_solver_does_not_update_ref_of_locked_vcs_package( + package: ProjectPackage, + repo: Repository, + pool: Pool, + io: NullIO, + is_locked: bool, +): + locked_ref = "123456" + latest_ref = "9cf87a285a2d3fbb0b9fa621997b3acc3631ed24" + demo_locked = Package( + "demo", + "0.1.2", + source_type="git", + source_url="https://github.com/demo/demo.git", + source_reference=DEFAULT_SOURCE_REF, + source_resolved_reference=locked_ref, + ) + demo_locked.add_dependency(Factory.create_dependency("pendulum", "*")) + demo_latest = Package( + "demo", + "0.1.2", + source_type="git", + source_url="https://github.com/demo/demo.git", + source_reference=DEFAULT_SOURCE_REF, + source_resolved_reference=latest_ref, + ) + locked = [demo_locked] if is_locked else [] + + package.add_dependency( + Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"}) + ) + + # transient dependencies of demo + pendulum = get_package("pendulum", "2.0.3") + repo.add_package(pendulum) + + solver = Solver(package, pool, [], locked, io) + transaction = solver.solve() + + ops = check_solver_result( + transaction, + [ + {"job": "install", "package": pendulum}, + {"job": "install", "package": demo_locked if is_locked else demo_latest}, + ], + ) + + op = ops[1] + + assert op.package.source_type == "git" + assert op.package.source_reference == DEFAULT_SOURCE_REF + assert ( + op.package.source_resolved_reference == locked_ref if is_locked else latest_ref + ) + + +def test_solver_does_not_fetch_locked_vcs_package_with_ref( + package: ProjectPackage, + repo: Repository, + pool: Pool, + io: NullIO, + mocker: MockerFixture, +): + locked_ref = "123456" + demo_locked = Package( + "demo", + "0.1.2", + source_type="git", + source_url="https://github.com/demo/demo.git", + source_reference=DEFAULT_SOURCE_REF, + source_resolved_reference=locked_ref, + ) + demo_locked.add_dependency(Factory.create_dependency("pendulum", "*")) + + package.add_dependency( + Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"}) + ) + + # transient dependencies of demo + pendulum = get_package("pendulum", "2.0.3") + repo.add_package(pendulum) + + solver = Solver(package, pool, [], [demo_locked], io) + spy = mocker.spy(solver._provider, "_search_for_vcs") + + solver.solve() + + spy.assert_not_called() + + def test_solver_direct_origin_dependency_with_extras_requested_by_other_package( solver: Solver, repo: Repository, package: ProjectPackage ):