Skip to content

Commit

Permalink
Add the force_latest_compatible_version keyword argument to Pkg.test
Browse files Browse the repository at this point in the history
  • Loading branch information
DilumAluthge committed Mar 19, 2021
1 parent 8b0045d commit 8d4a250
Show file tree
Hide file tree
Showing 23 changed files with 293 additions and 4 deletions.
3 changes: 2 additions & 1 deletion src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec};
coverage=false, test_fn=nothing,
julia_args::Union{Cmd, AbstractVector{<:AbstractString}}=``,
test_args::Union{Cmd, AbstractVector{<:AbstractString}}=``,
force_latest_compatible_version::Bool=false,
kwargs...)
julia_args = Cmd(julia_args)
test_args = Cmd(test_args)
Expand All @@ -424,7 +425,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec};
manifest_resolve!(ctx.env.manifest, pkgs)
ensure_resolved(ctx.env.manifest, pkgs)
end
Operations.test(ctx, pkgs; coverage=coverage, test_fn=test_fn, julia_args=julia_args, test_args=test_args)
Operations.test(ctx, pkgs; coverage, test_fn, julia_args, test_args, force_latest_compatible_version)
return
end

Expand Down
15 changes: 12 additions & 3 deletions src/Operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1423,7 +1423,8 @@ end

# ctx + pkg used to compute parent dep graph
function sandbox(fn::Function, ctx::Context, target::PackageSpec, target_path::String,
sandbox_path::String, sandbox_project_override)
sandbox_path::String, sandbox_project_override;
force_latest_compatible_version::Bool=false)
active_manifest = manifestfile_path(dirname(ctx.env.project_file))
sandbox_project = projectfile_path(sandbox_path)

Expand Down Expand Up @@ -1485,6 +1486,12 @@ function sandbox(fn::Function, ctx::Context, target::PackageSpec, target_path::S
end
write_env(temp_ctx.env, update_undo = false)

if force_latest_compatible_version
if !_force_latest_compatible_version(temp_ctx; target_name = target.name)
pkgerror("One or more direct dependencies is not at the latest compatible version")
end
end

# Run sandboxed code
path_sep = Sys.iswindows() ? ';' : ':'
withenv(fn, "JULIA_LOAD_PATH" => "@$(path_sep)$(tmp)", "JULIA_PROJECT" => nothing)
Expand Down Expand Up @@ -1566,7 +1573,7 @@ testdir(source_path::String) = joinpath(source_path, "test")
testfile(source_path::String) = joinpath(testdir(source_path), "runtests.jl")
function test(ctx::Context, pkgs::Vector{PackageSpec};
coverage=false, julia_args::Cmd=``, test_args::Cmd=``,
test_fn=nothing)
test_fn=nothing, force_latest_compatible_version::Bool=false)
Pkg.instantiate(ctx; allow_autoprecomp = false) # do precomp later within sandbox

