Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate role documentation #272

Merged
merged 1 commit into from
Aug 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions antsibull/augment_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,10 @@ def augment_docs(plugin_info: t.MutableMapping[str, t.MutableMapping[str, t.Any]
"""
for plugin_type, plugin_map in plugin_info.items():
for plugin_name, plugin_record in plugin_map.items():
add_full_key(plugin_record['return'], 'contains')
add_full_key(plugin_record['doc']['options'], 'suboptions')
if 'return' in plugin_record:
add_full_key(plugin_record['return'], 'contains')
if 'doc' in plugin_record:
add_full_key(plugin_record['doc']['options'], 'suboptions')
if 'entry_points' in plugin_record:
for entry_point in plugin_record['entry_points'].values():
add_full_key(entry_point['options'], 'options')
17 changes: 14 additions & 3 deletions antsibull/cli/doc_commands/stable.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,14 @@ def normalize_plugin_info(plugin_type: str,
in :mod:`antsibull.schemas.docs`. The nonfatal errors are strings representing the problems
encountered.
"""
new_info = {}
errors = []
if plugin_type == 'role':
try:
return DOCS_SCHEMAS[plugin_type].parse_obj(plugin_info).dict(by_alias=True), errors
except ValidationError as e:
raise ValueError(str(e))

new_info = {}
# Note: loop through "doc" before any other keys.
for field in ('doc', 'examples', 'return'):
try:
Expand Down Expand Up @@ -224,8 +230,13 @@ def get_plugin_contents(plugin_info: t.Mapping[str, t.Mapping[str, t.Any]],
for plugin_type, plugin_list in plugin_info.items():
for plugin_name, plugin_desc in plugin_list.items():
namespace, collection, short_name = get_fqcn_parts(plugin_name)
plugin_contents[plugin_type]['.'.join((namespace, collection))][short_name] = (
plugin_desc['doc']['short_description'])
if plugin_type == 'role':
desc = ''
if 'main' in plugin_desc['entry_points']:
desc = plugin_desc['entry_points']['main']['short_description']
else:
desc = plugin_desc['doc']['short_description']
plugin_contents[plugin_type]['.'.join((namespace, collection))][short_name] = desc

return plugin_contents

Expand Down
11 changes: 8 additions & 3 deletions antsibull/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
# Copyright: Ansible Project, 2020
"""Constant values for use throughout the antsibull codebase."""

from typing import FrozenSet
from typing import Dict, FrozenSet


#: All the types of ansible plugins
PLUGIN_TYPES: FrozenSet[str] = frozenset(('become', 'cache', 'callback', 'cliconf', 'connection',
'httpapi', 'inventory', 'lookup', 'shell', 'strategy',
'vars', 'module', 'module_utils',))
'vars', 'module', 'module_utils', 'role',))

#: The subset of PLUGINS which we build documentation for
DOCUMENTABLE_PLUGINS: FrozenSet[str] = frozenset(('become', 'cache', 'callback', 'cliconf',
'connection', 'httpapi', 'inventory', 'lookup',
'netconf', 'shell', 'vars', 'module',
'strategy',))
'strategy', 'role',))


DOCUMENTABLE_PLUGINS_MIN_VERSION: Dict[str, str] = {
'role': '2.11.0',
}
41 changes: 41 additions & 0 deletions antsibull/data/collection-enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,40 @@ def load_all_plugins(plugin_type, basedir, coll_filter):
return result


def load_role(role_mixin, role_name, collection_name, collection_path):
result = {
'directory': collection_path,
'collection_name': collection_name,
}

argspec = role_mixin._load_argspec(role_name, collection_path=collection_path)
fqcn, ansible_doc = role_mixin._build_doc(
role_name, collection_path, collection_name, argspec, None)

try:
# If this fails, the documentation cannot be serialized as JSON
json.dumps(ansible_doc, cls=AnsibleJSONEncoder)
# Store result. This is guaranteed to be serializable
result['ansible-doc'] = ansible_doc
except Exception as e:
result['error'] = (
'Cannot serialize documentation as JSON: %s' % to_native(e)
)

return result


def load_all_roles(RoleMixin, basedir, coll_filter):
role_mixin = RoleMixin()
roles = role_mixin._find_all_collection_roles()
result = {}
for role_name, collection_name, collection_path in roles:
fqcn = '{1}.{0}'.format(role_name, collection_name)
if match_filter(fqcn, coll_filter):
result[fqcn] = load_role(role_mixin, role_name, collection_name, collection_path)
return result


def load_collection_meta_manifest(b_manifest_path):
with open(b_manifest_path, 'rb') as f:
meta = json.load(f)
Expand Down Expand Up @@ -195,6 +229,13 @@ def main(args):
for plugin_type in C.DOCUMENTABLE_PLUGINS:
result['plugins'][plugin_type] = load_all_plugins(plugin_type, basedir, coll_filter)

# Export role docs
RoleMixin = getattr(doc, 'RoleMixin', None)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI, neither RoleMixin nor any of its methods were ever meant to be publicly accessible. Using this is at-your-own-risk as my intention was to try to make a proper public API for some of this in the future.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually most code in collection-enum.py is using internal stuff from ansible-doc that can break at any moment. I would prefer to have a stable API, but unfortunately there isn't one :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(In case it breaks, you can configure antsibull to use ansible-doc --json to extract all the docs. Unfortunately it's like 1000x slower, that's why this method is the default :) )

if RoleMixin is not None:
result['plugins']['role'] = load_all_roles(RoleMixin, basedir, coll_filter)
else:
result['plugins']['role'] = {}

# Export collection data
b_colldirs = list_collection_dirs(coll_filter=ansible_doc_coll_filter(coll_filter))
for b_path in b_colldirs:
Expand Down
3 changes: 3 additions & 0 deletions antsibull/data/docsite/list_of_plugins.rst.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
{% if plugin_type == 'module' %}
Index of all Modules
====================
{% elif plugin_type == 'role' %}
Index of all Roles
==================
{% else %}
Index of all @{ plugin_type | capitalize }@ Plugins
=============@{ '=' * (plugin_type | length) }@========
Expand Down
19 changes: 17 additions & 2 deletions antsibull/data/docsite/plugins_by_collection.rst.j2
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ Collection version @{ collection_version }@
Plugin Index
------------

{% if plugin_maps %}
{% if plugin_maps | reject('eq', 'role') | list %}
These are the plugins in the @{collection_name}@ collection
{% else %}
There are no plugins in the @{collection_name}@ collection with automatically generated documentation.
{% endif %}

{% for category, plugins in plugin_maps.items() | sort %}
{% for category, plugins in plugin_maps.items() | sort | rejectattr('0', 'eq', 'role') %}

{% if category == 'module' %}
Modules
~~~~~~~
{% elif category == 'role' %}
Roles
~~~~~
{% else %}
@{ category | capitalize }@ Plugins
@{ '~' * ((category | length) + 8) }@
Expand All @@ -53,6 +56,18 @@ Modules
{% endfor %}
{% endfor %}

{% if 'role' in plugin_maps %}
Role Index
----------

These are the roles in the @{collection_name}@ collection

{% for name, desc in plugin_maps['role'].items() | sort %}
* :ref:`@{ name }@ <ansible_collections.@{ collection_name }@.@{ name }@_role>` -- @{ desc | rst_ify | indent(width=2) }@
{% endfor %}

{% endif %}


.. seealso::

Expand Down
Loading