Skip to content

Commit e66997f

Browse files
Add write_exclude_list config option (#4256)
1 parent 4cc05a7 commit e66997f

File tree

5 files changed

+92
-11
lines changed

5 files changed

+92
-11
lines changed

src/ansiblelint/config.py

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class Options: # pylint: disable=too-many-instance-attributes
139139
list_rules: bool = False
140140
list_tags: bool = False
141141
write_list: list[str] = field(default_factory=list)
142+
write_exclude_list: list[str] = field(default_factory=list)
142143
parseable: bool = False
143144
quiet: bool = False
144145
rulesdirs: list[Path] = field(default_factory=list)

src/ansiblelint/schemas/ansible-lint-config.json

+7
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@
291291
"title": "Warn List",
292292
"type": "array"
293293
},
294+
"write_exclude_list": {
295+
"items": {
296+
"type": "string"
297+
},
298+
"title": "Write Exclude List",
299+
"type": "array"
300+
},
294301
"write_list": {
295302
"items": {
296303
"type": "string"

src/ansiblelint/transformer.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Transformer:
4949
def __init__(self, result: LintResult, options: Options):
5050
"""Initialize a Transformer instance."""
5151
self.write_set = self.effective_write_set(options.write_list)
52+
self.write_exclude_set = self.effective_write_set(options.write_exclude_list)
5253

5354
self.matches: list[MatchError] = result.matches
5455
self.files: set[Lintable] = result.files
@@ -150,13 +151,16 @@ def _do_transforms(
150151
if not isinstance(match.rule, TransformMixin):
151152
_logger.debug("%s %s", self.FIX_NA_MSG, match_id)
152153
continue
153-
if self.write_set != {"all"}:
154-
rule = cast("AnsibleLintRule", match.rule)
155-
rule_definition = set(rule.tags)
156-
rule_definition.add(rule.id)
157-
if rule_definition.isdisjoint(self.write_set):
158-
_logger.debug("%s %s", self.FIX_NE_MSG, match_id)
159-
continue
154+
rule = cast("AnsibleLintRule", match.rule)
155+
rule_definition = set(rule.tags)
156+
rule_definition.add(rule.id)
157+
if not rule_definition.isdisjoint(
158+
self.write_exclude_set,
159+
) or self.write_exclude_set == {"all"}:
160+
continue
161+
if rule_definition.isdisjoint(self.write_set) and self.write_set != {"all"}:
162+
_logger.debug("%s %s", self.FIX_NE_MSG, match_id)
163+
continue
160164
if file_is_yaml and not match.yaml_path:
161165
data = cast("CommentedMap | CommentedSeq", data)
162166
if match.match_type == "play":

test/test_transformer.py

+72-3
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@
99
from pathlib import Path
1010
from typing import TYPE_CHECKING, Any
1111
from unittest import mock
12+
from unittest.mock import Mock
1213

1314
import pytest
1415

1516
import ansiblelint.__main__ as main
1617
from ansiblelint.app import App
18+
from ansiblelint.config import Options
19+
from ansiblelint.errors import MatchError
1720
from ansiblelint.file_utils import Lintable
18-
from ansiblelint.rules import TransformMixin
21+
from ansiblelint.rules import AnsibleLintRule, TransformMixin
1922

2023
# noinspection PyProtectedMember
2124
from ansiblelint.runner import LintResult, get_matches
2225
from ansiblelint.transformer import Transformer
2326

2427
if TYPE_CHECKING:
25-
from ansiblelint.config import Options
26-
from ansiblelint.errors import MatchError
2728
from ansiblelint.rules import RulesCollection
2829

2930

@@ -297,6 +298,74 @@ def test_effective_write_set(write_list: list[str], expected: set[str]) -> None:
297298
assert actual == expected
298299

299300

301+
@pytest.mark.parametrize(
302+
("write_list", "write_exclude_list", "rules"),
303+
(
304+
(
305+
["all"],
306+
["none"],
307+
[("rule-id", True), ("rule1", True), ("rule-03", True)],
308+
),
309+
(
310+
["all"],
311+
["all"],
312+
[("rule-id", False), ("rule1", False), ("rule-03", False)],
313+
),
314+
(
315+
["none"],
316+
["none"],
317+
[("rule-id", False), ("rule1", False), ("rule-03", False)],
318+
),
319+
(
320+
["none"],
321+
["all"],
322+
[("rule-id", False), ("rule1", False), ("rule-03", False)],
323+
),
324+
(
325+
["rule-id"],
326+
["none"],
327+
[("rule-id", True), ("rule1", False), ("rule-03", False)],
328+
),
329+
(
330+
["rule-id"],
331+
["all"],
332+
[("rule-id", False), ("rule1", False), ("rule-03", False)],
333+
),
334+
),
335+
)
336+
def test_write_exclude_list(
337+
write_list: list[str],
338+
write_exclude_list: list[str],
339+
rules: list[tuple[str, bool]],
340+
) -> None:
341+
"""Test item matching write_exclude_list are excluded correctly."""
342+
matches: list[MatchError] = []
343+
344+
class TestRule(AnsibleLintRule, TransformMixin):
345+
"""Dummy class for transformable rules."""
346+
347+
for rule_id, transform_expected in rules:
348+
rule = Mock(spec=TestRule)
349+
rule.id = rule_id
350+
rule.tags = []
351+
rule.transform_expected = transform_expected
352+
match = MatchError(rule=rule)
353+
matches.append(match)
354+
355+
transformer = Transformer(
356+
LintResult(matches, set()),
357+
Options(write_list=write_list, write_exclude_list=write_exclude_list),
358+
)
359+
# noinspection PyTypeChecker
360+
Transformer._do_transforms(transformer, Mock(), "", False, matches) # noqa: SLF001
361+
362+
for match in matches:
363+
if match.rule.transform_expected: # type: ignore[attr-defined]
364+
match.rule.transform.assert_called() # type: ignore[attr-defined]
365+
else:
366+
match.rule.transform.assert_not_called() # type: ignore[attr-defined]
367+
368+
300369
def test_pruned_err_after_fix(monkeypatch: pytest.MonkeyPatch, tmpdir: Path) -> None:
301370
"""Test that pruned errors are not reported after fixing.
302371

tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ setenv =
7575
PRE_COMMIT_COLOR = always
7676
# Number of expected test passes, safety measure for accidental skip of
7777
# tests. Update value if you add/remove tests. (tox-extra)
78-
PYTEST_REQPASS = 900
78+
PYTEST_REQPASS = 906
7979
FORCE_COLOR = 1
8080
pre: PIP_PRE = 1
8181
allowlist_externals =

0 commit comments

Comments
 (0)