Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions upgrade/scripts/find_compatible_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
parse_requirements_txt,
to_requirements_obj,
)
from upgrade.scripts.utils import get_venv_executable, is_package_already_installed
from upgrade.scripts.utils import (
get_venv_executable,
is_development_cloudsmith,
is_package_already_installed,
)
from upgrade.scripts.validations import is_cloudsmith_url_valid


Expand Down Expand Up @@ -48,12 +52,16 @@ def get_compatible_upgrade_versions(
tree = et.HTML(package_index_html)
anchor_tags_el = tree.xpath("//a")
parsed_packages_versions = [
parse_wheel_filename(tag_el.text)[1] for tag_el in anchor_tags_el
parse_wheel_filename(tag_el.text)[1]
for tag_el in anchor_tags_el
if tag_el.text and tag_el.text.endswith(".whl")
]
logging.debug(f"Parsed packages versions: {parsed_packages_versions}")

compatible_versions = filter_versions(
requirements_obj.specifier, parsed_packages_versions
requirements_obj.specifier,
parsed_packages_versions,
prereleases=is_development_cloudsmith(cloudsmith_url),
)
logging.debug(f"Found compatible versions: {compatible_versions}")

Expand Down
11 changes: 9 additions & 2 deletions upgrade/scripts/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


def filter_versions(
specifier_set: Any, parsed_packages_versions: List[Any]
specifier_set: Any, parsed_packages_versions: List[Any], prereleases: bool = False
) -> List[str]:
"""Returns a list of versions that are compatible with the `SpecifierSet`.

Expand All @@ -21,8 +21,15 @@ def filter_versions(
or:
SpecifierSet("==2.5.14").filter(["2.5.14", "2.5.15", "2.6.0", "3.0.0"])
returns ["2.5.14"]

prereleases defaults to False, matching SpecifierSet.filter()'s own default - pass True
for a dev/pre-release channel whose versions are all pre-releases, or every version
would otherwise be filtered out and no upgrade would ever be found.
"""
return [str(version) for version in specifier_set.filter(parsed_packages_versions)]
return [
str(version)
for version in specifier_set.filter(parsed_packages_versions, prereleases=prereleases)
]


def parse_requirements_txt(
Expand Down
29 changes: 29 additions & 0 deletions upgrade/tests/manage_venv/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,35 @@ def mock_package_index_html():
yield


@pytest.fixture()
def mock_package_index_html_with_sdist_entry():
"""Mirrors a real Cloudsmith index page that also lists a non-wheel sdist
(e.g. a stray oll-test-top-level-0.0.0.tar.gz from an earlier bad publish),
to guard against parse_wheel_filename crashing on it.
"""
index_html_page = """
<!DOCTYPE html>
<html>
<head>
<title>Mock package index html page for testing compatible dependencies script.</title>
</head>
<body>
<h1>Links for oll-top-level-package</h1>
<a>oll-test-top-level-0.0.0.tar.gz</a><br />
<a>oll_test_top_level-1.0.0-py3-none-any.whl</a><br />
<a>oll_test_top_level-2.0.0-py3-none-any.whl</a><br />
<a>oll_test_top_level-2.0.1-py3-none-any.whl</a><br />
<a>oll_test_top_level-2.1.0-py3-none-any.whl</a><br />
</body>
</html>
"""
with patch(
"upgrade.scripts.find_compatible_versions._get_package_index_html",
lambda *_,: index_html_page,
):
yield


def install_upgrade_python_package(venv_executable, *rest):
run(
*([
Expand Down
19 changes: 19 additions & 0 deletions upgrade/tests/manage_venv/test_get_compatible_upgrade_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,22 @@ def test_get_compatible_version_where_current_is_2_0_0_and_venv_without_specifie
expected = "2.1.0"

assert actual == expected


def test_get_compatible_version_where_index_page_lists_a_non_wheel_sdist_expect_it_is_ignored(
initial_v2_0_0_venv,
envs_home,
mock_package_index_html_with_sdist_entry,
):
cut = get_compatible_version

requirements = "oll-test-top-level~=2.0.0"
venv_path = Path(envs_home, requirements)

actual = cut(
requirements_obj=to_requirements_obj(requirements),
venv_path=str(venv_path),
)
expected = "2.0.1"

assert actual == expected
18 changes: 18 additions & 0 deletions upgrade/tests/upgrade_package/test_filter_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,21 @@ def test_filter_versions_with_different_specifiers(
actual = cut(specifier_set, available_versions)

assert actual == expected


def test_filter_versions_where_channel_is_dev_only_expect_none_found_by_default():
cut = filter_versions

actual = cut(SpecifierSet("~=2.21"), ["2.21.6.dev184", "2.21.6.dev200"])

assert actual == []


def test_filter_versions_where_channel_is_dev_only_and_prereleases_true_expect_all_found():
cut = filter_versions

actual = cut(
SpecifierSet("~=2.21"), ["2.21.6.dev184", "2.21.6.dev200"], prereleases=True
)

assert actual == ["2.21.6.dev184", "2.21.6.dev200"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os

import pytest
from packaging.version import Version

from upgrade.scripts.find_compatible_versions import get_compatible_upgrade_versions
from upgrade.scripts.requirements import to_requirements_obj

# Set to a live openlawlibrary/development Cloudsmith index URL (with the entitlement
# token embedded, e.g. https://dl.cloudsmith.io/<token>/openlawlibrary/development/python/index/)
# to run this against the real index instead of a mocked one. Skipped otherwise, since it
# needs real network access and a real credential this repo doesn't store.
CLOUDSMITH_DEV_URL = os.environ.get("CLOUDSMITH_DEV_URL_TEST")

pytestmark = pytest.mark.skipif(
not CLOUDSMITH_DEV_URL,
reason="CLOUDSMITH_DEV_URL_TEST is not set - export a live development Cloudsmith "
"index URL to exercise this against the real index",
)


def test_get_compatible_upgrade_versions_where_dev_channel_expect_prereleases_included():
cut = get_compatible_upgrade_versions

requirements_obj = to_requirements_obj("oll-cls~=2.21")
versions = cut(requirements_obj, CLOUDSMITH_DEV_URL)

assert versions, "expected at least one dev version from the live development index"
assert any(Version(v) > Version("2.21.6.dev184") for v in versions), (
"expected a version newer than the known-stale 2.21.6.dev184 to be present - "
"if this fails, prereleases are being filtered out again (the bug this test guards)"
)
Loading