Skip to content

Commit

Permalink
Show deprecation marker in module/plugin/role lists (#320)
Browse files Browse the repository at this point in the history
* Refactor information provided for templates.

* Add simple deprecated markers for simplified RST output.

* Add fancy deprecation marker for regular RST output.

* Also test deprecation by date.

* Add changelog fragment.

* Do not show versions on the official docsite.

These could confuse users since it's not immediately clear whether these are collection versions or Ansible versions.
  • Loading branch information
felixfontein authored Aug 28, 2024
1 parent 18a168d commit ae8f0d3
Show file tree
Hide file tree
Showing 53 changed files with 199 additions and 92 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/320-deprecation-marker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- "Add deprecation markers next to module/plugin/role descriptions in lists (https://github.com/ansible-community/antsibull-docs/issues/141, https://github.com/ansible-community/antsibull-docs/pull/320)."
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
SPDX-License-Identifier: GPL-3.0-or-later
#}

{% from 'macros/deprecates.rst.j2' import deprecation_marker with context -%}

:orphan:

{% if antsibull_docs_version %}
Expand All @@ -22,8 +24,8 @@ See :ref:`list_of_callback_plugins` for the list of *all* callback plugins.
@{ collection_name }@
@{ '-' * (collection_name | column_width) }@

{% for plugin_name, plugin_desc in plugins.items() | sort %}
* :ansplugin:`@{ collection_name }@.@{ plugin_name }@#callback` -- @{ plugin_desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type='callback') }@
{% for plugin_name, plugin_info in plugins.items() | sort %}
* :ansplugin:`@{ collection_name }@.@{ plugin_name }@#callback` -- @{ plugin_info.short_description | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type='callback') }@ @{ deprecation_marker(plugin_info) }@
{% endfor %}

{% else %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
SPDX-License-Identifier: GPL-3.0-or-later
#}

{% from 'macros/deprecates.rst.j2' import deprecation_marker with context -%}

:orphan:

{% if antsibull_docs_version %}
Expand Down Expand Up @@ -38,8 +40,8 @@ Index of all @{ plugin_type | capitalize }@ Plugins
@{ collection_name }@
@{ '-' * (collection_name | column_width) }@

{% for plugin_name, plugin_desc in plugins.items() | sort %}
* :ansplugin:`@{ collection_name }@.@{ plugin_name }@#@{ plugin_type }@` -- @{ plugin_desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type=plugin_type) }@
{% for plugin_name, plugin_info in plugins.items() | sort %}
* :ansplugin:`@{ collection_name }@.@{ plugin_name }@#@{ plugin_type }@` -- @{ plugin_info.short_description | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type=plugin_type) }@ @{ deprecation_marker(plugin_info) }@
{% endfor %}

{% else %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@ Removed in: a future release
<p>@{ 'Alternative: ' ~ data['alternative'] | html_ify(role_entrypoint=role_entrypoint) | rst_indent(2, blank=true) }@</p>
{% endif %}
{% endmacro %}


{% macro deprecation_marker(plugin_info) %}
{%- if plugin_info.deprecation -%}
:ansdeprecatedmarker:`@{
(
{ "date": plugin_info.deprecation.removed_at_date }
if for_official_docsite else
{ "date": plugin_info.deprecation.removed_at_date, "version": plugin_info.deprecation.removed_in }
) | antsibull_to_json | rst_escape
}@`
{%- endif -%}
{% endmacro %}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#}

{% from 'macros/collection_links.rst.j2' import add as add_collection_links with context -%}
{% from 'macros/deprecates.rst.j2' import deprecation_marker with context -%}

{% if not breadcrumbs %}
:orphan:
Expand All @@ -16,8 +17,8 @@

{% endif %}
{% macro list_plugins(plugin_type) %}
{% for name, desc in plugin_maps[plugin_type].items() | sort %}
* :ansplugin:`@{ name }@ @{ plugin_type }@ <@{ collection_name }@.@{ name }@#@{ plugin_type }@>` -- @{ desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ name, plugin_type=plugin_type) | rst_indent(width=2) }@
{% for name, info in plugin_maps[plugin_type].items() | sort %}
* :ansplugin:`@{ name }@ @{ plugin_type }@ <@{ collection_name }@.@{ name }@#@{ plugin_type }@>` -- @{ info.short_description | rst_ify(plugin_fqcn=collection_name ~ '.' ~ name, plugin_type=plugin_type) | rst_indent(width=2) }@ @{ deprecation_marker(info) }@
{% endfor %}
{% if breadcrumbs %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
.. Created with antsibull-docs
{% endif %}

{% from 'macros/deprecates.rst.j2' import deprecation_marker with context -%}

Index of all @{ callback_type | capitalize }@ Callback Plugins
=============@{ '=' * (callback_type | column_width) }@=================

Expand All @@ -19,8 +21,8 @@ See `List of all Callback Plugins <index_callback.rst>`_ for the list of *all* c
@{ collection_name }@
@{ '-' * (collection_name | column_width) }@

{% for plugin_name, plugin_desc in plugins.items() | sort %}
* `@{ collection_name }@.@{ plugin_name }@ <@{ collection_name | replace('.', '/') }@/@{ get_plugin_filename(collection_name ~ '.' ~ plugin_name, 'callback') }@>`_ -- @{ plugin_desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type='callback') }@
{% for plugin_name, plugin_info in plugins.items() | sort %}
* `@{ collection_name }@.@{ plugin_name }@ <@{ collection_name | replace('.', '/') }@/@{ get_plugin_filename(collection_name ~ '.' ~ plugin_name, 'callback') }@>`_ -- @{ plugin_info.short_description | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type='callback') }@ @{ deprecation_marker(plugin_info) }@
{% endfor %}

