diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 557b255e94..deada31380 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -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: 798 + PYTEST_REQPASS: 799 steps: - name: Activate WSL1 if: "contains(matrix.shell, 'wsl')" diff --git a/src/ansiblelint/_internal/load-failure.md b/src/ansiblelint/_internal/load-failure.md index 78daa0dcd5..f88bfa9b7e 100644 --- a/src/ansiblelint/_internal/load-failure.md +++ b/src/ansiblelint/_internal/load-failure.md @@ -2,11 +2,16 @@ "Linter failed to process a file, possible invalid file. Possible reasons: -* contains unsupported encoding (only UTF-8 is supported) -* not an Ansible file -* it contains some unsupported custom YAML objects (`!!` prefix) -* it was not able to decrypt an inline `!vault` block. - -This violation **is not** skippable, so it cannot be added to the `warn_list` -or the `skip_list`. If a vault decryption issue cannot be avoided, the -offending file can be added to `exclude_paths` configuration. +- contains unsupported encoding (only UTF-8 is supported) +- not an Ansible file +- it contains some unsupported custom YAML objects (`!!` prefix) +- it was not able to decrypt an inline `!vault` block. + +This violation **is not** skippable, so it cannot be added to the `warn_list` or +the `skip_list`. If a vault decryption issue cannot be avoided, the offending +file can be added to `exclude_paths` configuration. + +Possible errors codes: + +- `load-failure[not-found]` - Indicates that one argument file or folder was not + found on disk. diff --git a/src/ansiblelint/_internal/rules.py b/src/ansiblelint/_internal/rules.py index ba661f6d95..9c84be9a33 100644 --- a/src/ansiblelint/_internal/rules.py +++ b/src/ansiblelint/_internal/rules.py @@ -193,6 +193,9 @@ class LoadingFailureRule(BaseRule): version_added = "v4.3.0" _help = LOAD_FAILURE_MD _order = 0 + _ids = { + "load-failure[not-found]": "File not found", + } class WarningRule(BaseRule): diff --git a/src/ansiblelint/file_utils.py b/src/ansiblelint/file_utils.py index 168113147c..9ed93fda21 100644 --- a/src/ansiblelint/file_utils.py +++ b/src/ansiblelint/file_utils.py @@ -205,7 +205,9 @@ def __init__( # noqa: C901 if is_relative: name = name.relative_to(name.cwd()) name = normpath_path(name) - self.path = name + # we need to be sure that we expanduser() because otherwise a simple + # test like .path.exists() will return unexpected results. + self.path = name.expanduser() # Filename is effective file on disk, for stdin is a namedtempfile self.name = self.filename = str(name) diff --git a/src/ansiblelint/runner.py b/src/ansiblelint/runner.py index 8e1f068028..4a62c13163 100644 --- a/src/ansiblelint/runner.py +++ b/src/ansiblelint/runner.py @@ -188,6 +188,16 @@ def _run(self) -> list[MatchError]: # noqa: C901 ), ) lintable.stop_processing = True + # identify missing files/folders + if not lintable.path.exists(): + matches.append( + MatchError( + lintable=lintable, + message="File or found not found.", + rule=LoadingFailureRule(), + tag="load-failure[not-found]", + ), + ) # -- phase 1 : syntax check in parallel -- def worker(lintable: Lintable) -> list[MatchError]: diff --git a/src/ansiblelint/schemas/ansible-lint-config.json b/src/ansiblelint/schemas/ansible-lint-config.json index 7a2042ba79..983e40b2e4 100644 --- a/src/ansiblelint/schemas/ansible-lint-config.json +++ b/src/ansiblelint/schemas/ansible-lint-config.json @@ -157,6 +157,7 @@ "latest", "literal-compare", "load-failure", + "load-failure[not-found]", "loop-var-prefix", "loop-var-prefix[missing]", "loop-var-prefix[wrong]", diff --git a/test/schemas/negative_test/.ansible-lint.md b/test/schemas/negative_test/.ansible-lint.md index b840e54cc6..f1f230887e 100644 --- a/test/schemas/negative_test/.ansible-lint.md +++ b/test/schemas/negative_test/.ansible-lint.md @@ -35,6 +35,7 @@ "latest", "literal-compare", "load-failure", + "load-failure[not-found]", "loop-var-prefix", "loop-var-prefix[missing]", "loop-var-prefix[wrong]", diff --git a/test/test_runner.py b/test/test_runner.py index 2dcf28e4c8..7b89f79867 100644 --- a/test/test_runner.py +++ b/test/test_runner.py @@ -173,3 +173,20 @@ def test_files_not_scanned_twice(default_rules_collection: RulesCollection) -> N # this second run should return 0 because the included filed was already # processed and added to checked_files, which acts like a bypass list. assert len(run2) == 0 + + +def test_runner_not_found(default_rules_collection: RulesCollection) -> None: + """Ensure that lintables aren't double-checked.""" + checked_files: set[Lintable] = set() + + filename = Path("this/folder/does/not/exist").resolve() + runner = Runner( + filename, + rules=default_rules_collection, + verbosity=0, + checked_files=checked_files, + ) + result = runner.run() + assert len(runner.checked_files) == 1 + assert len(result) == 1 + assert result[0].tag == "load-failure[not-found]"