From 1a6237155a1bde4799a49d0de46a8cae9e485004 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 19 Mar 2024 12:53:03 -0400 Subject: [PATCH] documented plugin documentation on documenting Apply suggestions from code review Move some comment to 'common snippet' to be included in both plugin and module pages Co-authored-by: Abhijeet Kasurde --- .../collection_requirements.rst | 4 +- .../community/documentation_contributions.rst | 2 +- .../rst/community/maintainers_guidelines.rst | 2 +- docs/docsite/rst/dev_guide/ansible_index.rst | 1 + docs/docsite/rst/dev_guide/core_index.rst | 1 + .../developing_collections_documenting.rst | 2 +- .../developing_modules_documenting.rst | 66 +--- .../rst/dev_guide/developing_plugins.rst | 2 +- .../rst/dev_guide/document_linking.rst | 25 ++ .../rst/dev_guide/plugins_documenting.rst | 365 ++++++++++++++++++ .../docsite/rst/dev_guide/semantic_markup.rst | 37 ++ 11 files changed, 438 insertions(+), 69 deletions(-) create mode 100644 docs/docsite/rst/dev_guide/document_linking.rst create mode 100644 docs/docsite/rst/dev_guide/plugins_documenting.rst create mode 100644 docs/docsite/rst/dev_guide/semantic_markup.rst diff --git a/docs/docsite/rst/community/collection_contributors/collection_requirements.rst b/docs/docsite/rst/community/collection_contributors/collection_requirements.rst index 581ae8d60f..f6760481b4 100644 --- a/docs/docsite/rst/community/collection_contributors/collection_requirements.rst +++ b/docs/docsite/rst/community/collection_contributors/collection_requirements.rst @@ -532,7 +532,9 @@ To be included in the `ansible` package, collections must meet the following cri * `Collection requirements `_ (this document). * The `Collection Inclusion Criteria Checklist `_ covers most of the criteria from this document. -* :ref:`Ansible documentation format ` and the :ref:`style guide `. +* :ref:`Ansible module documentation format `. +* :ref:`Ansible plugin documentation format `. +* And the :ref:`style guide ` for both. * To pass the Ansible :ref:`sanity tests `. * To have :ref:`unit `_and / or :ref:`integration tests ` according to the corresponding sections of this document. diff --git a/docs/docsite/rst/community/documentation_contributions.rst b/docs/docsite/rst/community/documentation_contributions.rst index 05657287b6..3d4b2b06e7 100644 --- a/docs/docsite/rst/community/documentation_contributions.rst +++ b/docs/docsite/rst/community/documentation_contributions.rst @@ -235,5 +235,5 @@ The Documentation Working Group (DaWGs) meets weekly on Tuesdays in the Docs cha .. seealso:: :ref:`More about testing module documentation ` - :ref:`More about documenting modules ` + :ref:`More about documenting plugins ` diff --git a/docs/docsite/rst/community/maintainers_guidelines.rst b/docs/docsite/rst/community/maintainers_guidelines.rst index c85f8a21b5..3530749ec2 100644 --- a/docs/docsite/rst/community/maintainers_guidelines.rst +++ b/docs/docsite/rst/community/maintainers_guidelines.rst @@ -147,7 +147,7 @@ Maintaining good collection documentation Maintainers look after the collection documentation to ensure it matches the :ref:`style_guide`. This includes keeping the following documents accurate and updated regularly: -* Collection module and plugin documentation that adheres to the :ref:`Ansible documentation format `. +* Collection module and plugin documentation that adheres to the :ref:`Ansible module documentation format ` and :ref:`Ansible plugin documentation format `. * Collection user guides that follow the :ref:`Collection documentation format `. * Repository files that includes at least a ``README`` and ``CONTRIBUTING`` file. diff --git a/docs/docsite/rst/dev_guide/ansible_index.rst b/docs/docsite/rst/dev_guide/ansible_index.rst index a5c6f90ae5..30d6eed59a 100644 --- a/docs/docsite/rst/dev_guide/ansible_index.rst +++ b/docs/docsite/rst/dev_guide/ansible_index.rst @@ -46,6 +46,7 @@ Find the task that best describes what you want to do: * I want to :ref:`debug my module code `. * I want to :ref:`add tests `. * I want to :ref:`document my module `. + * I want to :ref:`document my plugin `. * I want to :ref:`document my set of modules for a network platform `. * I want to follow :ref:`conventions and tips for clean, usable module code `. * I want to :ref:`make sure my code runs on Python 2 and Python 3 `. diff --git a/docs/docsite/rst/dev_guide/core_index.rst b/docs/docsite/rst/dev_guide/core_index.rst index 1e9555cc50..69ca22df1a 100644 --- a/docs/docsite/rst/dev_guide/core_index.rst +++ b/docs/docsite/rst/dev_guide/core_index.rst @@ -43,6 +43,7 @@ Find the task that best describes what you want to do: * I want to :ref:`debug my module code `. * I want to :ref:`add tests `. * I want to :ref:`document my module `. + * I want to :ref:`document my plugin `. * I want to :ref:`document my set of modules for a network platform `. * I want to follow :ref:`conventions and tips for clean, usable module code `. * I want to :ref:`make sure my code runs on Python 2 and Python 3 `. diff --git a/docs/docsite/rst/dev_guide/developing_collections_documenting.rst b/docs/docsite/rst/dev_guide/developing_collections_documenting.rst index a0d6067654..1dfdd3d21d 100644 --- a/docs/docsite/rst/dev_guide/developing_collections_documenting.rst +++ b/docs/docsite/rst/dev_guide/developing_collections_documenting.rst @@ -7,7 +7,7 @@ Documenting collections Documenting modules and plugins =============================== -Documenting modules is thoroughly documented in :ref:`module_documenting`. Plugins can be documented the same way as modules, that is with ``DOCUMENTATION``, ``EXAMPLES``, and ``RETURN`` blocks. +A comprehensive guide to documenting modules can be found in :ref:`module_documenting`. Plugins can be documented similarly to modules :ref:`plugins_documenting`, that is with ``DOCUMENTATION``, ``EXAMPLES``, and ``RETURN`` blocks. Documenting roles ================= diff --git a/docs/docsite/rst/dev_guide/developing_modules_documenting.rst b/docs/docsite/rst/dev_guide/developing_modules_documenting.rst index 161b84533f..7abc230557 100644 --- a/docs/docsite/rst/dev_guide/developing_modules_documenting.rst +++ b/docs/docsite/rst/dev_guide/developing_modules_documenting.rst @@ -252,73 +252,11 @@ All fields in the ``DOCUMENTATION`` block are lower-case. All fields are require .. _module_documents_linking: -Linking within module documentation ------------------------------------ - -You can link from your module documentation to other module docs, other resources on docs.ansible.com, and resources elsewhere on the internet with the help of some pre-defined macros. The correct formats for these macros are: - -* ``L()`` for links with a heading. For example: ``See L(Ansible Automation Platform,https://www.ansible.com/products/automation-platform).`` As of Ansible 2.10, do not use ``L()`` for relative links between Ansible documentation and collection documentation. -* ``U()`` for URLs. For example: ``See U(https://www.ansible.com/products/automation-platform) for an overview.`` -* ``R()`` for cross-references with a heading (added in Ansible 2.10). For example: ``See R(Cisco IOS Platform Guide,ios_platform_options)``. Use the RST anchor for the cross-reference. See :ref:`adding_anchors_rst` for details. -* ``M()`` for module names. For example: ``See also M(ansible.builtin.yum) or M(community.general.apt_rpm)``. A FQCN **must** be used, short names will create broken links; use ``ansible.builtin`` for modules in ansible-core. -* ``P()`` for plugin names. For example: ``See also P(ansible.builtin.file#lookup) or P(community.general.json_query#filter)``. This can also reference roles: ``P(community.sops.install#role)``. This is supported since ansible-core 2.15. FQCNs must be used; use ``ansible.builtin`` for plugins in ansible-core. - -.. note:: - - For links between modules and documentation within a collection, you can use any of the options above. For links outside of your collection, use ``R()`` if available. Otherwise, use ``U()`` or ``L()`` with full URLs (not relative links). For modules, use ``M()`` with the FQCN or ``ansible.builtin`` as shown in the example. If you are creating your own documentation site, you will need to use the `intersphinx extension `_ to convert ``R()`` and ``M()`` to the correct links. - -.. note:: - To refer to a group of modules in a collection, use ``R()``. When a collection is not the right granularity, use ``C(..)``: - - - ``Refer to the R(kubernetes.core collection, plugins_in_kubernetes.core) for information on managing kubernetes clusters.`` - - ``The C(win_*) modules (spread across several collections) allow you to manage various aspects of windows hosts.`` - -.. note:: - - Because it stands out better, use ``seealso`` for general references over the use of notes or adding links to the description. +.. include:: document_linking.rst .. _semantic_markup: -Semantic markup within module documentation -------------------------------------------- - -You can use semantic markup to highlight option names, option values, and environment variables. The markup processor formats these highlighted terms in a uniform way. With semantic markup, we can modify how the output looks without changing underlying code. - -The correct formats for semantic markup are as follows: - -* ``O()`` for option names, whether mentioned alone or with values. For example: ``Required if O(state=present).`` and ``Use with O(force) to require secure access.`` -* ``V()`` for option values when mentioned alone. For example: ``Possible values include V(monospace) and V(pretty).`` -* ``RV()`` for return value names, whether mentioned alone or with values. For example: ``The module returns RV(changed=true) in case of changes.`` and ``Use the RV(stdout) return value for standard output.`` -* ``E()`` for environment variables. For example: ``If not set, the environment variable E(ACME_PASSWORD) will be used.`` - -The parameters for these formatting functions can use escaping with backslashes: ``V(foo(bar="a\\b"\), baz)`` results in the formatted value ``foo(bar="a\b"), baz)``. - -Rules for using ``O()`` and ``RV()`` are very strict. You must follow syntax rules so that documentation renderers can create hyperlinks for the options and return values, respectively. - -The allowed syntaxes are as follows: -- To reference an option for the current plugin/module, or the entrypoint of the current role (inside role entrypoint documentation), use ``O(option)`` and ``O(option=name)``. -- To reference an option for another entrypoint ``entrypoint`` from inside role documentation, use ``O(entrypoint:option)`` and ``O(entrypoint:option=name)``. The entrypoint information can be ignored by the documentation renderer, turned into a link to that entrypoint, or even directly to the option of that entrypoint. -- To reference an option for *another* plugin/module ``plugin.fqcn.name`` of type ``type``, use ``O(plugin.fqcn.name#type:option)`` and ``O(plugin.fqcn.name#type:option=name)``. For modules, use ``type=module``. The FQCN and plugin type can be ignored by the documentation renderer, turned into a link to that plugin, or even directly to the option of that plugin. -- To reference an option for entrypoint ``entrypoint`` of *another* role ``role.fqcn.name``, use ``O(role.fqcn.name#role:entrypoint:option)`` and ``O(role.fqcn.name#role:entrypoint:option=name)``. The FQCN and entrypoint information can be ignored by the documentation renderer, turned into a link to that entrypoint, or even directly to the option of that entrypoint. -- To reference options that do not exist (for example, options that were removed in an earlier version), use ``O(ignore:option)`` and ``O(ignore:option=name)``. The ``ignore:`` part will not be shown to the user by documentation rendering. - -Option names can refer to suboptions by listing the path to the option separated by dots. For example, if you have an option ``foo`` with suboption ``bar``, then you must use ``O(foo.bar)`` to reference that suboption. You can add array indications like ``O(foo[].bar)`` or even ``O(foo[-1].bar)`` to indicate specific list elements. Everything between ``[`` and ``]`` pairs will be ignored to determine the real name of the option. For example, ``O(foo[foo | length - 1].bar[])`` results in the same link as ``O(foo.bar)``, but the text ``foo[foo | length - 1].bar[]`` displays instead of ``foo.bar``. - -The same syntaxes can be used for ``RV()``, except that these will refer to return value names instead of option names; for example ``RV(ansible.builtin.service_facts#module:ansible_facts.services)`` refers to the :ansretval:`ansible.builtin.service_facts#module:ansible_facts.services` fact returned by the :ansplugin:`ansible.builtin.service_facts module `. - -Format macros within module documentation ------------------------------------------ - -While it is possible to use standard Ansible formatting macros to control the look of other terms in module documentation, you should do so sparingly. - -Possible macros include the following: - -* ``C()`` for ``monospace`` (code) text. For example: ``This module functions like the unix command C(foo).`` -* ``B()`` for bold text. -* ``I()`` for italic text. -* ``HORIZONTALLINE`` for a horizontal rule (the ``
`` html tag) to separate long descriptions. - -Note that ``C()``, ``B()``, and ``I()`` do **not allow escaping**, and thus cannot contain the value ``)`` as it always ends the formatting sequence. If you need to use ``)`` inside ``C()``, we recommend to use ``V()`` instead; see the above section on semantic markup. +.. include:: semantic_markup.rst .. _module_docs_fragments: diff --git a/docs/docsite/rst/dev_guide/developing_plugins.rst b/docs/docsite/rst/dev_guide/developing_plugins.rst index dce4ed934f..e5fbca62fa 100644 --- a/docs/docsite/rst/dev_guide/developing_plugins.rst +++ b/docs/docsite/rst/dev_guide/developing_plugins.rst @@ -89,7 +89,7 @@ If you need to populate settings explicitly, use a ``self.set_options()`` call. Configuration sources follow the precedence rules for values in Ansible. When there are multiple values from the same category, the value defined last takes precedence. For example, in the above configuration block, if both ``name_of_ansible_var`` and ``name_of_second_var`` are defined, the value of the ``option_name`` option will be the value of ``name_of_second_var``. Refer to :ref:`general_precedence_rules` for further information. -Plugins that support embedded documentation (see :ref:`ansible-doc` for the list) should include well-formed doc strings. If you inherit from a plugin, you must document the options it takes, either through a documentation fragment or as a copy. See :ref:`module_documenting` for more information on correct documentation. Thorough documentation is a good idea even if you're developing a plugin for local use. +Plugins that support embedded documentation (see :ref:`ansible-doc` for the list) should include well-formed doc strings. If you inherit from a plugin, you must document the options it takes, either through a documentation fragment or as a copy. See :ref:`plugins_documenting` for more information on correct documentation. Thorough documentation is a good idea even if you're developing a plugin for local use. In ansible-core 2.14 we added support for documenting filter and test plugins. You have two options for providing documentation: - Define a Python file that includes inline documentation for each plugin. diff --git a/docs/docsite/rst/dev_guide/document_linking.rst b/docs/docsite/rst/dev_guide/document_linking.rst new file mode 100644 index 0000000000..6d7876e48a --- /dev/null +++ b/docs/docsite/rst/dev_guide/document_linking.rst @@ -0,0 +1,25 @@ +Linking within plugin documentation +----------------------------------- + +You can link from your plugin or module documentation to other plugin/module, other resources on docs.ansible.com, and resources elsewhere on the internet with the help of some pre-defined macros. The correct formats for these macros are: + +* ``L()`` for links with a heading. For example: ``See L(Ansible Automation Platform,https://www.ansible.com/products/automation-platform).`` As of Ansible 2.10, do not use ``L()`` for relative links between Ansible documentation and collection documentation. +* ``U()`` for URLs. For example: ``See U(https://www.ansible.com/products/automation-platform) for an overview.`` +* ``R()`` for cross-references with a heading (added in Ansible 2.10). For example: ``See R(Cisco IOS Platform Guide,ios_platform_options)``. Use the RST anchor for the cross-reference. See :ref:`adding_anchors_rst` for details. +* ``M()`` for module names. For example: ``See also M(ansible.builtin.yum) or M(community.general.apt_rpm)``. A FQCN **must** be used, short names will create broken links; use ``ansible.builtin`` for modules in ansible-core. +* ``P()`` for plugin names. For example: ``See also P(ansible.builtin.file#lookup) or P(community.general.json_query#filter)``. This can also reference roles: ``P(community.sops.install#role)``. This is supported since ansible-core 2.15. FQCNs must be used; use ``ansible.builtin`` for plugins in ansible-core. + +.. note:: + + For links between pluigins and documentation within a collection, you can use any of the options above. For links outside of your collection, use ``R()`` if available. Otherwise, use ``U()`` or ``L()`` with full URLs (not relative links). For modules, use ``M()`` with the FQCN or ``ansible.builtin`` as shown in the example. If you are creating your own documentation site, you will need to use the `intersphinx extension `_ to convert ``R()`` and ``M()`` to the correct links. + +.. note:: + To refer to a group of modules in a collection, use ``R()``. When a collection is not the right granularity, use ``C(..)``: + + - ``Refer to the R(kubernetes.core collection, plugins_in_kubernetes.core) for information on managing kubernetes clusters.`` + - ``The C(win_*) modules (spread across several collections) allow you to manage various aspects of windows hosts.`` + +.. note:: + + Because it stands out better, use ``seealso`` for general references over the use of notes or adding links to the description. + diff --git a/docs/docsite/rst/dev_guide/plugins_documenting.rst b/docs/docsite/rst/dev_guide/plugins_documenting.rst new file mode 100644 index 0000000000..c2408bfc1c --- /dev/null +++ b/docs/docsite/rst/dev_guide/plugins_documenting.rst @@ -0,0 +1,365 @@ +.. _plugins_documenting: + +******************************* +Plugin format and documentation +******************************* + +Not all plugins can be documented, but those that can (`documentable `), follow a specific common format, except modules that have their own extended format. Also, some of these plugin types (`configurable `) use the documentation to build their argument validation and type casting, unlike modules that require a separate 'args_spec'. + +This document will describe how the plugin configuration works in general, excluding modules, which have their own `documentation reference:developing_modules_documenting`. + +.. note:: While most plugins support having the documentation in YAML format inside the same Python code file, filters and tests also support an 'adjacent' YAML file as both of those plugins also support having multiple of them defined in the same file. + With YAML files, the examples below are easy to use by removing Python quoting and substituting ``=`` for ``:``, for example ``DOCUMENTATION = r''' ... '''` ` to ``DOCUMENTATION: ...`` and removing closing quotes. :ref:`adjacent_yaml_doc` + + +Every Ansible plugin must be written in Python, with modules being the main exception, also they must begin with several standard sections in a particular order, followed by the code. The sections in order are: + +.. contents:: + :depth: 1 + :local: + +.. note:: Why don't the imports go first? + + Keen Python programmers may notice that contrary to PEP 8's advice we don't put ``imports`` at the top of the file. This is because the ``DOCUMENTATION`` through ``RETURN`` sections are essentially extra docstrings for the file. The imports are placed after these special variables for the same reason as PEP 8 puts the imports after the introductory comments and docstrings. This keeps the active parts of the code together and the pieces which are purely informational apart. The decision to exclude E402 is based on readability (which is what PEP 8 is about). Documentation strings in a plugin are much more similar to module-level docstrings. Placing the imports below this documentation and closer to the code, consolidates and groups all related code in a congruent manner to improve readability, debugging and understanding. + + +.. _plugins_shebang_and_encoding: + +Python shebang & UTF-8 coding +=============================== + +Unlike modules, shebangs are not used by plugins since they are imported into Ansible's engine rather than being run as a script. +So your first line will normally be the encoding:: + + # -*- coding: utf-8 -*- + +.. _plugins_copyright: + +Copyright and license +===================== + +After the UTF-8 encoding notice, add a `copyright line `_ with the original copyright holder and a license declaration. The license declaration should be ONLY one line, not the full GPL prefix.:: + + # -*- coding: utf-8 -*- + + # Copyright: Contributors to the Ansible project + # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +Additions to the module (for example, rewrites) are not permitted to add additional copyright lines other than the default copyright statement if missing:: + + # Copyright: Contributors to the Ansible project + +Any legal review will include the source control history, so an exhaustive copyright header is not necessary. +Please do not include a copyright year. If the existing copyright statement includes a year, do not edit the existing copyright year. Any existing copyright header should not be modified without permission from the copyright author. + +.. _plugins_documentation_block: + +DOCUMENTATION block +=================== + +The next section is the ``DOCUMENTATION`` block. Ansible's plugin documentation is generated from the ``DOCUMENTATION`` blocks, both for the online site and the ``ansible-doc`` output. The ``DOCUMENTATION`` block must be valid YAML. You may find it easier to start writing your ``DOCUMENTATION`` string in an :ref:`editor with YAML syntax highlighting ` before you include it in your Python file. + +Plugin documentation should briefly and accurately define what each plugin is meant to accomplish and what and each option does. Documentation should be written for a broad audience--readable both by experts and non-experts. + * Descriptions should always start with a capital letter and end with a full stop. Consistency always helps. + +To create clear, concise, consistent, and useful documentation, follow the :ref:`style guide `. + +Each documentation field is described below. Before committing your plugin documentation, please test it at the command line and as HTML: + +* You can use ``ansible-doc -t `` to view your documentation at the command line. Any parsing errors will be obvious - you can view details by adding ``-vvv`` to the command. +* You should also :ref:`test the HTML output ` of your plugin documentation. + + +Documentation fields +-------------------- + +All fields in the ``DOCUMENTATION`` block are lower-case. All fields are required unless specified otherwise: + +:name: + + * The name of the plugin. + * For most plugins, it must be the same as the file name, without the ``.py`` extension. + * For filters and tests it must match the name used to invoke them in a template. + +:short_description: + + * The ``short_description`` is displayed by ``ansible-doc -l`` without any category grouping, + so it needs enough detail to explain the module's purpose without the context of the directory structure in which it lives. + * Unlike ``description:``, ``short_description`` should not have a trailing period/full stop. + +:description: + + * A detailed description (generally two or more sentences). + * Must be written in full sentences, in other words, with capital letters and periods/full stops. + * Should not mention the plugin name. + * Make use of multiple entries rather than using one long paragraph. + * Do not quote complete values unless it is required by YAML. + +:version_added: + + * The version of the collection when the plugin was added. In the case of adding to Ansible core, that version is used instead. + * This is a string, and not a float, for example, ``version_added: '2.1.0'``. + +:author: + + * Name of the author in the form ``First Last (@GitHubID)``. + * Use a multi-line list if there is more than one author. + * Do not use quotes as it should not be required by YAML. + +:deprecated: + + * Marks the plugin for removal in future releases. See also :ref:`module_lifecycle`. + +:options: + + * Options are often called `parameters` or `arguments`. Because the documentation field is called `options`, we will use that term. + * If the plugin has no options, all you need is one line: ``options: {}``. + * If your plugin has options (in other words, accepts arguments), each option should be documented thoroughly. For each option, include: + + :option-name: + + * Declarative operation (not CRUD), to focus on the final state, for example `online:`, rather than `is_online:`. + * The name of the option should be consistent with the rest of the plugin, as well as other plugins in the same category. + * When in doubt, look for other plugins to find option names that are used for the same purpose, we like to offer consistency to our users. + + :description: + + * Detailed explanation of what this option does. It should be written in full sentences. + * The first entry is a description of the option itself; subsequent entries detail its use, dependencies, or format of possible values. + * Should not list the possible values (that's what ``choices:`` is for, though it should explain what the values do if they aren't obvious). + * If an option is only sometimes required, describe the conditions. For example, "Required when I(state=present)." + * Mutually exclusive options must be documented as the final sentence on each of the options. + + :required: + + * Only needed if ``true``. + * If missing, we assume the option is not required. + + :default: + + * If ``required`` is false/missing, ``default`` may be specified (assumed 'null' if missing). + * Ensure that the default value in the docs matches the default value in the code. + * The default field must not be listed as part of the description, unless it requires additional information or conditions. + * If the option is a boolean value, you can use any of the boolean values recognized by Ansible + (such as ``true``/``false`` or ``yes``/``no``). Document booleans as ``true``/``false`` for consistency and compatibility with ansible-lint. + + :choices: + + * List of option values. + * Should be absent if empty. + + :type: + + * Specifies the data type that option accepts, must match the ``argspec``. + * If an argument is ``type='bool'``, this field should be set to ``type: bool`` and no ``choices`` should be specified. + * If an argument is ``type='list'``, ``elements`` should be specified. + + :elements: + + * Specifies the data type for list elements in case ``type='list'``. + + :version_added: + + * Only needed if this option was extended after initial release of the plugin, in other words, this is greater than the top level `version_added` field. + * This is a string, and not a float, for example, ``version_added: '2.3.0'``. + +:requirements: + + * List of requirements, this should include any Python non core libraries/imports and command line utilities (if applicable). + * Include minimum versions, maximum also if the requirement has made backward incompatible changes. + +:seealso: + + * A list of references to other plugins, documentation or Internet resources + * In Ansible 2.10 and later, references to plugins or modules must use the FQCN or ``ansible.builtin`` for plugins in ``ansible-core``. + * Plugin references are supported since ansible-core 2.15. + * A reference can be one of the following formats: + + + .. code-block:: yaml+jinja + + seealso: + + # Reference by module name + - module: cisco.aci.aci_tenant + + # Reference by module name, including description + - module: cisco.aci.aci_tenant + description: ACI module to create tenants on a Cisco ACI fabric. + + # Reference by plugin name + - plugin: ansible.builtin.file + plugin_type: lookup + + # Reference by plugin name, including description + - plugin: ansible.builtin.file + plugin_type: lookup + description: You can use the ansible.builtin.file lookup to read files on the control node. + + # Reference by rST documentation anchor + - ref: aci_guide + description: Detailed information on how to manage your ACI infrastructure using Ansible. + + # Reference by rST documentation anchor (with custom title) + - ref: The official Ansible ACI guide + description: Detailed information on how to manage your ACI infrastructure using Ansible. + + # Reference by Internet resource + - name: APIC Management Information Model reference + description: Complete reference of the APIC object model. + link: https://developer.cisco.com/docs/apic-mim-ref/ + + + * If you use ``ref:`` to link to an anchor that is not associated with a title, you must add a title to the ref for the link to work correctly. + + +:notes: + + * Details of any important information that doesn't fit in one of the above sections. + +.. _plugins_documents_linking: + +.. include:: document_linking.rst + +.. _plugins_semantic_markup: + +.. include:: semantic_markup.rst + +.. _plugins_docs_fragments: + +Documentation fragments +----------------------- + +If you are writing multiple related plugins, they may share common documentation, such as authentication details, file mode settings, ``notes:`` or ``seealso:`` entries. Rather than duplicate that information in each plugin's ``DOCUMENTATION`` block, you can save it once as a doc_fragment plugin and use it in each plugin's documentation. In Ansible, shared documentation fragments are contained in a ``ModuleDocFragment`` class in `lib/ansible/plugins/doc_fragments/ `_ or the equivalent directory in a collection. To include a documentation fragment, add ``extends_documentation_fragment: FRAGMENT_NAME`` in your plugin documentation. Use the fully qualified collection name for the FRAGMENT_NAME (for example, ``kubernetes.core.k8s_auth_options``). + +Plugins should only use items from a doc fragment if the plugin will implement all of the interface documented there in a manner that behaves the same as the existing plugin which import that fragment. The goal is that items imported from the doc fragment will behave identically when used in another plugin that imports the doc fragment. + +By default, only the ``DOCUMENTATION`` property from a doc fragment is inserted into the plugin documentation. It is possible to define additional properties in the doc fragment in order to import only certain parts of a doc fragment or mix and match as appropriate. If a property is defined in both the doc fragment and the plugin, the plugin value overrides the doc fragment. + +Here is an example doc fragment named ``example_fragment.py``: + +.. code-block:: python + + class ModuleDocFragment(object): + # Standard documentation + DOCUMENTATION = r''' + options: + # options here + ''' + + # Additional section + OTHER = r''' + options: + # other options here + ''' + + +To insert the contents of ``OTHER`` in a plugin: + +.. code-block:: yaml+jinja + + extends_documentation_fragment: example_fragment.other + +Or use both : + +.. code-block:: yaml+jinja + + extends_documentation_fragment: + - example_fragment + - example_fragment.other + +.. _note: + * Prior to Ansible 2.8, documentation fragments were kept in ``lib/ansible/utils/module_docs_fragments``. + +.. versionadded:: 2.8 + +Since Ansible 2.8, you can have user-supplied doc_fragments by using a ``doc_fragments`` directory adjacent to play or role, just like any other plugin. + +For example, all AWS modules should include: + +.. code-block:: yaml+jinja + + extends_documentation_fragment: + - aws + - ec2 + +:ref:`docfragments_collections` describes how to incorporate documentation fragments in a collection. + +.. _plugins_examples_block: + +EXAMPLES block +============== + +After the shebang, the UTF-8 coding, the copyright line, the license section, and the ``DOCUMENTATION`` block comes the ``EXAMPLES`` block. Here you show users how your plugin works with real-world examples in multi-line plain-text or YAML format. The best examples are ready for the user to copy and paste into a playbook. Review and update your examples with every change to your plugin. + +Use a fully qualified collection name (FQCN) as a part of the plugin's name. For plugins in ``ansible-core``, use the ``ansible.builtin.`` identifier, for example ``ansible.builtin.pipe``. + +If your examples use boolean options, favor yes/no values, this is not always possible as some plugins will force using Python or Jinja2 specific booleans. + +.. _plugins_return_block: + +RETURN block +============ + +After the shebang, the UTF-8 coding, the copyright line, the license section, ``DOCUMENTATION`` and ``EXAMPLES`` blocks comes the ``RETURN`` block. This section documents the information the plugin returns for use by other plugins. + +If your plugin doesn't return anything, this section should read: ``RETURN = r''' # '''`` +Otherwise, for each value returned, provide the following fields. All fields are required unless specified otherwise. + +:return name: + Name of the returned field. + + :description: + Detailed description of what this value represents. Capitalized and with trailing dot. + :type: + Data type. + :elements: + If ``type='list'``, specifies the data type of the list's elements. + :sample: + One or more examples. + :version_added: + Only needed if this return was extended after initial plugin release, in other words, this is greater than the top level `version_added` field. + This is a string, and not a float, for example, ``version_added: '2.3.0'``. + :contains: + Optional. To describe nested return values, set ``type: dict``, or ``type: list``/``elements: dict``, or if you really have to, ``type: complex``, and repeat the elements above for each sub-field. + +Here are two example ``RETURN`` sections, one with three simple fields and one with a complex nested field: + +.. code-block:: text + + # lookkup plugin + RETURN = r''' + _list: + description: List of destination file/path(s). + type: str + sample: /path/to/file.txt + ''' + + # test plugin + RETURN = r''' + _result: + description: If input matched test or not + type: bool + ''' + +.. _plugins_python_imports: + +Python imports +============== + +Now can finally add the python imports. Normally we order them in sections: python core, ansible libraries, other 3rd party libraries, then within each section we sort them alphabetically. + +.. code-block:: python + + from os import path + + from ansilbe.utils.path import unfrackpath + + import requests + +.. _dev_testing_plugin_documentation: + +Testing plugin documentation +============================ + +To test Ansible documentation locally please :ref:`follow instruction`. To test documentation in collections, please see :ref:`build_collection_docsite`. diff --git a/docs/docsite/rst/dev_guide/semantic_markup.rst b/docs/docsite/rst/dev_guide/semantic_markup.rst new file mode 100644 index 0000000000..0e8e1407e9 --- /dev/null +++ b/docs/docsite/rst/dev_guide/semantic_markup.rst @@ -0,0 +1,37 @@ +Semantic markup within plugin documentation +------------------------------------------- + +You can use semantic markup to highlight option names, option values, and environment variables. The markup processor formats these highlighted terms in a uniform way. With semantic markup, we can modify how the output looks without changing underlying code. + +The correct formats for semantic markup are as follows: + +* ``O()`` for option names, whether mentioned alone or with values. For example: ``Required if O(state=present).`` and ``Use with O(force) to require secure access.`` +* ``V()`` for option values when mentioned alone. For example: ``Possible values include V(monospace) and V(pretty).`` +* ``RV()`` for return value names, whether mentioned alone or with values. For example: ``The plugin returns RV(changed=true) in case of changes.`` and ``Use the RV(stdout) return value for standard output.`` +* ``E()`` for environment variables. For example: ``If not set, the environment variable E(ACME_PASSWORD) will be used.`` + +The parameters for these formatting functions can use escaping with backslashes: ``V(foo(bar="a\\b"\), baz)`` results in the formatted value ``foo(bar="a\b"), baz)``. + +Rules for using ``O()`` and ``RV()`` are very strict. You must follow syntax rules so that documentation renderer can create hyperlinks for the options and return values, respectively. + +The allowed syntax are as follows: +- To reference an option for the current plugin/module, or the entry point of the current role (inside role entry point documentation), use ``O(option)`` and ``O(option=name)``. +- To reference an option for another entry point ``entrypoint`` from inside role documentation, use ``O(entrypoint:option)`` and ``O(entrypoint:option=name)``. The entry point information can be ignored by the documentation renderer, turned into a link to that entry point, or even directly to the option of that entry point. +- To reference an option for *another* plugin/module ``plugin.fqcn.name`` of type ``type``, use ``O(plugin.fqcn.name#type:option)`` and ``O(plugin.fqcn.name#type:option=name)``. For modules, use ``type=module``. The FQCN and plugin type can be ignored by the documentation renderer, turned into a link to that plugin, or even directly to the option of that plugin. +- To reference an option for entry point ``entrypoint`` of *another* role ``role.fqcn.name``, use ``O(role.fqcn.name#role:entrypoint:option)`` and ``O(role.fqcn.name#role:entrypoint:option=name)``. The FQCN and entry point information can be ignored by the documentation renderer, turned into a link to that entry point, or even directly to the option of that entry point. +- To reference options that do not exist (for example, options that were removed in an earlier version), use ``O(ignore:option)`` and ``O(ignore:option=name)``. The ``ignore:`` part will not be shown to the user by documentation rendering. + +Format macros within module documentation +----------------------------------------- + +While it is possible to use standard Ansible formatting macros to control the look of other terms in plugin documentation, you should do so sparingly. + +Possible macros include the following: + +* ``C()`` for ``monospace`` (code) text. For example: ``This plugin functions like the unix command C(foo).`` +* ``B()`` for bold text. +* ``I()`` for italic text. +* ``HORIZONTALLINE`` for a horizontal rule (the ``
`` HTML tag) to separate long descriptions. + +Note that ``C()``, ``B()``, and ``I()`` do **not allow escaping**, and thus cannot contain the value ``)`` as it always ends the formatting sequence. If you need to use ``)`` inside ``C()``, we recommend to use ``V()`` instead; see the above section on semantic markup. +