Repository: jacebrowning/gitman

Issue:
filter_nested_configs is doing the opposite of what it should
When I introduced `filter_nested_configs`, I had meant to filter out any `gitman.yml` files that were present inside of the top-level config file. This requires more intelligently filtering any nested `gitman.yml` files that are present in already `gitman install`'d dependencies. This requires changing `filter_nested_configs` in `$PROJECT_ROOT/models/config.py` to:
```python
def filter_nested_configs(
    configs: List[Config]
) -> List[Config]:
    """Filter subdirectories inside of parent config."""
    filtered_configs = []
    for config_a in configs:
        is_nested = False
        for config_b in configs:
            if config_a == config_b:
                continue
            if Path(config_b.location_path) in Path(config_a.location_path).parents:
                is_nested = True
                break
        if not is_nested:
            filtered_configs.append(config_a)

    return filtered_configs
```

And also modifying L91-L95 in `$PROJECT_ROOT/gitman/commands.py` to:
```python
...
    config = load_config(root)
    configs = [config] if config else []
    configs.extend(find_nested_configs(root, depth, []))
    configs = filter_nested_configs(configs)
...
```

Discussion:

Patch:
diff --git a/Makefile b/Makefile
index b3fa4e6..943dad9 100644
--- a/Makefile
+++ b/Makefile
@@ -12,8 +12,8 @@ dev: install .clean-test ## Continuously run all CI tasks when files chanage
 
 .PHONY: demo
 demo: install
-	@ echo gitman update
-	@ poetry run gitman update
+	@ echo gitman install
+	@ poetry run gitman install --depth 1
 ifdef RECORDING_DELAY
 	@ sleep $(RECORDING_DELAY)
 	@ sleep $(RECORDING_DELAY)
@@ -21,7 +21,7 @@ ifdef RECORDING_DELAY
 	@ sleep $(RECORDING_DELAY)
 endif
 	@ echo gitman list
-	@ poetry run gitman list
+	@ poetry run gitman list --depth 1
 ifdef RECORDING_DELAY
 	@ sleep $(RECORDING_DELAY)
 	@ sleep $(RECORDING_DELAY)
@@ -29,15 +29,15 @@ ifdef RECORDING_DELAY
 	@ sleep $(RECORDING_DELAY)
 endif
 	@ echo gitman lock
-	@ poetry run gitman lock
+	@ poetry run gitman lock --depth 1
 ifdef RECORDING_DELAY
 	@ sleep $(RECORDING_DELAY)
 	@ sleep $(RECORDING_DELAY)
 	@ clear
 	@ sleep $(RECORDING_DELAY)
 endif
-	@ echo gitman install
-	@ poetry run gitman install
+	@ echo gitman update
+	@ poetry run gitman update --depth 1
 ifdef RECORDING_DELAY
 	@ sleep $(RECORDING_DELAY)
 	@ sleep $(RECORDING_DELAY)
diff --git a/gitman/cli.py b/gitman/cli.py
index 8c89a80..0466a8b 100644
--- a/gitman/cli.py
+++ b/gitman/cli.py
@@ -168,7 +168,7 @@ def main(args=None, function=None):
         "lock",
         description=info.capitalize() + ".",
         help=info,
-        parents=[debug, project],
+        parents=[debug, project, depth],
         formatter_class=common.WideHelpFormatter,
     )
     sub.add_argument("name", nargs="*", help="list of dependency names to lock")
@@ -287,6 +287,7 @@ def _get_command(function, namespace):
         args = namespace.name
         kwargs.update(
             root=namespace.root,
+            depth=namespace.depth,
         )
 
     elif namespace.command == "uninstall":
