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

Galaxy meta docs table #60171

Merged
merged 2 commits into from Aug 13, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 54 additions & 4 deletions docs/docsite/_static/ansible.css
Expand Up @@ -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;
}
70 changes: 38 additions & 32 deletions docs/templates/collections_galaxy_meta.rst.j2
Expand Up @@ -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
========
Expand Down
18 changes: 5 additions & 13 deletions docs/templates/plugin.rst.j2
Expand Up @@ -50,13 +50,9 @@ Synopsis
--------
{% if description -%}

{% if description is string -%}
- @{ description | rst_ify }@
{% else %}
{% for desc in description %}
{% for desc in description %}
- @{ desc | rst_ify }@
{% endfor %}
{% endif %}
{% endfor %}

{% endif %}

Expand Down Expand Up @@ -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 %}
{% for desc in value.description %}
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
{% endfor %}
{% if 'aliases' in value and value.aliases %}
<div style="font-size: small; color: darkgreen"><br/>aliases: @{ value.aliases|join(', ') }@</div>
{% endif %}
Expand Down
Expand Up @@ -12,18 +12,26 @@

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'

Expand Down Expand Up @@ -51,12 +59,14 @@ def main(args):
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', ''))
Expand Down
Expand Up @@ -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
Expand Down Expand Up @@ -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).
Expand All @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion hacking/build_library/build_ansible/jinja2/filters.py
Expand Up @@ -27,7 +27,7 @@ def html_escape(text, quote=True):
_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")

Expand Down