From 0741b655901b439d103443bcecc29968ec3cbab1 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 19 Jul 2025 11:29:47 +0200 Subject: [PATCH] Generate YAML output as well. --- docs/docsite/config.yml | 5 + docs/docsite/reformat-yaml.py | 27 ++ ...ations-lists_of_dictionaries-keep_keys.rst | 97 +++++- ...ions-lists_of_dictionaries-remove_keys.rst | 99 +++++- ...ons-lists_of_dictionaries-replace_keys.rst | 132 ++++++- ...rmations_merging_lists_of_dictionaries.rst | 323 ++++++++++++++++-- noxfile.py | 2 + 7 files changed, 636 insertions(+), 49 deletions(-) create mode 100644 docs/docsite/reformat-yaml.py diff --git a/docs/docsite/config.yml b/docs/docsite/config.yml index 50b4a2f347..642bbe9bfd 100644 --- a/docs/docsite/config.yml +++ b/docs/docsite/config.yml @@ -10,3 +10,8 @@ ansible_output: global_env: ANSIBLE_STDOUT_CALLBACK: community.general.tasks_only ANSIBLE_COLLECTIONS_TASKS_ONLY_NUMBER_OF_COLUMNS: 90 + global_postprocessors: + reformat-yaml: + command: + - python + - docs/docsite/reformat-yaml.py diff --git a/docs/docsite/reformat-yaml.py b/docs/docsite/reformat-yaml.py new file mode 100644 index 0000000000..4e28526b82 --- /dev/null +++ b/docs/docsite/reformat-yaml.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +import sys +from io import StringIO + +from ruamel.yaml import YAML + + +def main() -> None: + yaml = YAML(typ='rt') + yaml.indent(mapping=2, sequence=4, offset=2) + yaml.allow_duplicate_keys = True + + # Load + data = yaml.load(sys.stdin) + + # Dump + sio = StringIO() + yaml.dump(data, sio) + print(sio.getvalue().rstrip('\n')) + + +if __name__ == "__main__": + main() diff --git a/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-keep_keys.rst b/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-keep_keys.rst index 3549d29ba7..b16375a2fc 100644 --- a/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-keep_keys.rst +++ b/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-keep_keys.rst @@ -37,24 +37,80 @@ Let us use the below list in the following examples: gives +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - {k0_x0: A0, k1_x1: B0} - - {k0_x0: A1, k1_x1: B1} + - k0_x0: A0 + k1_x1: B0 + - k0_x0: A1 + k1_x1: B1 .. versionadded:: 9.1.0 * The results of the below examples 1-5 are all the same: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + + # I picked one of the examples + mp: equal + target: ['k0_x0', 'k1_x1'] + result: "{{ input | community.general.keep_keys(target=target, matching_parameter=mp) }}" + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - {k0_x0: A0, k1_x1: B0} - - {k0_x0: A1, k1_x1: B1} + - k0_x0: A0 + k1_x1: B0 + - k0_x0: A1 + k1_x1: B1 1. Match keys that equal any of the items in the target. @@ -105,12 +161,40 @@ gives * The results of the below examples 6-9 are all the same: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + + # I picked one of the examples + mp: equal + target: k0_x0 + result: "{{ input | community.general.keep_keys(target=target, matching_parameter=mp) }}" + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - {k0_x0: A0} - - {k0_x0: A1} + - k0_x0: A0 + - k0_x0: A1 6. Match keys that equal the target. @@ -148,4 +232,3 @@ gives mp: regex target: ^.*0_x.*$ result: "{{ input | community.general.keep_keys(target=target, matching_parameter=mp) }}" - diff --git a/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-remove_keys.rst b/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-remove_keys.rst index 4ac87ab79c..068869bbbf 100644 --- a/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-remove_keys.rst +++ b/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-remove_keys.rst @@ -37,13 +37,39 @@ Let us use the below list in the following examples: gives +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - k2_x2: [C0] + - k2_x2: + - C0 k3_x3: foo - - k2_x2: [C1] + - k2_x2: + - C1 k3_x3: bar @@ -51,13 +77,43 @@ gives * The results of the below examples 1-5 are all the same: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + + # I picked one of the examples + mp: equal + target: ['k0_x0', 'k1_x1'] + result: "{{ input | community.general.remove_keys(target=target, matching_parameter=mp) }}" + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - k2_x2: [C0] + - k2_x2: + - C0 k3_x3: foo - - k2_x2: [C1] + - k2_x2: + - C1 k3_x3: bar @@ -109,15 +165,45 @@ gives * The results of the below examples 6-9 are all the same: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + + # I picked one of the examples + mp: equal + target: k0_x0 + result: "{{ input | community.general.remove_keys(target=target, matching_parameter=mp) }}" + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - k1_x1: B0 - k2_x2: [C0] + k2_x2: + - C0 k3_x3: foo - k1_x1: B1 - k2_x2: [C1] + k2_x2: + - C1 k3_x3: bar @@ -156,4 +242,3 @@ gives mp: regex target: ^.*0_x.*$ result: "{{ input | community.general.remove_keys(target=target, matching_parameter=mp) }}" - diff --git a/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-replace_keys.rst b/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-replace_keys.rst index d0eb202bfe..086d79b2a9 100644 --- a/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-replace_keys.rst +++ b/docs/docsite/rst/filter_guide-abstract_informations-lists_of_dictionaries-replace_keys.rst @@ -40,17 +40,43 @@ Let us use the below list in the following examples: gives +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - a0: A0 a1: B0 - k2_x2: [C0] + k2_x2: + - C0 k3_x3: foo - a0: A1 a1: B1 - k2_x2: [C1] + k2_x2: + - C1 k3_x3: bar @@ -58,17 +84,49 @@ gives * The results of the below examples 1-3 are all the same: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + + # I picked one of the examples + mp: starts_with + target: + - {after: a0, before: k0} + - {after: a1, before: k1} + result: "{{ input | community.general.replace_keys(target=target, matching_parameter=mp) }}" + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - a0: A0 a1: B0 - k2_x2: [C0] + k2_x2: + - C0 k3_x3: foo - a0: A1 a1: B1 - k2_x2: [C1] + k2_x2: + - C1 k3_x3: bar @@ -111,12 +169,41 @@ gives * The results of the below examples 4-5 are the same: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + + # I picked one of the examples + mp: regex + target: + - {after: X, before: ^.*_x.*$} + result: "{{ input | community.general.replace_keys(target=target, matching_parameter=mp) }}" + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - {X: foo} - - {X: bar} + - X: foo + - X: bar 4. If more keys match the same attribute before the last one will be used. @@ -165,11 +252,36 @@ gives gives +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: result + .. code-block:: yaml :emphasize-lines: 1- result: - - {X: A, bbb1: B, ccc1: C} - - {X: D, bbb2: E, ccc2: F} - - + - X: A + bbb1: B + ccc1: C + - X: D + bbb2: E + ccc2: F diff --git a/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst b/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst index cafe04e5c4..330020c2bb 100644 --- a/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst +++ b/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst @@ -34,13 +34,42 @@ In the example below the lists are merged by the attribute ``name``: This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - - {name: bar, extra: false} - - {name: baz, path: /baz} - - {name: foo, extra: true, path: /foo} - - {name: meh, extra: true} + - extra: false + name: bar + - name: baz + path: /baz + - extra: true + name: foo + path: /foo + - extra: true + name: meh .. versionadded:: 2.0.0 @@ -56,13 +85,42 @@ It is possible to use a list of lists as an input of the filter: This produces the same result as in the previous example: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - - {name: bar, extra: false} - - {name: baz, path: /baz} - - {name: foo, extra: true, path: /foo} - - {name: meh, extra: true} + - extra: false + name: bar + - name: baz + path: /baz + - extra: true + name: foo + path: /foo + - extra: true + name: meh Single list """"""""""" @@ -75,13 +133,42 @@ It is possible to merge single list: This produces the same result as in the previous example: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 0 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - - {name: bar, extra: false} - - {name: baz, path: /baz} - - {name: foo, extra: true, path: /foo} - - {name: meh, extra: true} + - extra: false + name: bar + - name: baz + path: /baz + - extra: true + name: foo + path: /foo + - extra: true + name: meh The filter also accepts two optional parameters: :ansopt:`community.general.lists_mergeby#filter:recursive` and :ansopt:`community.general.lists_mergeby#filter:list_merge`. This is available since community.general 4.4.0. @@ -128,17 +215,45 @@ Example :ansopt:`community.general.lists_mergeby#filter:list_merge=replace` (def This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 4 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - name: myname01 param01: + list: + - patch_value x: default_value y: patch_value - list: [patch_value] z: patch_value - name: myname02 - param01: [3, 4, 4] + param01: + - 3 + - 4 + - 4 list_merge=keep """"""""""""""" @@ -153,17 +268,46 @@ Example :ansopt:`community.general.lists_mergeby#filter:list_merge=keep`: This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 4 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - name: myname01 param01: + list: + - default_value x: default_value y: patch_value - list: [default_value] z: patch_value - name: myname02 - param01: [1, 1, 2, 3] + param01: + - 1 + - 1 + - 2 + - 3 list_merge=append """"""""""""""""" @@ -178,17 +322,50 @@ Example :ansopt:`community.general.lists_mergeby#filter:list_merge=append`: This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 4 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - name: myname01 param01: + list: + - default_value + - patch_value x: default_value y: patch_value - list: [default_value, patch_value] z: patch_value - name: myname02 - param01: [1, 1, 2, 3, 3, 4, 4] + param01: + - 1 + - 1 + - 2 + - 3 + - 3 + - 4 + - 4 list_merge=prepend """""""""""""""""" @@ -203,17 +380,50 @@ Example :ansopt:`community.general.lists_mergeby#filter:list_merge=prepend`: This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 4 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - name: myname01 param01: + list: + - patch_value + - default_value x: default_value y: patch_value - list: [patch_value, default_value] z: patch_value - name: myname02 - param01: [3, 4, 4, 1, 1, 2, 3] + param01: + - 3 + - 4 + - 4 + - 1 + - 1 + - 2 + - 3 list_merge=append_rp """""""""""""""""""" @@ -228,17 +438,49 @@ Example :ansopt:`community.general.lists_mergeby#filter:list_merge=append_rp`: This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 4 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - name: myname01 param01: + list: + - default_value + - patch_value x: default_value y: patch_value - list: [default_value, patch_value] z: patch_value - name: myname02 - param01: [1, 1, 2, 3, 4, 4] + param01: + - 1 + - 1 + - 2 + - 3 + - 4 + - 4 list_merge=prepend_rp """"""""""""""""""""" @@ -253,15 +495,46 @@ Example :ansopt:`community.general.lists_mergeby#filter:list_merge=prepend_rp`: This produces: +.. ansible-output-data:: + + env: + ANSIBLE_CALLBACK_RESULT_FORMAT: yaml + variables: + data: + previous_code_block: yaml + previous_code_block_index: 4 + computation: + previous_code_block: yaml+jinja + postprocessors: + - name: reformat-yaml + language: yaml + skip_first_lines: 2 + playbook: |- + - hosts: localhost + gather_facts: false + tasks: + - vars: + @{{ data | indent(8) }}@ + @{{ computation | indent(8) }}@ + ansible.builtin.debug: + var: list3 + .. code-block:: yaml list3: - name: myname01 param01: + list: + - patch_value + - default_value x: default_value y: patch_value - list: [patch_value, default_value] z: patch_value - name: myname02 - param01: [3, 4, 4, 1, 1, 2] - + param01: + - 3 + - 4 + - 4 + - 1 + - 1 + - 2 diff --git a/noxfile.py b/noxfile.py index c04c3e0d06..ffeda8013f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -40,6 +40,8 @@ def ansible_output(session: nox.Session) -> None: # Needed libs for some code blocks: "jc", "hashids", + # Tools for post-processing + "ruamel.yaml", # used by docs/docsite/reformat-yaml.py ) session.run("antsibull-docs", "ansible-output", *session.posargs)