Skip to content

Commit 0d61898

Browse files
authored
Clarify auto-fix arguments use (#3751)
1 parent 94599dc commit 0d61898

File tree

5 files changed

+92
-30
lines changed

5 files changed

+92
-30
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ source = ["src", ".tox/*/site-packages"]
7373
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
7474
omit = ["test/*"]
7575
# Increase it just so it would pass on any single-python run
76-
fail_under = 93
76+
fail_under = 92
7777
skip_covered = true
7878
skip_empty = true
7979
# During development we might remove code (files) with coverage data, and we dont want to fail:

src/ansiblelint/__main__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ def main(argv: list[str] | None = None) -> int:
278278
ruamel_yaml_version_str,
279279
ruamel_safe_version,
280280
)
281+
acceptable_tags = {"all", "none", *rules.known_tags()}
282+
unknown_tags = set(options.write_list).difference(acceptable_tags)
283+
284+
if unknown_tags:
285+
_logger.error(
286+
"Found invalid value(s) (%s) for --fix arguments, must be one of: %s",
287+
", ".join(unknown_tags),
288+
", ".join(acceptable_tags),
289+
)
290+
sys.exit(RC.INVALID_CONFIG)
281291
_do_transform(result, options)
282292

283293
mark_as_success = True

src/ansiblelint/cli.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -216,16 +216,23 @@ def merge_fix_list_config(
216216
from_file: list[str],
217217
from_cli: list[str],
218218
) -> list[str]:
219-
"""Combine the write_list from file config with --fix CLI arg.
219+
"""Determine the write_list value based on cli vs config.
220220
221-
Handles the implicit "all" when "__default__" is present and file config is empty.
221+
When --fix is not passed from command line the from_cli is an empty list,
222+
so we use the file.
223+
224+
When from_cli is not an empty list, we ignore the from_file value.
222225
"""
223-
if not from_file or "none" in from_cli:
224-
# --fix is the same as --fix=all
225-
return ["all" if value == cls._default else value for value in from_cli]
226-
# --fix means use the config from the config file
227-
from_cli = [value for value in from_cli if value != cls._default]
228-
return from_file + from_cli
226+
arguments = from_file if from_cli == [cls._default] else from_cli
227+
for magic_value in ("none", "all"):
228+
if magic_value in arguments and len(arguments) > 1:
229+
msg = f"When passing '{magic_value}' to '--fix', you cannot pass other values."
230+
raise RuntimeError(
231+
msg,
232+
)
233+
if len(arguments) == 1 and arguments[0] == "none":
234+
arguments = []
235+
return arguments
229236

230237

231238
def get_cli_parser() -> argparse.ArgumentParser:
@@ -342,18 +349,12 @@ def get_cli_parser() -> argparse.ArgumentParser:
342349
dest="write_list",
343350
# this is a tri-state argument that takes an optional comma separated list:
344351
action=WriteArgAction,
345-
help="Allow ansible-lint to reformat YAML files and run rule transforms "
346-
"(Reformatting YAML files standardizes spacing, quotes, etc. "
347-
"A rule transform can fix or simplify fixing issues identified by that rule). "
352+
help="Allow ansible-lint to perform auto-fixes, including YAML reformatting. "
348353
"You can limit the effective rule transforms (the 'write_list') by passing a "
349354
"keywords 'all' or 'none' or a comma separated list of rule ids or rule tags. "
350355
"YAML reformatting happens whenever '--fix' or '--fix=' is used. "
351356
"'--fix' and '--fix=all' are equivalent: they allow all transforms to run. "
352-
"The effective list of transforms comes from 'write_list' in the config file, "
353-
"followed whatever '--fix' args are provided on the commandline. "
354-
"'--fix=none' resets the list of transforms to allow reformatting YAML "
355-
"without running any of the transforms (ie '--fix=none,rule-id' will "
356-
"ignore write_list in the config file and only run the rule-id transform).",
357+
"Presence of --fix in command overrides config file value.",
357358
)
358359
parser.add_argument(
359360
"--show-relpath",

src/ansiblelint/rules/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,15 @@ def __repr__(self) -> str:
503503
[rule.verbose() for rule in sorted(self.rules, key=lambda x: x.id)],
504504
)
505505

506+
def known_tags(self) -> list[str]:
507+
"""Return a list of known tags, without returning no sub-tags."""
508+
tags = set()
509+
for rule in self.rules:
510+
tags.add(rule.id)
511+
for tag in rule.tags:
512+
tags.add(tag)
513+
return sorted(tags)
514+
506515
def list_tags(self) -> str:
507516
"""Return a string with all the tags in the RulesCollection."""
508517
tag_desc = {

test/test_cli.py

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,37 +66,77 @@ def test_ensure_config_are_equal(
6666

6767

6868
@pytest.mark.parametrize(
69-
("with_base", "args", "config"),
69+
("with_base", "args", "config", "expected"),
7070
(
71-
(True, ["--fix"], "test/fixtures/config-with-write-all.yml"),
72-
(True, ["--fix=all"], "test/fixtures/config-with-write-all.yml"),
73-
(True, ["--fix", "all"], "test/fixtures/config-with-write-all.yml"),
74-
(True, ["--fix=none"], "test/fixtures/config-with-write-none.yml"),
75-
(True, ["--fix", "none"], "test/fixtures/config-with-write-none.yml"),
76-
(
71+
pytest.param(
72+
True,
73+
["--fix"],
74+
"test/fixtures/config-with-write-all.yml",
75+
[],
76+
id="1",
77+
),
78+
pytest.param(
79+
True,
80+
["--fix=all"],
81+
"test/fixtures/config-with-write-all.yml",
82+
["all"],
83+
id="2",
84+
),
85+
pytest.param(
86+
True,
87+
["--fix", "all"],
88+
"test/fixtures/config-with-write-all.yml",
89+
["all"],
90+
id="3",
91+
),
92+
pytest.param(
93+
True,
94+
["--fix=none"],
95+
"test/fixtures/config-with-write-none.yml",
96+
[],
97+
id="4",
98+
),
99+
pytest.param(
100+
True,
101+
["--fix", "none"],
102+
"test/fixtures/config-with-write-none.yml",
103+
[],
104+
id="5",
105+
),
106+
pytest.param(
77107
True,
78108
["--fix=rule-tag,rule-id"],
79109
"test/fixtures/config-with-write-subset.yml",
110+
["rule-tag", "rule-id"],
111+
id="6",
80112
),
81-
(
113+
pytest.param(
82114
True,
83115
["--fix", "rule-tag,rule-id"],
84116
"test/fixtures/config-with-write-subset.yml",
117+
["rule-tag", "rule-id"],
118+
id="7",
85119
),
86-
(
120+
pytest.param(
87121
True,
88122
["--fix", "rule-tag", "--fix", "rule-id"],
89123
"test/fixtures/config-with-write-subset.yml",
124+
["rule-tag", "rule-id"],
125+
id="8",
90126
),
91-
(
127+
pytest.param(
92128
False,
93129
["--fix", "examples/playbooks/example.yml"],
94130
"test/fixtures/config-with-write-all.yml",
131+
[],
132+
id="9",
95133
),
96-
(
134+
pytest.param(
97135
False,
98136
["--fix", "examples/playbooks/example.yml", "non-existent.yml"],
99137
"test/fixtures/config-with-write-all.yml",
138+
[],
139+
id="10",
100140
),
101141
),
102142
)
@@ -105,6 +145,7 @@ def test_ensure_write_cli_does_not_consume_lintables(
105145
with_base: bool,
106146
args: list[str],
107147
config: str,
148+
expected: list[str],
108149
) -> None:
109150
"""Check equality of the CLI --fix options to config files."""
110151
cli_parser = cli.get_cli_parser()
@@ -113,13 +154,14 @@ def test_ensure_write_cli_does_not_consume_lintables(
113154
options = cli_parser.parse_args(command)
114155
file_config = cli.load_config(config)[0]
115156

116-
file_value = file_config.get("write_list")
157+
file_config.get("write_list")
117158
orig_cli_value = options.write_list
118159
cli_value = cli.WriteArgAction.merge_fix_list_config(
119160
from_file=[],
120161
from_cli=orig_cli_value,
121162
)
122-
assert file_value == cli_value
163+
# breakpoint()
164+
assert cli_value == expected
123165

124166

125167
def test_config_can_be_overridden(base_arguments: list[str]) -> None:

0 commit comments

Comments
 (0)