Repository: dbt-labs/dbt-core

Issue:
v0.16.1: dbt deps doesn't respect "--project-dir" flag
I've attempted to fix the bug at #2339 

### Describe the bug
Upgrading from version `v0.16.0` to `v0.16.1` breaks running `dbt deps --project-dir project` when the `dbt deps --project-dir` command is run from outside the project directory.

`--project-dir` flag is not respected anymore.

### Steps To Reproduce
On `v0.16.1` this will fail

1. `cd ..` from a dbt project directory

2. `dbt deps --project-dir project` will fail

Example directory structure: https://github.com/nickwu241/dbt-bug
Example Logs of working in `v0.16.0` but not `v0.16.1`:
```bash
~/dbt-bug/project                                                                                 env
❯ cd ..
~/dbt-bug                                                                                         env
❯ dbt deps --project-dir project
Running with dbt=0.16.0
Installing https://github.com/fishtown-analytics/dbt-utils.git@0.1.21
  Installed from revision 0.1.21

~/dbt-bug                                                                                     5s  env
❯ dbt deps --project-dir project
Running with dbt=0.16.1
Encountered an error while reading the project:
  ERROR: Runtime Error
  no dbt_project.yml found at expected path /Users/nickwu/dbt-bug/dbt_project.yml
Encountered an error:
Runtime Error
  Could not run dbt
```

With `--debug`:
```bash
❯ dbt --debug deps --project-dir project
2020-04-17 09:16:55.283620 (MainThread): Running with dbt=0.16.1
2020-04-17 09:16:55.283825 (MainThread): Encountered an error while reading the project:
2020-04-17 09:16:55.283966 (MainThread):   ERROR: Runtime Error
  no dbt_project.yml found at expected path /Users/nickwu/dbt-bug/dbt_project.yml
2020-04-17 09:16:55.289265 (MainThread): Sending event: {'category': 'dbt', 'action': 'invocation', 'label': 'invalid', 'context': [<snowplow_tracker.self_describing_json.SelfDescribingJson object at 0x10b4248d0>, <snowplow_tracker.self_describing_json.SelfDescribingJson object at 0x10b440690>, <snowplow_tracker.self_describing_json.SelfDescribingJson object at 0x10b440cd0>]}
2020-04-17 09:16:55.289927 (MainThread): Encountered an error:
2020-04-17 09:16:55.290013 (MainThread): Runtime Error
  Could not run dbt
2020-04-17 09:16:55.290995 (MainThread): Traceback (most recent call last):
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/task/base.py", line 59, in from_args
    config = cls.ConfigType.from_args(args)
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/config/runtime.py", line 310, in from_args
    partial = Project.partial_load(os.getcwd())
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/config/project.py", line 508, in partial_load
    project_dict = _raw_project_from(project_root)
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/config/project.py", line 193, in _raw_project_from
    .format(project_yaml_filepath)
dbt.exceptions.DbtProjectError: Runtime Error
  no dbt_project.yml found at expected path /Users/nickwu/dbt-bug/dbt_project.yml

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/main.py", line 81, in main
    results, succeeded = handle_and_check(args)
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/main.py", line 159, in handle_and_check
    task, res = run_from_args(parsed)
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/main.py", line 198, in run_from_args
    task = parsed.cls.from_args(args=parsed)
  File "/Users/nickwu/src/github.com/nickwu241/dbt/core/dbt/task/base.py", line 67, in from_args
    raise dbt.exceptions.RuntimeException('Could not run dbt') from exc
dbt.exceptions.RuntimeException: Runtime Error
  Could not run dbt
```

### Expected behavior
`dbt deps --project-dir project` should install packages for my dbt project at `project` directory.

### Screenshots and log output
Please see Steps to Reproduce.

### System information
**Which database are you using dbt with?**
- [x] postgres
- [x] redshift
- [ ] bigquery
- [ ] snowflake
- [ ] other (specify: ____________)


**The output of `dbt --version`:**
```
installed version: 0.16.1
   latest version: 0.16.1

Up to date!
```

**The operating system you're using:** macOS

**The output of `python --version`:** Python 3.7.5



Discussion:

Resolving patch:
diff --git a/core/dbt/config/runtime.py b/core/dbt/config/runtime.py
--- a/core/dbt/config/runtime.py
+++ b/core/dbt/config/runtime.py
@@ -297,9 +297,9 @@ def from_parts(
 
     @classmethod
     def from_args(cls: Type[RuntimeConfig], args: Any) -> 'RuntimeConfig':
-        """Given arguments, read in dbt_project.yml from the current directory,
-        read in packages.yml if it exists, and use them to find the profile to
-        load.
+        """Given arguments, read in dbt_project.yml from the arg --project-dir
+        or current directory if not provided, read in packages.yml if it
+        exists, and use them to find the profile to load.
 
         :param args: The arguments as parsed from the cli.
         :raises DbtProjectError: If the project is invalid or missing.
@@ -307,7 +307,8 @@ def from_args(cls: Type[RuntimeConfig], args: Any) -> 'RuntimeConfig':
         :raises ValidationException: If the cli variables are invalid.
         """
         # profile_name from the project
-        partial = Project.partial_load(os.getcwd())
+        project_root = args.project_dir if args.project_dir else os.getcwd()
+        partial = Project.partial_load(project_root)
 
         # build the profile using the base renderer and the one fact we know
         cli_vars: Dict[str, Any] = parse_cli_vars(getattr(args, 'vars', '{}'))


Test patch:
diff --git a/test/integration/015_cli_invocation_tests/test_cli_invocation.py b/test/integration/015_cli_invocation_tests/test_cli_invocation.py
--- a/test/integration/015_cli_invocation_tests/test_cli_invocation.py
+++ b/test/integration/015_cli_invocation_tests/test_cli_invocation.py
@@ -1,6 +1,7 @@
 from test.integration.base import DBTIntegrationTest, use_profile
 import os
 import shutil
+import tempfile
 import yaml
 
 
@@ -111,3 +112,32 @@ def test_postgres_toplevel_dbt_run_with_profile_dir_arg(self):
         # make sure the test runs against `custom_schema`
         for test_result in res:
             self.assertTrue(self.custom_schema, test_result.node.injected_sql)
+
+
+class TestCLIInvocationWithProjectDir(ModelCopyingIntegrationTest):
+
+    @property
+    def schema(self):
+        return "test_cli_invocation_015"
+
+    @property
+    def models(self):
+        return "models"
+
+    @use_profile('postgres')
+    def test_postgres_dbt_commands_with_cwd_as_project_dir(self):
+        self._run_simple_dbt_commands(os.getcwd())
+
+    @use_profile('postgres')
+    def test_postgres_dbt_commands_with_randomdir_as_project_dir(self):
+        workdir = os.getcwd()
+        with tempfile.TemporaryDirectory() as tmpdir:
+            os.chdir(tmpdir)
+            self._run_simple_dbt_commands(workdir)
+            os.chdir(workdir)
+
+    def _run_simple_dbt_commands(self, project_dir):
+        self.run_dbt(['deps', '--project-dir', project_dir])
+        self.run_dbt(['seed', '--project-dir', project_dir])
+        self.run_dbt(['run', '--project-dir', project_dir])
+        self.run_dbt(['test', '--project-dir', project_dir])