Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check dbt-core version requirements when installing Hub packages #5651

Merged
merged 10 commits into from
Aug 19, 2022

Conversation

jtcohen6
Copy link
Contributor

@jtcohen6 jtcohen6 commented Aug 12, 2022

Resolves #5648

Depends on dbt-labs/hubcap#146
For testing, check out dbt-labs/hub.getdbt.com#1770

As mentioned in the Hubcap PR above, I'm reusing the existing (and always empty) works_with field from the Hub API to represent the package's require-dbt-version. I'm not sure it's an old field being used for something in very old versions of dbt-core. This PR leverages a new API field added in the Hubcap PR above: require_dbt_version.

Description

  • Replace registry.get_available_versions with registry.get_compatible_versions, which only returns package versions whose require-dbt-version config is compatible with the currently installed version of dbt-core
  • If a user has disabled VERSION_CHECK (e.g. dbt --no-version-check deps), then dbt will not check for version compatibility
  • Update unit tests

Checklist

@cla-bot cla-bot bot added the cla:yes label Aug 12, 2022
@github-actions
Copy link
Contributor

Thank you for your pull request! We could not find a changelog entry for this change. For details on how to document a change, see the contributing guide.

@jtcohen6 jtcohen6 changed the title First cut at checking version compat for hub pkgs Check dbt-core version requirements when installing Hub packages Aug 12, 2022
@jtcohen6 jtcohen6 marked this pull request as ready for review August 17, 2022 09:46
@jtcohen6 jtcohen6 requested review from a team as code owners August 17, 2022 09:46
Copy link
Contributor

@gshank gshank left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

" Requested range: {}\n"
" Available versions: {}"
" Compatible versions: {}\n"
" (Not shown: versions incompatible with installed version of dbt-core)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we recommend using the no-version-check flag here, like we do when a dbt project fails to run due to mismatching versions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea!

Copy link
Contributor

@dbeatty10 dbeatty10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two main cases in regards to pre-release versions of dbt-core:

  • excluded, because it's not within the range specified in require_dbt_version.
  • included, because it is within the range specified in require_dbt_version.

It looks like the first case is covered in the tests, but I couldn't tell if the second case is covered or not. Could you shed light if both are covered or not?

)
available_latest = installable[-1]
latest_compatible = installable[-1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for installable to be empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! We should be sure to raise a good exception before we try to access an element. I'll rearrange the logic accordingly

Comment on lines 781 to 784
"Could not find a matching compatible version for package {}\n"
" Requested range: {}\n"
" Available versions: {}"
" Compatible versions: {}\n"
" (Not shown: versions incompatible with installed version of dbt-core)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice 🤩

Comment on lines +515 to +520
def package(self, package_name, registry_base_url=None):
try:
pkg = self.packages[name]
pkg = self.packages[package_name]
except KeyError:
return []
return list(pkg)
return pkg
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice add, especially registry_base_url=None.

@jtcohen6
Copy link
Contributor Author

jtcohen6 commented Aug 18, 2022

Prereleases! A great callout.

We're using the exact same dbt.semver.versions_compatible method here, that we're already using to check require-dbt-version here. That already contains handling for how to perform version comparison with prereleases.

As you note, it's possible for a pre-release version of dbt-core to be included or excluded by the require-dbt-version config defined in a package. The current logic performs two checks:

  • First, are there any package versions incompatible with the installed version of dbt-core? If so, remove them from the compatible_versions list.
  • Second, is the user willing to install a prerelease version? If not, remove any prerelease versions from the compatible_versions list to produce the installable list.

After both checks, if there are no compatible + desired versions remaining in installable, we'll raise an exception saying as much.

@dbeatty10
Copy link
Contributor

As you note, it's possible for a pre-release version of dbt-core to be included or excluded by the require-dbt-version config defined in a package. The current logic performs two checks:

  • First, are there any package versions incompatible with the installed version of dbt-core? If so, remove them from the compatible_versions list.
  • Second, is the user willing to install a prerelease version? If not, remove any prerelease versions from the compatible_versions list to produce the installable list.

It sounds like there are two different contexts to consider prereleases (which of course makes it harder for me to think clearly, 😅 ):

  1. Prereleases of dbt-core
  2. Prereleases of a dbt package

I'm curious if the following case is represented in the continuous integration testing or not:

  • user has a prerelease version of dbt-core
  • the package has at least one version that is compatible with that particular prerelease version of dbt-core

Also

Separately (but related), do we have functional tests that cover all these relevant permutations?

  • installed version of dbt-core is a prerelease -- (2) options: yes/no
  • there exists a package prerelease compatible with the installed version of dbt-core -- (2) options: yes/no
  • user is willing to install a prerelease version of the package -- (2) options: yes/no

This is 8 different permutations (if I'm doing the math correctly). Potentially, there are some permutations that are not relevant for some reason -- I didn't expand it out fully and consider each.

@jtcohen6
Copy link
Contributor Author

@dbeatty10 You're right to push on this! There may very well be an edge case we're missing.

There is definitely a distinction in this functionality between prerelease and final releases of dbt packages. That's already pretty well tested for.

For the purposes of this functionality, I don't actually think there's any distinction between running with a prerelease versus final release of dbt-core. The same method — dbt.semver.versions_compatible(current_dbt_version, require_dbt_version_range) — will return True or False for the current installed version of dbt-core, whether it's a prerelease or final release.

So for instance:

  • There's a new prerelease of dbt-utils with require-dbt-version: [">=1.3.0b1"]. Let's call it version 0.9.0a1
  • You're using dbt-core==1.3.0b1 locally
    • You have install-prerelease: true, or a version: 0.9.0a1 spec that allows prereleases → you'd install that version
    • You have install-prerelease: false in packages.yml → you won't install 0.9.0a1, instead you'll install the most recent compatible non-prerelease of dbt-utils
  • You're using dbt-core==1.2.1rc1 locally
    • You will never install 0.9.0a1 because it is not compatible

@dbeatty10 dbeatty10 self-requested a review August 19, 2022 16:54
})
resolved = resolve_packages(package_config.packages, mock.MagicMock(project_name='test'))
self.assertEqual(resolved[0].name, 'dbt-labs-test/a')
self.assertEqual(resolved[0].version, '0.1.4a1')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤩

