Skip to content

Commit 2b48e6d

Browse files
committed
Hide private plugins.
1 parent 2f3cb0e commit 2b48e6d

File tree

17 files changed

+1415
-25
lines changed

17 files changed

+1415
-25
lines changed

changelogs/fragments/65-private.yml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
minor_changes:
2+
- "Supports hiding private plugins (https://github.com/ansible-community/antsibull-docs/pull/65)."

src/antsibull_docs/cli/doc_commands/_build.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def generate_docs_for_all_collections(venv: VenvRunner | FakeVenvRunner,
170170
breadcrumbs=breadcrumbs,
171171
for_official_docsite=for_official_docsite))
172172
flog.notice('Finished writing collection namespace index')
173-
asyncio.run(output_plugin_indexes(plugin_contents, dest_dir,
173+
asyncio.run(output_plugin_indexes(plugin_contents, collection_metadata, dest_dir,
174174
collection_url=collection_url,
175175
collection_install=collection_install,
176176
for_official_docsite=for_official_docsite))

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

+2
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ Index of all @{ plugin_type | capitalize }@ Plugins
3737
* :ref:`@{ collection_name }@.@{ plugin_name }@ <ansible_collections.@{ collection_name }@.@{ plugin_name }@_@{ plugin_type }@>` -- @{ plugin_desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type=plugin_type) }@
3838
{% endfor %}
3939

40+
{% else %}
41+
No public {% if plugin_type == 'module' %}module{% elif plugin_type == 'role' %}role{% else %}@{ plugin_type }@ plugin{% endif %} found.
4042
{% endfor %}

src/antsibull_docs/docs_parsing/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from __future__ import annotations
99

1010
import os
11+
from collections.abc import Mapping
1112

1213
from antsibull_core.venv import FakeVenvRunner, VenvRunner
1314

@@ -75,14 +76,17 @@ class AnsibleCollectionMetadata:
7576
path: str
7677
version: str | None
7778
requires_ansible: str | None
79+
private_plugins: Mapping[str, list[str]] # mapping plugin_type to FQCNs
7880

7981
def __init__(self,
8082
path: str,
8183
version: str | None = None,
82-
requires_ansible: str | None = None):
84+
requires_ansible: str | None = None,
85+
private_plugins: Mapping[str, list[str]] | None = None):
8386
self.path = path
8487
self.version = version
8588
self.requires_ansible = requires_ansible
89+
self.private_plugins = private_plugins or {}
8690

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

src/antsibull_docs/docs_parsing/routing.py