{% else %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
.. Created with antsibull-docs
{% endif %}

{% from 'macros/deprecates.rst.j2' import deprecation_marker with context -%}

{% if plugin_type == 'module' %}
Index of all Modules
====================
Expand All @@ -25,8 +27,8 @@ Index of all @{ plugin_type | capitalize }@ Plugins
@{ collection_name }@
@{ '-' * (collection_name | column_width) }@

{% for plugin_name, plugin_desc in plugins.items() | sort %}
* `@{ collection_name }@.@{ plugin_name }@ <@{ collection_name | replace('.', '/') }@/@{ get_plugin_filename(collection_name ~ '.' ~ plugin_name, plugin_type) }@>`_ -- @{ plugin_desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type=plugin_type) }@
{% for plugin_name, plugin_info in plugins.items() | sort %}
* `@{ collection_name }@.@{ plugin_name }@ <@{ collection_name | replace('.', '/') }@/@{ get_plugin_filename(collection_name ~ '.' ~ plugin_name, plugin_type) }@>`_ -- @{ plugin_info.short_description | rst_ify(plugin_fqcn=collection_name ~ '.' ~ plugin_name, plugin_type=plugin_type) }@ @{ deprecation_marker(plugin_info) }@
{% endfor %}

{% else %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,10 @@ Removed in: a future release
<p>@{ 'Alternative: ' ~ data['alternative'] | html_ify(role_entrypoint=role_entrypoint) | rst_indent(2, blank=true) }@</p>
{% endif %}
{% endmacro %}


{% macro deprecation_marker(plugin_info) %}
{%- if plugin_info.deprecation -%}
**(DEPRECATED)**
{%- endif -%}
{% endmacro %}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
{% endif %}

{% from 'macros/collection_links.rst.j2' import add as add_collection_links with context -%}
{% from 'macros/deprecates.rst.j2' import deprecation_marker with context -%}

{% macro list_plugins(plugin_type) %}
{% for name, desc in plugin_maps[plugin_type].items() | sort %}
* `@{ name }@ @{ plugin_type }@ <@{ get_plugin_filename(collection_name ~ '.' ~ name, plugin_type) }@>`_ -- @{ desc | rst_ify(plugin_fqcn=collection_name ~ '.' ~ name, plugin_type=plugin_type) | rst_indent(width=2) }@
{% for name, info in plugin_maps[plugin_type].items() | sort %}
* `@{ name }@ @{ plugin_type }@ <@{ get_plugin_filename(collection_name ~ '.' ~ name, plugin_type) }@>`_ -- @{ info.short_description | rst_ify(plugin_fqcn=collection_name ~ '.' ~ name, plugin_type=plugin_type) | rst_indent(width=2) }@ @{ deprecation_marker(info) }@
{% endfor %}
{% endmacro %}

Expand Down
8 changes: 5 additions & 3 deletions src/antsibull_docs/lint_plugin_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from .rstcheck import check_rst_content
from .schemas.collection_links import CollectionLinks
from .utils.collection_name_transformer import CollectionNameTransformer
from .write_docs import PluginErrorsT
from .write_docs import BasicPluginInfo, PluginErrorsT
from .write_docs.plugins import (
create_plugin_rst,
guess_relative_filename,
Expand Down Expand Up @@ -631,7 +631,9 @@ def _validate_markup(

def _collect_names(
new_plugin_info: Mapping[str, Mapping[str, t.Any]],
collection_to_plugin_info: Mapping[str, Mapping[str, Mapping[str, str]]],
collection_to_plugin_info: Mapping[
str, Mapping[str, Mapping[str, BasicPluginInfo]]
],
collection_name: str,
collections: list[str],
collection_metadata: Mapping[str, AnsibleCollectionMetadata],
Expand All @@ -647,7 +649,7 @@ def _collect_names(
if validate_collections_refs != "all" and collection_name_ not in collections:
continue
for plugin_type, plugins_dict in plugins_by_type.items():
for plugin_short_name, dummy_ in plugins_dict.items():
for plugin_short_name in plugins_dict:
plugin_name = ".".join((collection_name_, plugin_short_name))
plugin_record = new_plugin_info[plugin_type].get(plugin_name) or {}
if not has_broken_docs(plugin_record, plugin_type):
Expand Down
40 changes: 14 additions & 26 deletions src/antsibull_docs/process_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from . import app_context
from .docs_parsing.fqcn import get_fqcn_parts
from .schemas.docs import DOCS_SCHEMAS
from .write_docs import BasicPluginInfo

mlog = log.fields(mod=__name__)

Expand Down Expand Up @@ -155,7 +156,7 @@ async def normalize_all_plugin_info(

def get_plugin_contents(
plugin_info: Mapping[str, Mapping[str, t.Any]], nonfatal_errors: PluginErrorsRT
) -> defaultdict[str, defaultdict[str, dict[str, str]]]:
) -> defaultdict[str, defaultdict[str, dict[str, BasicPluginInfo]]]:
"""
Return the collections with their plugins for every plugin type.
Expand All @@ -169,7 +170,7 @@ def get_plugin_contents(
collection:
- plugin_short_name: short_description
"""
plugin_contents: defaultdict[str, defaultdict[str, dict[str, str]]]
plugin_contents: defaultdict[str, defaultdict[str, dict[str, BasicPluginInfo]]]
plugin_contents = defaultdict(lambda: defaultdict(dict))
# Some plugins won't have an entry in the plugin_info because documentation failed to parse.
# Those should be documented in the nonfatal_errors information.
Expand All @@ -178,35 +179,21 @@ def get_plugin_contents(
namespace, collection, short_name = get_fqcn_parts(plugin_name)
plugin_contents[plugin_type][".".join((namespace, collection))][
short_name
] = ""
] = BasicPluginInfo.empty()

for plugin_type, plugin_dict in plugin_info.items():
for plugin_name, plugin_desc in plugin_dict.items():
namespace, collection, short_name = get_fqcn_parts(plugin_name)
if plugin_type == "role":
desc = ""
if (
"entry_points" in plugin_desc
and "main" in plugin_desc["entry_points"]
):
desc = (
plugin_desc["entry_points"]["main"].get("short_description")
or ""
)
elif "doc" in plugin_desc:
desc = plugin_desc["doc"].get("short_description") or ""
else:
desc = ""
plugin_contents[plugin_type][".".join((namespace, collection))][
short_name
] = desc
] = BasicPluginInfo.from_doc(plugin_desc, plugin_type)

return plugin_contents


def get_callback_plugin_contents(
plugin_info: Mapping[str, Mapping[str, t.Any]],
) -> defaultdict[str, defaultdict[str, dict[str, str]]]:
) -> defaultdict[str, defaultdict[str, dict[str, BasicPluginInfo]]]:
"""
Return the collections with their plugins for every callback plugin type.
Expand All @@ -218,27 +205,28 @@ def get_callback_plugin_contents(
collection:
- plugin_short_name: short_description
"""
callback_plugin_contents: defaultdict[str, defaultdict[str, dict[str, str]]]
callback_plugin_contents: defaultdict[
str, defaultdict[str, dict[str, BasicPluginInfo]]
]
callback_plugin_contents = defaultdict(lambda: defaultdict(dict))

if plugin_info.get("callback"):
for plugin_name, plugin_desc in plugin_info["callback"].items():
if "doc" in plugin_desc:
desc = plugin_desc["doc"].get("short_description") or ""
callback_type = plugin_desc["doc"].get("type") or ""
if callback_type:
namespace, collection, short_name = get_fqcn_parts(plugin_name)
collection_name = ".".join((namespace, collection))
callback_plugin_contents[callback_type][collection_name][
short_name
] = desc
] = BasicPluginInfo.from_doc(plugin_desc, "callback")

return callback_plugin_contents


def get_collection_contents(
plugin_content: Mapping[str, Mapping[str, Mapping[str, str]]],
) -> defaultdict[str, dict[str, Mapping[str, str]]]:
plugin_content: Mapping[str, Mapping[str, Mapping[str, BasicPluginInfo]]],
) -> defaultdict[str, dict[str, Mapping[str, BasicPluginInfo]]]:
"""
Return the plugins which are in each collection.
Expand All @@ -250,8 +238,8 @@ def get_collection_contents(
plugin_type:
- plugin_short_name: short_description
"""
collection_plugins: defaultdict[str, dict[str, Mapping[str, str]]] = defaultdict(
dict
collection_plugins: defaultdict[str, dict[str, Mapping[str, BasicPluginInfo]]] = (
defaultdict(dict)
)

for plugin_type, collection_data in plugin_content.items():
Expand Down
45 changes: 41 additions & 4 deletions src/antsibull_docs/write_docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,65 @@

import os
from collections.abc import Mapping, Sequence
from typing import Any

from antsibull_core.logging import log
from jinja2 import Template

import antsibull_docs

from ..schemas.docs.base import DeprecationSchema, DocSchema
from ..utils.text import sanitize_whitespace as _sanitize_whitespace
from .io import Output

mlog = log.fields(mod=__name__)


class BasicPluginInfo:
short_description: str
deprecation: DeprecationSchema | None

def __init__(self, short_description: str, deprecation: DeprecationSchema | None):
self.short_description = short_description
self.deprecation = deprecation

@classmethod
def from_doc_schema(cls, doc_schema: DocSchema):
return cls(doc_schema.short_description, doc_schema.deprecated)

@classmethod
def from_doc(cls, plugin_desc: Mapping[str, Any], plugin_type: str):
desc: str
deprecation: DeprecationSchema | None = None
if plugin_type == "role":
desc = ""
if "entry_points" in plugin_desc and "main" in plugin_desc["entry_points"]:
entrypoint = plugin_desc["entry_points"]["main"]
desc = entrypoint.get("short_description") or ""
deprecation = entrypoint.get("deprecated")
elif "doc" in plugin_desc:
desc = plugin_desc["doc"].get("short_description") or ""
deprecation = plugin_desc["doc"].get("deprecated")
else:
desc = ""
return cls(desc, deprecation)

@classmethod
def empty(cls):
return cls("", None)


#: Mapping of plugins to nonfatal errors. This is the type to use when accepting the plugin.
#: The mapping is of plugin_type: plugin_name: [error_msgs]
PluginErrorsT = Mapping[str, Mapping[str, Sequence[str]]]

#: Mapping to collections to plugins.
#: The mapping is collection_name: plugin_type: plugin_name: plugin_short_description
CollectionInfoT = Mapping[str, Mapping[str, Mapping[str, str]]]
#: The mapping is collection_name: plugin_type: plugin_name: basic_plugin_info
CollectionInfoT = Mapping[str, Mapping[str, Mapping[str, BasicPluginInfo]]]

#: Plugins grouped first by plugin type, then by collection
#: The mapping is plugin_type: collection_name: plugin_name: plugin_short_description
PluginCollectionInfoT = Mapping[str, Mapping[str, Mapping[str, str]]]
#: The mapping is plugin_type: collection_name: plugin_name: basic_plugin_info
PluginCollectionInfoT = Mapping[str, Mapping[str, Mapping[str, BasicPluginInfo]]]


def _render_template(
Expand Down
4 changes: 2 additions & 2 deletions src/antsibull_docs/write_docs/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from ..jinja2 import FilenameGenerator, OutputFormat
from ..jinja2.environment import doc_environment, get_template_filename
from ..utils.collection_name_transformer import CollectionNameTransformer
from . import CollectionInfoT, _get_collection_dir, _render_template
from . import BasicPluginInfo, CollectionInfoT, _get_collection_dir, _render_template
from .io import Output

mlog = log.fields(mod=__name__)
Expand Down Expand Up @@ -56,7 +56,7 @@ def _parse_required_ansible(requires_ansible: str) -> list[str]:

async def write_plugin_lists(
collection_name: str,
plugin_maps: Mapping[str, Mapping[str, str]],
plugin_maps: Mapping[str, Mapping[str, BasicPluginInfo]],
template: Template,
output: Output,
collection_dir: str,
Expand Down
6 changes: 3 additions & 3 deletions src/antsibull_docs/write_docs/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
from ..jinja2 import FilenameGenerator, OutputFormat
from ..jinja2.environment import doc_environment, get_template_filename
from ..utils.collection_name_transformer import CollectionNameTransformer
from . import PluginCollectionInfoT, _render_template
from . import BasicPluginInfo, PluginCollectionInfoT, _render_template
from .io import Output

mlog = log.fields(mod=__name__)


async def write_callback_type_index(
callback_type: str,
per_collection_plugins: Mapping[str, Mapping[str, str]],
per_collection_plugins: Mapping[str, Mapping[str, BasicPluginInfo]],
template: Template,
output: Output,
dest_filename: str,
Expand Down Expand Up @@ -64,7 +64,7 @@ async def write_callback_type_index(

async def write_plugin_type_index(
plugin_type: str,
per_collection_plugins: Mapping[str, Mapping[str, str]],
per_collection_plugins: Mapping[str, Mapping[str, BasicPluginInfo]],
# pylint:disable-next=unused-argument
collection_metadata: Mapping[str, AnsibleCollectionMetadata],
template: Template,
Expand Down
Loading

0 comments on commit ae8f0d3

Please sign in to comment.