Galaxy meta docs table (#60171)
* Use an rst table instead of a raw html table * Rst is easier to read so we want to use it wherever possible * Fix the jinja2 filters which create links so that they do not include extraneous whitespace in the URL * Normalize description data before sending them to the templates
This commit is contained in:
parent
60f8483603
commit
d9b3af523b
6 changed files with 127 additions and 56 deletions
|
@ -4,13 +4,63 @@
|
||||||
/* override table width restrictions */
|
/* override table width restrictions */
|
||||||
@media screen and (min-width: 767px) {
|
@media screen and (min-width: 767px) {
|
||||||
|
|
||||||
|
/* If we ever publish to read the docs, we need to use !important for these
|
||||||
|
* two styles as read the docs itself loads their theme in a way that we
|
||||||
|
* can't otherwise override it.
|
||||||
|
*/
|
||||||
.wy-table-responsive table td {
|
.wy-table-responsive table td {
|
||||||
/* !important prevents the common CSS stylesheets from overriding
|
white-space: normal;
|
||||||
this as on RTD they are loaded after this stylesheet */
|
|
||||||
white-space: normal !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.wy-table-responsive {
|
.wy-table-responsive {
|
||||||
overflow: visible !important;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use the class documentation-table for attribute tables where the first
|
||||||
|
* column is the name of an attribute and the second column is the description.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* These tables look like this:
|
||||||
|
*
|
||||||
|
* Attribute Name Description
|
||||||
|
* -------------- -----------
|
||||||
|
* **NAME** This is a multi-line description
|
||||||
|
* str/required that can span multiple lines
|
||||||
|
*
|
||||||
|
* With multiple paragraphs
|
||||||
|
* -------------- -----------
|
||||||
|
*
|
||||||
|
* **NAME** is given the class .value-name
|
||||||
|
* str is given the class .value-type
|
||||||
|
* / is given the class .value-separator
|
||||||
|
* required is given the class .value-required
|
||||||
|
*/
|
||||||
|
|
||||||
|
table.documentation-table td:first-child {
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.documentation-table .value-name {
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.documentation-table .value-type {
|
||||||
|
font-size: x-small;
|
||||||
|
color: purple;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.documentation-table .value-separator {
|
||||||
|
font-size: x-small;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.documentation-table .value-required {
|
||||||
|
font-size: x-small;
|
||||||
|
color: red;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
68
docs/templates/collections_galaxy_meta.rst.j2
vendored
68
docs/templates/collections_galaxy_meta.rst.j2
vendored
|
@ -16,38 +16,44 @@ Structure
|
||||||
|
|
||||||
The ``galaxy.yml`` file must contain the following keys in valid YAML:
|
The ``galaxy.yml`` file must contain the following keys in valid YAML:
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
|
|
||||||
<table border=0 cellpadding=0 class="documentation-table">
|
.. rst-class:: documentation-table
|
||||||
{# Header of the documentation -#}
|
|
||||||
<tr>
|
.. list-table::
|
||||||
<th>Key</th>
|
:header-rows: 1
|
||||||
<th width="100%">Comments</th>
|
:widths: auto
|
||||||
</tr>
|
|
||||||
{% for entry in options %}
|
* - Key
|
||||||
<tr>
|
- Comment
|
||||||
{# key name with required or type label #}
|
|
||||||
<td>
|
{%- for entry in options %}
|
||||||
<b>@{ entry.key }@</b>
|
|
||||||
<div style="font-size: small">
|
|
||||||
<span style="color: purple">@{ entry.type | documented_type }@</span>
|
* - .. rst-class:: value-name
|
||||||
{% if entry.get('required', False) %} / <span style="color: red">required</span>{% endif %}
|
|
||||||
</div>
|
@{ entry.key }@ |br|
|
||||||
</td>
|
|
||||||
{# Comments #}
|
.. rst-class:: value-type
|
||||||
<td>
|
|
||||||
{% if entry.description is string %}
|
@{ entry.type | documented_type }@ |_|
|
||||||
<div>@{ entry.description | replace('\n', '\n ') | html_ify }@</div>
|
|
||||||
{% else %}
|
{% if entry.get('required', False) -%}
|
||||||
{% for desc in entry.description %}
|
.. rst-class:: value-separator
|
||||||
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
|
|
||||||
{% endfor %}
|
/ |_|
|
||||||
{% endif %}
|
|
||||||
</td>
|
.. rst-class:: value-required
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
required
|
||||||
</table>
|
{%- endif %}
|
||||||
<br/>
|
|
||||||
|
|
||||||
|
- {% for desc in entry.description -%}
|
||||||
|
@{ desc | trim | rst_ify }@
|
||||||
|
|
||||||
|
{% endfor -%}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
|
|
8
docs/templates/plugin.rst.j2
vendored
8
docs/templates/plugin.rst.j2
vendored
|
@ -50,13 +50,9 @@ Synopsis
|
||||||
--------
|
--------
|
||||||
{% if description -%}
|
{% if description -%}
|
||||||
|
|
||||||
{% if description is string -%}
|
|
||||||
- @{ description | rst_ify }@
|
|
||||||
{% else %}
|
|
||||||
{% for desc in description %}
|
{% for desc in description %}
|
||||||
- @{ desc | rst_ify }@
|
- @{ desc | rst_ify }@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -183,13 +179,9 @@ Parameters
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{# description #}
|
{# description #}
|
||||||
<td>
|
<td>
|
||||||
{% if value.description is string %}
|
|
||||||
<div>@{ value.description | replace('\n', '\n ') | html_ify }@</div>
|
|
||||||
{% else %}
|
|
||||||
{% for desc in value.description %}
|
{% for desc in value.description %}
|
||||||
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
|
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
|
||||||
{% if 'aliases' in value and value.aliases %}
|
{% if 'aliases' in value and value.aliases %}
|
||||||
<div style="font-size: small; color: darkgreen"><br/>aliases: @{ value.aliases|join(', ') }@</div>
|
<div style="font-size: small; color: darkgreen"><br/>aliases: @{ value.aliases|join(', ') }@</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -12,18 +12,26 @@ import pathlib
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
from ansible.module_utils.six import string_types
|
||||||
from ansible.module_utils._text import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
# Pylint doesn't understand Python3 namespace modules.
|
# Pylint doesn't understand Python3 namespace modules.
|
||||||
from ..change_detection import update_file_if_different # pylint: disable=relative-beyond-top-level
|
from ..change_detection import update_file_if_different # pylint: disable=relative-beyond-top-level
|
||||||
from ..commands import Command # pylint: disable=relative-beyond-top-level
|
from ..commands import Command # pylint: disable=relative-beyond-top-level
|
||||||
from ..jinja2.filters import documented_type, html_ify # pylint: disable=relative-beyond-top-level
|
from ..jinja2.filters import documented_type, rst_ify # pylint: disable=relative-beyond-top-level
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_TEMPLATE_FILE = 'collections_galaxy_meta.rst.j2'
|
DEFAULT_TEMPLATE_FILE = 'collections_galaxy_meta.rst.j2'
|
||||||
DEFAULT_TEMPLATE_DIR = pathlib.Path(__file__).parents[4] / 'docs/templates'
|
DEFAULT_TEMPLATE_DIR = pathlib.Path(__file__).parents[4] / 'docs/templates'
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_options(options):
|
||||||
|
"""Normalize the options to make for easy templating"""
|
||||||
|
for opt in options:
|
||||||
|
if isinstance(opt['description'], string_types):
|
||||||
|
opt['description'] = [opt['description']]
|
||||||
|
|
||||||
|
|
||||||
class DocumentCollectionMeta(Command):
|
class DocumentCollectionMeta(Command):
|
||||||
name = 'collection-meta'
|
name = 'collection-meta'
|
||||||
|
|
||||||
|
@ -51,12 +59,14 @@ class DocumentCollectionMeta(Command):
|
||||||
with open(args.collection_defs) as f:
|
with open(args.collection_defs) as f:
|
||||||
options = yaml.safe_load(f)
|
options = yaml.safe_load(f)
|
||||||
|
|
||||||
|
normalize_options(options)
|
||||||
|
|
||||||
env = Environment(loader=FileSystemLoader(template_dir),
|
env = Environment(loader=FileSystemLoader(template_dir),
|
||||||
variable_start_string="@{",
|
variable_start_string="@{",
|
||||||
variable_end_string="}@",
|
variable_end_string="}@",
|
||||||
trim_blocks=True)
|
trim_blocks=True)
|
||||||
env.filters['documented_type'] = documented_type
|
env.filters['documented_type'] = documented_type
|
||||||
env.filters['html_ify'] = html_ify
|
env.filters['rst_ify'] = rst_ify
|
||||||
|
|
||||||
template = env.get_template(template_file)
|
template = env.get_template(template_file)
|
||||||
output_name = os.path.join(output_dir, template_file.replace('.j2', ''))
|
output_name = os.path.join(output_dir, template_file.replace('.j2', ''))
|
||||||
|
|
|
@ -386,8 +386,17 @@ def process_plugins(module_map, templates, outputname, output_dir, ansible_versi
|
||||||
if field in doc and doc[field] in (None, ''):
|
if field in doc and doc[field] in (None, ''):
|
||||||
print("%s: WARNING: MODULE field '%s' DOCUMENTATION is null/empty value=%s" % (fname, field, doc[field]))
|
print("%s: WARNING: MODULE field '%s' DOCUMENTATION is null/empty value=%s" % (fname, field, doc[field]))
|
||||||
|
|
||||||
|
if 'description' in doc:
|
||||||
|
if isinstance(doc['description'], string_types):
|
||||||
|
doc['description'] = [doc['description']]
|
||||||
|
elif not isinstance(doc['description'], (list, tuple)):
|
||||||
|
raise AnsibleError("Description must be a string or list of strings. Got %s"
|
||||||
|
% type(doc['description']))
|
||||||
|
else:
|
||||||
|
doc['description'] = []
|
||||||
|
|
||||||
if 'version_added' not in doc:
|
if 'version_added' not in doc:
|
||||||
display.error("*** ERROR: missing version_added in: %s ***\n" % module)
|
raise AnsibleError("*** ERROR: missing version_added in: %s ***\n" % module)
|
||||||
|
|
||||||
#
|
#
|
||||||
# The present template gets everything from doc so we spend most of this
|
# The present template gets everything from doc so we spend most of this
|
||||||
|
@ -416,6 +425,14 @@ def process_plugins(module_map, templates, outputname, output_dir, ansible_versi
|
||||||
if 'description' not in doc['options'][k]:
|
if 'description' not in doc['options'][k]:
|
||||||
raise AnsibleError("Missing required description for parameter '%s' in '%s' " % (k, module))
|
raise AnsibleError("Missing required description for parameter '%s' in '%s' " % (k, module))
|
||||||
|
|
||||||
|
# Make sure description is a list of lines for later formatting
|
||||||
|
if isinstance(doc['options'][k]['description'], string_types):
|
||||||
|
doc['options'][k]['description'] = [doc['options'][k]['description']]
|
||||||
|
elif not isinstance(doc['options'][k]['description'], (list, tuple)):
|
||||||
|
raise AnsibleError("Invalid type for options['%s']['description']."
|
||||||
|
" Must be string or list of strings. Got %s" %
|
||||||
|
(k, type(doc['options'][k]['description'])))
|
||||||
|
|
||||||
# Error out if required isn't a boolean (people have been putting
|
# Error out if required isn't a boolean (people have been putting
|
||||||
# information on when something is required in here. Those need
|
# information on when something is required in here. Those need
|
||||||
# to go in the description instead).
|
# to go in the description instead).
|
||||||
|
@ -427,10 +444,6 @@ def process_plugins(module_map, templates, outputname, output_dir, ansible_versi
|
||||||
if 'version_added' in doc['options'][k] and too_old(doc['options'][k]['version_added']):
|
if 'version_added' in doc['options'][k] and too_old(doc['options'][k]['version_added']):
|
||||||
del doc['options'][k]['version_added']
|
del doc['options'][k]['version_added']
|
||||||
|
|
||||||
# Make sure description is a list of lines for later formatting
|
|
||||||
if not isinstance(doc['options'][k]['description'], list):
|
|
||||||
doc['options'][k]['description'] = [doc['options'][k]['description']]
|
|
||||||
|
|
||||||
option_names.append(k)
|
option_names.append(k)
|
||||||
|
|
||||||
option_names.sort()
|
option_names.sort()
|
||||||
|
|
|
@ -27,7 +27,7 @@ _ITALIC = re.compile(r"I\(([^)]+)\)")
|
||||||
_BOLD = re.compile(r"B\(([^)]+)\)")
|
_BOLD = re.compile(r"B\(([^)]+)\)")
|
||||||
_MODULE = re.compile(r"M\(([^)]+)\)")
|
_MODULE = re.compile(r"M\(([^)]+)\)")
|
||||||
_URL = re.compile(r"U\(([^)]+)\)")
|
_URL = re.compile(r"U\(([^)]+)\)")
|
||||||
_LINK = re.compile(r"L\(([^)]+),([^)]+)\)")
|
_LINK = re.compile(r"L\(([^)]+), *([^)]+)\)")
|
||||||
_CONST = re.compile(r"C\(([^)]+)\)")
|
_CONST = re.compile(r"C\(([^)]+)\)")
|
||||||
_RULER = re.compile(r"HORIZONTALLINE")
|
_RULER = re.compile(r"HORIZONTALLINE")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue