diff --git a/downgrade.jl b/downgrade.jl index f4410fd..39dd6b6 100644 --- a/downgrade.jl +++ b/downgrade.jl @@ -479,6 +479,19 @@ function get_resolved_versions(manifest_file::String) return versions end +""" + versions_match_ignoring_build(actual, expected) + +Return true if two versions are equal, ignoring SemVer build metadata +(the `+...` suffix). This allows `1.2.3` and `1.2.3+4` to match. +""" +function versions_match_ignoring_build(actual::VersionNumber, expected::VersionNumber) + return actual.major == expected.major && + actual.minor == expected.minor && + actual.patch == expected.patch && + actual.prerelease == expected.prerelease +end + """ check_forced_lower_bounds(project_file, manifest_file, ignore_pkgs) @@ -503,7 +516,7 @@ function check_forced_lower_bounds(project_file::String, manifest_file::String, # Check if the major.minor.patch matches # We compare the full version, but note that the lower bound might be # less specific (e.g., "1.2" means v1.2.0) - if actual != expected + if !versions_match_ignoring_build(actual, expected) @error "forcedeps check failed: $pkg resolved to $actual but lower bound is $expected" all_match = false else diff --git a/test/runtests.jl b/test/runtests.jl index a62d254..22ef162 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -152,6 +152,38 @@ downgrade_jl = joinpath(dirname(@__DIR__), "downgrade.jl") end end + @testset "forcedeps mode - ignores build metadata" begin + mktempdir() do dir + cd(dir) do + # JLL packages commonly resolve with build metadata (e.g., +0) + # while compat lower bounds typically omit it. + toml_content = """ + name = "TestPackage" + version = "0.1.0" + + [deps] + OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" + + [compat] + julia = "1.10" + OpenSSL_jll = "3.5.0" + """ + write("Project.toml", toml_content) + + # Should pass even when resolved version is like 3.5.0+0 + run(`$(Base.julia_cmd()) $downgrade_jl "" "." "forcedeps" "1.10"`) + + manifest = TOML.parsefile("Manifest.toml") + deps = manifest["deps"] + deps_OpenSSL_jll = get(deps, "OpenSSL_jll", []) + + @test !isempty(deps_OpenSSL_jll) + @test startswith(deps_OpenSSL_jll[1]["version"], "3.5.0") + @test occursin("+", deps_OpenSSL_jll[1]["version"]) + end + end + end + @testset "invalid cases" begin # Test invalid mode mktempdir() do dir