diff --git a/gitman/commands.py b/gitman/commands.py
index 297d432..739f9e3 100644
--- a/gitman/commands.py
+++ b/gitman/commands.py
@@ -90,10 +90,8 @@ def install(
 
     config = load_config(root)
     configs = [config] if config else []
-    nested_configs = find_nested_configs(root, depth, [])
-    if config is not None:
-        nested_configs = filter_nested_configs(config, nested_configs)
-    configs.extend(nested_configs)
+    configs.extend(find_nested_configs(root, depth, []))
+    configs = filter_nested_configs(configs)
 
     if configs:
         count = 0
@@ -274,6 +272,7 @@ def lock(*names, depth=None, root=None):
     config = load_config(root)
     configs = [config] if config else []
     configs.extend(find_nested_configs(root, depth, []))
+    configs = filter_nested_configs(configs)
     if configs:
         count = 0
         common.newline()
diff --git a/gitman/models/config.py b/gitman/models/config.py
index 97ea47c..6e99389 100644
--- a/gitman/models/config.py
+++ b/gitman/models/config.py
@@ -6,7 +6,7 @@ from typing import Iterator, List, Optional
 import log
 from datafiles import datafile, field
 
-from .. import common, exceptions, settings, shell
+from .. import common, exceptions, shell
 from ..decorators import preserve_cwd
 from .group import Group
 from .source import Identity, Source
@@ -426,7 +426,7 @@ def find_nested_configs(
     root = os.path.abspath(root) if root else _resolve_current_directory()
     configs: List[Config] = []
 
-    if (depth is not None and depth <= 1) or settings.CI:
+    if depth is not None and depth <= 1:
         return configs
 
     log.debug(f"Searching for nested project in: {root}")
@@ -467,15 +467,18 @@ def _valid_filename(filename):
     return name in {"gitman", "gdm"} and ext in {".yml", ".yaml"}
 
 
-def filter_nested_configs(
-    top_level_config: Config, nested_configs: List[Config]
-) -> List[Config]:
+def filter_nested_configs(configs: List[Config]) -> List[Config]:
     """Filter subdirectories inside of parent config."""
-    configs = []
-    config_location_path = Path(top_level_config.location_path)
-    for nested_config in nested_configs:
-        nested_config_root = Path(nested_config.location_path)
-        if config_location_path in nested_config_root.parents:
-            configs.append(nested_config)
+    filtered_configs = []
+    for config_a in configs:
+        is_nested = False
+        for config_b in configs:
+            if config_a == config_b:
+                continue
+            if Path(config_b.location_path) in Path(config_a.location_path).parents:
+                is_nested = True
+                break
+        if not is_nested:
+            filtered_configs.append(config_a)
 
-    return configs
+    return filtered_configs


Test patch:
diff --git a/gitman/tests/test_cli.py b/gitman/tests/test_cli.py
index 166b82c..906cb10 100644
--- a/gitman/tests/test_cli.py
+++ b/gitman/tests/test_cli.py
@@ -359,12 +359,12 @@ def describe_lock():
     @patch("gitman.commands.lock")
     def with_no_arguments(lock):
         cli.main(["lock"])
-        lock.assert_called_once_with(root=None)
+        lock.assert_called_once_with(root=None, depth=5)
 
     @patch("gitman.commands.lock")
     def with_dependencies(lock):
         cli.main(["lock", "foo", "bar"])
-        lock.assert_called_once_with("foo", "bar", root=None)
+        lock.assert_called_once_with("foo", "bar", root=None, depth=5)
 
 
 class TestUninstall:
diff --git a/gitman/tests/test_models_config.py b/gitman/tests/test_models_config.py
index f77d1c3..af4de82 100644
--- a/gitman/tests/test_models_config.py
+++ b/gitman/tests/test_models_config.py
@@ -5,7 +5,8 @@ import os
 import pytest
 from expecter import expect
 
-from gitman.models import Config, load_config
+from gitman.models import Config, find_nested_configs, load_config
+from gitman.models.config import filter_nested_configs
 
 from .conftest import FILES
 
@@ -148,3 +149,16 @@ class TestLoad:
         config = load_config()
 
         assert None is config
+
+    @pytest.mark.integration
+    def test_filter_nested_config(self):
+        """Verify that filter_nested_config removes nested configs"""
+        config = load_config(FILES)
+        assert None is not config
+        count = config.install_dependencies(depth=2)
+        assert 5 == count
+        configs = [config] if config else []
+        configs.extend(find_nested_configs(FILES, depth=2, skip_paths=[]))
+        assert 2 == len(configs)
+        configs = filter_nested_configs(configs)
+        assert 1 == len(configs)