Skip to content

Commit 21b8db7

Browse files
authored
Clarify package upgrade reasons in log output (#252)
* Output additional detail on why the current and (if applicable) upgraded versions are/aren't compatible
1 parent e83fc9e commit 21b8db7

File tree

12 files changed

+309
-220
lines changed

12 files changed

+309
-220
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ project2/*
2222
.DS_Store
2323

2424
# raw package hub output (because big)
25-
dbt_autofix/packages/scripts/output/*
25+
src/dbt_autofix/packages/scripts/output/*

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ dependencies = [
1313
"httpx>=0.27.0",
1414
"dbt-common>=1.27,<2",
1515
"dbt-extractor>=0.5.0,<=0.6",
16-
"dbt-fusion-package-tools",
1716
]
1817

1918
dynamic = ["version"]
@@ -71,7 +70,7 @@ ignore = []
7170

7271
[tool.pyright]
7372
include = [
74-
"dbt_autofix",
73+
"src/dbt_autofix",
7574
"tests",
7675
]
7776
exclude = []

src/dbt_autofix/main.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22
from importlib.metadata import version
3-
import os
43
from pathlib import Path
54
from typing import List, Optional
65

@@ -22,7 +21,6 @@
2221
from dbt_autofix.packages.dbt_package_file import DbtPackageFile
2322
from dbt_autofix.refactor import apply_changesets, changeset_all_sql_yml_files
2423
from dbt_autofix.retrieve_schemas import SchemaSpecs
25-
from dbt_fusion_package_tools.package_example import output_package_name
2624

2725
console = Console()
2826
error_console = Console(stderr=True)
@@ -38,10 +36,6 @@
3836
current_dir = Path.cwd()
3937

4038

41-
def print_package():
42-
output_package_name()
43-
44-
4539
@app.command(name="list-yaml-duplicates")
4640
def identify_duplicate_keys(
4741
path: Annotated[Path, typer.Option("--path", "-p", help="The path to the dbt project")] = current_dir,

src/dbt_autofix/package_upgrade.py

Lines changed: 174 additions & 88 deletions
Large diffs are not rendered by default.

src/dbt_autofix/packages/dbt_package.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
from rich.console import Console
44
from dbt_autofix.packages.dbt_package_version import (
55
DbtPackageVersion,
6+
)
7+
from dbt_common.semver import VersionSpecifier, VersionRange, versions_compatible
8+
from dbt_autofix.packages.manual_overrides import EXPLICIT_DISALLOW_ALL_VERSIONS, EXPLICIT_ALLOW_ALL_VERSIONS
9+
from dbt_autofix.packages.upgrade_status import PackageVersionFusionCompatibilityState, PackageFusionCompatibilityState
10+
from dbt_autofix.packages.fusion_version_compatibility_output import FUSION_VERSION_COMPATIBILITY_OUTPUT
11+
from dbt_autofix.packages.version_utils import (
612
construct_version_list_from_raw,
713
convert_optional_version_string_to_spec,
814
convert_version_specifiers_to_range,
915
convert_version_string_list_to_spec,
1016
get_version_specifiers,
1117
)
12-
from dbt_common.semver import VersionSpecifier, VersionRange, versions_compatible
13-
from dbt_autofix.packages.manual_overrides import EXPLICIT_DISALLOW_ALL_VERSIONS, EXPLICIT_ALLOW_ALL_VERSIONS
14-
from dbt_autofix.packages.upgrade_status import PackageVersionFusionCompatibilityState, PackageFusionCompatibilityState
15-
from dbt_autofix.packages.fusion_version_compatibility_output import FUSION_VERSION_COMPATIBILITY_OUTPUT
1618

1719

1820
console = Console()
@@ -149,7 +151,7 @@ def find_fusion_compatible_versions_in_requested_range(self) -> list[VersionSpec
149151
version, self.project_config_version_range.start, self.project_config_version_range.end
150152
):
151153
compatible_versions.append(version)
152-
sorted_versions = sorted(compatible_versions, reverse=True)
154+
sorted_versions = sorted(compatible_versions)
153155
return sorted_versions
154156

155157
def find_fusion_compatible_versions_above_requested_range(self) -> list[VersionSpecifier]:
@@ -177,7 +179,7 @@ def find_fusion_compatible_versions_above_requested_range(self) -> list[VersionS
177179
and version > self.project_config_version_range.start
178180
):
179181
compatible_versions.append(version)
180-
sorted_versions = sorted(compatible_versions, reverse=True)
182+
sorted_versions = sorted(compatible_versions)
181183
return sorted_versions
182184

183185
def find_fusion_incompatible_versions_in_requested_range(self) -> list[VersionSpecifier]:
@@ -191,7 +193,7 @@ def find_fusion_incompatible_versions_in_requested_range(self) -> list[VersionSp
191193
version, self.project_config_version_range.start, self.project_config_version_range.end
192194
):
193195
incompatible_versions.append(version)
194-
sorted_versions = sorted(incompatible_versions, reverse=True)
196+
sorted_versions = sorted(incompatible_versions)
195197
return sorted_versions
196198

197199
def find_fusion_unknown_versions_in_requested_range(self) -> list[VersionSpecifier]:
@@ -205,7 +207,7 @@ def find_fusion_unknown_versions_in_requested_range(self) -> list[VersionSpecifi
205207
version, self.project_config_version_range.start, self.project_config_version_range.end
206208
):
207209
unknown_compatibility_versions.append(version)
208-
sorted_versions = sorted(unknown_compatibility_versions, reverse=True)
210+
sorted_versions = sorted(unknown_compatibility_versions)
209211
return sorted_versions
210212

211213
def get_installed_package_version(self) -> str:

src/dbt_autofix/packages/dbt_package_version.py

Lines changed: 6 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,83 +9,15 @@
99
)
1010

1111
from dbt_autofix.packages.upgrade_status import PackageVersionFusionCompatibilityState
12+
from dbt_autofix.packages.version_utils import (
13+
FUSION_COMPATIBLE_VERSION,
14+
construct_version_list_from_raw,
15+
convert_version_specifiers_to_range,
16+
get_version_specifiers,
17+
)
1218

1319
console = Console()
1420

15-
FUSION_COMPATIBLE_VERSION: VersionSpecifier = VersionSpecifier.from_version_string("2.0.0")
16-
17-
# `float` also allows `int`, according to PEP484 (and jsonschema!)
18-
RawVersion = Union[str, float]
19-
20-
21-
def get_versions(version: Union[RawVersion, list[RawVersion]]) -> list[str]:
22-
if isinstance(version, list):
23-
return [str(v) for v in version]
24-
else:
25-
return [str(version)]
26-
27-
28-
def construct_version_list(raw_versions: Union[str, list[str], None]) -> list[str]:
29-
if raw_versions is None:
30-
return []
31-
elif type(raw_versions) == str:
32-
return [raw_versions]
33-
elif type(raw_versions) == list:
34-
return raw_versions
35-
else:
36-
return []
37-
38-
39-
def construct_version_list_from_raw(raw_versions: Any) -> list[str]:
40-
if raw_versions is None:
41-
return []
42-
# isinstance is needed here because when ruyaml parses the YAML,
43-
# sometimes it stores it as an instance of a class that extend str or list
44-
elif isinstance(raw_versions, str):
45-
return [str(raw_versions)]
46-
elif isinstance(raw_versions, list):
47-
versions = []
48-
for version in raw_versions:
49-
if isinstance(version, str) or isinstance(version, float):
50-
versions.append(str(version))
51-
return versions
52-
else:
53-
return []
54-
55-
56-
def get_version_specifiers(raw_version: list[str]) -> list[VersionSpecifier]:
57-
return [VersionSpecifier.from_version_string(v) for v in raw_version]
58-
59-
60-
def convert_version_specifiers_to_range(specs: list[VersionSpecifier]) -> VersionRange:
61-
if len(specs) == 0 or len(specs) > 2:
62-
# assume any version compatible
63-
any_version = VersionSpecifier.from_version_string(">=0.0.0")
64-
return VersionRange(any_version, any_version)
65-
elif len(specs) == 1:
66-
return VersionRange(specs[0], specs[0])
67-
elif specs[0] < specs[1]:
68-
return VersionRange(specs[0], specs[1])
69-
else:
70-
return VersionRange(specs[1], specs[0])
71-
72-
73-
def convert_optional_version_string_to_spec(version_string: Optional[str]) -> Optional[VersionSpecifier]:
74-
try:
75-
if type(version_string) == str:
76-
return VersionSpecifier.from_version_string(version_string)
77-
else:
78-
return None
79-
except:
80-
return None
81-
82-
83-
def convert_version_string_list_to_spec(version_string: list[str]) -> list[VersionSpecifier]:
84-
if len(version_string) == 0:
85-
return []
86-
else:
87-
return [VersionSpecifier.from_version_string(x) for x in version_string]
88-
8921

9022
@dataclass
9123
class DbtPackageVersion:

src/dbt_autofix/packages/upgrade_status.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
class PackageVersionFusionCompatibilityState(str, Enum):
55
"""String enum for Fusion compatibility of a specific version of a package."""
66

7-
NO_DBT_VERSION_RANGE = "Package does not define required dbt version range"
8-
DBT_VERSION_RANGE_EXCLUDES_2_0 = "Package's dbt version range excludes version 2.0"
9-
DBT_VERSION_RANGE_INCLUDES_2_0 = "Package's dbt versions range include version 2.0"
10-
EXPLICIT_ALLOW = "Package version has been verified as Fusion-compatible"
11-
EXPLICIT_DISALLOW = "Package version has been verified as incompatible with Fusion"
12-
UNKNOWN = "Package version state unknown"
7+
NO_DBT_VERSION_RANGE = "require-dbt-version is not defined"
8+
DBT_VERSION_RANGE_EXCLUDES_2_0 = "require-dbt-version excludes version 2.0"
9+
DBT_VERSION_RANGE_INCLUDES_2_0 = "require-dbt-version includes version 2.0"
10+
EXPLICIT_ALLOW = "Version has been verified by dbt as Fusion-compatible even though its declared require-dbt-version may not include 2.0"
11+
EXPLICIT_DISALLOW = "Version has been verified by dbt as incompatible with Fusion"
12+
UNKNOWN = "Version state unknown"
1313

1414

1515
class PackageFusionCompatibilityState(str, Enum):
@@ -27,7 +27,9 @@ class PackageVersionUpgradeType(str, Enum):
2727

2828
NO_UPGRADE_REQUIRED = "Package is already compatible with Fusion"
2929
UPGRADE_AVAILABLE = "Package has Fusion-compatible version available"
30-
PUBLIC_PACKAGE_MISSING_FUSION_ELIGIBILITY = "Public package has not defined Fusion eligibility"
30+
PUBLIC_PACKAGE_MISSING_FUSION_ELIGIBILITY = (
31+
"Public package has not defined require-dbt-version so Fusion eligibility cannot be determined"
32+
)
3133
PUBLIC_PACKAGE_NOT_COMPATIBLE_WITH_FUSION = "Public package is not compatible with Fusion"
3234
PUBLIC_PACKAGE_FUSION_COMPATIBLE_VERSION_EXCEEDS_PROJECT_CONFIG = (
3335
"Public package has Fusion-compatible version that is outside the project's requested version range"
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from typing import Any, Optional, Union
2+
from dbt_common.semver import VersionRange, VersionSpecifier
3+
4+
FUSION_COMPATIBLE_VERSION: VersionSpecifier = VersionSpecifier.from_version_string("2.0.0")
5+
# `float` also allows `int`, according to PEP484 (and jsonschema!)
6+
RawVersion = Union[str, float]
7+
8+
9+
def get_versions(version: Union[RawVersion, list[RawVersion]]) -> list[str]:
10+
if isinstance(version, list):
11+
return [str(v) for v in version]
12+
else:
13+
return [str(version)]
14+
15+
16+
def construct_version_list(raw_versions: Union[str, list[str], None]) -> list[str]:
17+
if raw_versions is None:
18+
return []
19+
elif type(raw_versions) == str:
20+
return [raw_versions]
21+
elif type(raw_versions) == list:
22+
return raw_versions
23+
else:
24+
return []
25+
26+
27+
def construct_version_list_from_raw(raw_versions: Any) -> list[str]:
28+
if raw_versions is None:
29+
return []
30+
# isinstance is needed here because when ruyaml parses the YAML,
31+
# sometimes it stores it as an instance of a class that extend str or list
32+
elif isinstance(raw_versions, str):
33+
return [str(raw_versions)]
34+
elif isinstance(raw_versions, list):
35+
versions = []
36+
for version in raw_versions:
37+
if isinstance(version, str) or isinstance(version, float):
38+
versions.append(str(version))
39+
return versions
40+
else:
41+
return []
42+
43+
44+
def get_version_specifiers(raw_version: list[str]) -> list[VersionSpecifier]:
45+
return [VersionSpecifier.from_version_string(v) for v in raw_version]
46+
47+
48+
def convert_version_specifiers_to_range(specs: list[VersionSpecifier]) -> VersionRange:
49+
if len(specs) == 0 or len(specs) > 2:
50+
# assume any version compatible
51+
any_version = VersionSpecifier.from_version_string(">=0.0.0")
52+
return VersionRange(any_version, any_version)
53+
elif len(specs) == 1:
54+
return VersionRange(specs[0], specs[0])
55+
elif specs[0] < specs[1]:
56+
return VersionRange(specs[0], specs[1])
57+
else:
58+
return VersionRange(specs[1], specs[0])
59+
60+
61+
def convert_optional_version_string_to_spec(version_string: Optional[str]) -> Optional[VersionSpecifier]:
62+
try:
63+
if type(version_string) == str:
64+
return VersionSpecifier.from_version_string(version_string)
65+
else:
66+
return None
67+
except:
68+
return None
69+
70+
71+
def convert_version_string_list_to_spec(version_string: list[str]) -> list[VersionSpecifier]:
72+
if len(version_string) == 0:
73+
return []
74+
else:
75+
return [VersionSpecifier.from_version_string(x) for x in version_string]

tests/unit_tests/package_upgrades/test_dbt_package_version.py

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any, Optional
22
import pytest
3-
from dbt_autofix.packages.dbt_package_version import DbtPackageVersion, construct_version_list_from_raw
3+
from dbt_autofix.packages.dbt_package_version import DbtPackageVersion
44
from dbt_common.semver import VersionSpecifier, VersionRange, Matchers, versions_compatible, UnboundedVersionSpecifier
55

66

@@ -320,28 +320,3 @@ def test_fusion_compatible_from_raw(input_yaml: dict[Any, Any], expected_match:
320320

321321
fusion_compatible: bool = package_version.is_require_dbt_version_fusion_compatible()
322322
assert fusion_compatible == expected_match
323-
324-
325-
@pytest.mark.parametrize(
326-
"input_yaml,expected_match",
327-
[
328-
([">=1.1.0", "<2.0.0"], [">=1.1.0", "<2.0.0"]),
329-
(None, []),
330-
(
331-
[">=1.1.0"],
332-
[">=1.1.0"],
333-
),
334-
(
335-
">=1.1.0",
336-
[">=1.1.0"],
337-
),
338-
(">0.2.1", [">0.2.1"]),
339-
],
340-
)
341-
def test_convert_version_string_from_raw(input_yaml: Any, expected_match: list[str]):
342-
version_list = construct_version_list_from_raw(input_yaml)
343-
344-
assert version_list == expected_match
345-
if input_yaml is not None:
346-
for i, version in enumerate(version_list):
347-
assert version == expected_match[i]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from dbt_autofix.packages.version_utils import construct_version_list_from_raw
2+
3+
4+
import pytest
5+
6+
7+
from typing import Any
8+
9+
10+
@pytest.mark.parametrize(
11+
"input_yaml,expected_match",
12+
[
13+
([">=1.1.0", "<2.0.0"], [">=1.1.0", "<2.0.0"]),
14+
(None, []),
15+
(
16+
[">=1.1.0"],
17+
[">=1.1.0"],
18+
),
19+
(
20+
">=1.1.0",
21+
[">=1.1.0"],
22+
),
23+
(">0.2.1", [">0.2.1"]),
24+
],
25+
)
26+
def test_convert_version_string_from_raw(input_yaml: Any, expected_match: list[str]):
27+
version_list = construct_version_list_from_raw(input_yaml)
28+
29+
assert version_list == expected_match
30+
if input_yaml is not None:
31+
for i, version in enumerate(version_list):
32+
assert version == expected_match[i]

0 commit comments

Comments
 (0)