Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recognize adjacent plugins #4131

Merged
merged 1 commit into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
env:
# Number of expected test passes, safety measure for accidental skip of
# tests. Update value if you add/remove tests.
PYTEST_REQPASS: 856
PYTEST_REQPASS: 857
steps:
- uses: actions/checkout@v4
with:
Expand Down
13 changes: 13 additions & 0 deletions examples/playbooks/action_plugins/some_action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Sample action_plugin."""

from ansible.plugins.action import ActionBase


class ActionModule(ActionBase): # type: ignore[misc]
"""Sample module."""

def run(self, tmp=None, task_vars=None): # type: ignore[no-untyped-def]
"""."""
super().run(tmp, task_vars)
ret = {"foo": "bar"}
return {"ansible_facts": ret}
10 changes: 10 additions & 0 deletions examples/playbooks/adj_action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
- name: Fixture for testing adjacent plugins
hosts: localhost
tasks:
- name: Call adjacent action plugin
some_action: {}

- name: Call adjacent filter plugin
ansible.builtin.debug:
msg: "{{ 'foo' | some_filter }}"
4 changes: 2 additions & 2 deletions examples/playbooks/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
- git # yamllint wrong indentation
- bobbins

- name: Yum latest
ansible.builtin.yum: state=latest name=httpd
- name: Dnf latest
ansible.builtin.dnf: state=latest name=httpd

- ansible.builtin.debug: msg="debug task without a name"

Expand Down
13 changes: 13 additions & 0 deletions examples/playbooks/filter_plugins/some_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Sample adjacent filter plugin."""

from __future__ import annotations


class FilterModule: # pylint: disable=too-few-public-methods
"""Ansible filters."""

def filters(self): # type: ignore[no-untyped-def]
"""Return list of exposed filters."""
return {
"some_filter": str,
}
4 changes: 2 additions & 2 deletions examples/playbooks/test_skip_inside_yaml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
- name: Test no-free-form # <-- 3 no-free-form
ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form
- name: Test no-free-form # <-- 4 no-free-form
ansible.builtin.command: warn=yes creates=B chmod 644 A # noqa: no-free-form
ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form
- name: Test no-free-form (skipped via no warn)
ansible.builtin.command: warn=no creates=B chmod 644 A # noqa: no-free-form
ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form
- name: Test no-free-form (skipped via skip_ansible_lint)
ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form
tags:
Expand Down
2 changes: 1 addition & 1 deletion src/ansiblelint/schemas/__store__.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/requirements.json"
},
"role-arg-spec": {
"etag": "74fc5d429919813f2c977a2e3ed2afee1ca3dba242f6978bded8199895642db6",
"etag": "e41a42e1ca634a9eb2edbc4a180f404bdc71e17aafa464e6651387c08152bbc5",
"url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/role-arg-spec.json"
},
"rulebook": {
Expand Down
15 changes: 13 additions & 2 deletions src/ansiblelint/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
from ansible.parsing.yaml.constructor import AnsibleConstructor, AnsibleMapping
from ansible.parsing.yaml.loader import AnsibleLoader
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleSequence
from ansible.plugins.loader import PluginLoadContext, add_all_plugin_dirs, module_loader
from ansible.plugins.loader import (
PluginLoadContext,
action_loader,
add_all_plugin_dirs,
module_loader,
)
from ansible.template import Templar
from ansible.utils.collection_loader import AnsibleCollectionConfig
from yaml.composer import Composer
Expand Down Expand Up @@ -1071,11 +1076,17 @@ def parse_examples_from_plugin(lintable: Lintable) -> tuple[int, str]:
@lru_cache
def load_plugin(name: str) -> PluginLoadContext:
"""Return loaded ansible plugin/module."""
loaded_module = module_loader.find_plugin_with_context(
loaded_module = action_loader.find_plugin_with_context(
name,
ignore_deprecated=True,
check_aliases=True,
)
if not loaded_module.resolved:
loaded_module = module_loader.find_plugin_with_context(
name,
ignore_deprecated=True,
check_aliases=True,
)
if not loaded_module.resolved and name.startswith("ansible.builtin."):
# fallback to core behavior of using legacy
loaded_module = module_loader.find_plugin_with_context(
Expand Down
25 changes: 25 additions & 0 deletions test/test_adjacent_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Test ability to recognize adjacent modules/plugins."""

import logging

import pytest

from ansiblelint.rules import RulesCollection
from ansiblelint.runner import Runner


def test_adj_action(
default_rules_collection: RulesCollection,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Assures local collections are found."""
playbook_path = "examples/playbooks/adj_action.yml"

with caplog.at_level(logging.DEBUG):
runner = Runner(playbook_path, rules=default_rules_collection, verbosity=1)
results = runner.run()
assert "Unable to load module" not in caplog.text
assert "Unable to resolve FQCN" not in caplog.text

assert len(runner.lintables) == 1
assert len(results) == 0
2 changes: 1 addition & 1 deletion test/test_skip_inside_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_role_tasks_with_block(default_rules_collection: RulesCollection) -> Non

@pytest.mark.parametrize(
("lintable", "expected"),
(pytest.param("examples/playbooks/test_skip_inside_yaml.yml", 6, id="yaml"),),
(pytest.param("examples/playbooks/test_skip_inside_yaml.yml", 4, id="yaml"),),
)
def test_inline_skips(
default_rules_collection: RulesCollection,
Expand Down
Loading