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:
Toshio Kuratomi 2019-08-13 13:00:13 -07:00 committed by Alicia Cozine
parent 60f8483603
commit d9b3af523b
6 changed files with 127 additions and 56 deletions

View file

@ -4,13 +4,63 @@
/* override table width restrictions */
@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 {
/* !important prevents the common CSS stylesheets from overriding
this as on RTD they are loaded after this stylesheet */
white-space: normal !important;
white-space: normal;
}
.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;
}

View file

@ -16,38 +16,44 @@ Structure
The ``galaxy.yml`` file must contain the following keys in valid YAML:
.. raw:: html
<table border=0 cellpadding=0 class="documentation-table">
{# Header of the documentation -#}
<tr>
<th>Key</th>
<th width="100%">Comments</th>
</tr>
{% for entry in options %}
<tr>
{# key name with required or type label #}
<td>
<b>@{ entry.key }@</b>
<div style="font-size: small">
<span style="color: purple">@{ entry.type | documented_type }@</span>
{% if entry.get('required', False) %} / <span style="color: red">required</span>{% endif %}
</div>
</td>
{# Comments #}
<td>
{% if entry.description is string %}
<div>@{ entry.description | replace('\n', '\n ') | html_ify }@</div>
{% else %}
{% for desc in entry.description %}
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
{% endfor %}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br/>
.. rst-class:: documentation-table
.. list-table::
:header-rows: 1
:widths: auto
* - Key
- Comment
{%- for entry in options %}
* - .. rst-class:: value-name
@{ entry.key }@ |br|
.. rst-class:: value-type
@{ entry.type | documented_type }@ |_|
{% if entry.get('required', False) -%}
.. rst-class:: value-separator
/ |_|
.. rst-class:: value-required
required
{%- endif %}
- {% for desc in entry.description -%}
@{ desc | trim | rst_ify }@
{% endfor -%}
{%- endfor %}
Examples
========

View file

@ -50,13 +50,9 @@ Synopsis
--------
{% if description -%}
{% if description is string -%}
- @{ description | rst_ify }@
{% else %}
{% for desc in description %}
- @{ desc | rst_ify }@
{% endfor %}
{% endif %}
{% endif %}
@ -183,13 +179,9 @@ Parameters
{% endif %}
{# description #}
<td>
{% if value.description is string %}
<div>@{ value.description | replace('\n', '\n ') | html_ify }@</div>
{% else %}
{% for desc in value.description %}
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
{% endfor %}
{% endif %}
{% if 'aliases' in value and value.aliases %}
<div style="font-size: small; color: darkgreen"><br/>aliases: @{ value.aliases|join(', ') }@</div>
{% endif %}

View file

@ -12,18 +12,26 @@ import pathlib
import yaml
from jinja2 import Environment, FileSystemLoader
from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_bytes
# Pylint doesn't understand Python3 namespace modules.
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 ..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_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):
name = 'collection-meta'
@ -51,12 +59,14 @@ class DocumentCollectionMeta(Command):
with open(args.collection_defs) as f:
options = yaml.safe_load(f)
normalize_options(options)
env = Environment(loader=FileSystemLoader(template_dir),
variable_start_string="@{",
variable_end_string="}@",
trim_blocks=True)
env.filters['documented_type'] = documented_type
env.filters['html_ify'] = html_ify
env.filters['rst_ify'] = rst_ify
template = env.get_template(template_file)
output_name = os.path.join(output_dir, template_file.replace('.j2', ''))

View file

@ -386,8 +386,17 @@ def process_plugins(module_map, templates, outputname, output_dir, ansible_versi
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]))
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:
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
@ -416,6 +425,14 @@ def process_plugins(module_map, templates, outputname, output_dir, ansible_versi
if 'description' not in doc['options'][k]:
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
# information on when something is required in here. Those need
# 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']):
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.sort()

View file

@ -27,7 +27,7 @@ _ITALIC = re.compile(r"I\(([^)]+)\)")
_BOLD = re.compile(r"B\(([^)]+)\)")
_MODULE = re.compile(r"M\(([^)]+)\)")
_URL = re.compile(r"U\(([^)]+)\)")
_LINK = re.compile(r"L\(([^)]+),([^)]+)\)")
_LINK = re.compile(r"L\(([^)]+), *([^)]+)\)")
_CONST = re.compile(r"C\(([^)]+)\)")
_RULER = re.compile(r"HORIZONTALLINE")