Merge "Allow comments in variable files to be rendered in docs"

This commit is contained in:
Zuul 2021-06-28 17:30:00 +00:00 committed by Gerrit Code Review
commit fb29b03c1f
2 changed files with 98 additions and 79 deletions

View File

@ -6,4 +6,5 @@ sphinxcontrib-apidoc>=0.2.0 # BSD License
sphinxcontrib-svg2pdfconverter>=1.1.1 # BSD License sphinxcontrib-svg2pdfconverter>=1.1.1 # BSD License
doc8>=0.8.0 # Apache-2.0 doc8>=0.8.0 # Apache-2.0
bashate>=0.6.0 # Apache-2.0 bashate>=0.6.0 # Apache-2.0
ruamel.yaml>=0.15.5 # MIT
six>=1.11.0 # MIT six>=1.11.0 # MIT

View File

@ -26,6 +26,7 @@ from docutils.writers.html4css1 import Writer
from sphinx import addnodes from sphinx import addnodes
import yaml import yaml
from ruamel.yaml import YAML as RYAML
try: try:
import io import io
@ -34,17 +35,14 @@ except ImportError:
import StringIO import StringIO
class DocYaml: class DocYaml(RYAML):
"""
Wrapper clas around calls to yaml lib.
"""
def _license_filter(self, data): def _license_filter(self, data):
"""This will filter out our boilerplate license heading in return data. """This will filter out our boilerplate license heading in return data.
The filter is used to allow documentation we're creating in variable The filter is used to allow documentation we're creating in variable
files to be rendered more beautifully. files to be rendered more beautifully.
""" """
lines = [] lines = list()
mark = True mark = True
for line in data.splitlines(): for line in data.splitlines():
if '# Copyright' in line: if '# Copyright' in line:
@ -59,15 +57,14 @@ class DocYaml:
if not stream: if not stream:
stream = StringIO() stream = StringIO()
try: try:
yaml.dump(data=data, stream=stream, Dumper=yaml.Dumper, **kw) RYAML.dump(self, data, stream, **kw)
return self._license_filter(stream.getvalue().strip()) return self._license_filter(stream.getvalue().strip())
finally: finally:
stream.close() stream.close()
def load(self, data):
return yaml.load(data, Loader=yaml.Loader)
DOCYAML = DocYaml() DOCYAML = DocYaml()
DOCYAML.default_flow_style = False
class AnsibleAutoPluginDirective(Directive): class AnsibleAutoPluginDirective(Directive):
@ -208,28 +205,37 @@ class AnsibleAutoPluginDirective(Directive):
def _run_role(self, role): def _run_role(self, role):
section = self._section_block( section = self._section_block(
title='Role Documentation', title="Role Documentation",
text='Welcome to the "{}" role documentation.'.format( text="Welcome to the '{}' role documentation.".format(
os.path.basename(role) os.path.basename(role)
),
) )
molecule_defaults = None
abspath_role = os.path.dirname(os.path.abspath(role))
molecule_shared_file = os.path.join(
os.path.dirname(abspath_role), "../.config/molecule/config.yml"
) )
defaults_file = os.path.join(role, 'defaults', 'main.yml')
if os.path.exists(molecule_shared_file):
with open(molecule_shared_file) as msf:
molecule_defaults = DOCYAML.load(msf.read())
defaults_file = os.path.join(role, "defaults", "main.yml")
if os.path.exists(defaults_file): if os.path.exists(defaults_file):
with open(defaults_file) as f: with open(defaults_file) as f:
role_defaults = DOCYAML.load(f.read()) role_defaults = DOCYAML.load(f.read())
section.append( section.append(
self._yaml_section( self._yaml_section(
to_yaml_data=role_defaults, to_yaml_data=role_defaults,
section_title='Role Defaults', section_title="Role Defaults",
section_text='This section highlights all of the defaults' section_text="This section highlights all of the defaults"
' and variables set within the "{}"' " and variables set within the '{}'"
' role.'.format( " role.".format(os.path.basename(role)),
os.path.basename(role)
)
) )
) )
vars_path = os.path.join(role, 'vars') vars_path = os.path.join(role, "vars")
if os.path.exists(vars_path): if os.path.exists(vars_path):
for v_file in os.listdir(vars_path): for v_file in os.listdir(vars_path):
vars_file = os.path.join(vars_path, v_file) vars_file = os.path.join(vars_path, v_file)
@ -238,81 +244,96 @@ class AnsibleAutoPluginDirective(Directive):
section.append( section.append(
self._yaml_section( self._yaml_section(
to_yaml_data=vars_values, to_yaml_data=vars_values,
section_title='Role Variables: {}'.format(v_file) section_title="Role Variables: {}".format(v_file),
) )
) )
test_list = nodes.field_list() test_list = nodes.field_list()
test_section = self._section_block( test_section = self._section_block(
title='Molecule Scenarios', title="Molecule Scenarios",
text='Molecule is being used to test the "{}" role. The' text="Molecule is being used to test the '{}' role. The"
' following section highlights the drivers in service' " following section highlights the drivers in service"
' and provides an example playbook showing how the role' " and provides an example playbook showing how the role"
' is leveraged.'.format( " is leveraged.".format(os.path.basename(role)),
os.path.basename(role)
) )
)
molecule_path = os.path.join(role, 'molecule') molecule_path = os.path.join(role, "molecule")
if os.path.exists(molecule_path): if os.path.exists(molecule_path):
for test in os.listdir(molecule_path): for test in os.listdir(molecule_path):
molecule_section = self._section_block( molecule_section = self._section_block(
title='Scenario: {}'.format(test) title="Scenario: {}".format(test)
)
molecule_file = os.path.join(
molecule_path,
test,
'molecule.yml'
) )
molecule_file = os.path.join(molecule_path, test, "molecule.yml")
if not os.path.exists(molecule_file):
continue
with open(molecule_file) as f: with open(molecule_file) as f:
molecule_conf = DOCYAML.load(f.read()) molecule_conf = DOCYAML.load(f.read())
if molecule_conf:
driver_data = molecule_conf.get('driver') # if molecule.yml file from the scenarios, we get the
# information from the molecule shared configuration file.
if not molecule_conf:
molecule_conf = molecule_defaults
# Now that we use a shared molecule configuration file, the
# molecule.yml file in the role scenarios could be empty or
# contains only overriding keys.
driver_data = molecule_conf.get('driver',
molecule_defaults.get('driver'))
if driver_data: if driver_data:
molecule_section.append( molecule_section.append(
nodes.field_name( nodes.field_name(text="Driver: {}".format(driver_data["name"]))
text='Driver: {}'.format(
driver_data['name']
)
)
) )
options = driver_data.get('options') options = driver_data.get("options")
if options: if options:
molecule_section.append( molecule_section.append(
self._yaml_section( self._yaml_section(
to_yaml_data=options, to_yaml_data=options, section_title="Molecule Options"
section_title='Molecule Options'
) )
) )
provisioner_data = molecule_conf.get('provisioner') platforms_data = molecule_conf.get('platforms',
molecule_defaults.get('platforms'))
if platforms_data:
molecule_section.append(
self._yaml_section(
to_yaml_data=platforms_data,
section_title="Molecule Platform(s)",
)
)
default_playbook = [molecule_path, test, "converge.yml"]
provisioner_data = molecule_conf.get('provisioner',
molecule_defaults.get('provisioner'))
if provisioner_data: if provisioner_data:
inventory = provisioner_data.get('inventory') inventory = provisioner_data.get('inventory')
if inventory: if inventory:
molecule_section.append( molecule_section.append(
self._yaml_section( self._yaml_section(
to_yaml_data=inventory, to_yaml_data=inventory,
section_title='Molecule Inventory' section_title="Molecule Inventory",
) )
) )
molecule_playbook_path = os.path.join( try:
molecule_path, converge = provisioner_data['playbooks']['converge']
test, default_playbook = default_playbook[:-1] + [converge]
'converge.yml' except KeyError:
) pass
if not os.path.exists(molecule_playbook_path):
molecule_playbook_path = os.path.join( molecule_playbook_path = os.path.join(*default_playbook)
molecule_path,
test,
'playbook.yml'
)
with open(molecule_playbook_path) as f: with open(molecule_playbook_path) as f:
molecule_playbook = DOCYAML.load(f.read()) molecule_playbook = DOCYAML.load(f.read())
molecule_section.append( molecule_section.append(
self._yaml_section( self._yaml_section(
to_yaml_data=molecule_playbook, to_yaml_data=molecule_playbook,
section_title='Example {} playbook'.format(test) section_title="Example {} playbook".format(test),
) )
) )
test_list.append(molecule_section) test_list.append(molecule_section)
@ -323,21 +344,18 @@ class AnsibleAutoPluginDirective(Directive):
self.run_returns.append(section) self.run_returns.append(section)
# Document any libraries nested within the role # Document any libraries nested within the role
library_path = os.path.join(role, 'library') library_path = os.path.join(role, "library")
if os.path.exists(library_path): if os.path.exists(library_path):
self.options['documentation'] = True self.options['documentation'] = True
self.options['examples'] = True self.options['examples'] = True
for lib in os.listdir(library_path): for lib in os.listdir(library_path):
if lib.endswith('.py'): if lib.endswith(".py"):
self._run_module( self._run_module(
module=self.load_module( module=self.load_module(
filename=os.path.join( filename=os.path.join(library_path, lib)
library_path,
lib
)
), ),
module_title='Embedded module: {}'.format(lib), module_title="Embedded module: {}".format(lib),
example_title='Examples for embedded module' example_title="Examples for embedded module",
) )
def _run_module(self, module, module_title="Module Documentation", def _run_module(self, module, module_title="Module Documentation",