Comment on lines 136 to 149
installable = semver.filter_installable(
available, self.install_prerelease or prerelease_version_specified
compatible_versions, self.install_prerelease or prerelease_version_specified
)
available_latest = installable[-1]

# for now, pick a version and then recurse. later on,
# we'll probably want to traverse multiple options
# so we can match packages. not going to make a difference
# right now.
target = semver.resolve_to_specific_version(range_, installable)
if installable:
# for now, pick a version and then recurse. later on,
# we'll probably want to traverse multiple options
# so we can match packages. not going to make a difference
# right now.
target = semver.resolve_to_specific_version(range_, installable)
else:
target = None
if not target:
package_version_not_found(self.package, range_, installable)
package_version_not_found(self.package, range_, installable, should_version_check)
latest_compatible = installable[-1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be misreading this, but it looks like this will throw an error if installable is empty or None when it tries to get the last item via installable[-1].

Do we have a test case for when there are no installable versions available after the semver filter?

Copy link
Contributor Author

@jtcohen6 jtcohen6 Aug 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! If installable is None or [], then we'll set target = None on line 146. That would cause us to raise the package_version_not_found exception, rather than proceed to get the indexed element [-1].

Does that logic feel too tricky? Another way you'd want to express it, or an additional annotation?

Copy link
Contributor

@dbeatty10 dbeatty10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jtcohen6 Ready to rock 🎸

@jtcohen6 jtcohen6 merged commit 7f8d9a7 into main Aug 19, 2022
@jtcohen6 jtcohen6 deleted the feature/hub-install-compatible-versions branch August 19, 2022 21:13
VersusFacit pushed a commit that referenced this pull request Sep 5, 2022
* First cut at checking version compat for hub pkgs

* Account for field rename

* Add changelog entry

* Update error message

* Fix unit test

* PR feedback

* Try fixing test

* Edit exception msg

* Expand unit test to include pkg prerelease

* Update core/dbt/deps/registry.py

Co-authored-by: Doug Beatty <[email protected]>

Co-authored-by: Doug Beatty <[email protected]>
agoblet pushed a commit to BigDataRepublic/dbt-core that referenced this pull request Sep 16, 2022
…-labs#5651)

* First cut at checking version compat for hub pkgs

* Account for field rename

* Add changelog entry

* Update error message

* Fix unit test

* PR feedback

* Try fixing test

* Edit exception msg

* Expand unit test to include pkg prerelease

* Update core/dbt/deps/registry.py

Co-authored-by: Doug Beatty <[email protected]>

Co-authored-by: Doug Beatty <[email protected]>
josephberni pushed a commit to Gousto/dbt-core that referenced this pull request Sep 16, 2022
…-labs#5651)

* First cut at checking version compat for hub pkgs

* Account for field rename

* Add changelog entry

* Update error message

* Fix unit test

* PR feedback

* Try fixing test

* Edit exception msg

* Expand unit test to include pkg prerelease

* Update core/dbt/deps/registry.py

Co-authored-by: Doug Beatty <[email protected]>

Co-authored-by: Doug Beatty <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CT-1035] [Feature] dbt deps should take require-dbt-version into account when resolving dependencies
4 participants