Repository: dbt-labs/dbt-core

Issue:
[CT-963] [Regression] Docs blocks in metric descriptions
### Is this a regression in a recent version of dbt-core?

- [X] I believe this is a regression in dbt-core functionality
- [X] I have searched the existing issues, and I could not find an existing issue for this regression

### Current Behavior

References to docs blocks are unsupported in metric `description` fields in v1.2

### Expected/Previous Behavior

References to docs blocks were supported in v1.0 + v1.1, and should be supported again

### Steps To Reproduce

```sql
-- models/model_a.sql
select 1 as id
```
```sql
-- models/docs.md
{% docs my_doc_block %}
  Something something
{% enddocs %}
```
```yml
# models/schema.yml

version: 2

models:
  - name: model_a
    # this one works!
    description: "{{ doc('my_doc_block') }}"

metrics:
  - name: some_metric
    label: Some Metric
    model: ref('model_a')
    # this one works in v1.1, raises an error in v1.2
    description: "{{ doc('my_doc_block') }}"

    type: count
    sql: user_id

    timestamp: signup_date
    time_grains: [day, week, month]

    dimensions:
      - plan
      - country
```

### Relevant log output

```shell
(env) 13:53:00 ~/dev/scratch/testy $ dbt parse
11:53:05  Running with dbt=1.2.0
11:53:05  Start parsing.
11:53:05  Dependencies loaded
11:53:05  ManifestLoader created
11:53:06  Encountered an error:
Compilation Error
  Could not render {{ doc('my_doc_block') }}: 'doc' is undefined
11:53:06  Traceback (most recent call last):
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 494, in catch_jinja
    yield
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 526, in render_template
    return template.render(ctx)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 178, in render
    return self.environment.handle_exception()
  File "/Users/jerco/dev/product/dbt-core/env/lib/python3.9/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/Users/jerco/dev/product/dbt-core/env/lib/python3.9/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 135, in quoted_native_concat
    head = list(islice(nodes, 2))
  File "<template>", line 1, in top-level template code
  File "/Users/jerco/dev/product/dbt-core/env/lib/python3.9/site-packages/jinja2/sandbox.py", line 460, in call
    if not __self.is_safe_callable(__obj):
  File "/Users/jerco/dev/product/dbt-core/env/lib/python3.9/site-packages/jinja2/sandbox.py", line 360, in is_safe_callable
    getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False)
jinja2.exceptions.UndefinedError: 'doc' is undefined

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/jerco/dev/product/dbt-core/core/dbt/config/renderer.py", line 42, in render_value
    return get_rendered(value, self.context, native=True)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 571, in get_rendered
    return render_template(template, ctx, node)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 526, in render_template
    return template.render(ctx)
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/contextlib.py", line 137, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/clients/jinja.py", line 499, in catch_jinja
    raise UndefinedMacroException(str(e), node) from e
dbt.exceptions.UndefinedMacroException: Compilation Error
  'doc' is undefined. This can happen when calling a macro that does not exist. Check for typos and/or install package dependencies with "dbt deps".

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/jerco/dev/product/dbt-core/core/dbt/main.py", line 129, in main
    results, succeeded = handle_and_check(args)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/main.py", line 191, in handle_and_check
    task, res = run_from_args(parsed)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/main.py", line 238, in run_from_args
    results = task.run()
  File "/Users/jerco/dev/product/dbt-core/core/dbt/task/parse.py", line 93, in run
    self.get_full_manifest()
  File "/Users/jerco/dev/product/dbt-core/core/dbt/task/parse.py", line 74, in get_full_manifest
    manifest = loader.load()
  File "/Users/jerco/dev/product/dbt-core/core/dbt/parser/manifest.py", line 366, in load
    self.parse_project(
  File "/Users/jerco/dev/product/dbt-core/core/dbt/parser/manifest.py", line 469, in parse_project
    parser.parse_file(block, dct=dct)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/parser/schemas.py", line 544, in parse_file
    for metric_node in metric_parser.parse():
  File "/Users/jerco/dev/product/dbt-core/core/dbt/parser/schemas.py", line 1061, in parse
    for data in self.get_key_dicts():
  File "/Users/jerco/dev/product/dbt-core/core/dbt/parser/schemas.py", line 637, in get_key_dicts
    entry = self.render_entry(entry)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/parser/schemas.py", line 651, in render_entry
    dct = self.renderer.render_data(dct)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/config/renderer.py", line 49, in render_data
    return deep_map_render(self.render_entry, data)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/utils.py", line 228, in deep_map_render
    return _deep_map_render(func, value, ())
  File "/Users/jerco/dev/product/dbt-core/core/dbt/utils.py", line 194, in _deep_map_render
    ret = {k: _deep_map_render(func, v, (keypath + (str(k),))) for k, v in value.items()}
  File "/Users/jerco/dev/product/dbt-core/core/dbt/utils.py", line 194, in <dictcomp>
    ret = {k: _deep_map_render(func, v, (keypath + (str(k),))) for k, v in value.items()}
  File "/Users/jerco/dev/product/dbt-core/core/dbt/utils.py", line 196, in _deep_map_render
    ret = func(value, keypath)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/config/renderer.py", line 33, in render_entry
    return self.render_value(value, keypath)
  File "/Users/jerco/dev/product/dbt-core/core/dbt/config/renderer.py", line 45, in render_value
    raise CompilationException(msg) from exc
dbt.exceptions.CompilationException: Compilation Error
  Could not render {{ doc('my_doc_block') }}: 'doc' is undefined

(env) 13:53:06 ~/dev/scratch/testy $ dbt parse
11:58:05  Running with dbt=1.1.2
11:58:05  Start parsing.
11:58:05  Dependencies loaded
11:58:05  Unable to do partial parsing because of a dbt version mismatch. Saved manifest version: 1.2.0. Current version: 1.1.2.
11:58:05  ManifestLoader created
11:58:06  Manifest loaded
11:58:06  Manifest checked
11:58:06  Flat graph built
11:58:06  Manifest loaded
11:58:06  Performance info: target/perf_info.json
11:58:06  Done.
```


