diff --git a/changelogs/fragments/225-examples-format.yml b/changelogs/fragments/225-examples-format.yml new file mode 100644 index 00000000..6e6f637e --- /dev/null +++ b/changelogs/fragments/225-examples-format.yml @@ -0,0 +1,2 @@ +bugfixes: + - "When ``EXAMPLES`` has the format specified by ``# fmt: ``, this value is used to determine the code block type (https://github.com/ansible-community/antsibull-docs/pull/225)." diff --git a/src/antsibull_docs/data/docsite/ansible-docsite/plugin.rst.j2 b/src/antsibull_docs/data/docsite/ansible-docsite/plugin.rst.j2 index 194d1850..079c8728 100644 --- a/src/antsibull_docs/data/docsite/ansible-docsite/plugin.rst.j2 +++ b/src/antsibull_docs/data/docsite/ansible-docsite/plugin.rst.j2 @@ -331,7 +331,7 @@ See Also Examples -------- -.. code-block:: yaml+jinja +.. code-block:: @{ examples_format | rst_format(for_sphinx=true) }@ @{ examples | indent(4, True) }@ diff --git a/src/antsibull_docs/data/docsite/simplified-rst/plugin.rst.j2 b/src/antsibull_docs/data/docsite/simplified-rst/plugin.rst.j2 index a576fd98..8b44af04 100644 --- a/src/antsibull_docs/data/docsite/simplified-rst/plugin.rst.j2 +++ b/src/antsibull_docs/data/docsite/simplified-rst/plugin.rst.j2 @@ -260,7 +260,7 @@ See Also Examples -------- -.. code-block:: yaml +.. code-block:: @{ examples_format | rst_format }@ @{ examples | indent(4, True) }@ diff --git a/src/antsibull_docs/jinja2/environment.py b/src/antsibull_docs/jinja2/environment.py index 1ed907e9..55af574a 100644 --- a/src/antsibull_docs/jinja2/environment.py +++ b/src/antsibull_docs/jinja2/environment.py @@ -26,6 +26,7 @@ plugin_shortname, remove_options_from_list, rst_fmt, + rst_format, rst_xline, suboption_depth, to_ini_value, @@ -153,6 +154,7 @@ def doc_environment( env.filters["collection_name"] = collection_name env.filters["plugin_shortname"] = plugin_shortname env.filters["suboption_depth"] = suboption_depth + env.filters["rst_format"] = rst_format if collection_url is not None: env.filters["collection_url"] = collection_url if collection_install is not None: diff --git a/src/antsibull_docs/jinja2/filters.py b/src/antsibull_docs/jinja2/filters.py index b82685d8..1958d7bf 100644 --- a/src/antsibull_docs/jinja2/filters.py +++ b/src/antsibull_docs/jinja2/filters.py @@ -238,3 +238,16 @@ def suboption_depth( if subdata and isinstance(subdata, Mapping): subdepth = max(subdepth, suboption_depth(subdata.items(), subkey)) return subdepth + 1 + + +def rst_format(fmt: str, for_sphinx: bool = False) -> str: + if fmt == "ini": + return "ini" + if fmt == "toml": + return "toml" + if fmt == "yaml": + return "yaml+jinja" if for_sphinx else "yaml" + if fmt == "json": + return "json" + # Unknown format: no syntax highlighting + return "text" diff --git a/src/antsibull_docs/schemas/docs/plugin.py b/src/antsibull_docs/schemas/docs/plugin.py index d2607820..729a489b 100644 --- a/src/antsibull_docs/schemas/docs/plugin.py +++ b/src/antsibull_docs/schemas/docs/plugin.py @@ -9,6 +9,7 @@ # to initialize the attributes when data is loaded into them. # pyre-ignore-all-errors[13] +import re import typing as t import pydantic as p @@ -32,6 +33,8 @@ _SENTINEL = object() +_EXAMPLES_FMT_RE = re.compile(r"^# fmt:\s+(\S+)") + class OptionCliSchema(BaseModel): name: str = REQUIRED_CLI_F @@ -207,6 +210,15 @@ class PluginDocSchema(BaseModel): class PluginExamplesSchema(BaseModel): examples: str = "" + examples_format: str = "yaml" + + @p.validator("examples_format", always=True) + # pylint:disable=no-self-argument + def extract_examples_format(cls, value: t.Any, values: dict[str, t.Any]): + if isinstance(examples := values.get("examples"), str): + if fmt_match := _EXAMPLES_FMT_RE.match(examples.lstrip()): + value = fmt_match.group(1) + return value @p.validator("examples", pre=True) # pylint:disable=no-self-argument diff --git a/src/antsibull_docs/write_docs/plugins.py b/src/antsibull_docs/write_docs/plugins.py index 19ee9a00..be940a48 100644 --- a/src/antsibull_docs/write_docs/plugins.py +++ b/src/antsibull_docs/write_docs/plugins.py @@ -236,6 +236,7 @@ def create_plugin_rst( plugin_name=plugin_name, doc=plugin_record["doc"], examples=plugin_record["examples"], + examples_format=plugin_record["examples_format"], returndocs=plugin_record["return"], nonfatal_errors=nonfatal_errors, edit_on_github_url=edit_on_github_url, diff --git a/tests/functional/schema/good_data/one_become_results.json b/tests/functional/schema/good_data/one_become_results.json index dbe0bbb4..8ce68725 100644 --- a/tests/functional/schema/good_data/one_become_results.json +++ b/tests/functional/schema/good_data/one_become_results.json @@ -88,6 +88,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_cache_results.json b/tests/functional/schema/good_data/one_cache_results.json index 805c3bd0..650b3103 100644 --- a/tests/functional/schema/good_data/one_cache_results.json +++ b/tests/functional/schema/good_data/one_cache_results.json @@ -130,6 +130,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_callback_results.json b/tests/functional/schema/good_data/one_callback_results.json index 4df2e46a..49020a93 100644 --- a/tests/functional/schema/good_data/one_callback_results.json +++ b/tests/functional/schema/good_data/one_callback_results.json @@ -25,6 +25,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "\nexample: >\n To enable, add this to your ansible.cfg file in the defaults block\n [defaults]\n callback_whitelist = aws_resource_actions\nsample output: >\n#\n# AWS ACTIONS: ['s3:PutBucketAcl', 's3:HeadObject', 's3:DeleteObject', 's3:PutObjectAcl', 's3:CreateMultipartUpload',\n# 's3:DeleteBucket', 's3:GetObject', 's3:DeleteObjects', 's3:CreateBucket', 's3:CompleteMultipartUpload',\n# 's3:ListObjectsV2', 's3:HeadBucket', 's3:UploadPart', 's3:PutObject']\n#\nsample output: >\n#\n# AWS ACTIONS: ['ec2:DescribeVpcAttribute', 'ec2:DescribeVpcClassicLink', 'ec2:ModifyVpcAttribute', 'ec2:CreateTags',\n# 'sts:GetCallerIdentity', 'ec2:DescribeSecurityGroups', 'ec2:DescribeTags', 'ec2:DescribeVpcs', 'ec2:CreateVpc']\n#\n", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_cliconf_results.json b/tests/functional/schema/good_data/one_cliconf_results.json index 94be039e..375a0536 100644 --- a/tests/functional/schema/good_data/one_cliconf_results.json +++ b/tests/functional/schema/good_data/one_cliconf_results.json @@ -59,6 +59,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_connection_results.json b/tests/functional/schema/good_data/one_connection_results.json index 511ce50f..82e2c7dc 100644 --- a/tests/functional/schema/good_data/one_connection_results.json +++ b/tests/functional/schema/good_data/one_connection_results.json @@ -497,6 +497,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_filter_results.json b/tests/functional/schema/good_data/one_filter_results.json index 6be103f4..93664bff 100644 --- a/tests/functional/schema/good_data/one_filter_results.json +++ b/tests/functional/schema/good_data/one_filter_results.json @@ -111,6 +111,7 @@ "version_added": "1.9", "version_added_collection": "ansible.builtin" }, + "examples_format": "yaml", "examples": "# set first 10 volumes rw, rest as dp\nvolume_mode: \"{{ (item|int < 11)|ternary('rw', 'dp') }}\"\n\n# choose correct vpc subnet id, note that vars as values are evaluated even if not returned\nvpc_subnet_id: \"{{ (ec2_subnet_type == 'public') | ternary(ec2_vpc_public_subnet_id, ec2_vpc_private_subnet_id) }}\"\n\n- name: service-foo, use systemd module unless upstart is present, then use old service module\n service:\n state: restarted\n enabled: yes\n use: \"{{ (ansible_service_mgr == 'upstart') | ternary('service', 'systemd') }}\"\n", "metadata": null, "return_": { diff --git a/tests/functional/schema/good_data/one_httpapi_results.json b/tests/functional/schema/good_data/one_httpapi_results.json index 59bd3979..c3bf077c 100644 --- a/tests/functional/schema/good_data/one_httpapi_results.json +++ b/tests/functional/schema/good_data/one_httpapi_results.json @@ -52,6 +52,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_inventory_results.json b/tests/functional/schema/good_data/one_inventory_results.json index 85cb5382..50dc1118 100644 --- a/tests/functional/schema/good_data/one_inventory_results.json +++ b/tests/functional/schema/good_data/one_inventory_results.json @@ -665,6 +665,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "\n# Minimal example using environment vars or instance role credentials\n# Fetch all hosts in us-east-1, the hostname is the public DNS if it exists, otherwise the private IP address\nplugin: aws_ec2\nregions:\n - us-east-1\n\n# Example using filters, ignoring permission errors, and specifying the hostname precedence\nplugin: aws_ec2\nboto_profile: aws_profile\n# Populate inventory with instances in these regions\nregions:\n - us-east-1\n - us-east-2\nfilters:\n # All instances with their `Environment` tag set to `dev`\n tag:Environment: dev\n # All dev and QA hosts\n tag:Environment:\n - dev\n - qa\n instance.group-id: sg-xxxxxxxx\n# Ignores 403 errors rather than failing\nstrict_permissions: False\n# Note: I(hostnames) sets the inventory_hostname. To modify ansible_host without modifying\n# inventory_hostname use compose (see example below).\nhostnames:\n - tag:Name=Tag1,Name=Tag2 # Return specific hosts only\n - tag:CustomDNSName\n - dns-name\n - private-ip-address\n\n# Example using constructed features to create groups and set ansible_host\nplugin: aws_ec2\nregions:\n - us-east-1\n - us-west-1\n# keyed_groups may be used to create custom groups\nstrict: False\nkeyed_groups:\n # Add e.g. x86_64 hosts to an arch_x86_64 group\n - prefix: arch\n key: 'architecture'\n # Add hosts to tag_Name_Value groups for each Name/Value tag pair\n - prefix: tag\n key: tags\n # Add hosts to e.g. instance_type_z3_tiny\n - prefix: instance_type\n key: instance_type\n # Create security_groups_sg_abcd1234 group for each SG\n - key: 'security_groups|json_query(\"[].group_id\")'\n prefix: 'security_groups'\n # Create a group for each value of the Application tag\n - key: tags.Application\n separator: ''\n # Create a group per region e.g. aws_region_us_east_2\n - key: placement.region\n prefix: aws_region\n # Create a group (or groups) based on the value of a custom tag \"Role\" and add them to a metagroup called \"project\"\n - key: tags['Role']\n prefix: foo\n parent_group: \"project\"\n# Set individual variables with compose\ncompose:\n # Use the private IP address to connect to the host\n # (note: this does not modify inventory_hostname, which is set via I(hostnames))\n ansible_host: private_ip_address\n", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_lookup_results.json b/tests/functional/schema/good_data/one_lookup_results.json index 831e46c2..8225904b 100644 --- a/tests/functional/schema/good_data/one_lookup_results.json +++ b/tests/functional/schema/good_data/one_lookup_results.json @@ -275,6 +275,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "\n - debug:\n msg: 'key contains {{item}}'\n with_consul_kv:\n - 'key/to/retrieve'\n\n - name: Parameters can be provided after the key be more specific about what to retrieve\n debug:\n msg: 'key contains {{item}}'\n with_consul_kv:\n - 'key/to recurse=true token=E6C060A9-26FB-407A-B83E-12DDAFCB4D98'\n\n - name: retrieving a KV from a remote cluster on non default port\n debug:\n msg: \"{{ lookup('consul_kv', 'my/key', host='10.10.10.10', port='2000') }}\"\n", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_module_results.json b/tests/functional/schema/good_data/one_module_results.json index 6427467b..7af47042 100644 --- a/tests/functional/schema/good_data/one_module_results.json +++ b/tests/functional/schema/good_data/one_module_results.json @@ -250,6 +250,7 @@ "version_added": "0.9", "version_added_collection": "foo.bar" }, + "examples_format": "yaml", "examples": "\n- name: Add host to group 'just_created' with variable foo=42\n add_host:\n name: '{{ ip_from_ec2 }}'\n groups: just_created\n foo: 42\n\n- name: Add host to multiple groups\n add_host:\n hostname: '{{ new_ip }}'\n groups:\n - group1\n - group2\n\n- name: Add a host with a non-standard port local to your machines\n add_host:\n name: '{{ new_ip }}:{{ new_port }}'\n\n- name: Add a host alias that we reach through a tunnel (Ansible 1.9 and older)\n add_host:\n hostname: '{{ new_ip }}'\n ansible_ssh_host: '{{ inventory_hostname }}'\n ansible_ssh_port: '{{ new_port }}'\n\n- name: Add a host alias that we reach through a tunnel (Ansible 2.0 and newer)\n add_host:\n hostname: '{{ new_ip }}'\n ansible_host: '{{ inventory_hostname }}'\n ansible_port: '{{ new_port }}'\n\n- name: Ensure inventory vars are set to the same value as the inventory_hostname has (close to pre Ansible 2.4 behaviour)\n add_host:\n hostname: charlie\n inventory_dir: '{{ inventory_dir }}'\n", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_netconf_results.json b/tests/functional/schema/good_data/one_netconf_results.json index 3453b206..35e14327 100644 --- a/tests/functional/schema/good_data/one_netconf_results.json +++ b/tests/functional/schema/good_data/one_netconf_results.json @@ -45,6 +45,7 @@ "version_added": "historical", "version_added_collection": "" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_shell_results.json b/tests/functional/schema/good_data/one_shell_results.json index a1db21ce..22c8d7fc 100644 --- a/tests/functional/schema/good_data/one_shell_results.json +++ b/tests/functional/schema/good_data/one_shell_results.json @@ -223,6 +223,7 @@ "version_added": "historical", "version_added_collection": "foo.bar" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_strategy_results.json b/tests/functional/schema/good_data/one_strategy_results.json index d3dbee93..416cd165 100644 --- a/tests/functional/schema/good_data/one_strategy_results.json +++ b/tests/functional/schema/good_data/one_strategy_results.json @@ -25,6 +25,7 @@ "version_added": "2.0", "version_added_collection": "foo.bar" }, + "examples_format": "yaml", "examples": "", "metadata": { "status": [ diff --git a/tests/functional/schema/good_data/one_test_results.json b/tests/functional/schema/good_data/one_test_results.json index 3f6615db..09267c30 100644 --- a/tests/functional/schema/good_data/one_test_results.json +++ b/tests/functional/schema/good_data/one_test_results.json @@ -47,6 +47,7 @@ "version_added": "1.9", "version_added_collection": "ansible.builtin" }, + "examples_format": "yaml", "examples": "# test 'status' to know how to respond\n{{ (taskresults is changed }}\n", "metadata": null, "return_": { diff --git a/tests/functional/schema/good_data/one_vars.json b/tests/functional/schema/good_data/one_vars.json index c78b8a3b..c5bab5a0 100644 --- a/tests/functional/schema/good_data/one_vars.json +++ b/tests/functional/schema/good_data/one_vars.json @@ -70,7 +70,7 @@ "version_added": "2.4", "version_added_collection": "foo.bar" }, - "examples": null, + "examples": " # fmt: ini\n[foo]\nbar = bam", "metadata": { "status": [ "preview" diff --git a/tests/functional/schema/good_data/one_vars_results.json b/tests/functional/schema/good_data/one_vars_results.json index 2b2b430e..b4f67f87 100644 --- a/tests/functional/schema/good_data/one_vars_results.json +++ b/tests/functional/schema/good_data/one_vars_results.json @@ -112,7 +112,8 @@ "version_added": "2.4", "version_added_collection": "foo.bar" }, - "examples": "", + "examples_format": "ini", + "examples": " # fmt: ini\n[foo]\nbar = bam", "metadata": { "status": [ "preview" diff --git a/tests/functional/schema/good_data/ssh_connection_results.json b/tests/functional/schema/good_data/ssh_connection_results.json index df2e71e8..21317bf5 100644 --- a/tests/functional/schema/good_data/ssh_connection_results.json +++ b/tests/functional/schema/good_data/ssh_connection_results.json @@ -1207,6 +1207,7 @@ "version_added": "historical", "version_added_collection": "ansible.builtin" }, + "examples_format": "yaml", "examples": "", "metadata": null, "return_": {}