summaryrefslogtreecommitdiffstats
path: root/src/ansiblelint/cli.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ansiblelint/cli.py89
1 files changed, 55 insertions, 34 deletions
diff --git a/src/ansiblelint/cli.py b/src/ansiblelint/cli.py
index c9178a7..ce8d9ec 100644
--- a/src/ansiblelint/cli.py
+++ b/src/ansiblelint/cli.py
@@ -1,4 +1,5 @@
"""CLI parser setup and helpers."""
+
from __future__ import annotations
import argparse
@@ -7,7 +8,7 @@ import os
import sys
from argparse import Namespace
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable
+from typing import TYPE_CHECKING, Any
from ansiblelint.config import (
DEFAULT_KINDS,
@@ -16,7 +17,7 @@ from ansiblelint.config import (
Options,
log_entries,
)
-from ansiblelint.constants import CUSTOM_RULESDIR_ENVVAR, DEFAULT_RULESDIR, RC
+from ansiblelint.constants import CUSTOM_RULESDIR_ENVVAR, DEFAULT_RULESDIR, EPILOG, RC
from ansiblelint.file_utils import (
Lintable,
abspath,
@@ -29,7 +30,7 @@ from ansiblelint.schemas.main import validate_file_schema
from ansiblelint.yaml_utils import clean_json
if TYPE_CHECKING:
- from collections.abc import Sequence
+ from collections.abc import Callable, Sequence
_logger = logging.getLogger(__name__)
@@ -91,7 +92,7 @@ def load_config(config_file: str | None) -> tuple[dict[Any, Any], str | None]:
config = clean_json(config_lintable.data)
if not isinstance(config, dict):
msg = "Schema failed to properly validate the config file."
- raise RuntimeError(msg)
+ raise TypeError(msg)
config["config_file"] = config_path
config_dir = os.path.dirname(config_path)
expand_to_normalized_paths(config, config_dir)
@@ -134,7 +135,7 @@ class AbspathArgAction(argparse.Action):
values: str | Sequence[Any] | None,
option_string: str | None = None,
) -> None:
- if isinstance(values, (str, Path)):
+ if isinstance(values, str | Path):
values = [values]
if values:
normalized_values = [
@@ -145,7 +146,7 @@ class AbspathArgAction(argparse.Action):
class WriteArgAction(argparse.Action):
- """Argparse action to handle the --write flag with optional args."""
+ """Argparse action to handle the --fix flag with optional args."""
_default = "__default__"
@@ -174,8 +175,8 @@ class WriteArgAction(argparse.Action):
super().__init__(
option_strings=option_strings,
dest=dest,
- nargs="?", # either 0 (--write) or 1 (--write=a,b,c) argument
- const=self._default, # --write (no option) implicitly stores this
+ nargs="?", # either 0 (--fix) or 1 (--fix=a,b,c) argument
+ const=self._default, # --fix (no option) implicitly stores this
default=default,
type=type,
choices=choices,
@@ -194,8 +195,8 @@ class WriteArgAction(argparse.Action):
lintables = getattr(namespace, "lintables", None)
if not lintables and isinstance(values, str):
# args are processed in order.
- # If --write is after lintables, then that is not ambiguous.
- # But if --write comes first, then it might actually be a lintable.
+ # If --fix is after lintables, then that is not ambiguous.
+ # But if --fix comes first, then it might actually be a lintable.
maybe_lintable = Path(values)
if maybe_lintable.exists():
namespace.lintables = [values]
@@ -211,26 +212,40 @@ class WriteArgAction(argparse.Action):
setattr(namespace, self.dest, values)
@classmethod
- def merge_write_list_config(
+ def merge_fix_list_config(
cls,
from_file: list[str],
from_cli: list[str],
) -> list[str]:
- """Combine the write_list from file config with --write CLI arg.
+ """Determine the write_list value based on cli vs config.
+
+ When --fix is not passed from command line the from_cli is an empty list,
+ so we use the file.
- Handles the implicit "all" when "__default__" is present and file config is empty.
+ When from_cli is not an empty list, we ignore the from_file value.
"""
- if not from_file or "none" in from_cli:
- # --write is the same as --write=all
- return ["all" if value == cls._default else value for value in from_cli]
- # --write means use the config from the config file
- from_cli = [value for value in from_cli if value != cls._default]
- return from_file + from_cli
+ if not from_file:
+ arguments = ["all"] if from_cli == [cls._default] else from_cli
+ else:
+ arguments = from_file
+ for magic_value in ("none", "all"):
+ if magic_value in arguments and len(arguments) > 1:
+ msg = f"When passing '{magic_value}' to '--fix', you cannot pass other values."
+ raise RuntimeError(
+ msg,
+ )
+ if len(arguments) == 1 and arguments[0] == "none":
+ arguments = []
+ return arguments
def get_cli_parser() -> argparse.ArgumentParser:
"""Initialize an argument parser."""
- parser = argparse.ArgumentParser()
+ parser = argparse.ArgumentParser(
+ epilog=EPILOG,
+ # Avoid rewrapping description and epilog
+ formatter_class=argparse.RawTextHelpFormatter,
+ )
listing_group = parser.add_mutually_exclusive_group()
listing_group.add_argument(
@@ -338,22 +353,16 @@ def get_cli_parser() -> argparse.ArgumentParser:
help="Return non-zero exit code on warnings as well as errors",
)
parser.add_argument(
- "--write",
+ "--fix",
dest="write_list",
# this is a tri-state argument that takes an optional comma separated list:
action=WriteArgAction,
- help="Allow ansible-lint to reformat YAML files and run rule transforms "
- "(Reformatting YAML files standardizes spacing, quotes, etc. "
- "A rule transform can fix or simplify fixing issues identified by that rule). "
+ help="Allow ansible-lint to perform auto-fixes, including YAML reformatting. "
"You can limit the effective rule transforms (the 'write_list') by passing a "
"keywords 'all' or 'none' or a comma separated list of rule ids or rule tags. "
- "YAML reformatting happens whenever '--write' or '--write=' is used. "
- "'--write' and '--write=all' are equivalent: they allow all transforms to run. "
- "The effective list of transforms comes from 'write_list' in the config file, "
- "followed whatever '--write' args are provided on the commandline. "
- "'--write=none' resets the list of transforms to allow reformatting YAML "
- "without running any of the transforms (ie '--write=none,rule-id' will "
- "ignore write_list in the config file and only run the rule-id transform).",
+ "YAML reformatting happens whenever '--fix' or '--fix=' is used. "
+ "'--fix' and '--fix=all' are equivalent: they allow all transforms to run. "
+ "Presence of --fix in command overrides config file value.",
)
parser.add_argument(
"--show-relpath",
@@ -490,6 +499,7 @@ def merge_config(file_config: dict[Any, Any], cli_config: Options) -> Options:
"enable_list": [],
"only_builtins_allow_collections": [],
"only_builtins_allow_modules": [],
+ "supported_ansible_also": [],
# do not include "write_list" here. See special logic below.
}
@@ -506,6 +516,10 @@ def merge_config(file_config: dict[Any, Any], cli_config: Options) -> Options:
for entry, default in lists_map.items():
if not getattr(cli_config, entry, None):
setattr(cli_config, entry, default)
+ if cli_config.write_list is None:
+ cli_config.write_list = []
+ elif cli_config.write_list == [WriteArgAction._default]: # noqa: SLF001
+ cli_config.write_list = ["all"]
return cli_config
for entry in bools:
@@ -513,8 +527,8 @@ def merge_config(file_config: dict[Any, Any], cli_config: Options) -> Options:
v = getattr(cli_config, entry) or file_value
setattr(cli_config, entry, v)
- for entry, default in scalar_map.items():
- file_value = file_config.pop(entry, default)
+ for entry, default_scalar in scalar_map.items():
+ file_value = file_config.pop(entry, default_scalar)
v = getattr(cli_config, entry, None) or file_value
setattr(cli_config, entry, v)
@@ -533,7 +547,7 @@ def merge_config(file_config: dict[Any, Any], cli_config: Options) -> Options:
setattr(
cli_config,
entry,
- WriteArgAction.merge_write_list_config(
+ WriteArgAction.merge_fix_list_config(
from_file=file_config.pop(entry, []),
from_cli=getattr(cli_config, entry, []) or [],
),
@@ -557,6 +571,13 @@ def merge_config(file_config: dict[Any, Any], cli_config: Options) -> Options:
def get_config(arguments: list[str]) -> Options:
"""Extract the config based on given args."""
parser = get_cli_parser()
+ # translate deprecated options
+ for i, value in enumerate(arguments):
+ if arguments[i].startswith("--write"):
+ arguments[i] = value.replace("--write", "--fix")
+ _logger.warning(
+ "Replaced deprecated '--write' option with '--fix', change you call to avoid future regressions when we remove old option.",
+ )
options = Options(**vars(parser.parse_args(arguments)))
# docs is not document, being used for internal documentation building