Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the force_latest_compatible_version keyword argument to Pkg.test #2439

Merged
merged 1 commit into from
Mar 30, 2021
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
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what this means.

(also very long line).


!!! 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