diff --git a/repo2docker/semver.py b/repo2docker/semver.py index 97650fa6..661829ec 100644 --- a/repo2docker/semver.py +++ b/repo2docker/semver.py @@ -95,11 +95,32 @@ def create_semver_matcher(constraint_str): else: return VersionRange(constraint, (major(constraint) + 1,), True) - # '~' matching (only allowed to bump the last present number by one) + # '~' matching, bumps minor version unless only major specified or leading 0.0. + # https://pkgdocs.julialang.org/v1/compatibility/#Tilde-specifiers if comparison_symbol == "~": - return VersionRange( - constraint, constraint[:-1] + (constraint[-1] + 1,), exclusive=False - ) + if len(constraint) == 1: + # only major specified + # ~x -> [x-x+1) + return VersionRange(constraint, (constraint[0] + 1,), exclusive=True) + elif len(constraint) == 2: + # ~x.y -> [x.y-x.y+1) + return VersionRange( + constraint, + ( + major(constraint), + minor(constraint) + 1, + ), + exclusive=True, + ) + else: + # 3 parts, different depending on if starts with 0.0 + if major(constraint) == 0 and minor(constraint) == 0: + # ~0.0.3 = [0.0.3-0.0.4) + upper = (0, 0, patch(constraint) + 1) + else: + # ~0.2.3 = [0.2.3-0.3) + upper = (major(constraint), minor(constraint) + 1) + return VersionRange(constraint, upper, exclusive=True) # Use semver package's comparisons for everything else: diff --git a/tests/unit/test_semver.py b/tests/unit/test_semver.py index b07272be..dedbcc2e 100644 --- a/tests/unit/test_semver.py +++ b/tests/unit/test_semver.py @@ -29,13 +29,14 @@ def test_major_minor_patch(): ("^0.0.3", "[0.0.3-0.0.4)"), ("^0.0", "[0.0-0.1)"), ("^0", "[0-1)"), - # This one seems wrong: `~1.2.3 = [1.2.3, 1.2.4)` - # but ~ is special in Julia from - # https://docs.julialang.org/en/latest/stdlib/Pkg/#Tilde-specifiers-1 - ("~1.2.3", "[1.2.3-1.2.4]"), - ("~1.3.5", "[1.3.5-1.3.6]"), - ("~1.2", "[1.2-1.3]"), - ("~1", "[1-2]"), + # https://pkgdocs.julialang.org/v1/compatibility/#Tilde-specifiers + ("~1.2.3", "[1.2.3-1.3)"), + ("~1.3.5", "[1.3.5-1.4)"), + ("~1.2", "[1.2-1.3)"), + ("~1", "[1-2)"), + ("~0.0.3", "[0.0.3-0.0.4)"), + ("~0.0", "[0.0-0.1)"), + ("~0", "[0-1)"), ], ) def test_simple_matches(test_input, expected): @@ -65,6 +66,9 @@ def test_range_matches(test_input, expected): ("1.2.3", "1.2.3"), ("~1.2.3", "1.2.4"), ("~1.2.3", "1.2.3"), + ("~1.2", "1.2.10"), + ("~1", "1.99"), + ("~0.0.3", "0.0.3"), ("1.2", "1.2.0"), ("1.2", "1.9.9"), ("0.2.3", "0.2.3"), @@ -86,6 +90,9 @@ def test_match_particular_version_expected_true(test_input, expected): ("1.2.3", "2.0.0"), ("1.2.3", "1.2.2"), ("~1.2.3", "1.3"), + ("~1.2", "1.3"), + ("~1", "2"), + ("~0.0.3", "0.0.4"), ("1.2", "2.0.0"), ("1.2", "1.1.9"), ("0.2.3", "0.3.0"),