diff --git a/.changes/unreleased/Features-20230916-120547.yaml b/.changes/unreleased/Features-20230916-120547.yaml new file mode 100644 index 00000000000..c31081ca053 --- /dev/null +++ b/.changes/unreleased/Features-20230916-120547.yaml @@ -0,0 +1,6 @@ +kind: Features +body: resolve packages with same git repo and unique subdirectory +time: 2023-09-16T12:05:47.353417149-04:00 +custom: + Author: philippeboyd + Issue: "5374" diff --git a/core/dbt/deps/git.py b/core/dbt/deps/git.py index 31d83fa6cd4..cc3fa1af6a2 100644 --- a/core/dbt/deps/git.py +++ b/core/dbt/deps/git.py @@ -20,13 +20,18 @@ def md5sum(s: str): class GitPackageMixin: - def __init__(self, git: str) -> None: + def __init__( + self, + git: str, + subdirectory: Optional[str] = None, + ) -> None: super().__init__() self.git = git + self.subdirectory = subdirectory @property def name(self): - return self.git + return f"{self.git}/{self.subdirectory}" if self.subdirectory else self.git def source_type(self) -> str: return "git" @@ -40,11 +45,11 @@ def __init__( warn_unpinned: bool = True, subdirectory: Optional[str] = None, ) -> None: - super().__init__(git) + super().__init__(git, subdirectory) self.revision = revision self.warn_unpinned = warn_unpinned self.subdirectory = subdirectory - self._checkout_name = md5sum(self.git) + self._checkout_name = md5sum(self.name) def get_version(self): return self.revision @@ -106,7 +111,7 @@ def __init__( warn_unpinned: bool = True, subdirectory: Optional[str] = None, ) -> None: - super().__init__(git) + super().__init__(git, subdirectory) self.revisions = revisions self.warn_unpinned = warn_unpinned self.subdirectory = subdirectory @@ -129,7 +134,14 @@ def all_names(self) -> List[str]: other = self.git[:-4] else: other = self.git + ".git" - return [self.git, other] + + if self.subdirectory: + git_name = f"{self.git}/{self.subdirectory}" + other = f"{other}/{self.subdirectory}" + else: + git_name = self.git + + return [git_name, other] def incorporate(self, other: "GitUnpinnedPackage") -> "GitUnpinnedPackage": warn_unpinned = self.warn_unpinned and other.warn_unpinned @@ -146,7 +158,7 @@ def resolved(self) -> GitPinnedPackage: if len(requested) == 0: requested = {"HEAD"} elif len(requested) > 1: - raise MultipleVersionGitDepsError(self.git, requested) + raise MultipleVersionGitDepsError(self.name, requested) return GitPinnedPackage( git=self.git, diff --git a/tests/unit/test_deps.py b/tests/unit/test_deps.py index 39a799e638e..aaa55b04c50 100644 --- a/tests/unit/test_deps.py +++ b/tests/unit/test_deps.py @@ -120,11 +120,17 @@ def test_resolve_ok(self): b_contract = GitPackage.from_dict( {"git": "http://example.com", "revision": "0.0.1", "warn-unpinned": False}, ) + d_contract = GitPackage.from_dict( + {"git": "http://example.com", "revision": "0.0.1", "subdirectory": "foo-bar"}, + ) a = GitUnpinnedPackage.from_contract(a_contract) b = GitUnpinnedPackage.from_contract(b_contract) + c = a.incorporate(b) + d = GitUnpinnedPackage.from_contract(d_contract) + self.assertTrue(a.warn_unpinned) self.assertFalse(b.warn_unpinned) - c = a.incorporate(b) + self.assertTrue(d.warn_unpinned) c_pinned = c.resolved() self.assertEqual(c_pinned.name, "http://example.com") @@ -132,6 +138,12 @@ def test_resolve_ok(self): self.assertEqual(c_pinned.source_type(), "git") self.assertFalse(c_pinned.warn_unpinned) + d_pinned = d.resolved() + self.assertEqual(d_pinned.name, "http://example.com/foo-bar") + self.assertEqual(d_pinned.get_version(), "0.0.1") + self.assertEqual(d_pinned.source_type(), "git") + self.assertEqual(d_pinned.subdirectory, "foo-bar") + def test_resolve_fail(self): a_contract = GitPackage.from_dict( {"git": "http://example.com", "revision": "0.0.1"},