+31-18
Original file line numberDiff line numberDiff line change
@@ -215,41 +215,54 @@ def load_meta_runtime(collection_name: str,
215215
return meta_runtime
216216

217217

218+
def _add_symlink_redirects(collection_name: str,
219+
collection_metadata: AnsibleCollectionMetadata,
220+
plugin_routing_out: dict[str, dict[str, dict[str, t.Any]]]
221+
) -> None:
222+
for plugin_type in DOCUMENTABLE_PLUGINS:
223+
directory_name = 'modules' if plugin_type == 'module' else plugin_type
224+
directory_path = os.path.join(collection_metadata.path, 'plugins', directory_name)
225+
plugin_type_routing = plugin_routing_out[plugin_type]
226+
227+
symlink_redirects = find_symlink_redirects(collection_name, plugin_type, directory_path)
228+
for redirect_name, redirect_dst in symlink_redirects.items():
229+
if redirect_name not in plugin_type_routing:
230+
plugin_type_routing[redirect_name] = {}
231+
if 'redirect' not in plugin_type_routing[redirect_name]:
232+
plugin_type_routing[redirect_name]['redirect'] = redirect_dst
233+
if plugin_type_routing[redirect_name]['redirect'] == redirect_dst:
234+
plugin_type_routing[redirect_name]['redirect_is_symlink'] = True
235+
236+
218237
async def load_collection_routing(collection_name: str,
219238
collection_metadata: AnsibleCollectionMetadata
220239
) -> dict[str, dict[str, dict[str, t.Any]]]:
221240
"""
222-
Load plugin routing for a collection.
241+
Load plugin routing for a collection, and populate the private plugins lists
242+
in collection metadata.
223243
"""
224244
meta_runtime = load_meta_runtime(collection_name, collection_metadata)
225245
plugin_routing_out: dict[str, dict[str, dict[str, t.Any]]] = {}
226246
plugin_routing_in = meta_runtime.get('plugin_routing') or {}
247+
private_plugins: dict[str, list[str]] = {}
248+
collection_metadata.private_plugins = private_plugins
227249
for plugin_type in DOCUMENTABLE_PLUGINS:
228250
plugin_type_id = 'modules' if plugin_type == 'module' else plugin_type
229251
plugin_type_routing = plugin_routing_in.get(plugin_type_id) or {}
230-
plugin_routing_out[plugin_type] = {
231-
f'{collection_name}.{plugin_name}': process_dates(plugin_record)
232-
for plugin_name, plugin_record in plugin_type_routing.items()
233-
}
252+
plugin_routing_out[plugin_type] = {}
253+
private_plugins[plugin_type] = []
254+
for plugin_name, plugin_record in plugin_type_routing.items():
255+
fqcn = f'{collection_name}.{plugin_name}'
256+
plugin_routing_out[plugin_type][fqcn] = process_dates(plugin_record)
257+
if plugin_record.get('private', False):
258+
private_plugins[plugin_type].append(plugin_name)
234259

235260
if collection_name == 'ansible.builtin':
236261
# ansible-core has a special directory structure we currently do not want
237262
# (or need) to handle
238263
return plugin_routing_out
239264

240-
for plugin_type in DOCUMENTABLE_PLUGINS:
241-
directory_name = 'modules' if plugin_type == 'module' else plugin_type
242-
directory_path = os.path.join(collection_metadata.path, 'plugins', directory_name)
243-
plugin_type_routing = plugin_routing_out[plugin_type]
244-
245-
symlink_redirects = find_symlink_redirects(collection_name, plugin_type, directory_path)
246-
for redirect_name, redirect_dst in symlink_redirects.items():
247-
if redirect_name not in plugin_type_routing:
248-
plugin_type_routing[redirect_name] = {}
249-
if 'redirect' not in plugin_type_routing[redirect_name]:
250-
plugin_type_routing[redirect_name]['redirect'] = redirect_dst
251-
if plugin_type_routing[redirect_name]['redirect'] == redirect_dst:
252-
plugin_type_routing[redirect_name]['redirect_is_symlink'] = True
265+
_add_symlink_redirects(collection_name, collection_metadata, plugin_routing_out)
253266

254267
if collection_name in COLLECTIONS_WITH_FLATMAPPING:
255268
remove_flatmapping_artifacts(plugin_routing_out)

src/antsibull_docs/write_docs/collections.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,22 @@ async def write_plugin_lists(collection_name: str,
9494
'Cannot parse required_ansible specifier set for {collection_name}',
9595
collection_name=collection_name,
9696
)
97+
98+
public_plugin_maps: dict[str, Mapping[str, str]] = {}
99+
for plugin_type, plugin_data in plugin_maps.items():
100+
private_plugins = collection_meta.private_plugins.get(plugin_type) or []
101+
public_plugin_data = {}
102+
for plugin_name, plugin_info in plugin_data.items():
103+
if plugin_name not in private_plugins:
104+
public_plugin_data[plugin_name] = plugin_info
105+
if public_plugin_data:
106+
public_plugin_maps[plugin_type] = public_plugin_data
107+
97108
index_contents = _render_template(
98109
template,
99110
dest_dir,
100111
collection_name=collection_name,
101-
plugin_maps=plugin_maps,
112+
plugin_maps=public_plugin_maps,
102113
collection_version=collection_meta.version,
103114
requires_ansible=requires_ansible,
104115
link_data=link_data,

src/antsibull_docs/write_docs/indexes.py

+19-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from antsibull_core.utils.io import write_file
1919
from jinja2 import Template
2020

21+
from ..docs_parsing import AnsibleCollectionMetadata
2122
from ..env_variables import EnvironmentVariableInfo
2223
from ..jinja2.environment import doc_environment
2324
from ..utils.collection_name_transformer import CollectionNameTransformer
@@ -55,6 +56,7 @@ async def write_callback_type_index(callback_type: str,
5556

5657
async def write_plugin_type_index(plugin_type: str,
5758
per_collection_plugins: Mapping[str, Mapping[str, str]],
59+
collection_metadata: Mapping[str, AnsibleCollectionMetadata],
5860
template: Template,
5961
dest_filename: str,
6062
for_official_docsite: bool = False) -> None:
@@ -64,16 +66,28 @@ async def write_plugin_type_index(plugin_type: str,
6466
:arg plugin_type: The plugin type to write the index for.
6567
:arg per_collection_plugins: Mapping of collection_name to Mapping of plugin_name to
6668
short_description.
69+
:arg collection_metadata: Dictionary mapping collection names to collection metadata objects.
6770
:arg template: A template to render the plugin index.
6871
:arg dest_filename: The destination filename.
6972
:kwarg for_official_docsite: Default False. Set to True to use wording specific for the
7073
official docsite on docs.ansible.com.
7174
"""
75+
public_per_collection_plugins = {}
76+
for collection_name, plugins in per_collection_plugins.items():
77+
public_plugins = {}
78+
collection_meta = collection_metadata[collection_name]
79+
private_plugins = collection_meta.private_plugins.get(plugin_type) or []
80+
for plugin_name, plugin_data in plugins.items():
81+
if plugin_name not in private_plugins:
82+
public_plugins[plugin_name] = plugin_data
83+
if public_plugins:
84+
public_per_collection_plugins[collection_name] = public_plugins
85+
7286
index_contents = _render_template(
7387
template,
7488
dest_filename,
7589
plugin_type=plugin_type,
76-
per_collection_plugins=per_collection_plugins,
90+
per_collection_plugins=public_per_collection_plugins,
7791
for_official_docsite=for_official_docsite,
7892
)
7993

@@ -128,6 +142,7 @@ async def output_callback_indexes(plugin_info: PluginCollectionInfoT,
128142

129143

130144
async def output_plugin_indexes(plugin_info: PluginCollectionInfoT,
145+
collection_metadata: Mapping[str, AnsibleCollectionMetadata],
131146
dest_dir: str,
132147
collection_url: CollectionNameTransformer,
133148
collection_install: CollectionNameTransformer,
@@ -137,6 +152,7 @@ async def output_plugin_indexes(plugin_info: PluginCollectionInfoT,
137152
138153
:arg plugin_info: Mapping of plugin_type to Mapping of collection_name to Mapping of
139154
plugin_name to short_description.
155+
:arg collection_metadata: Dictionary mapping collection names to collection metadata objects.
140156
:arg dest_dir: The directory to place the documentation in.
141157
:kwarg for_official_docsite: Default False. Set to True to use wording specific for the
142158
official docsite on docs.ansible.com.
@@ -165,8 +181,8 @@ async def output_plugin_indexes(plugin_info: PluginCollectionInfoT,
165181
filename = os.path.join(collection_toplevel, f'index_{plugin_type}.rst')
166182
writers.append(await pool.spawn(
167183
write_plugin_type_index(
168-
plugin_type, per_collection_data, plugin_list_tmpl, filename,
169-
for_official_docsite=for_official_docsite)))
184+
plugin_type, per_collection_data, collection_metadata, plugin_list_tmpl,
185+
filename, for_official_docsite=for_official_docsite)))
170186

171187
await asyncio.gather(*writers)
172188

tests/functional/ansible-doc-cache-all.json

+33
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,39 @@
10081008
}
10091009
},
10101010
"lookup": {
1011+
"ns2.col.bar": {
1012+
"doc": {
1013+
"author": "Felix Fontein (@felixfontein)",
1014+
"collection": "ns2.col",
1015+
"description": [
1016+
"This one is private."
1017+
],
1018+
"filename": "ansible_collections/ns2/col/plugins/lookup/bar.py",
1019+
"name": "bar",
1020+
"options": {
1021+
"_terms": {
1022+
"description": "Something",
1023+
"elements": "dict",
1024+
"required": true,
1025+
"type": "list"
1026+
}
1027+
},
1028+
"short_description": "Look up some bar",
1029+
"version_added": "1.0.0",
1030+
"version_added_collection": "ns2.col"
1031+
},
1032+
"examples": "\n- name: Look up!\n ansible.builtin.debug:\n msg: \"{{ lookup('ns2.col.bar', {}) }}\"\n",
1033+
"metadata": null,
1034+
"return": {
1035+
"_raw": {
1036+
"description": [
1037+
"The resulting stuff."
1038+
],
1039+
"elements": "dict",
1040+
"type": "list"
1041+
}
1042+
}
1043+
},
10111044
"ns2.col.foo": {
10121045
"doc": {
10131046
"author": "Felix Fontein (@felixfontein)",

tests/functional/ansible-doc-cache-ns2.col.json

+33
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,39 @@
10081008
}
10091009
},
10101010
"lookup": {
1011+
"ns2.col.bar": {
1012+
"doc": {
1013+
"author": "Felix Fontein (@felixfontein)",
1014+
"collection": "ns2.col",
1015+
"description": [
1016+
"This one is private."
1017+
],
1018+
"filename": "ansible_collections/ns2/col/plugins/lookup/bar.py",
1019+
"name": "bar",
1020+
"options": {
1021+
"_terms": {
1022+
"description": "Something",
1023+
"elements": "dict",
1024+
"required": true,
1025+
"type": "list"
1026+
}
1027+
},
1028+
"short_description": "Look up some bar",
1029+
"version_added": "1.0.0",
1030+
"version_added_collection": "ns2.col"
1031+
},
1032+
"examples": "\n- name: Look up!\n ansible.builtin.debug:\n msg: \"{{ lookup('ns2.col.bar', {}) }}\"\n",
1033+
"metadata": null,
1034+
"return": {
1035+
"_raw": {
1036+
"description": [
1037+
"The resulting stuff."
1038+
],
1039+
"elements": "dict",
1040+
"type": "list"
1041+
}
1042+
}
1043+
},
10111044
"ns2.col.foo": {
10121045
"doc": {
10131046
"author": "Felix Fontein (@felixfontein)",

tests/functional/ansible-version.output

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ansible [core 2.15.0b1.post0] (stable-2.15 8f0ddcba2c) last updated 2023/04/06 20:47:29 (GMT +200)
1+
ansible [core 2.16.0.dev0] (devel 88a380c8f0) last updated 2023/04/06 20:47:05 (GMT +200)
22
config file = None
33
configured module search path = ['<<<<<HOME>>>>>/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
44
ansible python module location = <<<<<ANSIBLE>>>>>

0 commit comments

Comments
 (0)