diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 634a0b8dadc..10927e8126e 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -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: 870 + PYTEST_REQPASS: 871 steps: - uses: actions/checkout@v4 with: diff --git a/examples/playbooks/test_import_playbook_invalid.yml b/examples/playbooks/test_import_playbook_invalid.yml new file mode 100644 index 00000000000..85bea98d8f0 --- /dev/null +++ b/examples/playbooks/test_import_playbook_invalid.yml @@ -0,0 +1,7 @@ +--- +- name: Fixture 3 - not supported + ansible.builtin.import_playbook: + file: community.molecule.validate.yml +- name: Fixture 4 - not supported + ansible.builtin.import_playbook: + other: community.molecule.validate.yml diff --git a/src/ansiblelint/rules/role_name.py b/src/ansiblelint/rules/role_name.py index ee59c9fba56..ebe0b1a1799 100644 --- a/src/ansiblelint/rules/role_name.py +++ b/src/ansiblelint/rules/role_name.py @@ -164,7 +164,7 @@ def _infer_role_name(meta: Path, default: str) -> str: if meta_data: try: return str(meta_data["galaxy_info"]["role_name"]) - except KeyError: + except (KeyError, TypeError): pass return default diff --git a/src/ansiblelint/utils.py b/src/ansiblelint/utils.py index 12700e272db..a939ee3b159 100644 --- a/src/ansiblelint/utils.py +++ b/src/ansiblelint/utils.py @@ -28,7 +28,7 @@ import logging import os import re -from collections.abc import ItemsView, Iterator, Mapping, Sequence +from collections.abc import ItemsView, Iterable, Iterator, Mapping, Sequence from dataclasses import _MISSING_TYPE, dataclass, field from functools import cache, lru_cache from pathlib import Path @@ -292,7 +292,7 @@ class HandleChildren: rules: RulesCollection = field(init=True, repr=False) app: App - def include_children( + def include_children( # pylint: disable=too-many-return-statements self, basedir: str, k: str, @@ -300,6 +300,13 @@ def include_children( parent_type: FileType, ) -> list[Lintable]: """Include children.""" + # import_playbook only accepts a string as argument (no dict syntax) + if k in ( + "import_playbook", + "ansible.builtin.import_playbook", + ) and not isinstance(v, str): + return [] + # handle special case include_tasks: name=filename.yml if k in INCLUSION_ACTION_NAMES and isinstance(v, dict) and "file" in v: v = v["file"] @@ -322,12 +329,19 @@ def include_children( # pylint: disable=unused-variable (command, args, kwargs) = tokenize(f"{k}: {v}") - result = path_dwim(basedir, args[0]) + if args: + file = args[0] + elif "file" in kwargs: + file = kwargs["file"] + else: + return [] + + result = path_dwim(basedir, file) while basedir not in ["", "/"]: if os.path.exists(result): break basedir = os.path.dirname(basedir) - result = path_dwim(basedir, args[0]) + result = path_dwim(basedir, file) return [Lintable(result, kind=parent_type)] @@ -435,7 +449,7 @@ def roles_children( """Roles children.""" # pylint: disable=unused-argument # parent_type) results: list[Lintable] = [] - if not v: + if not v or not isinstance(v, Iterable): # typing does not prevent junk from being passed in return results for role in v: diff --git a/test/test_import_playbook.py b/test/test_import_playbook.py index 27ef4541b17..63c91d2b9d0 100644 --- a/test/test_import_playbook.py +++ b/test/test_import_playbook.py @@ -29,3 +29,17 @@ def test_import_playbook_from_collection( assert len(runner.lintables) == 1 assert len(results) == 0 + + +def test_import_playbook_invalid( + default_rules_collection: RulesCollection, +) -> None: + """Assures import_playbook from collection.""" + playbook_path = "examples/playbooks/test_import_playbook_invalid.yml" + runner = Runner(playbook_path, rules=default_rules_collection) + results = runner.run() + + assert len(runner.lintables) == 1 + assert len(results) == 1 + assert results[0].tag == "syntax-check[specific]" + assert results[0].lineno == 2