### Environment

```markdown
- OS: macOS 12.4 / M1
- Python: 3.9.13
- dbt (working version): 1.1.2
- dbt (regression version): 1.2.0
```


### Which database adapter are you using with dbt?

postgres

### Additional Context

_No response_


Discussion:

Resolving patch:
diff --git a/core/dbt/parser/schema_renderer.py b/core/dbt/parser/schema_renderer.py
--- a/core/dbt/parser/schema_renderer.py
+++ b/core/dbt/parser/schema_renderer.py
@@ -69,6 +69,8 @@ def should_render_keypath(self, keypath: Keypath) -> bool:
         elif self.key == "metrics":
             if keypath[0] == "sql":
                 return False
+            elif self._is_norender_key(keypath[0:]):
+                return False
         else:  # models, seeds, snapshots, analyses
             if self._is_norender_key(keypath[0:]):
                 return False


Test patch:
diff --git a/test/unit/test_yaml_renderer.py b/test/unit/test_yaml_renderer.py
--- a/test/unit/test_yaml_renderer.py
+++ b/test/unit/test_yaml_renderer.py
@@ -101,3 +101,25 @@ def test__macros(self):
         dct = renderer.render_data(dct)
         self.assertEqual(dct, expected)
 
+    def test__metrics(self):
+        context = {
+            "my_time_grains": "[day]"
+        }
+        renderer = SchemaYamlRenderer(context, 'metrics')
+
+        dct = {
+            "name": "my_source",
+            "description": "{{ docs('my_doc') }}",
+            "sql": "select {{ var('my_var') }} from my_table",
+            "time_grains": "{{ my_time_grains }}",
+        }
+        # We expect the sql and description will not be rendered, but
+        # other fields will be
+        expected = {
+            "name": "my_source",
+            "description": "{{ docs('my_doc') }}",
+            "sql": "select {{ var('my_var') }} from my_table",
+            "time_grains": "[day]"
+        }
+        dct = renderer.render_data(dct)
+        self.assertEqual(dct, expected)