Skip to content

Commit

Permalink
Declare compatibility for previous artifact versions (#5346)
Browse files Browse the repository at this point in the history
* Add functional test

* Add is_compatible_version logic

* Add changelog entry

* Fix mypy
  • Loading branch information
jtcohen6 authored Jun 16, 2022
1 parent 6572b7e commit 6e8388c
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .changes/unreleased/Fixes-20220608-080914.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kind: Fixes
body: 'Define compatibility for older manifest versions when using state: selection
methods'
time: 2022-06-08T08:09:14.321735+02:00
custom:
Author: jtcohen6
Issue: "5213"
PR: "5346"
4 changes: 4 additions & 0 deletions core/dbt/contracts/graph/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,10 @@ class WritableManifest(ArtifactMixin):
)
)

@classmethod
def compatible_previous_versions(self):
return [("manifest", 4)]

def __post_serialize__(self, dct):
for unique_id, node in dct["nodes"].items():
if "config_call_dict" in node:
Expand Down
10 changes: 9 additions & 1 deletion core/dbt/contracts/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ def json_schema(cls, embeddable: bool = False) -> Dict[str, Any]:
result["$id"] = str(cls.dbt_schema_version)
return result

@classmethod
def is_compatible_version(cls, schema_version):
compatible_versions = [str(cls.dbt_schema_version)]
if hasattr(cls, "compatible_previous_versions"):
for name, version in cls.compatible_previous_versions():
compatible_versions.append(str(SchemaVersion(name, version)))
return str(schema_version) in compatible_versions

@classmethod
def read_and_check_versions(cls, path: str):
try:
Expand All @@ -217,7 +225,7 @@ def read_and_check_versions(cls, path: str):
if "metadata" in data and "dbt_schema_version" in data["metadata"]:
previous_schema_version = data["metadata"]["dbt_schema_version"]
# cls.dbt_schema_version is a SchemaVersion object
if str(cls.dbt_schema_version) != previous_schema_version:
if not cls.is_compatible_version(previous_schema_version):
raise IncompatibleSchemaException(
expected=str(cls.dbt_schema_version), found=previous_schema_version
)
Expand Down
1 change: 1 addition & 0 deletions tests/functional/artifacts/data/previous/v1/manifest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/functional/artifacts/data/previous/v2/manifest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/functional/artifacts/data/previous/v3/manifest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/functional/artifacts/data/previous/v4/manifest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/functional/artifacts/data/previous/v5/manifest.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions tests/functional/artifacts/test_previous_version_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pytest
import os
from dbt.tests.util import run_dbt
from dbt.exceptions import IncompatibleSchemaException

models__my_model_sql = """
select 1 as id
"""


class TestPreviousVersionState:
@pytest.fixture(scope="class")
def models(self):
return {"my_model.sql": models__my_model_sql}

def compare_previous_state(
self,
project,
compare_manifest_version,
expect_pass,
):
state_path = os.path.join(project.test_data_dir, f"previous/{compare_manifest_version}")
cli_args = [
"list",
"--select",
"state:modified",
"--state",
state_path,
]
if expect_pass:
results = run_dbt(cli_args, expect_pass=expect_pass)
assert len(results) == 0
else:
with pytest.raises(IncompatibleSchemaException):
run_dbt(cli_args, expect_pass=expect_pass)

def test_compare_state_v5(self, project):
self.compare_previous_state(project, "v5", True)

def test_compare_state_v4(self, project):
self.compare_previous_state(project, "v4", True)

def test_compare_state_v3(self, project):
self.compare_previous_state(project, "v3", False)

def test_compare_state_v2(self, project):
self.compare_previous_state(project, "v2", False)

def test_compare_state_v1(self, project):
self.compare_previous_state(project, "v1", False)

0 comments on commit 6e8388c

Please sign in to comment.