Skip to content

Commit 1b6ac46

Browse files
authored
Generate plugin documentation from their sources (teemtee#2549)
This required a small refactoring of how field properties were stored. Instead of treating them as something owned by CLI options, they have their use outside of CLI area, and must exist in field metadata to be consumable in general. Now we have a template, a script, a section in docs. Fixing the content would be the next step...
1 parent e951241 commit 1b6ac46

14 files changed

+332
-65
lines changed

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
/tmp/
44
docs/code/autodocs/*.rst
5+
docs/plugins/discover.rst
6+
docs/plugins/execute.rst
7+
docs/plugins/finish.rst
8+
docs/plugins/prepare.rst
9+
docs/plugins/provision.rst
10+
docs/plugins/report.rst
11+
docs/plugins/test-checks.rst
512
docs/_build
613
docs/spec
714
docs/stories

docs/Makefile

+24-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
1616
# the i18n builder cannot share the environment and doctrees with the others
1717
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
1818

19-
.PHONY: help generate-stories generate-autodocs clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
19+
.PHONY: help generate-plugins plugins/*.rst generate-stories generate-autodocs clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
2020

2121
clean:
2222
rm -rf $(BUILDDIR) stories spec code/autodocs/*.rst
@@ -53,7 +53,9 @@ TMTDIR = $(REPODIR)/tmt
5353
SCRIPTSDIR = scripts
5454
TEMPLATESDIR = templates
5555

56-
generate: spec stories generate-lint-checks generate-test-checks generate-stories generate-autodocs ## Refresh all generated documentation sources
56+
PLUGINS_TEMPLATE := $(TEMPLATESDIR)/plugins.rst.j2
57+
58+
generate: spec stories generate-lint-checks generate-plugins generate-stories generate-autodocs ## Refresh all generated documentation sources
5759

5860
spec:
5961
mkdir -p spec
@@ -64,15 +66,33 @@ stories:
6466
spec/lint.rst: $(SCRIPTSDIR)/generate-lint-checks.py $(TEMPLATESDIR)/lint-checks.rst.j2 $(TMTDIR)/base.py
6567
$(SCRIPTSDIR)/generate-lint-checks.py $(TEMPLATESDIR)/lint-checks.rst.j2 $@
6668

67-
spec/test-checks.rst: $(SCRIPTSDIR)/generate-test-checks.py $(TEMPLATESDIR)/test-checks.rst.j2 $(TMTDIR)/checks/*.py
69+
plugins/discover.rst: $(SCRIPTSDIR)/generate-plugins.py $(PLUGINS_TEMPLATE) $(TMTDIR)/steps/discover/*.py
70+
$(SCRIPTSDIR)/generate-plugins.py discover $(PLUGINS_TEMPLATE) $@
71+
72+
plugins/execute.rst: $(SCRIPTSDIR)/generate-plugins.py $(PLUGINS_TEMPLATE) $(TMTDIR)/steps/execute/*.py
73+
$(SCRIPTSDIR)/generate-plugins.py execute $(PLUGINS_TEMPLATE) $@
74+
75+
plugins/finish.rst: $(SCRIPTSDIR)/generate-plugins.py $(PLUGINS_TEMPLATE) $(TMTDIR)/steps/finish/*.py
76+
$(SCRIPTSDIR)/generate-plugins.py finish $(PLUGINS_TEMPLATE) $@
77+
78+
plugins/prepare.rst: $(SCRIPTSDIR)/generate-plugins.py $(PLUGINS_TEMPLATE) $(TMTDIR)/steps/prepare/*.py
79+
$(SCRIPTSDIR)/generate-plugins.py prepare $(PLUGINS_TEMPLATE) $@
80+
81+
plugins/provision.rst: $(SCRIPTSDIR)/generate-plugins.py $(PLUGINS_TEMPLATE) $(TMTDIR)/steps/provision/*.py
82+
$(SCRIPTSDIR)/generate-plugins.py provision $(PLUGINS_TEMPLATE) $@
83+
84+
plugins/report.rst: $(SCRIPTSDIR)/generate-plugins.py $(PLUGINS_TEMPLATE) $(TMTDIR)/steps/report/*.py
85+
$(SCRIPTSDIR)/generate-plugins.py report $(PLUGINS_TEMPLATE) $@
86+
87+
plugins/test-checks.rst: $(SCRIPTSDIR)/generate-test-checks.py $(TEMPLATESDIR)/test-checks.rst.j2 $(TMTDIR)/checks/*.py
6888
$(SCRIPTSDIR)/generate-test-checks.py $(TEMPLATESDIR)/test-checks.rst.j2 $@
6989

7090
generate-lint-checks: spec spec/lint.rst ## Generate documentation sources for lint checks
7191

7292
generate-stories: stories $(TEMPLATESDIR)/story.rst.j2 ## Generate documentation sources for stories
7393
$(SCRIPTSDIR)/generate-stories.py $(TEMPLATESDIR)/story.rst.j2
7494

75-
generate-test-checks: spec spec/test-checks.rst ## Generate documentation sources for test checks
95+
generate-plugins: plugins/discover.rst plugins/execute.rst plugins/finish.rst plugins/prepare.rst plugins/provision.rst plugins/report.rst plugins/test-checks.rst ## Generate documentation sources for plugins
7696

7797
generate-autodocs: ## Generate autodocs from source docstrings
7898
cd ../ && sphinx-apidoc --force --implicit-namespaces --no-toc -o docs/code/autodocs tmt

docs/code/index.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55

66
In order to get a quick start with the ``tmt`` source code you
77
might want look through the :ref:`classes` first to learn about
8-
the overall structure of the code. The :ref:`plugins` can help if
9-
you are planning to write a new plugin. To find detailed
8+
the overall structure of the code. The :ref:`plugin_introduction`
9+
can help if you are planning to write a new plugin. To find detailed
1010
information about individual classes, modules and packages inspect
1111
the documentation generated from sources linked below.
1212

1313
.. toctree::
1414
:maxdepth: 2
1515

1616
Class Overview <classes>
17-
Plugin Introduction <plugins>
17+
Plugin Introduction <plugin-introduction>
1818
tmt <autodocs/tmt>
1919

2020
.. toctree::

docs/code/plugins.rst docs/code/plugin-introduction.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.. _plugins:
1+
.. _plugin_introduction:
22

33
===========================
44
Plugin Introduction

docs/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Table of Contents
2929
Overview <overview>
3030
Guide <guide>
3131
Specification <spec>
32+
Plugins <plugins/index>
3233
Examples <examples>
3334
Stories <stories>
3435
Questions <questions>

docs/plugins/index.rst

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.. _plugins:
2+
3+
Plugins
4+
=======
5+
6+
Here you will find documentation for plugins shipped with tmt.
7+
8+
.. warning::
9+
10+
Please, be aware that the documentation below is a work in progress. We are
11+
working on fixing it, adding missing bits and generally making it better.
12+
Also, it was originaly used for command line help only, therefore the
13+
formatting is often suboptional.
14+
15+
.. toctree::
16+
:maxdepth: 2
17+
18+
Discover <discover>
19+
Provision <provision>
20+
Prepare <prepare>
21+
Execute <execute>
22+
Finish <finish>
23+
Report <report>
24+
Test Checks <test-checks>

docs/scripts/generate-plugins.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
import textwrap
5+
6+
import tmt.log
7+
import tmt.plugins
8+
import tmt.steps.discover
9+
import tmt.steps.execute
10+
import tmt.steps.finish
11+
import tmt.steps.prepare
12+
import tmt.steps.provision
13+
import tmt.steps.report
14+
import tmt.utils
15+
from tmt.utils import Path, render_template_file
16+
17+
HELP = textwrap.dedent("""
18+
Usage: generate-plugins.py <STEP-NAME> <TEMPLATE-PATH> <OUTPUT-PATH>
19+
20+
Generate pages for step plugins sources.
21+
""").strip()
22+
23+
24+
def main() -> None:
25+
if len(sys.argv) != 4:
26+
print(HELP)
27+
28+
sys.exit(1)
29+
30+
step_name = sys.argv[1]
31+
template_filepath = Path(sys.argv[2])
32+
output_filepath = Path(sys.argv[3])
33+
34+
# We will need a logger...
35+
logger = tmt.log.Logger.create()
36+
logger.add_console_handler()
37+
38+
# ... explore available plugins...
39+
tmt.plugins.explore(logger)
40+
41+
if step_name == 'discover':
42+
registry = tmt.steps.discover.DiscoverPlugin._supported_methods
43+
44+
elif step_name == 'execute':
45+
registry = tmt.steps.execute.ExecutePlugin._supported_methods
46+
47+
elif step_name == 'finish':
48+
registry = tmt.steps.finish.FinishPlugin._supported_methods
49+
50+
elif step_name == 'prepare':
51+
registry = tmt.steps.prepare.PreparePlugin._supported_methods
52+
53+
elif step_name == 'provision':
54+
registry = tmt.steps.provision.ProvisionPlugin._supported_methods
55+
56+
elif step_name == 'report':
57+
registry = tmt.steps.report.ReportPlugin._supported_methods
58+
59+
else:
60+
raise tmt.utils.GeneralError(f"Unhandled step name '{step_name}'.")
61+
62+
# ... and render the template.
63+
output_filepath.write_text(render_template_file(
64+
template_filepath,
65+
STEP=step_name,
66+
REGISTRY=registry,
67+
container_fields=tmt.utils.container_fields,
68+
container_field=tmt.utils.container_field))
69+
70+
71+
if __name__ == '__main__':
72+
main()

docs/spec.rst

+1-4
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ Level 1: Tests
2727
Metadata closely related to individual :ref:`/spec/tests` such
2828
as the :ref:`/spec/tests/test` script, directory
2929
:ref:`/spec/tests/path` or maximum :ref:`/spec/tests/duration`
30-
which are stored directly with the test code. See
31-
:ref:`/spec/test-checks` for the list of available test
32-
:ref:`checks</spec/tests/check>`.
30+
which are stored directly with the test code.
3331

3432
Level 2: Plans
3533
:ref:`/spec/plans` are used to group relevant tests and enable
@@ -56,5 +54,4 @@ Level 3: Stories
5654
spec/stories
5755
spec/context
5856
spec/hardware
59-
spec/test-checks
6057
spec/lint

docs/templates/plugins.rst.j2

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
:tocdepth: 0
2+
3+
.. _/plugins/{{ STEP }}:
4+
5+
{{ STEP | capitalize }} Plugins
6+
{{ '=' * (8 + (STEP | length)) }}
7+
8+
{% for PLUGIN_ID in REGISTRY.iter_plugin_ids() %}
9+
{% set method = REGISTRY.get_plugin(PLUGIN_ID) %}
10+
{% set PLUGIN = method.class_ %}
11+
12+
.. _plugins/{{ STEP }}/{{ PLUGIN_ID | strip }}:
13+
14+
{{ PLUGIN_ID }}
15+
{{ '^' * (PLUGIN_ID | length)}}
16+
17+
{#
18+
TODO: once we start getting reviewed and polished plugins, drop the warning
19+
for those that would be done and ready. Probably with some temporary list
20+
to which we would add their names.
21+
#}
22+
.. warning::
23+
24+
Please, be aware that the documentation below is a work in progress. We are
25+
working on fixing it, adding missing bits and generally making it better.
26+
Also, it was originaly used for command line help only, therefore the
27+
formatting is often suboptional.
28+
29+
{% if PLUGIN.__doc__ %}
30+
{{ PLUGIN.__doc__ | dedent | strip }}
31+
{% endif %}
32+
33+
**Configuration**
34+
35+
{% for field in container_fields(PLUGIN._data_class) %}
36+
{% if (
37+
field.name not in ('how', 'name', 'where', '_OPTIONLESS_FIELDS')
38+
and field.internal != true
39+
and (
40+
not PLUGIN._data_class._OPTIONLESS_FIELDS
41+
or field.name not in PLUGIN._data_class._OPTIONLESS_FIELDS
42+
)
43+
) %}
44+
{% set _, option, _, metadata = container_field(PLUGIN._data_class, field.name) %}
45+
46+
{% if metadata.metavar %}
47+
{{ option }}: ``{{ metadata.metavar }}``
48+
{% elif metadata.default is boolean %}
49+
{{ option }}: ``true|false``
50+
{% else %}
51+
{{ option }}:
52+
{% endif %}
53+
{% if metadata.help %}
54+
{{ metadata.help | strip | indent(4, first=true) }}
55+
{% endif %}
56+
{% endif %}
57+
{% endfor %}
58+
59+
{% if not loop.last %}
60+
----
61+
{% endif %}
62+
{% endfor %}

docs/templates/test-checks.rst.j2

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
:tocdepth: 0
22

3-
.. _/spec/test-checks:
3+
.. _/plugins/test-checks:
44

55
Tests Checks
66
============
@@ -19,7 +19,7 @@ tmt.
1919
{% for PLUGIN_ID in REGISTRY.iter_plugin_ids() %}
2020
{% set PLUGIN = REGISTRY.get_plugin(PLUGIN_ID) %}
2121

22-
.. _spec/test-checks/{{ PLUGIN_ID | strip }}:
22+
.. _plugins/test-checks/{{ PLUGIN_ID | strip }}:
2323

2424
{{ PLUGIN_ID }}
2525
{{ '^' * (PLUGIN_ID | length)}}
@@ -37,7 +37,7 @@ tmt.
3737
{% if metadata.metavar %}
3838
{{ option }}: ``{{ metadata.metavar }}``
3939
{% elif metadata.default is boolean %}
40-
{{ option }}: ``true | false``
40+
{{ option }}: ``true|false``
4141
{% else %}
4242
{{ option }}: ...
4343
{% endif %}

spec/tests/check.fmf

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ description: |
1414
panic detection, core dump collection or collection of system
1515
logs.
1616

17-
See :ref:`/spec/test-checks` for the list of available checks.
17+
See :ref:`/plugins/test-checks` for the list of available checks.
1818

1919
example:
2020
- |

tmt/checks/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class Check(
9797
how: str
9898
enabled: bool = field(
9999
default=True,
100+
is_flag=True,
100101
help='Whether the check is enabled or not.')
101102

102103
@cached_property

tmt/steps/__init__.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,14 @@ class StepData(
251251
# TODO: we can easily add lists of keys for various verbosity levels...
252252
_KEYS_SHOW_ORDER = ['name', 'how']
253253

254-
name: str
255-
how: str
256-
order: int = tmt.utils.DEFAULT_PLUGIN_ORDER
257-
summary: Optional[str] = None
254+
name: str = field(help='The name of the step phase.')
255+
how: str = field()
256+
order: int = field(
257+
default=tmt.utils.DEFAULT_PLUGIN_ORDER,
258+
help='Order in which the phase should be handled.')
259+
summary: Optional[str] = field(
260+
default=None,
261+
help='Concise summary describing purpose of the phase.')
258262

259263
def to_spec(self) -> _RawStepData:
260264
""" Convert to a form suitable for saving in a specification file """

0 commit comments

Comments
 (0)