Skip to content

Commit

Permalink
Scaffold filter plugin through add subcommand (#332)
Browse files Browse the repository at this point in the history
* Scaffold filter plugin through add subcommand

* Add tests

* Differentiate plugin output based on plugin type

* cleanup in the plugin template

* minor test fix
  • Loading branch information
shatakshiiii authored Nov 20, 2024
1 parent 6f0c674 commit f9f666e
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/ansible_creator/arg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
"add resource devcontainer",
"add resource role",
"add plugin action",
"add plugin filter",
)


Expand Down Expand Up @@ -351,6 +350,7 @@ def _add_plugin_filter(self, subparser: SubParser[ArgumentParser]) -> None:
formatter_class=CustomHelpFormatter,
)
self._add_args_common(parser)
self._add_overwrite(parser)
self._add_args_plugin_common(parser)

def _add_plugin_lookup(self, subparser: SubParser[ArgumentParser]) -> None:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
"""A hello-world filter plugin in {{ namespace }}.{{ collection_name }}."""
{# filter_plugin_template.j2 #}
{%- set filter_name = plugin_name | default("hello_world") -%}
{%- set author = author | default("Your Name") -%}
{%- set description = description | default("A custom filter plugin for Ansible.") -%}
{%- set license = license | default("GPL-3.0-or-later") -%}
# {{ filter_name }}.py - {{ description }}
# Author: {{ author }}
# License: {{ license }}

from __future__ import absolute_import, annotations, division, print_function

Expand All @@ -13,10 +20,10 @@ if TYPE_CHECKING:


DOCUMENTATION = """
name: hello_world
author: {{ namespace | capitalize }} {{ collection_name | capitalize }}
name: {{ filter_name }}
author: {{ author }}
version_added: "1.0.0"
short_description: Demo filter plugin that returns a Hello message.
short_description: {{ description }}
description:
- This is a demo filter plugin designed to return Hello message.
options:
Expand All @@ -26,11 +33,11 @@ DOCUMENTATION = """
"""

EXAMPLES = """
# hello_world filter example
# {{ filter_name }} filter example
{% raw %}
- name: Display a hello message
ansible.builtin.debug:
msg: "{{ 'ansible-creator' {%- endraw %} | {{ namespace }}.{{ collection_name }}.hello_world }}"
msg: "{{ 'ansible-creator' {%- endraw %} | {{ filter_name }} }}"
"""


Expand All @@ -55,4 +62,4 @@ class FilterModule:
Returns:
dict: The filter plugin functions.
"""
return {"hello_world": _hello_world}
return {"{{ filter_name }}": _hello_world}
10 changes: 5 additions & 5 deletions src/ansible_creator/subcommands/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ def _plugin_scaffold(self, plugin_path: Path) -> None:
self.output.debug(f"Started copying {self._project} plugin to destination")

# Call the appropriate scaffolding function based on the plugin type
if self._plugin_type == "lookup":
template_data = self._get_lookup_plugin_template_data()
if self._plugin_type in ("lookup", "filter"):
template_data = self._get_plugin_template_data()

else:
msg = f"Unsupported plugin type: {self._plugin_type}"
Expand Down Expand Up @@ -212,7 +212,7 @@ def _perform_plugin_scaffold(self, template_data: TemplateData, plugin_path: Pat

if not paths.has_conflicts() or self._force or self._overwrite:
copier.copy_containers(paths)
self.output.note(f"Plugin added to {plugin_path}")
self.output.note(f"{self._plugin_type.capitalize()} plugin added to {plugin_path}")
return

if not self._overwrite:
Expand All @@ -228,7 +228,7 @@ def _perform_plugin_scaffold(self, template_data: TemplateData, plugin_path: Pat
)
raise CreatorError(msg)

self.output.note(f"Plugin added to {plugin_path}")
self.output.note(f"{self._plugin_type.capitalize()} plugin added to {plugin_path}")

def _get_devfile_template_data(self) -> TemplateData:
"""Get the template data for devfile resources.
Expand All @@ -242,7 +242,7 @@ def _get_devfile_template_data(self) -> TemplateData:
dev_file_name=self.unique_name_in_devfile(),
)

def _get_lookup_plugin_template_data(self) -> TemplateData:
def _get_plugin_template_data(self) -> TemplateData:
"""Get the template data for lookup plugin.
Returns:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""A hello-world filter plugin in testorg.testcol."""
# hello_world.py - A custom filter plugin for Ansible.
# Author: Your Name
# License: GPL-3.0-or-later

from __future__ import absolute_import, annotations, division, print_function

Expand All @@ -14,9 +16,9 @@

DOCUMENTATION = """
name: hello_world
author: Testorg Testcol
author: Your Name
version_added: "1.0.0"
short_description: Demo filter plugin that returns a Hello message.
short_description: A custom filter plugin for Ansible.
description:
- This is a demo filter plugin designed to return Hello message.
options:
Expand All @@ -30,7 +32,7 @@
- name: Display a hello message
ansible.builtin.debug:
msg: "{{ 'ansible-creator' | testorg.testcol.hello_world }}"
msg: "{{ 'ansible-creator' | hello_world }}"
"""


Expand Down
83 changes: 79 additions & 4 deletions tests/units/test_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,82 @@ def test_run_error_unsupported_resource_type(
assert "Unsupported resource type: unsupported_type" in str(exc_info.value)


def test_run_success_add_plugin_filter(
capsys: pytest.CaptureFixture[str],
tmp_path: Path,
cli_args: ConfigDict,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test Add.run().
Successfully add plugin to path
Args:
capsys: Pytest fixture to capture stdout and stderr.
tmp_path: Temporary directory path.
cli_args: Dictionary, partial Add class object.
monkeypatch: Pytest monkeypatch fixture.
"""
cli_args["plugin_type"] = "filter"
add = Add(
Config(**cli_args),
)

# Mock the "_check_collection_path" method
def mock_check_collection_path() -> None:
"""Mock function to skip checking collection path."""

monkeypatch.setattr(
Add,
"_check_collection_path",
staticmethod(mock_check_collection_path),
)
add.run()
result = capsys.readouterr().out
assert re.search("Note: Filter plugin added to", result) is not None

expected_file = tmp_path / "plugins" / "filter" / "hello_world.py"
effective_file = (
FIXTURES_DIR
/ "collection"
/ "testorg"
/ "testcol"
/ "plugins"
/ "filter"
/ "hello_world.py"
)
cmp_result = cmp(expected_file, effective_file, shallow=False)
assert cmp_result

conflict_file = tmp_path / "plugins" / "filter" / "hello_world.py"
conflict_file.write_text("Author: Your Name")

# expect a CreatorError when the response to overwrite is no.
monkeypatch.setattr("builtins.input", lambda _: "n")
fail_msg = (
"The destination directory contains files that will be overwritten."
" Please re-run ansible-creator with --overwrite to continue."
)
with pytest.raises(
CreatorError,
match=fail_msg,
):
add.run()

# expect a warning followed by playbook project creation msg
# when response to overwrite is yes.
monkeypatch.setattr("builtins.input", lambda _: "y")
add.run()
result = capsys.readouterr().out
assert (
re.search(
"already exists",
result,
)
is not None
), result
assert re.search("Note: Filter plugin added to", result) is not None


def test_run_success_add_plugin_lookup(
capsys: pytest.CaptureFixture[str],
tmp_path: Path,
Expand Down Expand Up @@ -335,7 +411,7 @@ def mock_check_collection_path() -> None:
)
add.run()
result = capsys.readouterr().out
assert re.search("Note: Plugin added to", result) is not None
assert re.search("Note: Lookup plugin added to", result) is not None

expected_file = tmp_path / "plugins" / "lookup" / "hello_world.py"
effective_file = (
Expand Down Expand Up @@ -377,7 +453,7 @@ def mock_check_collection_path() -> None:
)
is not None
), result
assert re.search("Note: Plugin added to", result) is not None
assert re.search("Note: Lookup plugin added to", result) is not None


def test_run_error_plugin_no_overwrite(
Expand Down Expand Up @@ -412,7 +488,7 @@ def mock_check_collection_path() -> None:
)
add.run()
result = capsys.readouterr().out
assert re.search("Note: Plugin added to", result) is not None
assert re.search("Note: Lookup plugin added to", result) is not None

expected_file = tmp_path / "plugins" / "lookup" / "hello_world.py"
effective_file = (
Expand Down Expand Up @@ -452,7 +528,6 @@ def test_run_error_unsupported_plugin_type(
cli_args: Dictionary, partial Add class object.
monkeypatch: Pytest monkeypatch fixture.
"""
cli_args["plugin_type"] = "lookup"
add = Add(
Config(**cli_args),
)
Expand Down

0 comments on commit f9f666e

Please sign in to comment.