diff --git a/changelogs/fragments/drop-resolvelib-lt-0_8_0.yml b/changelogs/fragments/drop-resolvelib-lt-0_8_0.yml new file mode 100644 index 00000000000..66c5a2a8c85 --- /dev/null +++ b/changelogs/fragments/drop-resolvelib-lt-0_8_0.yml @@ -0,0 +1,2 @@ +removed_features: + - ansible-galaxy - remove support for resolvelib >= 0.5.3, < 0.8.0. diff --git a/lib/ansible/galaxy/dependency_resolution/providers.py b/lib/ansible/galaxy/dependency_resolution/providers.py index 8cfb14b0b15..1df0e9b7af2 100644 --- a/lib/ansible/galaxy/dependency_resolution/providers.py +++ b/lib/ansible/galaxy/dependency_resolution/providers.py @@ -5,6 +5,7 @@ from __future__ import annotations +import collections.abc as _c import functools import typing as t @@ -37,16 +38,16 @@ except ImportError: # TODO: add python requirements to ansible-test's ansible-core distribution info and remove the hardcoded lowerbound/upperbound fallback -RESOLVELIB_LOWERBOUND = SemanticVersion("0.5.3") +RESOLVELIB_LOWERBOUND = SemanticVersion("0.8.0") RESOLVELIB_UPPERBOUND = SemanticVersion("2.0.0") RESOLVELIB_VERSION = SemanticVersion.from_loose_version(LooseVersion(resolvelib_version)) -class CollectionDependencyProviderBase(AbstractProvider): +class CollectionDependencyProvider(AbstractProvider): """Delegate providing a requirement interface for the resolver.""" def __init__( - self, # type: CollectionDependencyProviderBase + self, apis, # type: MultiGalaxyAPIProxy concrete_artifacts_manager=None, # type: ConcreteArtifactsManager preferred_candidates=None, # type: t.Iterable[Candidate] @@ -102,8 +103,14 @@ class CollectionDependencyProviderBase(AbstractProvider): """ return requirement_or_candidate.canonical_package_id - def get_preference(self, *args, **kwargs): - # type: (t.Any, t.Any) -> t.Union[float, int] + def get_preference( + self, + identifier: str, + resolutions: _c.Mapping[str, Candidate], + candidates: _c.Mapping[str, _c.Iterator[Candidate]], + information: _c.Iterator[t.NamedTuple], + backtrack_causes: _c.Sequence, + ) -> float | int: """Return sort key function return value for given requirement. This result should be based on preference that is defined as @@ -111,38 +118,6 @@ class CollectionDependencyProviderBase(AbstractProvider): The lower the return value is, the more preferred this group of arguments is. - resolvelib >=0.5.3, <0.7.0 - - :param resolution: Currently pinned candidate, or ``None``. - - :param candidates: A list of possible candidates. - - :param information: A list of requirement information. - - Each ``information`` instance is a named tuple with two entries: - - * ``requirement`` specifies a requirement contributing to - the current candidate list - - * ``parent`` specifies the candidate that provides - (depended on) the requirement, or `None` - to indicate a root requirement. - - resolvelib >=0.7.0, < 0.8.0 - - :param identifier: The value returned by ``identify()``. - - :param resolutions: Mapping of identifier, candidate pairs. - - :param candidates: Possible candidates for the identifier. - Mapping of identifier, list of candidate pairs. - - :param information: Requirement information of each package. - Mapping of identifier, list of named tuple pairs. - The named tuples have the entries ``requirement`` and ``parent``. - - resolvelib >=0.8.0, <= 1.0.1 - :param identifier: The value returned by ``identify()``. :param resolutions: Mapping of identifier, candidate pairs. @@ -178,10 +153,6 @@ class CollectionDependencyProviderBase(AbstractProvider): the value is, the more preferred this requirement is (i.e. the sorting function is called with ``reverse=False``). """ - raise NotImplementedError - - def _get_preference(self, candidates): - # type: (list[Candidate]) -> t.Union[float, int] if any( candidate in self._preferred_candidates for candidate in candidates @@ -191,8 +162,12 @@ class CollectionDependencyProviderBase(AbstractProvider): return float('-inf') return len(candidates) - def find_matches(self, *args, **kwargs): - # type: (t.Any, t.Any) -> list[Candidate] + def find_matches( + self, + identifier: str, + requirements: _c.Mapping[str, _c.Iterator[Requirement]], + incompatibilities: _c.Mapping[str, _c.Iterator[Candidate]], + ) -> list[Candidate]: r"""Find all possible candidates satisfying given requirements. This tries to get candidates based on the requirements' types. @@ -203,32 +178,13 @@ class CollectionDependencyProviderBase(AbstractProvider): For a "named" requirement, Galaxy-compatible APIs are consulted to find concrete candidates for this requirement. If there's a pre-installed candidate, it's prepended in front of others. - - resolvelib >=0.5.3, <0.6.0 - - :param requirements: A collection of requirements which all of \ - the returned candidates must match. \ - All requirements are guaranteed to have \ - the same identifier. \ - The collection is never empty. - - resolvelib >=0.6.0 - - :param identifier: The value returned by ``identify()``. - - :param requirements: The requirements all returned candidates must satisfy. - Mapping of identifier, iterator of requirement pairs. - - :param incompatibilities: Incompatible versions that must be excluded - from the returned list. - - :returns: An iterable that orders candidates by preference, \ - e.g. the most preferred candidate comes first. """ - raise NotImplementedError + return [ + match for match in self._find_matches(list(requirements[identifier])) + if not any(match.ver == incompat.ver for incompat in incompatibilities[identifier]) + ] - def _find_matches(self, requirements): - # type: (list[Requirement]) -> list[Candidate] + def _find_matches(self, requirements: list[Requirement]) -> list[Candidate]: # FIXME: The first requirement may be a Git repo followed by # FIXME: its cloned tmp dir. Using only the first one creates # FIXME: loops that prevent any further dependency exploration. @@ -456,52 +412,3 @@ class CollectionDependencyProviderBase(AbstractProvider): self._make_req_from_dict({'name': dep_name, 'version': dep_req}) for dep_name, dep_req in req_map.items() ] - - -# Classes to handle resolvelib API changes between minor versions for 0.X -class CollectionDependencyProvider050(CollectionDependencyProviderBase): - def find_matches(self, requirements): # type: ignore[override] - # type: (list[Requirement]) -> list[Candidate] - return self._find_matches(requirements) - - def get_preference(self, resolution, candidates, information): # type: ignore[override] - # type: (t.Optional[Candidate], list[Candidate], list[t.NamedTuple]) -> t.Union[float, int] - return self._get_preference(candidates) - - -class CollectionDependencyProvider060(CollectionDependencyProviderBase): - def find_matches(self, identifier, requirements, incompatibilities): # type: ignore[override] - # type: (str, t.Mapping[str, t.Iterator[Requirement]], t.Mapping[str, t.Iterator[Requirement]]) -> list[Candidate] - return [ - match for match in self._find_matches(list(requirements[identifier])) - if not any(match.ver == incompat.ver for incompat in incompatibilities[identifier]) - ] - - def get_preference(self, resolution, candidates, information): # type: ignore[override] - # type: (t.Optional[Candidate], list[Candidate], list[t.NamedTuple]) -> t.Union[float, int] - return self._get_preference(candidates) - - -class CollectionDependencyProvider070(CollectionDependencyProvider060): - def get_preference(self, identifier, resolutions, candidates, information): # type: ignore[override] - # type: (str, t.Mapping[str, Candidate], t.Mapping[str, t.Iterator[Candidate]], t.Iterator[t.NamedTuple]) -> t.Union[float, int] - return self._get_preference(list(candidates[identifier])) - - -class CollectionDependencyProvider080(CollectionDependencyProvider060): - def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # type: ignore[override] - # type: (str, t.Mapping[str, Candidate], t.Mapping[str, t.Iterator[Candidate]], t.Iterator[t.NamedTuple], t.Sequence) -> t.Union[float, int] - return self._get_preference(list(candidates[identifier])) - - -def _get_provider(): # type () -> CollectionDependencyProviderBase - if RESOLVELIB_VERSION >= SemanticVersion("0.8.0"): - return CollectionDependencyProvider080 - if RESOLVELIB_VERSION >= SemanticVersion("0.7.0"): - return CollectionDependencyProvider070 - if RESOLVELIB_VERSION >= SemanticVersion("0.6.0"): - return CollectionDependencyProvider060 - return CollectionDependencyProvider050 - - -CollectionDependencyProvider = _get_provider() diff --git a/test/integration/targets/ansible-galaxy-collection-scm/vars/main.yml b/test/integration/targets/ansible-galaxy-collection-scm/vars/main.yml index cd198c64b9f..2de572093d4 100644 --- a/test/integration/targets/ansible-galaxy-collection-scm/vars/main.yml +++ b/test/integration/targets/ansible-galaxy-collection-scm/vars/main.yml @@ -5,7 +5,5 @@ test_repo_path: "{{ galaxy_dir }}/development/ansible_test" test_error_repo_path: "{{ galaxy_dir }}/development/error_test" supported_resolvelib_versions: - - "0.5.3" # Oldest supported - - "0.6.0" - - "0.7.0" - - "0.8.0" + - "0.8.0" # Oldest supported + - "< 2.0.0" diff --git a/test/integration/targets/ansible-galaxy-collection/vars/main.yml b/test/integration/targets/ansible-galaxy-collection/vars/main.yml index c865871c4fe..855b382e5ca 100644 --- a/test/integration/targets/ansible-galaxy-collection/vars/main.yml +++ b/test/integration/targets/ansible-galaxy-collection/vars/main.yml @@ -5,18 +5,14 @@ gpg_homedir: "{{ galaxy_dir }}/gpg" offline_server: https://test-hub.demolab.local/api/galaxy/content/api/ # Test oldest and most recently supported, and versions with notable changes. -# The last breaking change for a feature ansible-galaxy uses was in 0.8.0. -# It would be redundant to test every minor version since 0.8.0, so we just test against the latest minor release. # NOTE: If ansible-galaxy incorporates new resolvelib features, this matrix should be updated to verify the features work on all supported versions. supported_resolvelib_versions: - - "0.5.3" # test CollectionDependencyProvider050 - - "0.6.0" # test CollectionDependencyProvider060 - - "0.7.0" # test CollectionDependencyProvider070 - - "<2.0.0" # test CollectionDependencyProvider080 + - "0.8.0" + - "< 2.0.0" unsupported_resolvelib_versions: - "0.2.0" # Fails on import - - "0.5.1" + - "0.5.3" pulp_repositories: - primary