Skip to content
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
15 changes: 15 additions & 0 deletions .config/vulture_whitelist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
_.configured # unused attribute (src/ansiblelint/__main__.py:140)
configured # unused variable (src/ansiblelint/config.py:132)
_.keep_trailing_newline # unused attribute (src/ansiblelint/rules/jinja.py:280)
_.lstrip_blocks # unused attribute (src/ansiblelint/rules/jinja.py:282)
_.trim_blocks # unused attribute (src/ansiblelint/rules/jinja.py:283)
_.autoescape # unused attribute (src/ansiblelint/rules/jinja.py:284)
_.newline_sequence # unused attribute (src/ansiblelint/rules/jinja.py:285)
_.allow_duplicate_keys # unused attribute (src/ansiblelint/skip_utils.py:138)
_.playbook_paths # unused attribute (src/ansiblelint/utils.py:257)
_.explicit_end # unused attribute (src/ansiblelint/yaml_utils.py:915)
_.default_flow_style # unused attribute (src/ansiblelint/yaml_utils.py:923)
_.compact_seq_seq # unused attribute (src/ansiblelint/yaml_utils.py:924)
_.compact_seq_map # unused attribute (src/ansiblelint/yaml_utils.py:925)
_.Constructor # unused attribute (src/ansiblelint/yaml_utils.py:946)
_.preserve_quotes # unused attribute (src/ansiblelint/yaml_utils.py:956)
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,4 @@ src/ansiblelint/_version.py
test/eco
test/local-content
test/schemas/node_modules
node_modules
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ repos:
- wcmatch
exclude: >
(?x)^(
.config/.*|
collections/.*|
test/local-content/.*|
plugins/.*
Expand Down Expand Up @@ -227,6 +228,10 @@ repos:
- typing_extensions
- wcmatch
- yamllint
- repo: https://github.com/jendrikseipp/vulture
rev: v2.13
hooks:
- id: vulture
- # keep at bottom as these are slower
repo: local
hooks:
Expand Down
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,8 @@
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
},
"evenBetterToml.formatter.arrayTrailingComma": true
"evenBetterToml.formatter.arrayTrailingComma": true,
"[toml]": {
"editor.defaultFormatter": "panekj.even-betterer-toml"
}
}
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"devDependencies": {
"prettier": "^3.3.3"
}
}
30 changes: 28 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ error_summary = true
# warn_return_any = True
# warn_unused_configs = True
# site-packages is here to help vscode mypy integration getting confused
exclude = "(build|dist|test/local-content|site-packages|~/.pyenv|examples/playbooks/collections|plugins/modules)"
exclude = "(.config|build|dist|test/local-content|site-packages|~/.pyenv|examples/playbooks/collections|plugins/modules)"
# https://github.com/python/mypy/issues/12664
incremental = false
python_version = "3.10"
Expand Down Expand Up @@ -122,7 +122,7 @@ bad-names = [
# pylint defaults + f,fh,v,id
good-names = ["i", "j", "k", "Run", "_", "f", "fh", "v", "id", "T"]
# Ignore as being generated:
ignore-paths = "^src/ansiblelint/_version.*$"
ignore-paths = "^(src/ansiblelint/_version|.config/).*$"

[tool.pylint."MESSAGES CONTROL"]
disable = [
Expand Down Expand Up @@ -195,6 +195,7 @@ minversion = "4.6.6"
norecursedirs = [
"*.egg",
".cache",
".config",
".eggs",
".git",
".github",
Expand Down Expand Up @@ -222,6 +223,7 @@ xfail_strict = true

[tool.ruff]
cache-dir = "./.cache/.ruff"
exclude = [".config"]
fix = true
# Same as Black.
line-length = 88
Expand Down Expand Up @@ -322,3 +324,27 @@ sort_table_keys = true
annotation-style = "line"
custom-compile-command = "tox run deps"
no-emit-package = ["ansible-core", "pip", "resolvelib", "typing_extensions", "uv"]

[tool.vulture]
exclude = [
".eggs",
".tox",
"build",
"collections",
"examples",
"plugins",
"test/local-content",
"venv",
"src/ansiblelint/_version.py"
]
ignore_names = [
"_ANSIBLE_ARGS",
"__rich_console__",
"fixture_*",
"pytest_addoption",
"pytest_collection_modifyitems",
"pytest_configure",
"side_effect",
"test_*"
]
paths = ["src", "test", ".config/vulture_whitelist.py"]
1 change: 1 addition & 0 deletions src/ansiblelint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def __call__(
values: str | Sequence[Any] | None,
option_string: str | None = None,
) -> None:
logging.debug(option_string)
if isinstance(values, str | Path):
values = [values]
if values:
Expand Down
17 changes: 0 additions & 17 deletions src/ansiblelint/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import urllib.request
import warnings
from dataclasses import dataclass, field
from functools import lru_cache
from http.client import HTTPException
from importlib.metadata import PackageNotFoundError, distribution, version
from pathlib import Path
Expand Down Expand Up @@ -201,26 +200,10 @@ def supported_ansible(self) -> list[str]:
# Used to store detected tag deprecations
used_old_tags: dict[str, str] = {}

# Used to store collection list paths (with mock paths if needed)
collection_list: list[str] = []

# Used to store log messages before logging is initialized (level, message)
log_entries: list[tuple[int, str]] = []


@lru_cache
def ansible_collections_path() -> str:
"""Return collection path variable for current version of Ansible."""
# respect Ansible behavior, which is to load old name if present
for env_var in [
"ANSIBLE_COLLECTIONS_PATHS",
"ANSIBLE_COLLECTIONS_PATH",
]: # pragma: no cover
if env_var in os.environ:
return env_var
return "ANSIBLE_COLLECTIONS_PATH"


def in_venv() -> bool:
"""Determine whether Python is running from a venv."""
if hasattr(sys, "real_prefix") or os.environ.get("CONDA_EXE", None) is not None:
Expand Down
10 changes: 0 additions & 10 deletions src/ansiblelint/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ class RC: # pylint: disable=too-few-public-methods
EXIT_CONTROL_C = 130


# Minimal version of Ansible we support for runtime
ANSIBLE_MIN_VERSION = "2.12"

ANSIBLE_MOCKED_MODULE = """\
# This is a mocked Ansible module generated by ansible-lint
from ansible.module_utils.basic import AnsibleModule
Expand Down Expand Up @@ -208,13 +205,6 @@ def main():
"include_role",
}

# Newer versions of git might fail to run when different file ownership is
# found of repo. One example is on GHA runners executing containerized
# reusable actions, where the mounted volume might have different owner.
#
# https://github.com/ansible/ansible-lint-action/issues/138
GIT_CMD = ["git", "-c", f"safe.directory={Path.cwd()}"]

CONFIG_FILENAMES = [
".ansible-lint",
".config/ansible-lint.yml",
Expand Down
5 changes: 0 additions & 5 deletions src/ansiblelint/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,11 +478,6 @@ def discover_lintables(options: Options) -> list[str]:
]


def strip_dotslash_prefix(fname: str) -> str:
"""Remove ./ leading from filenames."""
return fname.removeprefix("./")


def find_project_root(
srcs: Sequence[str],
config_file: str | None = None,
Expand Down
2 changes: 1 addition & 1 deletion src/ansiblelint/rules/deprecated_local_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
_logger = logging.getLogger(__name__)


class TaskNoLocalAction(AnsibleLintRule, TransformMixin):
class TaskNoLocalActionRule(AnsibleLintRule, TransformMixin):
"""Do not use 'local_action', use 'delegate_to: localhost'."""

id = "deprecated-local-action"
Expand Down
1 change: 0 additions & 1 deletion src/ansiblelint/rules/jinja.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,6 @@ def uncook(value: str, *, implicit: bool = False) -> str:

except jinja2.exceptions.TemplateSyntaxError as exc:
return "", str(exc.message), "invalid"
# pylint: disable=c-extension-no-member
except (NotImplementedError, ValueError) as exc:
# black is not able to recognize all valid jinja2 templates, so we
# just ignore InvalidInput errors.
Expand Down
32 changes: 0 additions & 32 deletions src/ansiblelint/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,38 +76,6 @@ def run_role_tasks_main(
shutil.rmtree(role_path)
return results

def run_role_meta_main(
self,
meta_main_text: str,
temp_path: Path,
) -> list[MatchError]:
"""Lints received text as meta."""
role_path = temp_path
meta_path = role_path / "meta"
meta_path.mkdir(parents=True, exist_ok=True)
with (meta_path / "main.yml").open("w", encoding="utf-8") as fh:
fh.write(meta_main_text)
fh.flush()
results = self._call_runner(role_path)
shutil.rmtree(role_path)
return results

def run_role_defaults_main(
self,
defaults_main_text: str,
tmp_path: Path,
) -> list[MatchError]:
"""Lints received text as vars file in defaults."""
role_path = tmp_path
defaults_path = role_path / "defaults"
defaults_path.mkdir(parents=True, exist_ok=True)
with (defaults_path / "main.yml").open("w", encoding="utf-8") as fh:
fh.write(defaults_main_text)
fh.flush()
results = self._call_runner(role_path)
shutil.rmtree(role_path)
return results


def run_ansible_lint(
*argv: str | Path,
Expand Down
16 changes: 0 additions & 16 deletions src/ansiblelint/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
INCLUSION_ACTION_NAMES,
LINE_NUMBER_KEY,
NESTED_TASK_KEYS,
PLAYBOOK_TASK_KEYWORDS,
ROLE_IMPORT_ACTION_NAMES,
SKIPPED_RULES_KEY,
FileType,
Expand All @@ -86,7 +85,6 @@
# string as the password to enable such yaml files to be opened and parsed
# successfully.
DEFAULT_VAULT_PASSWORD = "x" # noqa: S105
COLLECTION_PLAY_RE = re.compile(r"^[\w\d_]+\.[\w\d_]+\.[\w\d_]+$")

PLAYBOOK_DIR = os.environ.get("ANSIBLE_PLAYBOOK_DIR", None)

Expand Down Expand Up @@ -965,20 +963,6 @@ def add_action_type(actions: AnsibleBaseYAMLObject, action_type: str) -> list[An
return results


def get_action_tasks(data: AnsibleBaseYAMLObject, file: Lintable) -> list[Any]:
"""Get a flattened list of action tasks from the file."""
tasks = []
if file.kind in ["tasks", "handlers"]:
tasks = add_action_type(data, file.kind)
else:
tasks.extend(extract_from_list(data, PLAYBOOK_TASK_KEYWORDS))

# Add sub-elements of block/rescue/always to tasks list
tasks.extend(extract_from_list(tasks, NESTED_TASK_KEYS, recursive=True))

return tasks


@cache
def parse_yaml_linenumbers(
lintable: Lintable,
Expand Down
18 changes: 5 additions & 13 deletions test/test_skip_import_playbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from pathlib import Path

import pytest

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

Expand Down Expand Up @@ -31,20 +29,14 @@
"""


@pytest.fixture(name="playbook")
def fixture_playbook(tmp_path: Path) -> str:
"""Create a reusable per-test playbook."""
def test_skip_import_playbook(
default_rules_collection: RulesCollection, tmp_path: Path
) -> None:
"""Verify that a playbook import is skipped after a failure."""
playbook_path = tmp_path / "playbook.yml"
playbook_path.write_text(MAIN_PLAYBOOK)
(tmp_path / "imported_playbook.yml").write_text(IMPORTED_PLAYBOOK)
return str(playbook_path)


def test_skip_import_playbook(
default_rules_collection: RulesCollection,
playbook: str,
) -> None:
"""Verify that a playbook import is skipped after a failure."""
runner = Runner(playbook, rules=default_rules_collection)
runner = Runner(playbook_path, rules=default_rules_collection)
results = runner.run()
assert len(results) == 0
34 changes: 34 additions & 0 deletions test/test_vulture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Used only by vulture to determine reachable code."""

# ExampleComRule
from ansiblelint.rules.args import ArgsRule
from ansiblelint.rules.deprecated_local_action import TaskNoLocalActionRule
from ansiblelint.rules.key_order import KeyOrderRule
from ansiblelint.rules.latest import LatestRule
from ansiblelint.rules.literal_compare import ComparisonToLiteralBoolRule
from ansiblelint.rules.meta_incorrect import MetaChangeFromDefaultRule
from ansiblelint.rules.meta_video_links import MetaVideoLinksRule
from ansiblelint.rules.no_handler import UseHandlerRatherThanWhenChangedRule
from ansiblelint.rules.no_relative_paths import RoleRelativePath
from ansiblelint.rules.risky_file_permissions import MissingFilePermissionsRule
from ansiblelint.rules.syntax_check import AnsibleSyntaxCheckRule
from test.custom_rules.example_com.example_com_rule import ExampleComRule
from test.custom_rules.example_inc.custom_rule import CustomRule
from test.rules.fixtures.unset_variable_matcher import UnsetVariableMatcherRule

__all__ = [
"AnsibleSyntaxCheckRule",
"ArgsRule",
"ComparisonToLiteralBoolRule",
"CustomRule",
"ExampleComRule",
"KeyOrderRule",
"LatestRule",
"MetaChangeFromDefaultRule",
"MetaVideoLinksRule",
"MissingFilePermissionsRule",
"RoleRelativePath",
"TaskNoLocalActionRule",
"UnsetVariableMatcherRule",
"UseHandlerRatherThanWhenChangedRule",
]
Loading