Skip to content

Commit

Permalink
Merge pull request #182 from filippog/cli-dry-run
Browse files Browse the repository at this point in the history
CLI --check / dry-run mode
  • Loading branch information
lyz-code committed Sep 14, 2022
2 parents 549ef09 + 23f3ebb commit 79742a0
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 8 deletions.
16 changes: 13 additions & 3 deletions src/yamlfix/entrypoints/cli.py
@@ -1,6 +1,7 @@
"""Command line interface definition."""

import logging
import sys
from typing import Tuple

import click
Expand All @@ -20,17 +21,26 @@ def _format_file_list(files: Tuple[TextIOWrapper]) -> str:
@click.command()
@click.version_option(version="", message=version.version_info())
@click.option("--verbose", is_flag=True, help="Enable verbose logging.")
@click.option(
"--check",
is_flag=True,
help="Check if file(s) needs fixing. No files will be written in this case.",
)
@click.argument("files", type=click.File("r+"), required=True, nargs=-1)
def cli(files: Tuple[str], verbose: bool) -> None:
def cli(files: Tuple[str], verbose: bool, check: bool) -> None:
"""Corrects the source code of the specified files."""
load_logger(verbose)
log.info("Fixing files:%s", _format_file_list(files))
fixed_code = services.fix_files(files)
log.info("%s files:%s", "Checking" if check else "Fixing", _format_file_list(files))

fixed_code, changed = services.fix_files(files, check)

if fixed_code is not None:
print(fixed_code, end="")
log.info("Done.")

if changed and check:
sys.exit(1)


if __name__ == "__main__": # pragma: no cover
cli() # pylint: disable=E1120
50 changes: 46 additions & 4 deletions src/yamlfix/services.py
Expand Up @@ -6,8 +6,9 @@

import logging
import re
import warnings
from io import StringIO
from typing import List, Optional, Tuple, Union
from typing import List, Optional, Tuple, Union, overload

import ruyaml
from _io import TextIOWrapper
Expand All @@ -17,17 +18,47 @@
Files = Union[Tuple[TextIOWrapper], List[str]]


@overload
def fix_files(files: Files) -> Optional[str]:
...


@overload
def fix_files(files: Files, dry_run: Optional[bool]) -> Tuple[Optional[str], bool]:
...


def fix_files( # pylint: disable=too-many-branches
files: Files, dry_run: Optional[bool] = None
) -> Union[Optional[str], Tuple[Optional[str], bool]]: # noqa: TAE002
"""Fix the yaml source code of a list of files.
If the input is taken from stdin, it will return the fixed value.
Args:
files: List of files to fix.
dry_run: Whether to write changes or not.
Returns:
Fixed code retrieved from stdin or None.
A tuple with the following items:
* Fixed code or None.
* A bool to indicate whether at least one file has been changed.
"""
changed = False

if dry_run is None:
warnings.warn(
"""
From 2023-01-12 fix_files will change the return type from
`Optional[str]` to Tuple[Optional[str], bool], where the first
element of the Tuple is the fixed source and the second a bool that
returns whether the source has changed.
For more information check https://github.com/lyz-code/yamlfix/pull/182
""",
UserWarning,
)

for file_ in files:
if isinstance(file_, str):
with open(file_, "r", encoding="utf-8") as file_descriptor:
Expand All @@ -40,10 +71,18 @@ def fix_files(files: Files) -> Optional[str]:
log.debug("Fixing file %s...", file_name)
fixed_source = fix_code(source)

if fixed_source != source:
changed = True

if file_name == "<stdin>":
return fixed_source
if dry_run is None:
return fixed_source
return (fixed_source, changed)

if fixed_source != source:
if dry_run:
log.debug("Need to fix file %s.", file_name)
continue
if isinstance(file_, str):
with open(file_, "w", encoding="utf-8") as file_descriptor:
file_descriptor.write(fixed_source)
Expand All @@ -55,7 +94,10 @@ def fix_files(files: Files) -> Optional[str]:
else:
log.debug("Left file %s unmodified.", file_name)

return None
if dry_run is None:
return None

return (None, changed)


def fix_code(source_code: str) -> str:
Expand Down
31 changes: 31 additions & 0 deletions tests/e2e/test_cli.py
Expand Up @@ -124,3 +124,34 @@ def test_ignores_correct_files(
logging.DEBUG,
f"Left file {test_file} unmodified.",
) in caplog.record_tuples


def test_check_one_file_changes(runner: CliRunner, tmpdir: LocalPath) -> None:
"""The --check flag is working with fixes to do."""
# ignore: call to untyped join method, they don't have type hints
test_file_source = "program: yamlfix"
test_file = tmpdir.join("source.yaml") # type: ignore
test_file.write(test_file_source)

result = runner.invoke(cli, [str(test_file), "--check"])

assert result.exit_code == 1
assert test_file.read() == test_file_source


def test_check_one_file_no_changes(runner: CliRunner, tmpdir: LocalPath) -> None:
"""The --check flag is working with pending changes."""
# ignore: call to untyped join method, they don't have type hints
test_file_source = dedent(
"""\
---
program: yamlfix
"""
)
test_file = tmpdir.join("source.yaml") # type: ignore
test_file.write(test_file_source)

result = runner.invoke(cli, [str(test_file), "--check"])

assert result.exit_code == 0
assert test_file.read() == test_file_source
14 changes: 13 additions & 1 deletion tests/unit/test_services.py
Expand Up @@ -52,10 +52,22 @@ def test_fix_files_can_process_string_arguments(self, tmpdir: LocalPath) -> None
"""
)

fix_files([str(test_file)]) # act
fix_files([str(test_file)], False) # act

assert test_file.read() == fixed_source

def test_fix_files_issues_warning(self, tmpdir: LocalPath) -> None:
"""
Given: A file to fix
When: Using the old signature
Then: A warning is issued
"""
test_file = tmpdir.join("source.yaml") # type: ignore
test_file.write("program: yamlfix")
with pytest.warns(UserWarning, match="yamlfix/pull/182"):

fix_files([str(test_file)]) # act


class TestFixCode:
"""Test the fix_code function."""
Expand Down

0 comments on commit 79742a0

Please sign in to comment.