Repository: dbt-labs/dbt-core

Issue:
[CT-1869] Turn `--output-keys` into MultiOption
### Current state

Users can supply `--output-keys` to customize the set of information returned by `dbt list`:
```bash
$ dbt ls --output json --output-keys name,resource_type,description
{"name": "my_incremental_model", "resource_type": "model", "description": "cool docs bro"}
{"name": "my_seed", "resource_type": "seed", "description": ""}
```

The type of `--output-keys` is a string. I've always thought the string needed to be a comma-delimited list, but really it could be ... anything? ... so long as the string contains the relevant key name:

https://github.com/dbt-labs/dbt-core/blob/c85be323f537ff31991e618319bbf9763e16b65c/core/dbt/cli/params.py#L157-L159

```
$ dbt ls --output json --output-keys nameNotACommaresource_type==blabladescription
{"name": "my_incremental_model", "resource_type": "model", "description": "cool docs bro"}
{"name": "my_seed", "resource_type": "seed", "description": ""}
```

### Proposal

We just (https://github.com/dbt-labs/dbt-core/pull/6641) added a [`MultiOption`](https://github.com/dbt-labs/dbt-core/blob/feature/click-cli/core/dbt/cli/options.py#L6) option to support params like `--select`, that take multiple space-limited arguments:
```
$ dbt run --select thing_a thing_b --another-flag ...
```

This would be more consistent, and allow us to treat the type of `output_keys` as a list (right?) for programmatic invocations:
```
$ dbt ls --output json --output-keys name resource_type description
```

Looks like that's even how we've been documenting it (incorrectly)! https://docs.getdbt.com/reference/commands/list

### Add a test

We also need an automated test for `dbt list --output json --output-keys`!


Discussion:

Resolving patch:
diff --git a/core/dbt/cli/params.py b/core/dbt/cli/params.py
--- a/core/dbt/cli/params.py
+++ b/core/dbt/cli/params.py
@@ -172,7 +172,15 @@
 )
 
 output_keys = click.option(
-    "--output-keys", envvar=None, help="TODO: No current help text", type=click.STRING
+    "--output-keys",
+    envvar=None,
+    help=(
+        "Space-delimited listing of node properties to include as custom keys for JSON output "
+        "(e.g. `--output json --output-keys name resource_type description`)"
+    ),
+    type=list,
+    cls=MultiOption,
+    default=[],
 )
 
 output_path = click.option(
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
@@ -112,7 +112,7 @@ def generate_json(self):
                     for k, v in node.to_dict(omit_none=False).items()
                     if (
                         k in self.args.output_keys
-                        if self.args.output_keys is not None
+                        if self.args.output_keys
                         else k in self.ALLOWED_KEYS
                     )
                 }


Test patch:
diff --git a/tests/functional/list/test_list.py b/tests/functional/list/test_list.py
--- a/tests/functional/list/test_list.py
+++ b/tests/functional/list/test_list.py
@@ -563,7 +563,16 @@ def expect_selected_keys(self, project):
             {"database": project.database, "schema": project.test_schema, "alias": "inner"}
         ]
         results = self.run_dbt_ls(
-            ["--model", "inner", "--output", "json", "--output-keys", "database,schema,alias"]
+            [
+                "--model",
+                "inner",
+                "--output",
+                "json",
+                "--output-keys",
+                "database",
+                "schema",
+                "alias",
+            ]
         )
         assert len(results) == len(expectations)
 
@@ -578,7 +587,15 @@ def expect_selected_keys(self, project):
             {"name": "unique_outer_id", "column_name": "id"},
         ]
         results = self.run_dbt_ls(
-            ["--resource-type", "test", "--output", "json", "--output-keys", "name,column_name"]
+            [
+                "--resource-type",
+                "test",
+                "--output",
+                "json",
+                "--output-keys",
+                "name",
+                "column_name",
+            ]
         )
         assert len(results) == len(expectations)
 
@@ -592,7 +609,14 @@ def expect_selected_keys(self, project):
         """
         expectations = [{}, {}]
         results = self.run_dbt_ls(
-            ["--model", "inner outer", "--output", "json", "--output-keys", "non_existent_key"]
+            [
+                "--model",
+                "inner outer",
+                "--output",
+                "json",
+                "--output-keys",
+                "non_existent_key",
+            ]
         )
         assert len(results) == len(expectations)
 
diff --git a/tests/functional/schema_tests/test_schema_v2_tests.py b/tests/functional/schema_tests/test_schema_v2_tests.py
--- a/tests/functional/schema_tests/test_schema_v2_tests.py
+++ b/tests/functional/schema_tests/test_schema_v2_tests.py
@@ -1034,7 +1034,8 @@ def test_wrong_specification_block(
                     "--output",
                     "json",
                     "--output-keys",
-                    "name, description",
+                    "name",
+                    "description",
                 ]
             )