Repository: dbt-labs/dbt-core

Issue:
[Bug] dbt_project.yml does not fully support semantic versioning
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

One can read [in the docs](https://docs.getdbt.com/reference/project-configs/version) that semantic versioning is supported. If so, pre-versions like 1.0.0-pre.1 should be supportes (as the link in the docs says).
Currently the version number causes a Runtime Error:
```
Encountered an error while reading the project:
  ERROR: Runtime Error
  at path ['version']: '0.0.0-pre.1' is not valid under any of the given schemas
```

```
# dbt_project.yml

version: '1.0.0-pre.1'
```

### Expected Behavior

Version 1.0.0-pre.1 should be an accepted version, because it follows the rules of [semantic versioning](https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions)

### Steps To Reproduce

_No response_

### Relevant log output

_No response_

### Environment

```markdown
- OS: macOS 11.5.2
- Python: 3.9.7
- dbt: 21.1
```


### What database are you using dbt with?

_No response_

### Additional Context

_No response_


Discussion:
@b0lle Thanks for opening!

The codepath for this one is fairly straightforward, and leads us to a comment indicating that `version` only supports "semver lite":

https://github.com/dbt-labs/dbt-core/blob/3fc715f06673f24718c761e5d0cf173766954816/core/dbt/contracts/project.py#L172

https://github.com/dbt-labs/dbt-core/blob/3fc715f06673f24718c761e5d0cf173766954816/core/dbt/contracts/project.py#L25-L40

At the same time, [the docs say](https://docs.getdbt.com/reference/project-configs/version):

> The version must be in a semantic version format, e.g. 1.0.0

Why not support real semver? Well... the `version` field isn't used for _anything_ today. It serves no functional purpose. But it is required, in all projects—and I could imagine it being useful for something, someday. In particular, there's no way currently to see the _currently installed versions_ of any packages, because there's no actual correspondence between the `version` in their `dbt_project.yml`, and the `version` (GitHub tag) specified in `packages.yml`. But imagine if they did correspond—if we did a good job of enforcing their alignment—which would unlock the ability for a `dbt deps freeze` to do something like:
```text
$ dbt deps freeze
dbt-utils==0.7.1
snowplow==0.13.0

Updates available for packages: ['dbt-labs/dbt_utils', 'dbt-labs/snowplow']
Update your versions in packages.yml, then run dbt deps
```
Currently, that version report is only available by running `dbt deps`, i.e. actually re-installing packages based on the specification in `packages.yml`.

So, I think we have two valid options:
1. Validate this via an actual semantic version specification, such as by using [`dbt.semver.VersionSpecifier.from_version_string`](https://github.com/dbt-labs/dbt-core/blob/0ed14fa2361c98e5119f52afebb3d5d8ee18c419/core/dbt/semver.py#L93)
2. Support any string in the `version` field, because it serves no functional purpose today. (If we do this now, though, it will be much harder to do anything useful with it in the future.)

I'm inclined to prefer the former: This should be a semantic version, rather than an anything-goes string. We already have logic (a whole module, even) dedicated to validating semantic versions.

I think the lift here would be pretty small, so I'm going to mark this a `good first issue`! Would you be interested in contributing the fix? :)
I can handle this if no one else is @jtcohen6.

Resolving patch:
diff --git a/core/dbt/contracts/project.py b/core/dbt/contracts/project.py
--- a/core/dbt/contracts/project.py
+++ b/core/dbt/contracts/project.py
@@ -43,12 +43,11 @@ def _deserialize(cls, value: str) -> 'SemverString':
         return SemverString(value)
 
 
-# this does not support the full semver (does not allow a trailing -fooXYZ) and
-# is not restrictive enough for full semver, (allows '1.0'). But it's like
-# 'semver lite'.
+# this supports full semver,
+# but also allows for 2 group version numbers, (allows '1.0').
 register_pattern(
     SemverString,
-    r'^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(\.(?:0|[1-9]\d*))?$',
+    r'^(0|[1-9]\d*)\.(0|[1-9]\d*)(\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)?$', # noqa
 )
 
 


Test patch: