From cde68eb47ce8f19976572981538650637013a2f9 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Mon, 3 Oct 2022 21:30:27 +0200 Subject: [PATCH] Show ansible-core compatibility in collection index page (#49) * Show ansible-core compatibility in collection index page. * Fix order of specifier set. --- .../49-collection-supported-ansible-core.yml | 3 ++ pyproject.toml | 1 + .../data/docsite/plugins_by_collection.rst.j2 | 10 ++++- src/antsibull_docs/docs_parsing/__init__.py | 7 +++- .../docs_parsing/ansible_doc.py | 3 +- src/antsibull_docs/docs_parsing/routing.py | 16 ++++++- src/antsibull_docs/write_docs.py | 42 +++++++++++++++++++ .../collections/ns/col1/index.rst | 1 + .../collections/ns/col2/index.rst | 4 ++ .../collections/ns2/col/index.rst | 6 +++ .../collections/ns/col1/index.rst | 1 + .../collections/ns/col2/index.rst | 4 ++ .../collections/ns2/col/index.rst | 6 +++ .../collections/ns/col1/index.rst | 1 + .../collections/ns/col2/index.rst | 4 ++ .../collections/ns2/col/index.rst | 6 +++ .../baseline-squash-hierarchy/index.rst | 6 +++ .../collections/ns2/col/index.rst | 6 +++ 18 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/49-collection-supported-ansible-core.yml diff --git a/changelogs/fragments/49-collection-supported-ansible-core.yml b/changelogs/fragments/49-collection-supported-ansible-core.yml new file mode 100644 index 00000000..ba5ba352 --- /dev/null +++ b/changelogs/fragments/49-collection-supported-ansible-core.yml @@ -0,0 +1,3 @@ +minor_changes: + - "Antsibull-docs now depends on `packaging `__ (https://github.com/ansible-community/antsibull-docs/pull/49)." + - "The collection index pages now contain the supported versions of ansible-core of the collection in case collection's ``meta/runtime.yml`` specifies ``requires_ansible`` (https://github.com/ansible-community/antsibull-docs/issues/48, https://github.com/ansible-community/antsibull-docs/pull/49)." diff --git a/pyproject.toml b/pyproject.toml index 808c4c61..1c6010a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ antsibull-core = ">= 1.2.0, < 2.0.0" asyncio-pool = "*" docutils = "*" jinja2 = "*" +packaging = "*" rstcheck = ">= 3.0.0, < 7.0.0" sphinx = "*" diff --git a/src/antsibull_docs/data/docsite/plugins_by_collection.rst.j2 b/src/antsibull_docs/data/docsite/plugins_by_collection.rst.j2 index bb566dd2..09d86741 100644 --- a/src/antsibull_docs/data/docsite/plugins_by_collection.rst.j2 +++ b/src/antsibull_docs/data/docsite/plugins_by_collection.rst.j2 @@ -27,7 +27,7 @@ Collection version @{ collection_version }@ :local: :depth: 1 -{% if collection_description or collection_authors or collection_links %} +{% if collection_description or collection_authors or collection_links or requires_ansible %} Description ----------- @@ -43,6 +43,14 @@ Description {% endfor %} {% endif %} +{% if requires_ansible %} +**Supported ansible-core versions:** + +{% for part in requires_ansible %} +* @{ part | rst_escape }@ +{% endfor %} +{% endif %} + {% if collection_links %} .. raw:: html diff --git a/src/antsibull_docs/docs_parsing/__init__.py b/src/antsibull_docs/docs_parsing/__init__.py index 6a1e3a47..b99f4ac2 100644 --- a/src/antsibull_docs/docs_parsing/__init__.py +++ b/src/antsibull_docs/docs_parsing/__init__.py @@ -69,10 +69,15 @@ def _get_environment(collection_dir: t.Optional[str]) -> t.Dict[str, str]: class AnsibleCollectionMetadata: path: str version: t.Optional[str] + requires_ansible: t.Optional[str] - def __init__(self, path: str, version: t.Optional[str]): + def __init__(self, + path: str, + version: t.Optional[str] = None, + requires_ansible: t.Optional[str] = None): self.path = path self.version = version + self.requires_ansible = requires_ansible def __repr__(self): return f'AnsibleCollectionMetadata({repr(self.path)}, {repr(self.version)})' diff --git a/src/antsibull_docs/docs_parsing/ansible_doc.py b/src/antsibull_docs/docs_parsing/ansible_doc.py index 00636a4f..c4ab64b3 100644 --- a/src/antsibull_docs/docs_parsing/ansible_doc.py +++ b/src/antsibull_docs/docs_parsing/ansible_doc.py @@ -230,7 +230,8 @@ def get_collection_metadata(venv: t.Union['VenvRunner', 'FakeVenvRunner'], raw_result = ansible_collection_list_cmd.stdout.decode('utf-8', errors='surrogateescape') collection_list = parse_ansible_galaxy_collection_list(raw_result, collection_names) for namespace, name, path, version in collection_list: - collection_metadata[f'{namespace}.{name}'] = AnsibleCollectionMetadata( + collection_name = f'{namespace}.{name}' + collection_metadata[collection_name] = AnsibleCollectionMetadata( path=path, version=version) return collection_metadata diff --git a/src/antsibull_docs/docs_parsing/routing.py b/src/antsibull_docs/docs_parsing/routing.py index a392a95e..deabeae4 100644 --- a/src/antsibull_docs/docs_parsing/routing.py +++ b/src/antsibull_docs/docs_parsing/routing.py @@ -189,7 +189,14 @@ def remove_flatmapping_artifacts(plugin_routing: t.Dict[str, t.Dict[str, t.Dict[ plugin_routing_type.pop(plugin_name, None) -def calculate_meta_runtime(collection_name, collection_metadata): +def load_meta_runtime(collection_name: str, + collection_metadata: AnsibleCollectionMetadata) -> t.Mapping[str, t.Any]: + ''' + Load meta/runtime.yml for collections, and ansible_builtin_runtime.yml for ansible-core. + + Also extracts additional metadata stored in meta/runtime.yml, like requires_ansible, + and stores it in collection_metadata + ''' if collection_name == 'ansible.builtin': meta_runtime_path = os.path.join( collection_metadata.path, 'config', 'ansible_builtin_runtime.yml') @@ -201,6 +208,11 @@ def calculate_meta_runtime(collection_name, collection_metadata): else: meta_runtime = {} + if collection_name != 'ansible.builtin': + requires_ansible = meta_runtime.get('requires_ansible') + if isinstance(requires_ansible, str): + collection_metadata.requires_ansible = requires_ansible + return meta_runtime @@ -210,7 +222,7 @@ async def load_collection_routing(collection_name: str, """ Load plugin routing for a collection. """ - meta_runtime = calculate_meta_runtime(collection_name, collection_metadata) + meta_runtime = load_meta_runtime(collection_name, collection_metadata) plugin_routing_out: t.Dict[str, t.Dict[str, t.Dict[str, t.Any]]] = {} plugin_routing_in = meta_runtime.get('plugin_routing') or {} for plugin_type in DOCUMENTABLE_PLUGINS: diff --git a/src/antsibull_docs/write_docs.py b/src/antsibull_docs/write_docs.py index 5d36ace3..1bf1175a 100644 --- a/src/antsibull_docs/write_docs.py +++ b/src/antsibull_docs/write_docs.py @@ -13,6 +13,7 @@ import asyncio_pool # type: ignore[import] from jinja2 import Template +from packaging.specifiers import SpecifierSet from antsibull_core import app_context from antsibull_core.logging import log @@ -602,6 +603,29 @@ async def write_plugin_type_index(plugin_type: str, await write_file(dest_filename, index_contents) +def _parse_required_ansible(requires_ansible: str) -> t.List[str]: + result = [] + for specifier in reversed(sorted( + SpecifierSet(requires_ansible), + key=lambda specifier: (specifier.operator, specifier.version) + )): + if specifier.operator == '>=': + result.append(f'{specifier.version} or newer') + elif specifier.operator == '>': + result.append(f'newer than {specifier.version}') + elif specifier.operator == '<=': + result.append(f'{specifier.version} or older') + elif specifier.operator == '<': + result.append(f'older than {specifier.version}') + elif specifier.operator == '!=': + result.append(f'version {specifier.version} is specifically not supported') + elif specifier.operator == '==': + result.append(f'version {specifier.version} is specifically supported') + else: + result.append(f'{specifier.operator} {specifier.version}') + return result + + async def write_plugin_lists(collection_name: str, plugin_maps: t.Mapping[str, t.Mapping[str, str]], template: Template, @@ -627,12 +651,28 @@ async def write_plugin_lists(collection_name: str, :kwarg for_official_docsite: Default False. Set to True to use wording specific for the official docsite on docs.ansible.com. """ + flog = mlog.fields(func='write_plugin_lists') + flog.debug('Enter') + + requires_ansible = [] + if collection_name != 'ansible.builtin' and collection_meta.requires_ansible: + try: + requires_ansible = _parse_required_ansible(collection_meta.requires_ansible) + except Exception as exc: # pylint:disable=broad-except + flog.fields( + collection_name=collection_name, + exception=exc, + ).error( + 'Cannot parse required_ansible specifier set for {collection_name}', + collection_name=collection_name, + ) index_contents = _render_template( template, dest_dir, collection_name=collection_name, plugin_maps=plugin_maps, collection_version=collection_meta.version, + requires_ansible=requires_ansible, link_data=link_data, breadcrumbs=breadcrumbs, extra_docs_sections=extra_docs_data[0], @@ -650,6 +690,8 @@ async def write_plugin_lists(collection_name: str, await write_file(index_file, index_contents) + flog.debug('Leave') + async def output_collection_index(collection_to_plugin_info: CollectionInfoT, collection_namespaces: t.Mapping[str, t.List[str]], diff --git a/tests/functional/baseline-default/collections/ns/col1/index.rst b/tests/functional/baseline-default/collections/ns/col1/index.rst index f8d0d6dd..72a3e08b 100644 --- a/tests/functional/baseline-default/collections/ns/col1/index.rst +++ b/tests/functional/baseline-default/collections/ns/col1/index.rst @@ -25,6 +25,7 @@ A short description. + .. toctree:: :maxdepth: 1 diff --git a/tests/functional/baseline-default/collections/ns/col2/index.rst b/tests/functional/baseline-default/collections/ns/col2/index.rst index b395e8ad..2259e71b 100644 --- a/tests/functional/baseline-default/collections/ns/col2/index.rst +++ b/tests/functional/baseline-default/collections/ns/col2/index.rst @@ -20,6 +20,10 @@ Description * Ansible (https://github.com/ansible) +**Supported ansible-core versions:** + +* newer than 2.11.0 + diff --git a/tests/functional/baseline-default/collections/ns2/col/index.rst b/tests/functional/baseline-default/collections/ns2/col/index.rst index 05a43cc3..4fa9cf5c 100644 --- a/tests/functional/baseline-default/collections/ns2/col/index.rst +++ b/tests/functional/baseline-default/collections/ns2/col/index.rst @@ -24,6 +24,12 @@ With multiple paragraphs. * Ansible (https://github.com/ansible) +**Supported ansible-core versions:** + +* 2.11.0 or newer +* older than 2.99.0 +* version 2.12.2 is specifically not supported + .. raw:: html