Repository: dbt-labs/dbt-core

Issue:
[CT-2513] [Regression] dbt deps --project-dir $DBT_PROJECT_DIR hangs with dbt=1.5.0
### Is this a new bug in dbt-core?

- [X] I believe this is a new bug in dbt-core
- [X] I have searched the existing issues, and I could not find an existing issue for this bug

### Current Behavior

After upgrading dbt-core to 1.5.0, our CI jobs hangs after running the following command from the parent directory of `integration_tests`:
```
dbt-expectations git:(main) dbt deps --project-dir integration_tests
```
Output:
```
01:29:08  Running with dbt=1.5.0
```
This will eventually result in a timeout [error](https://app.circleci.com/pipelines/github/calogica/dbt-expectations/253/workflows/92c6f533-2054-4b39-b033-ca8d77701187/jobs/177/parallel-runs/0/steps/0-103).
```
Too long with no output (exceeded 10m0s): context deadline exceeded
```

This was previously working under dbt version 1.4.1 and is currently blocking CI jobs for `dbt-expectations` and `dbt-date`.

If you `cd integrations_tests` and then run `dbt deps`, this command succeeds:

```
integration_tests git:(main) dbt deps
01:37:38  Running with dbt=1.5.0
01:37:39  Installing ../
01:37:39  Installed from <local @ ../>
01:37:39  Installing calogica/dbt_date
01:37:39  Installed from version 0.7.2
01:37:39  Up to date!
``` 

### Expected Behavior

This was previously working under dbt version 1.4.1 and should simply install the packages defined in `integration_tests/packages.yml`.

### Steps To Reproduce

Using dbt=1.5.0, in a project that contains a subproject, such as dbt-utils or dbt-expectations, run the following from the root folder:

`dbt deps --project-dir subproject` where `subproject` is the name of the folder containing the subproject.


After downgrading to dbt=1.4.1, the previous command succeeds:

```
dbt-expectations git:(main) dbt deps --project-dir integration_tests
01:42:13  Running with dbt=1.4.1
01:42:14  Installing ../
01:42:14    Installed from <local @ ../>
01:42:14  Installing calogica/dbt_date
01:42:14    Installed from version 0.7.2
01:42:14    Up to date!
```

### Relevant log output

_No response_

### Environment

```markdown
- OS: MacOS 13.3.1
- Python: 3.9
- dbt: 1.5.0
```


### Which database adapter are you using with dbt?

postgres

### Additional Context

_No response_


Discussion:
Thank you for reporting this @clausherther 🙏 

I was able to reproduce what you described between 1.4 (working) and 1.5 (terminating after 10 minutes), and I'm going to label this as a regression.

### Reprex

Directory structure:
```
.
├── dbt_project.yml
├── packages.yml
└── subproject
    ├── dbt_project.yml
    └── packages.yml
```

`dbt_project.yml`
```yaml
name: "my_dbt_project"
version: "1.0.0"
config-version: 2
profile: "sandcastle"
```

`packages.yml`
```yaml
packages:
  - package: calogica/dbt_date
    version: [">=0.7.0", "<0.8.0"]
```

`subproject/dbt_project.yml`
```yaml
name: "my_dbt_subproject"
version: "1.0.0"
config-version: 2
profile: "sandcastle"
```

`subproject/packages.yml`
```yaml
packages:
    - local: ../
```

Install dependencies:
```shell
 dbt deps --project-dir subproject
 ```
### TLDR
This problem is triggered when both `packages.yml` _and_ `--profiles-dir` contain relative paths.

### More detail

Some more findings from troubleshooting:
- Affects both `--project-dir` and `$DBT_PROJECT_DIR`
- Absolute paths work fine for both
- Only affects relative paths

This works in a `zsh` shell:
```shell
dbt deps --project-dir $(pwd)/subproject
```

Also, when `subproject/packages.yml` contains absolute paths, it works regardless if `--profiles-dir` is relative or not.
@iknox-fa I suspect there is some kind of circular dependency that gets introduced in the scenario outlined above (which maybe introduces an infinite loop 🤷).

Resolving patch:
diff --git a/core/dbt/clients/system.py b/core/dbt/clients/system.py
--- a/core/dbt/clients/system.py
+++ b/core/dbt/clients/system.py
@@ -211,7 +211,7 @@ def _windows_rmdir_readonly(func: Callable[[str], Any], path: str, exc: Tuple[An
 
 def resolve_path_from_base(path_to_resolve: str, base_path: str) -> str:
     """
-    If path-to_resolve is a relative path, create an absolute path
+    If path_to_resolve is a relative path, create an absolute path
     with base_path as the base.
 
     If path_to_resolve is an absolute path or a user path (~), just
diff --git a/core/dbt/task/deps.py b/core/dbt/task/deps.py
--- a/core/dbt/task/deps.py
+++ b/core/dbt/task/deps.py
@@ -1,5 +1,5 @@
 from typing import Any, Optional
-
+from pathlib import Path
 import dbt.utils
 import dbt.deprecations
 import dbt.exceptions
@@ -29,6 +29,12 @@
 
 class DepsTask(BaseTask):
     def __init__(self, args: Any, project: Project):
+        # N.B. This is a temporary fix for a bug when using relative paths via
+        # --project-dir with deps.  A larger overhaul of our path handling methods
+        # is needed to fix this the "right" way.
+        # See GH-7615
+        project.project_root = str(Path(project.project_root).resolve())
+
         move_to_nearest_project_dir(project.project_root)
         super().__init__(args=args, config=None, project=project)
         self.cli_vars = args.vars


Test patch:
diff --git a/tests/functional/dependencies/test_local_dependency.py b/tests/functional/dependencies/test_local_dependency.py
--- a/tests/functional/dependencies/test_local_dependency.py
+++ b/tests/functional/dependencies/test_local_dependency.py
@@ -13,10 +13,7 @@
 import dbt.config
 import dbt.exceptions
 
-from dbt.tests.util import (
-    check_relations_equal,
-    run_dbt,
-)
+from dbt.tests.util import check_relations_equal, run_dbt, run_dbt_and_capture
 
 models__dep_source = """
 {# If our dependency source didn't exist, this would be an errror #}
@@ -155,23 +152,16 @@ def test_local_dependency(self, project):
             [f"{project.test_schema}.dep_source_model", f"{project.test_schema}.seed"],
         )
 
-    def test_no_dependency_paths(self, project):
-        run_dbt(["deps"])
-        run_dbt(["seed"])
-
-        # prove dependency does not exist as model in project
-        dep_path = os.path.join("models_local", "model_to_import.sql")
-        results = run_dbt(
-            ["run", "--models", f"+{dep_path}"],
-        )
-        assert len(results) == 0
 
-        # prove model can run when importing that dependency
-        local_path = Path("models") / "my_model.sql"
-        results = run_dbt(
-            ["run", "--models", f"+{local_path}"],
-        )
-        assert len(results) == 2
+class TestSimpleDependencyRelativePath(BaseDependencyTest):
+    def test_local_dependency_relative_path(self, project):
+        last_dir = Path(project.project_root).name
+        os.chdir("../")
+        _, stdout = run_dbt_and_capture(["deps", "--project-dir", last_dir])
+        assert (
+            "Installed from <local @ local_dependency>" in stdout
+        ), "Test output didn't contain expected string"
+        os.chdir(project.project_root)
 
 
 class TestMissingDependency(object):