From 93b9783f1addeac45539ab958171d7dca5e7037d Mon Sep 17 00:00:00 2001 From: Guillaume Leurquin Date: Wed, 14 Jun 2023 12:36:11 +0000 Subject: [PATCH] feat: add include and exclude cli options --- docs/index.md | 4 ++++ src/yamlfix/entrypoints/cli.py | 41 +++++++++++++++++++++++++++++----- tests/e2e/test_cli.py | 28 +++++++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/docs/index.md b/docs/index.md index 3ba9813..734bcbe 100644 --- a/docs/index.md +++ b/docs/index.md @@ -160,6 +160,10 @@ These provided arguments and environment variables would result in a merged runt none_representation = "~" ``` +## Configure include and exclude files + +Per default `yamlfix`, when run through cli, will include all `*.yaml` and `*.yml` files from the directories passed via the CLI. With `--exclude ` and `--include ` you can include or exclude specific files within those directories. + ## Configuration Options All fields configured in the [YamlfixConfig class](./reference/#yamlfix.model.YamlfixConfig) can be provided through the means mentioned in [Configuration](#configuration). Here are the currently available configuration options with short examples on their impact to provided `yaml`-files. diff --git a/src/yamlfix/entrypoints/cli.py b/src/yamlfix/entrypoints/cli.py index d0158fd..38f447a 100644 --- a/src/yamlfix/entrypoints/cli.py +++ b/src/yamlfix/entrypoints/cli.py @@ -17,9 +17,20 @@ log = logging.getLogger(__name__) -def _find_all_yaml_files(dir_: Path) -> List[Path]: - files = [dir_.rglob(f"*.{ext}") for ext in ["yml", "yaml"]] - return [file for list_ in files for file in list_] +def _matches_any_glob(file_to_test: Path, globs: Optional[List[str]]) -> bool: + return any(file_to_test.match(glob) for glob in (globs or [])) + + +def _find_all_yaml_files( + dir_: Path, include_globs: Optional[List[str]], exclude_globs: Optional[List[str]] +) -> List[Path]: + files = [dir_.rglob(glob) for glob in (include_globs or [])] + return [ + file + for list_ in files + for file in list_ + if not _matches_any_glob(file, exclude_globs) + ] @click.command() @@ -43,12 +54,32 @@ def _find_all_yaml_files(dir_: Path) -> List[Path]: default="YAMLFIX", help="Read yamlfix relevant environment variables starting with this prefix.", ) +@click.option( + "--exclude", + "-e", + multiple=True, + type=str, + help="Files matching this glob pattern will be ignored.", +) +@click.option( + "--include", + "-i", + multiple=True, + type=str, + default=["*.yaml", "*.yml"], + help=( + "Files matching this glob pattern will be included, " + "unless they are also excluded. Default to '*.yaml' and '*.yml'." + ), +) @click.argument("files", type=str, required=True, nargs=-1) -def cli( +def cli( # pylint: disable=too-many-arguments files: Tuple[str], verbose: bool, check: bool, config_file: Optional[List[str]], + include: Optional[List[str]], + exclude: Optional[List[str]], env_prefix: str, ) -> None: """Corrects the source code of the specified files. @@ -67,7 +98,7 @@ def cli( real_files = [] for provided_file in paths: if provided_file.is_dir(): - real_files.extend(_find_all_yaml_files(provided_file)) + real_files.extend(_find_all_yaml_files(provided_file, include, exclude)) else: real_files.append(provided_file) files_to_fix = [file.open("r+") for file in real_files] diff --git a/tests/e2e/test_cli.py b/tests/e2e/test_cli.py index 36e0e56..2db1e70 100644 --- a/tests/e2e/test_cli.py +++ b/tests/e2e/test_cli.py @@ -86,6 +86,34 @@ def test_corrects_code_from_stdin(runner: CliRunner) -> None: assert result.stdout == fixed_source +def test_include_exclude_files(runner: CliRunner, tmp_path: Path) -> None: + """Correct only files matching include, and ignore files matching exclude.""" + include1 = tmp_path / "source_1.yaml" + exclude1 = tmp_path / "source_2.txt" + (tmp_path / "foo").mkdir() + exclude2 = tmp_path / "foo" / "source_3.yaml" + test_files = [include1, exclude1, exclude2] + init_source = "program: yamlfix" + for test_file in test_files: + test_file.write_text(init_source) + fixed_source = dedent( + """\ + --- + program: yamlfix + """ + ) + + result = runner.invoke( + cli, + [str(tmp_path)] + ["--include", "*.yaml", "--exclude", "foo/*.yaml"], + ) + + assert result.exit_code == 0 + assert include1.read_text() == fixed_source + assert exclude1.read_text() == init_source + assert exclude2.read_text() == init_source + + @pytest.mark.secondary() @pytest.mark.parametrize( ("verbose", "requires_fixing"), product([0, 1, 2], [True, False])