Consider all configured collection paths when installing collections (#81243)

* Only install collections which can't be satisfied by a collection in any of the configured paths.

* Improve warning for unexpected collection install path

Fix warning when path is configured, but is a pip-managed path

Normalize the path before validating to fix warning consistency
pull/81149/head
Sloane Hertel 1 year ago committed by GitHub
parent c5d18c39d8
commit efbc00b6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,7 @@
bugfixes:
- >-
``ansible-galaxy`` now considers all collection paths when identifying which collection requirements are already installed.
Use the ``COLLECTIONS_PATHS`` and ``COLLECTIONS_SCAN_SYS_PATHS`` config options to modify these.
Previously only the install path was considered when resolving the candidates.
The install path will remain the only one potentially modified.
(https://github.com/ansible/ansible/issues/79767, https://github.com/ansible/ansible/issues/81163)

@ -1414,10 +1414,19 @@ class GalaxyCLI(CLI):
upgrade = context.CLIARGS.get('upgrade', False) upgrade = context.CLIARGS.get('upgrade', False)
collections_path = C.COLLECTIONS_PATHS collections_path = C.COLLECTIONS_PATHS
if (
C.GALAXY_COLLECTIONS_PATH_WARNING managed_paths = set(validate_collection_path(p) for p in C.COLLECTIONS_PATHS)
and len([p for p in collections_path if p.startswith(path)]) == 0 read_req_paths = set(validate_collection_path(p) for p in AnsibleCollectionConfig.collection_paths)
):
unexpected_path = C.GALAXY_COLLECTIONS_PATH_WARNING and not any(p.startswith(path) for p in managed_paths)
if unexpected_path and any(p.startswith(path) for p in read_req_paths):
display.warning(
f"The specified collections path '{path}' appears to be part of the pip Ansible package. "
"Managing these directly with ansible-galaxy could break the Ansible package. "
"Install collections to a configured collections path, which will take precedence over "
"collections found in the PYTHONPATH."
)
elif unexpected_path:
display.warning("The specified collections path '%s' is not part of the configured Ansible " display.warning("The specified collections path '%s' is not part of the configured Ansible "
"collections paths '%s'. The installed collection will not be picked up in an Ansible " "collections paths '%s'. The installed collection will not be picked up in an Ansible "
"run, unless within a playbook-adjacent collections directory." % (to_text(path), to_text(":".join(collections_path)))) "run, unless within a playbook-adjacent collections directory." % (to_text(path), to_text(":".join(collections_path))))
@ -1434,6 +1443,7 @@ class GalaxyCLI(CLI):
artifacts_manager=artifacts_manager, artifacts_manager=artifacts_manager,
disable_gpg_verify=disable_gpg_verify, disable_gpg_verify=disable_gpg_verify,
offline=context.CLIARGS.get('offline', False), offline=context.CLIARGS.get('offline', False),
read_requirement_paths=read_req_paths,
) )
return 0 return 0

@ -654,6 +654,7 @@ def install_collections(
artifacts_manager, # type: ConcreteArtifactsManager artifacts_manager, # type: ConcreteArtifactsManager
disable_gpg_verify, # type: bool disable_gpg_verify, # type: bool
offline, # type: bool offline, # type: bool
read_requirement_paths, # type: set[str]
): # type: (...) -> None ): # type: (...) -> None
"""Install Ansible collections to the path specified. """Install Ansible collections to the path specified.
@ -668,7 +669,8 @@ def install_collections(
""" """
existing_collections = { existing_collections = {
Requirement(coll.fqcn, coll.ver, coll.src, coll.type, None) Requirement(coll.fqcn, coll.ver, coll.src, coll.type, None)
for coll in find_existing_collections(output_path, artifacts_manager) for path in {output_path} | read_requirement_paths
for coll in find_existing_collections(path, artifacts_manager)
} }
unsatisfied_requirements = set( unsatisfied_requirements = set(

@ -14,6 +14,8 @@
command: 'ansible-galaxy collection install {{ artifact_path }} -p {{ alt_install_path }} --no-deps' command: 'ansible-galaxy collection install {{ artifact_path }} -p {{ alt_install_path }} --no-deps'
vars: vars:
artifact_path: "{{ galaxy_dir }}/ansible_test-collection_1-1.0.0.tar.gz" artifact_path: "{{ galaxy_dir }}/ansible_test-collection_1-1.0.0.tar.gz"
environment:
ANSIBLE_COLLECTIONS_PATH: ""
- name: check if the files and folders in build_ignore were respected - name: check if the files and folders in build_ignore were respected
stat: stat:

@ -822,7 +822,8 @@ def test_install_collections_from_tar(collection_artifact, monkeypatch):
concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False)
requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)]
collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True, False) collection.install_collections(
requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True, False, set())
assert os.path.isdir(collection_path) assert os.path.isdir(collection_path)
@ -860,7 +861,8 @@ def test_install_collection_with_circular_dependency(collection_artifact, monkey
concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False)
requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)]
collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True, False) collection.install_collections(
requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True, False, set())
assert os.path.isdir(collection_path) assert os.path.isdir(collection_path)
@ -897,7 +899,8 @@ def test_install_collection_with_no_dependency(collection_artifact, monkeypatch)
concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False)
requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)]
collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True, False) collection.install_collections(
requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True, False, set())
assert os.path.isdir(collection_path) assert os.path.isdir(collection_path)

Loading…
Cancel
Save