diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index bdd0b4a629..4d81529414 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -92,6 +92,8 @@ files: maintainers: ryancurrah $callbacks/syslog_json.py: maintainers: imjoseangel + $callbacks/tasks_only.py: + maintainers: felixfontein $callbacks/timestamp.py: maintainers: kurokobo $callbacks/unixy.py: diff --git a/plugins/callback/tasks_only.py b/plugins/callback/tasks_only.py new file mode 100644 index 0000000000..f64c4c57db --- /dev/null +++ b/plugins/callback/tasks_only.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2025, Felix Fontein +# 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 + +from __future__ import annotations + +DOCUMENTATION = r""" +author: Felix Fontein (@felixfontein) +name: tasks_only +type: stdout +version_added: 11.1.0 +short_description: Only show tasks +description: + - Removes play start and stats marker from P(ansible.builtin.default#callback)'s output. + - Can be used to generate output for documentation examples. + For this, the O(number_of_columns) option should be set to an explicit value. +extends_documentation_fragment: + - default_callback +options: + number_of_columns: + description: + - Sets the number of columns for Ansible's display. + type: int + env: + - name: ANSIBLE_COLLECTIONS_TASKS_ONLY_NUMBER_OF_COLUMNS +""" + +EXAMPLES = r""" +--- +# Enable callback in ansible.cfg: +ansible_config: |- + [defaults] + stdout_callback = community.general.tasks_only + +--- +# Enable callback with environment variables: +environment_variable: |- + ANSIBLE_STDOUT_CALLBACK=community.general.tasks_only +""" + +from ansible.plugins.callback.default import CallbackModule as Default + + +class CallbackModule(Default): + CALLBACK_VERSION = 2.0 + CALLBACK_TYPE = 'stdout' + CALLBACK_NAME = 'community.general.tasks_only' + + def v2_playbook_on_play_start(self, play): + pass + + def v2_playbook_on_stats(self, stats): + pass + + def set_options(self, *args, **kwargs): + result = super(CallbackModule, self).set_options(*args, **kwargs) + self.number_of_columns = self.get_option("number_of_columns") + if self.number_of_columns is not None: + self._display.columns = self.number_of_columns + return result diff --git a/tests/integration/targets/callback_tasks_only/aliases b/tests/integration/targets/callback_tasks_only/aliases new file mode 100644 index 0000000000..3e2dd244c1 --- /dev/null +++ b/tests/integration/targets/callback_tasks_only/aliases @@ -0,0 +1,6 @@ +# 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 + +azp/posix/3 +needs/target/callback diff --git a/tests/integration/targets/callback_tasks_only/tasks/main.yml b/tests/integration/targets/callback_tasks_only/tasks/main.yml new file mode 100644 index 0000000000..b02ddc8efc --- /dev/null +++ b/tests/integration/targets/callback_tasks_only/tasks/main.yml @@ -0,0 +1,79 @@ +--- +#################################################################### +# WARNING: These are designed specifically for Ansible tests # +# and should not be used as examples of how to write Ansible roles # +#################################################################### + +# 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 + +- block: + - name: Create temporary file + tempfile: + register: tempfile + + - name: Run tests + include_role: + name: callback + vars: + tests: + - name: Simple test + environment: + ANSIBLE_NOCOLOR: 'true' + ANSIBLE_FORCE_COLOR: 'false' + ANSIBLE_PYTHON_INTERPRETER: "{{ ansible_python_interpreter }}" + ANSIBLE_STDOUT_CALLBACK: community.general.tasks_only + playbook: | + - hosts: testhost + gather_facts: true + tasks: + - name: Create file + copy: + dest: "{{ tempfile.path }}" + content: | + Foo bar + + - name: Modify file + copy: + dest: "{{ tempfile.path }}" + content: | + Foo bar + Bar baz bam! + expected_output: + - "" + - "TASK [Gathering Facts] *********************************************************" + - "ok: [testhost]" + - "" + - "TASK [Create file] *************************************************************" + - "changed: [testhost]" + - "" + - "TASK [Modify file] *************************************************************" + - "changed: [testhost]" + - name: Different column width + environment: + ANSIBLE_NOCOLOR: 'true' + ANSIBLE_FORCE_COLOR: 'false' + ANSIBLE_PYTHON_INTERPRETER: "{{ ansible_python_interpreter }}" + ANSIBLE_STDOUT_CALLBACK: community.general.tasks_only + ANSIBLE_COLLECTIONS_TASKS_ONLY_NUMBER_OF_COLUMNS: 40 + playbook: | + - hosts: testhost + gather_facts: false + tasks: + - name: A task + debug: + msg: Test. + expected_output: + - "" + - "TASK [A task] ***************************" + - "ok: [testhost] => {" + - ' "msg": "Test."' + - "}" + + + always: + - name: Clean up temp file + file: + path: "{{ tempfile.path }}" + state: absent diff --git a/tests/sanity/ignore-2.16.txt b/tests/sanity/ignore-2.16.txt index 1642c0d275..1a4c8f89b1 100644 --- a/tests/sanity/ignore-2.16.txt +++ b/tests/sanity/ignore-2.16.txt @@ -1,3 +1,4 @@ +plugins/callback/tasks_only.py yamllint:unparsable-with-libyaml plugins/connection/wsl.py yamllint:unparsable-with-libyaml plugins/inventory/gitlab_runners.py yamllint:unparsable-with-libyaml plugins/inventory/iocage.py yamllint:unparsable-with-libyaml