From 2082e314ad7eb5c88774780e34b31ca56efa8eaf Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea <ssbarnea@redhat.com> Date: Sat, 20 May 2023 17:05:45 +0100 Subject: [PATCH] Do not exclude files that given as arguments If a file or folder is given as an argument to the linter, it will be treated as explicit and exclude rules will not apply to it. This will allow linting of files outside current project too. Fixes: #2628 --- .github/workflows/tox.yml | 2 +- examples/playbooks/deep/empty.yml | 4 ++++ src/ansiblelint/file_utils.py | 1 + src/ansiblelint/runner.py | 13 ++++++++++--- src/ansiblelint/schemas/__store__.json | 2 +- test/test_runner.py | 24 +++++++++++++++++++++--- 6 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 examples/playbooks/deep/empty.yml diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index deada31380..9931e4fe65 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: 799 + PYTEST_REQPASS: 800 steps: - name: Activate WSL1 if: "contains(matrix.shell, 'wsl')" diff --git a/examples/playbooks/deep/empty.yml b/examples/playbooks/deep/empty.yml new file mode 100644 index 0000000000..722df737e2 --- /dev/null +++ b/examples/playbooks/deep/empty.yml @@ -0,0 +1,4 @@ +--- +- name: some playbook with incorrect name # <- should raise name[casing] + hosts: localhost + tasks: [] diff --git a/src/ansiblelint/file_utils.py b/src/ansiblelint/file_utils.py index 9ed93fda21..1dd2ea97e3 100644 --- a/src/ansiblelint/file_utils.py +++ b/src/ansiblelint/file_utils.py @@ -197,6 +197,7 @@ def __init__( # noqa: C901 self.line_skips: dict[int, set[str]] = defaultdict(set) self.exc: Exception | None = None # Stores data loading exceptions self.parent = parent + self.explicit = False # Indicates if the file was explicitly provided or was indirectly included. if isinstance(name, str): name = Path(name) diff --git a/src/ansiblelint/runner.py b/src/ansiblelint/runner.py index 4a62c13163..3412ff4ef9 100644 --- a/src/ansiblelint/runner.py +++ b/src/ansiblelint/runner.py @@ -63,10 +63,12 @@ def __init__( if exclude_paths is None: exclude_paths = [] - # Assure consistent type + # Assure consistent type and configure given lintables as explicit (so + # excludes paths would not apply on them). for item in lintables: if not isinstance(item, Lintable): item = Lintable(item) + item.explicit = True self.lintables.add(item) # Expand folders (roles) to their components @@ -99,6 +101,11 @@ def is_excluded(self, lintable: Lintable) -> bool: # Exclusions should be evaluated only using absolute paths in order # to work correctly. + + # Explicit lintables are never excluded + if lintable.explicit: + return False + abs_path = str(lintable.abspath) if self.project_dir and not abs_path.startswith(self.project_dir): _logger.debug( @@ -193,7 +200,7 @@ def _run(self) -> list[MatchError]: # noqa: C901 matches.append( MatchError( lintable=lintable, - message="File or found not found.", + message="File or directory found not found.", rule=LoadingFailureRule(), tag="load-failure[not-found]", ), @@ -251,7 +258,7 @@ def worker(lintable: Lintable) -> list[MatchError]: # remove any matches made inside excluded files matches = list( filter( - lambda match: not self.is_excluded(Lintable(match.filename)) + lambda match: not self.is_excluded(match.lintable) and hasattr(match, "lintable") and match.tag not in match.lintable.line_skips[match.lineno], matches, diff --git a/src/ansiblelint/schemas/__store__.json b/src/ansiblelint/schemas/__store__.json index 453af0ed48..1ca0e19c46 100644 --- a/src/ansiblelint/schemas/__store__.json +++ b/src/ansiblelint/schemas/__store__.json @@ -1,6 +1,6 @@ { "ansible-lint-config": { - "etag": "0c180fc60da7bfbbf70d0ffa6dd4871aefce5e6f987f9c8073cb203dacd991b2", + "etag": "b5caa5405047dad89bb9fb419a17d8a67750f3a7ecdbabe16e0eb1897d316c5a", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json" }, "ansible-navigator-config": { diff --git a/test/test_runner.py b/test/test_runner.py index 7b89f79867..c2dfbf0e9d 100644 --- a/test/test_runner.py +++ b/test/test_runner.py @@ -48,7 +48,7 @@ pytest.param( LOTS_OF_WARNINGS_PLAYBOOK, [LOTS_OF_WARNINGS_PLAYBOOK], - 0, + 992, id="lots_of_warnings", ), pytest.param(Path("examples/playbooks/become.yml"), [], 0, id="become"), @@ -77,9 +77,9 @@ def test_runner( def test_runner_exclude_paths(default_rules_collection: RulesCollection) -> None: """Test that exclude paths do work.""" runner = Runner( - "examples/playbooks/example.yml", + "examples/playbooks/deep/", rules=default_rules_collection, - exclude_paths=["examples/"], + exclude_paths=["examples/playbooks/deep/empty.yml"], ) matches = runner.run() @@ -190,3 +190,21 @@ def test_runner_not_found(default_rules_collection: RulesCollection) -> None: assert len(runner.checked_files) == 1 assert len(result) == 1 assert result[0].tag == "load-failure[not-found]" + + +def test_runner_tmp_file( + tmp_path: Path, + default_rules_collection: RulesCollection, +) -> None: + """Ensure we do not ignore an explicit temporary file from linting.""" + # https://github.com/ansible/ansible-lint/issues/2628 + filename = tmp_path / "playbook.yml" + filename.write_text("---\n") + runner = Runner( + filename, + rules=default_rules_collection, + verbosity=0, + ) + result = runner.run() + assert len(result) == 1 + assert result[0].tag == "syntax-check[empty-playbook]"