diff --git a/CHANGES.md b/CHANGES.md index ba9f4c06f28..b1e8f6c75b1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,9 @@ +- Fix incorrectly ignoring .gitignore presence when more than one source directory is + specified (#3336) + ### Packaging diff --git a/src/black/__init__.py b/src/black/__init__.py index 5293796aea1..2e43e800c40 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -30,6 +30,7 @@ import click from click.core import ParameterSource from mypy_extensions import mypyc_attr +from pathspec import PathSpec from pathspec.patterns.gitwildmatch import GitWildMatchPatternError from _black_version import version as __version__ @@ -625,6 +626,11 @@ def get_sources( sources: Set[Path] = set() root = ctx.obj["root"] + exclude_is_None = exclude is None + exclude = re_compile_maybe_verbose(DEFAULT_EXCLUDES) if exclude is None else exclude + gitignore = None # type: Optional[PathSpec] + root_gitignore = get_gitignore(root) + for s in src: if s == "-" and stdin_filename: p = Path(stdin_filename) @@ -658,16 +664,14 @@ def get_sources( sources.add(p) elif p.is_dir(): - if exclude is None: - exclude = re_compile_maybe_verbose(DEFAULT_EXCLUDES) - gitignore = get_gitignore(root) + if exclude_is_None: p_gitignore = get_gitignore(p) # No need to use p's gitignore if it is identical to root's gitignore # (i.e. root and p point to the same directory). - if gitignore != p_gitignore: - gitignore += p_gitignore - else: - gitignore = None + if root_gitignore == p_gitignore: + gitignore = root_gitignore + else: + gitignore = root_gitignore + p_gitignore sources.update( gen_python_files( p.iterdir(), diff --git a/tests/data/gitignore_used_on_multiple_sources/.gitignore b/tests/data/gitignore_used_on_multiple_sources/.gitignore new file mode 100644 index 00000000000..2987e7bb646 --- /dev/null +++ b/tests/data/gitignore_used_on_multiple_sources/.gitignore @@ -0,0 +1 @@ +a.py diff --git a/tests/data/gitignore_used_on_multiple_sources/dir1/a.py b/tests/data/gitignore_used_on_multiple_sources/dir1/a.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/gitignore_used_on_multiple_sources/dir1/b.py b/tests/data/gitignore_used_on_multiple_sources/dir1/b.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/gitignore_used_on_multiple_sources/dir2/a.py b/tests/data/gitignore_used_on_multiple_sources/dir2/a.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/data/gitignore_used_on_multiple_sources/dir2/b.py b/tests/data/gitignore_used_on_multiple_sources/dir2/b.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/test_black.py b/tests/test_black.py index 5d0175d9d66..d66305becf0 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1956,6 +1956,17 @@ def test_gitignore_used_as_default(self) -> None: ctx.obj["root"] = base assert_collected_sources(src, expected, ctx=ctx, extend_exclude=r"/exclude/") + def test_gitignore_used_on_multiple_sources(self) -> None: + root = Path(DATA_DIR / "gitignore_used_on_multiple_sources") + expected = [ + root / "dir1" / "b.py", + root / "dir2" / "b.py", + ] + ctx = FakeContext() + ctx.obj["root"] = root + src = [root / "dir1", root / "dir2"] + assert_collected_sources(src, expected, ctx=ctx) + @patch("black.find_project_root", lambda *args: (THIS_DIR.resolve(), None)) def test_exclude_for_issue_1572(self) -> None: # Exclude shouldn't touch files that were explicitly given to Black through the