Repository: dbt-labs/dbt-core

Issue:
[CT-2970] [Regression] Fix `path:` selector with `--project-dir` for `dbt list`
### Housekeeping

- [X] I am a maintainer of dbt-core

### Short description

The hopeful end of a brief saga:
- We fixed https://github.com/dbt-labs/dbt-core/issues/7819 for all commands
- Then we adjusted the fix to use a context manager (https://github.com/dbt-labs/dbt-core/pull/7949)
- That preserved the fix for all commands except `list`, which doesn't use the context manager because it doesn't inherit from `RunnableTask`

### Acceptance criteria

I can run this from outside the root directory of my dbt project:
```
$ dbt -q ls -s path:models/my_model.sql --project-dir my_dbt_project/
my_dbt_project.my_model
```

### Impact to Adapters

zero impact

### Context

https://github.com/dbt-labs/dbt-core/issues/7819#issuecomment-1677402512


Discussion:

Resolving patch:
diff --git a/core/dbt/task/list.py b/core/dbt/task/list.py
--- a/core/dbt/task/list.py
+++ b/core/dbt/task/list.py
@@ -15,6 +15,7 @@
     ListCmdOut,
 )
 from dbt.exceptions import DbtRuntimeError, DbtInternalError
+from dbt.events.contextvars import task_contextvars
 
 
 class ListTask(GraphRunnableTask):
@@ -123,20 +124,23 @@ def generate_paths(self):
             yield node.original_file_path
 
     def run(self):
-        self.compile_manifest()
-        output = self.args.output
-        if output == "selector":
-            generator = self.generate_selectors
-        elif output == "name":
-            generator = self.generate_names
-        elif output == "json":
-            generator = self.generate_json
-        elif output == "path":
-            generator = self.generate_paths
-        else:
-            raise DbtInternalError("Invalid output {}".format(output))
+        # We set up a context manager here with "task_contextvars" because we
+        # we need the project_root in compile_manifest.
+        with task_contextvars(project_root=self.config.project_root):
+            self.compile_manifest()
+            output = self.args.output
+            if output == "selector":
+                generator = self.generate_selectors
+            elif output == "name":
+                generator = self.generate_names
+            elif output == "json":
+                generator = self.generate_json
+            elif output == "path":
+                generator = self.generate_paths
+            else:
+                raise DbtInternalError("Invalid output {}".format(output))
 
-        return self.output_results(generator())
+            return self.output_results(generator())
 
     def output_results(self, results):
         """Log, or output a plain, newline-delimited, and ready-to-pipe list of nodes found."""


Test patch:
diff --git a/tests/functional/graph_selection/test_graph_selection.py b/tests/functional/graph_selection/test_graph_selection.py
--- a/tests/functional/graph_selection/test_graph_selection.py
+++ b/tests/functional/graph_selection/test_graph_selection.py
@@ -142,6 +142,24 @@ def test_locally_qualified_name(self, project):
         check_result_nodes_by_name(results, ["subdir"])
         assert_correct_schemas(project)
 
+        # Check that list command works
+        os.chdir(
+            project.profiles_dir
+        )  # Change to random directory to test that Path selector works with project-dir
+        results = run_dbt(
+            [
+                "-q",
+                "ls",
+                "-s",
+                "path:models/test/subdir.sql",
+                "--project-dir",
+                str(project.project_root),
+            ]
+            #           ["list", "--project-dir", str(project.project_root), "--select", "models/test/subdir*"]
+        )
+        print(f"--- results: {results}")
+        assert len(results) == 1
+
     def test_locally_qualified_name_model_with_dots(self, project):
         results = run_dbt(["run", "--select", "alternative.users"], expect_pass=False)
         check_result_nodes_by_name(results, ["alternative.users"])
@@ -268,3 +286,22 @@ def test_exposure_parents(self, project):
                 "users",
             ],
         )
+
+
+class TestListPathGraphSelection(SelectionFixtures):
+    def test_list_select_with_project_dir(self, project):
+        # Check that list command works
+        os.chdir(
+            project.profiles_dir
+        )  # Change to random directory to test that Path selector works with project-dir
+        results = run_dbt(
+            [
+                "-q",
+                "ls",
+                "-s",
+                "path:models/test/subdir.sql",
+                "--project-dir",
+                str(project.project_root),
+            ]
+        )
+        assert results == ["test.test.subdir"]