# load manifest data
Expand Down Expand Up @@ -1602,7 +1609,7 @@ function test(ctx::Context, pkgs::Vector{PackageSpec};
gen_target_project(ctx.env, ctx.registries, pkg, source_path, "test")
# now we sandbox
printpkgstyle(ctx.io, :Testing, pkg.name)
sandbox(ctx, pkg, source_path, testdir(source_path), test_project_override) do
sandbox(ctx, pkg, source_path, testdir(source_path), test_project_override; force_latest_compatible_version) do
test_fn !== nothing && test_fn()
sandbox_ctx = Context()
status(sandbox_ctx.env; mode=PKGMODE_COMBINED, io=sandbox_ctx.io)
Expand Down Expand Up @@ -1809,4 +1816,6 @@ function status(env::EnvCache, pkgs::Vector{PackageSpec}=PackageSpec[];
end
end

include("force_latest_compatible_version.jl")

end # module
1 change: 1 addition & 0 deletions src/Pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ const update = API.up
- `coverage::Bool=false`: enable or disable generation of coverage statistics.
- `julia_args::Union{Cmd, Vector{String}}`: options to be passed the test process.
- `test_args::Union{Cmd, Vector{String}}`: test arguments (`ARGS`) available in the test process.
- `force_latest_compatible_version::Bool=false`: force the latest compatible version of each direct dependency.
!!! compat "Julia 1.3"
`julia_args` and `test_args` requires at least Julia 1.3.
Expand Down
74 changes: 74 additions & 0 deletions src/force_latest_compatible_version.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# const Types = Pkg.Types
# const load_direct_deps = Pkg.Operations.load_direct_deps
# const load_manifest_deps = Pkg.Operations.load_manifest_deps
# const stdlibs = Pkg.Types.stdlibs

# activate ../Foo
# ctx = Types.Context()

function _force_latest_compatible_version(ctx::Types.Context; target_name = nothing)
direct_deps = load_direct_deps(ctx.env)
direct_deps_uuids = getproperty.(direct_deps, Ref(:uuid))
nonstdlib_direct_deps_uuids = filter(x -> x keys(stdlibs()), direct_deps_uuids)
return _force_latest_compatible_version(ctx, nonstdlib_direct_deps_uuids; target_name)
end

function _force_latest_compatible_version(ctx::Types.Context, uuid_list::AbstractVector{Base.UUID};
target_name = nothing)
isempty(uuid_list) && return true
results = _force_latest_compatible_version.(Ref(ctx), uuid_list; target_name)
return all(results)
end

function _force_latest_compatible_version(ctx::Types.Context, uuid::Base.UUID;
target_name= nothing)
manifest_deps = load_manifest_deps(ctx.env.manifest)
manifest_deps_uuids = getproperty.(manifest_deps, Ref(:uuid))
idx = only(findall(manifest_deps_uuids .== uuid))
dep = manifest_deps[idx]
name = dep.name
active_version = dep.version
if haskey(ctx.env.project.compat, name)
compat_entry_string = ctx.env.project.compat[name]
latest_compatible_version = _get_latest_compatible_version(ctx, uuid, compat_entry_string)
else
if name != target_name
@warn(
"Package does not have a [compat] entry",
name, uuid, active_version,
)
end
return true
end
result = active_version == latest_compatible_version
if !result
@error(
"Package is not at the latest compatible version",
name, uuid, active_version,
latest_compatible_version, compat_entry_string,
)
end
return result
end

function _get_latest_compatible_version(ctx::Types.Context, uuid::Base.UUID,
compat_entry_string::AbstractString)
all_registered_versions = _get_all_registered_versions(ctx, uuid)
compat_spec = Pkg.Types.semver_spec(compat_entry_string)
compatible_versions = filter(x -> x in compat_spec, all_registered_versions)
latest_compatible_version = maximum(compatible_versions)
return latest_compatible_version
end

function _get_all_registered_versions(ctx::Types.Context, uuid::Base.UUID)
versions = Base.VersionNumber[]
for reg in ctx.registries
pkg = get(reg, uuid, nothing)
pkg == nothing && continue
info = Registry.registry_info(pkg)
append!(versions, keys(info.version_info))
end
unique!(versions)
sort!(versions)
return versions
end
71 changes: 71 additions & 0 deletions test/force_latest_compatible_version.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

module ForceLatestCompatibleVersionTests

import ..Pkg # ensure we are using the correct Pkg
import ..Utils
using Test

@testset "force_latest_compatible_version" begin
@testset "`force_latest_compatible_version` kwarg to `Pkg.test`" begin
parent_dir = joinpath(@__DIR__, "test_packages", "force_latest_compatible_version")

@testset "OldOnly1: `SomePkg = \"=0.1.0\"`" begin
mktempdir() do tmp_dir
test_package = joinpath(tmp_dir, "OldOnly1")
cp(joinpath(parent_dir, "OldOnly1"), test_package; force = true)
Utils.isolate() do
Pkg.activate(test_package)
Pkg.instantiate()
Pkg.build()
@test Pkg.test(; force_latest_compatible_version = false) == nothing
@test Pkg.test(; force_latest_compatible_version = true) == nothing
end
end
end

@testset "OldOnly2: `SomePkg = \"0.1\"`" begin
mktempdir() do tmp_dir
test_package = joinpath(tmp_dir, "OldOnly2")
cp(joinpath(parent_dir, "OldOnly2"), test_package; force = true)
Utils.isolate() do
Pkg.activate(test_package)
Pkg.instantiate()
Pkg.build()
@test Pkg.test(; force_latest_compatible_version = false) == nothing
@test_throws Pkg.Types.PkgError Pkg.test(; force_latest_compatible_version = true)
end
end
end

@testset "BothOldAndNew: `SomePkg = \"0.1, 0.2\"`" begin
mktempdir() do tmp_dir
test_package = joinpath(tmp_dir, "BothOldAndNew")
cp(joinpath(parent_dir, "BothOldAndNew"), test_package; force = true)
Utils.isolate() do
Pkg.activate(test_package)
Pkg.instantiate()
Pkg.build()
@test Pkg.test(; force_latest_compatible_version = false) == nothing
@test_throws Pkg.Types.PkgError Pkg.test(; force_latest_compatible_version = true)
end
end
end

@testset "NewOnly: `SomePkg = \"0.2\"`" begin
mktempdir() do tmp_dir
test_package = joinpath(tmp_dir, "NewOnly")
cp(joinpath(parent_dir, "NewOnly"), test_package; force = true)
Utils.isolate() do
Pkg.activate(test_package)
Pkg.instantiate()
Pkg.build()
@test_throws Pkg.Resolve.ResolverError Pkg.test(; force_latest_compatible_version = false)
@test_throws Pkg.Resolve.ResolverError Pkg.test(; force_latest_compatible_version = true)
end
end
end
end
end

end # module
File renamed without changes.
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ include("platformengines.jl")
include("sandbox.jl")
include("resolve.jl")
include("misc.jl")
include("force_latest_compatible_version.jl")

# clean up locally cached registry
rm(joinpath(@__DIR__, "registries"); force = true, recursive = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "BothOldAndNew"
uuid = "ebb7d249-15d2-4389-abff-d529bd2cf37c"
authors = ["Dilum Aluthge <dilum@aluthge.com>"]
version = "0.1.0"

[deps]
MLJModelInterface = "e80e1ace-859a-464e-9ed9-23947d8ae3ea"

[compat]
MLJModelInterface = "0.1, 0.2"
ScientificTypes = "0.6"

[extras]
ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["ScientificTypes", "Test"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module BothOldAndNew

import MLJModelInterface

f(x) = x + x

end # module
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import BothOldAndNew
import ScientificTypes
import Test

Test.@testset "BothOldAndNew.jl" begin
Test.@test BothOldAndNew.f(1) == 2
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "NewOnly"
uuid = "2c7b3c3b-62b6-437a-a36e-3d5963db0b1f"
authors = ["Dilum Aluthge <dilum@aluthge.com>"]
version = "0.1.0"

[deps]
MLJModelInterface = "e80e1ace-859a-464e-9ed9-23947d8ae3ea"

[compat]
MLJModelInterface = "0.2"
ScientificTypes = "0.6"

[extras]
ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["ScientificTypes", "Test"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module NewOnly

import MLJModelInterface

f(x) = x + x

end # module
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import NewOnly
import ScientificTypes
import Test

Test.@testset "NewOnly.jl" begin
Test.@test NewOnly.f(1) == 2
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "OldOnly1"
uuid = "abc047b9-6ad4-4533-a374-d50ae908e3e9"
authors = ["Dilum Aluthge <dilum@aluthge.com>"]
version = "0.1.0"

[deps]
MLJModelInterface = "e80e1ace-859a-464e-9ed9-23947d8ae3ea"

[compat]
MLJModelInterface = "=0.1.0"
ScientificTypes = "0.6"

[extras]
ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["ScientificTypes", "Test"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module OldOnly1

import MLJModelInterface

f(x) = x + x

end # module
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import OldOnly1
import ScientificTypes
import Test

Test.@testset "OldOnly1.jl" begin
Test.@test OldOnly1.f(1) == 2
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "OldOnly2"
uuid = "abc047b9-6ad4-4533-a374-d50ae908e3e9"
authors = ["Dilum Aluthge <dilum@aluthge.com>"]
version = "0.1.0"

[deps]
MLJModelInterface = "e80e1ace-859a-464e-9ed9-23947d8ae3ea"

[compat]
MLJModelInterface = "0.1"
ScientificTypes = "0.6"

[extras]
ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["ScientificTypes", "Test"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module OldOnly2

import MLJModelInterface

f(x) = x + x

end # module
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import OldOnly2
import ScientificTypes
import Test

Test.@testset "OldOnly2.jl" begin
Test.@test OldOnly2.f(1) == 2
end

0 comments on commit 8d4a250

Please sign in to comment.