diff --git a/src/ansiblelint/__main__.py b/src/ansiblelint/__main__.py index 5450f0455a..16900ed117 100755 --- a/src/ansiblelint/__main__.py +++ b/src/ansiblelint/__main__.py @@ -46,6 +46,7 @@ if TYPE_CHECKING: # RulesCollection must be imported lazily or ansible gets imported too early. from ansiblelint.rules import RulesCollection + from ansiblelint.runner import LintResult _logger = logging.getLogger(__name__) @@ -137,6 +138,19 @@ def _do_list(rules: "RulesCollection") -> int: return 1 +def _do_transform(result: "LintResult") -> None: + """Create and run Transformer.""" + # On purpose lazy-imports to avoid loading transforms unless requested + # pylint: disable=import-outside-toplevel + from ansiblelint.transformer import Transformer + + # future: maybe pass options to Transformer + transformer = Transformer(result) + + # this will mark any matches as fixed if the transforms repaired the issue + transformer.run() + + def main(argv: Optional[List[str]] = None) -> int: """Linter CLI entry point.""" # alter PATH if needed (venv support) @@ -174,6 +188,9 @@ def main(argv: Optional[List[str]] = None) -> int: result = _get_matches(rules, options) + if options.write: + _do_transform(result) + mark_as_success = False if result.matches and options.progressive: _logger.info( diff --git a/src/ansiblelint/cli.py b/src/ansiblelint/cli.py index 68bedd8db6..d1c9391fd1 100644 --- a/src/ansiblelint/cli.py +++ b/src/ansiblelint/cli.py @@ -189,6 +189,13 @@ def get_cli_parser() -> argparse.ArgumentParser: dest="use_default_rules", help="Keep default rules when using -r", ) + parser.add_argument( + "--write", + dest="write", + action="store_true", + help="Reformat YAML files to standardize spacing, quotes, etc. " + "Future versions will expand this option so it fixes more issues.", + ) parser.add_argument( "--show-relpath", dest="display_relative_path", diff --git a/src/ansiblelint/config.py b/src/ansiblelint/config.py index c4cbc15be4..5ac1ec7bda 100644 --- a/src/ansiblelint/config.py +++ b/src/ansiblelint/config.py @@ -69,6 +69,7 @@ lintables=[], listrules=False, listtags=False, + write=False, parseable=False, quiet=False, rulesdirs=[], diff --git a/src/ansiblelint/transformer.py b/src/ansiblelint/transformer.py new file mode 100644 index 0000000000..ccb0d6ce2c --- /dev/null +++ b/src/ansiblelint/transformer.py @@ -0,0 +1,28 @@ +"""Transformer implementation.""" +import logging +from typing import List, Set + +from ansiblelint.errors import MatchError +from ansiblelint.file_utils import Lintable +from ansiblelint.runner import LintResult + +__all__ = ["Transformer"] + +_logger = logging.getLogger(__name__) + + +class Transformer: + """Transformer class marshals transformations. + + The Transformer is similar to the ``ansiblelint.runner.Runner`` which manages + running each of the rules. We only expect there to be one ``Transformer`` instance + which should be instantiated from the main entrypoint function. + """ + + def __init__(self, result: LintResult): + """Initialize a Transformer instance.""" + self.matches: List[MatchError] = result.matches + self.files: Set[Lintable] = result.files + + def run(self) -> None: + """For each file, read it, execute transforms on it, then write it."""