diff --git a/changelogs/fragments/85361-collection-name-from-path-none.yml b/changelogs/fragments/85361-collection-name-from-path-none.yml new file mode 100644 index 00000000000..4acbbe8af1a --- /dev/null +++ b/changelogs/fragments/85361-collection-name-from-path-none.yml @@ -0,0 +1,3 @@ +bugfixes: + - "ansible-doc - prevent crash when scanning collections in paths that have more than one ``ansible_collections`` in it + (https://github.com/ansible/ansible/issues/84909, https://github.com/ansible/ansible/pull/85361)." diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index 719afd2a4f9..45f4cc75f46 100755 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -231,7 +231,9 @@ class RoleMixin(object): b_colldirs = list_collection_dirs(coll_filter=collection_filter) for b_path in b_colldirs: path = to_text(b_path, errors='surrogate_or_strict') - collname = _get_collection_name_from_path(b_path) + if not (collname := _get_collection_name_from_path(b_path)): + display.debug(f'Skipping invalid path {b_path!r}') + continue roles_dir = os.path.join(path, 'roles') if os.path.exists(roles_dir): diff --git a/lib/ansible/collections/list.py b/lib/ansible/collections/list.py index 473c56d0945..1c8fdae9508 100644 --- a/lib/ansible/collections/list.py +++ b/lib/ansible/collections/list.py @@ -17,8 +17,10 @@ def list_collections(coll_filter=None, search_paths=None, dedupe=True, artifacts collections = {} for candidate in list_collection_dirs(search_paths=search_paths, coll_filter=coll_filter, artifacts_manager=artifacts_manager, dedupe=dedupe): - collection = _get_collection_name_from_path(candidate) - collections[collection] = candidate + if collection := _get_collection_name_from_path(candidate): + collections[collection] = candidate + else: + display.debug(f'Skipping invalid collection in path: {candidate!r}') return collections diff --git a/test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/playbooks/collections/ansible_collections/ns/col/plugins/modules/test.py b/test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/playbooks/collections/ansible_collections/ns/col/plugins/modules/test.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/integration/targets/ansible-doc/runme.sh b/test/integration/targets/ansible-doc/runme.sh index 93a0d1b2500..752ab6d2672 100755 --- a/test/integration/targets/ansible-doc/runme.sh +++ b/test/integration/targets/ansible-doc/runme.sh @@ -208,6 +208,13 @@ ANSIBLE_LIBRARY='./nolibrary' ansible-doc --metadata-dump --no-fail-on-errors -- output=$(ANSIBLE_LIBRARY='./nolibrary' ansible-doc --metadata-dump --playbook-dir broken-docs testns.testcol 2>&1 | grep -c 'ERROR!' || true) test "${output}" -eq 1 +# ensure --metadata-dump does not crash if the ansible_collections is nested (https://github.com/ansible/ansible/issues/84909) +testdir="$(pwd)" +pbdir="collections/ansible_collections/testns/testcol/playbooks" +cd "$pbdir" +ANSIBLE_COLLECTIONS_PATH="$testdir/$pbdir/collections" ansible-doc -vvv --metadata-dump --no-fail-on-errors +cd "$testdir" + # ensure that role doc does not fail when --no-fail-on-errors is supplied ANSIBLE_LIBRARY='./nolibrary' ansible-doc --no-fail-on-errors --playbook-dir broken-docs testns.testcol.testrole -t role 1>/dev/null 2>&1