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
2 changes: 1 addition & 1 deletion .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:GITHUB_STEP_SUMMARY
# Number of expected test passes, safety measure for accidental skip of
# tests. Update value if you add/remove tests.
PYTEST_REQPASS: 794
PYTEST_REQPASS: 795
steps:
- name: Activate WSL1
if: "contains(matrix.shell, 'wsl')"
Expand Down
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ exclude: >
.config/requirements.*|
.vscode/extensions.json|
.vscode/settings.json|
examples/broken/encoding.yml|
examples/broken/encoding.j2|
examples/broken/yaml-with-tabs/invalid-due-tabs.yaml|
examples/playbooks/collections/.*|
Expand Down
Binary file added examples/broken/encoding.yml
Binary file not shown.
27 changes: 16 additions & 11 deletions src/ansiblelint/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def __init__(
self.dir: str = ""
self.kind: FileType | None = None
self.stop_processing = False # Set to stop other rules from running
self._data: Any = States.NOT_LOADED
self.state: Any = States.NOT_LOADED
self.line_skips: dict[int, set[str]] = defaultdict(set)
self.exc: Exception | None = None # Stores data loading exceptions

Expand Down Expand Up @@ -359,17 +359,17 @@ def __repr__(self) -> str:
@property
def data(self) -> Any:
"""Return loaded data representation for current file, if possible."""
if self._data == States.NOT_LOADED:
if self.state == States.NOT_LOADED:
if self.path.is_dir():
self._data = None
return self._data
self.state = None
return self.state
try:
if str(self.base_kind) == "text/yaml":
from ansiblelint.utils import ( # pylint: disable=import-outside-toplevel
parse_yaml_linenumbers,
)

self._data = parse_yaml_linenumbers(self)
self.state = parse_yaml_linenumbers(self)
# now that _data is not empty, we can try guessing if playbook or rulebook
# it has to be done before append_skipped_rules() call as it's relying
# on self.kind.
Expand All @@ -380,19 +380,24 @@ def data(self) -> Any:
# pylint: disable=import-outside-toplevel
from ansiblelint.skip_utils import append_skipped_rules

self._data = append_skipped_rules(self._data, self)
self.state = append_skipped_rules(self.state, self)
else:
logging.debug(
"data set to None for %s due to being of %s kind.",
self.path,
self.base_kind or "unknown",
)
self._data = States.UNKNOWN_DATA

except (RuntimeError, FileNotFoundError, YAMLError) as exc:
self._data = States.LOAD_FAILED
self.state = States.UNKNOWN_DATA

except (
RuntimeError,
FileNotFoundError,
YAMLError,
UnicodeDecodeError,
) as exc:
self.state = States.LOAD_FAILED
self.exc = exc
return self._data
return self.state


# pylint: disable=redefined-outer-name
Expand Down
2 changes: 2 additions & 0 deletions src/ansiblelint/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,14 @@ def run(self) -> list[MatchError]: # noqa: C901
self.lintables.remove(lintable)
continue
if isinstance(lintable.data, States) and lintable.exc:
lintable.exc.__class__.__name__.lower()
matches.append(
MatchError(
lintable=lintable,
message=str(lintable.exc),
details=str(lintable.exc.__cause__),
rule=LoadingFailureRule(),
tag=f"load-failure[{lintable.exc.__class__.__name__.lower()}]",
),
)
lintable.stop_processing = True
Expand Down
16 changes: 14 additions & 2 deletions test/test_load_failure.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
"""Tests for LoadFailureRule."""
import pytest

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


def test_load_failure_encoding(default_rules_collection: RulesCollection) -> None:
@pytest.mark.parametrize(
"path",
(
pytest.param("examples/broken/encoding.j2", id="jinja2"),
pytest.param("examples/broken/encoding.yml", id="yaml"),
),
)
def test_load_failure_encoding(
path: str,
default_rules_collection: RulesCollection,
) -> None:
"""Check that we fail when file encoding is wrong."""
runner = Runner("examples/broken/encoding.j2", rules=default_rules_collection)
runner = Runner(path, rules=default_rules_collection)
matches = runner.run()
assert len(matches) == 1, matches
assert matches[0].rule.id == "load-failure"
Expand Down