Skip to content

Commit cde68eb

Browse files
authored
Show ansible-core compatibility in collection index page (#49)
* Show ansible-core compatibility in collection index page. * Fix order of specifier set.
1 parent 141b9b0 commit cde68eb

File tree

18 files changed

+122
-5
lines changed

18 files changed

+122
-5
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
minor_changes:
2+
- "Antsibull-docs now depends on `packaging <https://pypi.org/project/packaging/>`__ (https://github.com/ansible-community/antsibull-docs/pull/49)."
3+
- "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)."

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ antsibull-core = ">= 1.2.0, < 2.0.0"
3939
asyncio-pool = "*"
4040
docutils = "*"
4141
jinja2 = "*"
42+
packaging = "*"
4243
rstcheck = ">= 3.0.0, < 7.0.0"
4344
sphinx = "*"
4445

src/antsibull_docs/data/docsite/plugins_by_collection.rst.j2

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Collection version @{ collection_version }@
2727
:local:
2828
:depth: 1
2929

30-
{% if collection_description or collection_authors or collection_links %}
30+
{% if collection_description or collection_authors or collection_links or requires_ansible %}
3131
Description
3232
-----------
3333

@@ -43,6 +43,14 @@ Description
4343
{% endfor %}
4444
{% endif %}
4545

46+
{% if requires_ansible %}
47+
**Supported ansible-core versions:**
48+
49+
{% for part in requires_ansible %}
50+
* @{ part | rst_escape }@
51+
{% endfor %}
52+
{% endif %}
53+
4654
{% if collection_links %}
4755
.. raw:: html
4856

src/antsibull_docs/docs_parsing/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,15 @@ def _get_environment(collection_dir: t.Optional[str]) -> t.Dict[str, str]:
6969
class AnsibleCollectionMetadata:
7070
path: str
7171
version: t.Optional[str]
72+
requires_ansible: t.Optional[str]
7273

73-
def __init__(self, path: str, version: t.Optional[str]):
74+
def __init__(self,
75+
path: str,
76+
version: t.Optional[str] = None,
77+
requires_ansible: t.Optional[str] = None):
7478
self.path = path
7579
self.version = version
80+
self.requires_ansible = requires_ansible
7681

7782
def __repr__(self):
7883
return f'AnsibleCollectionMetadata({repr(self.path)}, {repr(self.version)})'

src/antsibull_docs/docs_parsing/ansible_doc.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ def get_collection_metadata(venv: t.Union['VenvRunner', 'FakeVenvRunner'],
230230
raw_result = ansible_collection_list_cmd.stdout.decode('utf-8', errors='surrogateescape')
231231
collection_list = parse_ansible_galaxy_collection_list(raw_result, collection_names)
232232
for namespace, name, path, version in collection_list:
233-
collection_metadata[f'{namespace}.{name}'] = AnsibleCollectionMetadata(
233+
collection_name = f'{namespace}.{name}'
234+
collection_metadata[collection_name] = AnsibleCollectionMetadata(
234235
path=path, version=version)
235236

236237
return collection_metadata

src/antsibull_docs/docs_parsing/routing.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,14 @@ def remove_flatmapping_artifacts(plugin_routing: t.Dict[str, t.Dict[str, t.Dict[
189189
plugin_routing_type.pop(plugin_name, None)
190190

191191

192-
def calculate_meta_runtime(collection_name, collection_metadata):
192+
def load_meta_runtime(collection_name: str,
193+
collection_metadata: AnsibleCollectionMetadata) -> t.Mapping[str, t.Any]:
194+
'''
195+
Load meta/runtime.yml for collections, and ansible_builtin_runtime.yml for ansible-core.
196+
197+
Also extracts additional metadata stored in meta/runtime.yml, like requires_ansible,
198+
and stores it in collection_metadata
199+
'''
193200
if collection_name == 'ansible.builtin':
194201
meta_runtime_path = os.path.join(
195202
collection_metadata.path, 'config', 'ansible_builtin_runtime.yml')
@@ -201,6 +208,11 @@ def calculate_meta_runtime(collection_name, collection_metadata):
201208
else:
202209
meta_runtime = {}
203210

211+
if collection_name != 'ansible.builtin':
212+
requires_ansible = meta_runtime.get('requires_ansible')
213+
if isinstance(requires_ansible, str):
214+
collection_metadata.requires_ansible = requires_ansible
215+
204216
return meta_runtime
205217

206218

@@ -210,7 +222,7 @@ async def load_collection_routing(collection_name: str,
210222
"""
211223
Load plugin routing for a collection.
212224
"""
213-
meta_runtime = calculate_meta_runtime(collection_name, collection_metadata)
225+
meta_runtime = load_meta_runtime(collection_name, collection_metadata)
214226
plugin_routing_out: t.Dict[str, t.Dict[str, t.Dict[str, t.Any]]] = {}
215227
plugin_routing_in = meta_runtime.get('plugin_routing') or {}
216228
for plugin_type in DOCUMENTABLE_PLUGINS:

src/antsibull_docs/write_docs.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import asyncio_pool # type: ignore[import]
1414

1515
from jinja2 import Template
16+
from packaging.specifiers import SpecifierSet
1617

1718
from antsibull_core import app_context
1819
from antsibull_core.logging import log
@@ -602,6 +603,29 @@ async def write_plugin_type_index(plugin_type: str,
602603
await write_file(dest_filename, index_contents)
603604

604605

606+
def _parse_required_ansible(requires_ansible: str) -> t.List[str]:
607+
result = []
608+
for specifier in reversed(sorted(
609+
SpecifierSet(requires_ansible),
610+
key=lambda specifier: (specifier.operator, specifier.version)
611+
)):
612+
if specifier.operator == '>=':
613+
result.append(f'{specifier.version} or newer')
614+
elif specifier.operator == '>':
615+
result.append(f'newer than {specifier.version}')
616+
elif specifier.operator == '<=':
617+
result.append(f'{specifier.version} or older')
618+
elif specifier.operator == '<':
619+
result.append(f'older than {specifier.version}')
620+
elif specifier.operator == '!=':
621+
result.append(f'version {specifier.version} is specifically not supported')
622+
elif specifier.operator == '==':
623+
result.append(f'version {specifier.version} is specifically supported')
624+
else:
625+
result.append(f'{specifier.operator} {specifier.version}')
626+
return result
627+
628+
605629
async def write_plugin_lists(collection_name: str,
606630
plugin_maps: t.Mapping[str, t.Mapping[str, str]],
607631
template: Template,
@@ -627,12 +651,28 @@ async def write_plugin_lists(collection_name: str,
627651
:kwarg for_official_docsite: Default False. Set to True to use wording specific for the
628652
official docsite on docs.ansible.com.
629653
"""
654+
flog = mlog.fields(func='write_plugin_lists')
655+
flog.debug('Enter')
656+
657+
requires_ansible = []
658+
if collection_name != 'ansible.builtin' and collection_meta.requires_ansible:
659+
try:
660+
requires_ansible = _parse_required_ansible(collection_meta.requires_ansible)
661+
except Exception as exc: # pylint:disable=broad-except
662+
flog.fields(
663+
collection_name=collection_name,
664+
exception=exc,
665+
).error(
666+
'Cannot parse required_ansible specifier set for {collection_name}',
667+
collection_name=collection_name,
668+
)
630669
index_contents = _render_template(
631670
template,
632671
dest_dir,
633672
collection_name=collection_name,
634673
plugin_maps=plugin_maps,
635674
collection_version=collection_meta.version,
675+
requires_ansible=requires_ansible,
636676
link_data=link_data,
637677
breadcrumbs=breadcrumbs,
638678
extra_docs_sections=extra_docs_data[0],
@@ -650,6 +690,8 @@ async def write_plugin_lists(collection_name: str,
650690

651691
await write_file(index_file, index_contents)
652692

693+
flog.debug('Leave')
694+
653695

654696
async def output_collection_index(collection_to_plugin_info: CollectionInfoT,
655697
collection_namespaces: t.Mapping[str, t.List[str]],

tests/functional/baseline-default/collections/ns/col1/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ A short description.
2525

2626

2727

28+
2829
.. toctree::
2930
:maxdepth: 1
3031

tests/functional/baseline-default/collections/ns/col2/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Description
2020

2121
* Ansible (https://github.com/ansible)
2222

23+
**Supported ansible-core versions:**
24+
25+
* newer than 2.11.0
26+
2327

2428

2529

tests/functional/baseline-default/collections/ns2/col/index.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ With multiple paragraphs.
2424

2525
* Ansible (https://github.com/ansible)
2626

27+
**Supported ansible-core versions:**
28+
29+
* 2.11.0 or newer
30+
* older than 2.99.0
31+
* version 2.12.2 is specifically not supported
32+
2733
.. raw:: html
2834

2935
<p class="ansible-links">

0 commit comments

Comments
 (0)