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
Co-authored-by: Kristoffer Carlsson <kcarlsson89@gmail.com>
Co-authored-by: Ian Butterworth <i.r.butterworth@gmail.com>
Co-authored-by: David Varela <00.varela.david@gmail.com>
  • Loading branch information
4 people committed Mar 30, 2021
1 parent 97f8db8 commit 4c441e0
Show file tree
Hide file tree
Showing 28 changed files with 619 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
echo "TEMP=${USERPROFILE}\AppData\Local\Temp" >> ${GITHUB_ENV}
- name: Run tests
run: |
julia test/pkg-uuid.jl
julia test/pkg_uuid.jl
julia --project --color=yes -e 'write("Project.toml", replace(read("Project.toml", String), r"uuid = .*?\n" =>"uuid = \"54cfe95a-1eb2-52ea-b672-e2afdf69b78f\"\n"));'
julia --project --color=yes --check-bounds=yes -e 'import Pkg; Pkg.build(); Pkg.test(; coverage=true)'
env:
Expand Down
13 changes: 12 additions & 1 deletion src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ 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,
allow_earlier_backwards_compatible_versions::Bool=true,
kwargs...)
julia_args = Cmd(julia_args)
test_args = Cmd(test_args)
Expand All @@ -424,7 +426,16 @@ 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,
allow_earlier_backwards_compatible_versions,
)
return
end

Expand Down
112 changes: 108 additions & 4 deletions src/Operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ function download_source(ctx::Context; readonly=true)
missed_packages = eltype(pkgs_to_install)[]
widths = [textwidth(pkg.name) for (pkg, _) in pkgs_to_install]
max_name = maximum(widths; init=0)

@sync begin
jobs = Channel{eltype(pkgs_to_install)}(ctx.num_concurrent_downloads)
results = Channel(ctx.num_concurrent_downloads)
Expand Down Expand Up @@ -1377,7 +1377,9 @@ 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,
allow_earlier_backwards_compatible_versions::Bool=true)
active_manifest = manifestfile_path(dirname(ctx.env.project_file))
sandbox_project = projectfile_path(sandbox_path)

Expand Down Expand Up @@ -1439,6 +1441,17 @@ 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
result = check_force_latest_compatible_version(
temp_ctx;
target_name = target.name,
allow_earlier_backwards_compatible_versions,
)
if !result
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 @@ -1512,7 +1525,9 @@ 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,
allow_earlier_backwards_compatible_versions::Bool=true)
Pkg.instantiate(ctx; allow_autoprecomp = false) # do precomp later within sandbox

# load manifest data
Expand Down Expand Up @@ -1554,7 +1569,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, allow_earlier_backwards_compatible_versions) do
test_fn !== nothing && test_fn()
sandbox_ctx = Context(;io=ctx.io)
status(sandbox_ctx.env; mode=PKGMODE_COMBINED, io=sandbox_ctx.io)
Expand Down Expand Up @@ -1782,4 +1797,93 @@ function status(env::EnvCache, pkgs::Vector{PackageSpec}=PackageSpec[];
end
end

function check_force_latest_compatible_version(ctx::Types.Context;
target_name = nothing,
allow_earlier_backwards_compatible_versions::Bool = true)
direct_deps = load_direct_deps(ctx.env)
direct_deps_uuids = [dep.uuid for dep in direct_deps]
uuid_list = filter(!is_stdlib, direct_deps_uuids)
isempty(uuid_list) && return true
results = check_force_latest_compatible_version.(
Ref(ctx),
uuid_list;
target_name,
allow_earlier_backwards_compatible_versions,
)
return all(results)
end

function check_force_latest_compatible_version(ctx::Types.Context,
uuid::Base.UUID;
target_name= nothing,
allow_earlier_backwards_compatible_versions::Bool = true)
dep = ctx.env.manifest[uuid]
name = dep.name
active_version = dep.version
has_compat = haskey(ctx.env.project.compat, name)
if !has_compat
if name != target_name
@warn(
"Package does not have a [compat] entry",
name, uuid, active_version, target_name,
)
end
return true
end
compat_entry_string = ctx.env.project.compat[name]
latest_compatible_version = get_latest_compatible_version(
ctx,
uuid,
compat_entry_string,
)
earliest_backwards_compatible_version = get_earliest_backwards_compatible_version(latest_compatible_version)
if allow_earlier_backwards_compatible_versions
result = active_version >= earliest_backwards_compatible_version
else
result = active_version >= latest_compatible_version
end
if !result
@error(
"Package is not at the latest compatible version",
name,
uuid,
compat_entry_string,
active_version,
latest_compatible_version,
earliest_backwards_compatible_version,
allow_earlier_backwards_compatible_versions,
)
end
return result
end

function get_earliest_backwards_compatible_version(ver::Base.VersionNumber)
(ver.major > 0) && return Base.VersionNumber(ver.major, 0, 0)
(ver.minor > 0) && return Base.VersionNumber(0, ver.minor, 0)
return Base.VersionNumber(0, 0, ver.patch)
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(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 = Set{VersionNumber}()
for reg in ctx.registries
pkg = get(reg, uuid, nothing)
if pkg !== nothing
info = Registry.registry_info(pkg)
union!(versions, keys(info.version_info))
end
end
return versions
end

end # module
12 changes: 12 additions & 0 deletions src/Pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,22 @@ 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`: [EXPERIMENTAL] force the latest compatible version of each direct dependency.
- `allow_earlier_backwards_compatible_versions::Bool=false`: [EXPERIMENTAL] allow any version that is backwards-compatible with the latest compatible version of a direct dependency. If `force_latest_compatible_version` is `false`, then the value of `force_latest_compatible_version` has no effect.
!!! compat "Julia 1.3"
`julia_args` and `test_args` requires at least Julia 1.3.
!!! compat "Julia 1.7"
`force_latest_compatible_version` and
`allow_earlier_backwards_compatible_versions` require at least Julia 1.7.
!!! note
The `force_latest_compatible_version` and
`allow_earlier_backwards_compatible_versions` keyword arguments are
experimental features. The behavior is subject to change or removal in minor
or patch releases of Julia.
Run the tests for package `pkg`, or for the current project (which thus needs to be a package) if no
positional argument is given to `Pkg.test`. A package is tested by running its
`test/runtests.jl` file.
Expand Down
Loading

0 comments on commit 4c441e0

Please sign in to comment.