From 12ded96009386e043306562ffc11a6f6f6898dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnar=20Farneb=C3=A4ck?= Date: Thu, 21 Oct 2021 22:45:17 +0200 Subject: [PATCH] Support registering with a temporary git clone and on a specific branch. --- Project.toml | 6 +- README.md | 8 +- src/LocalRegistry.jl | 200 +++++++++++++++++----- test/check_git_registry.jl | 50 ++++++ test/find_package_path.jl | 45 +++++ test/find_registry_path.jl | 69 ++++++++ test/register.jl | 245 +++++++++++++++++++++++++++ test/regression.jl | 86 ++++++++++ test/runtests.jl | 333 ++----------------------------------- test/utils.jl | 24 +++ 10 files changed, 705 insertions(+), 361 deletions(-) create mode 100644 test/check_git_registry.jl create mode 100644 test/find_package_path.jl create mode 100644 test/find_registry_path.jl create mode 100644 test/register.jl create mode 100644 test/regression.jl diff --git a/Project.toml b/Project.toml index 267d3f4..300d6b1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LocalRegistry" uuid = "89398ba2-070a-4b16-a995-9893c55d93cf" authors = ["Gunnar Farnebäck "] -version = "0.4.0" +version = "0.5.0" [deps] Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" @@ -10,11 +10,13 @@ RegistryTools = "d1eb7eb1-105f-429d-abf5-b0f65cb9e2c4" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] +CodecZlib = "0.5, 0.6, 0.7" RegistryTools = "1.4" julia = "~1.1, ~1.2, ~1.3, ~1.4, ~1.5, ~1.6, ~1.7" [extras] +CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test"] +test = ["CodecZlib", "Test"] diff --git a/README.md b/README.md index 07e5a1d..9eeb134 100644 --- a/README.md +++ b/README.md @@ -79,11 +79,13 @@ Notes: * The package must be stored as a git working copy, e.g. having been cloned with `Pkg.develop`. * The package must be available in the current `Pkg` environment. -* The package must have a `Project.toml` file. +* The package must have a `Project.toml` or `JuliaProject.toml` file. * There is no checking that the dependencies are available in any registry. * If you have exactly one installed registry beside the `General` registry, it is not necessary to specify `registry`. +* By default the registry changes are `git push`ed to the upstream + registry repository. ## Register a New Version of a Package @@ -96,7 +98,7 @@ When adding a new version of a package, the registry can be omitted. The new version number is obtained from the `version` field of the package's `Project.toml` file. -## Simplified Registration of Active Package +## Simplified Registration of Active Package or Current Directory If you start Julia with the `--project` flag or use `Pkg.activate` to activate a developed package, this package can be registered simply by @@ -109,6 +111,8 @@ register() This is also sufficient for registering a new package, provided that you have exactly one installed registry beside the `General` registry. +If you run `register()` but the active project is not a package, it +will look for a package in the current directory. ## Advanced Topics diff --git a/src/LocalRegistry.jl b/src/LocalRegistry.jl index d359ed7..45bb40c 100644 --- a/src/LocalRegistry.jl +++ b/src/LocalRegistry.jl @@ -86,20 +86,20 @@ function create_registry(name_or_path, repo; description = nothing, end """ - register(package, registry = registry) - -Register the new `package` in the registry `registry`. The version -number and other information is obtained from the package's -`Project.toml`. - + register(package; registry = registry) register(package) - -Register a new version of `package`. The version number is obtained -from the package's `Project.toml`. - register() -Register a new version of the package in the currently active project. +Register `package`. If `package` is omitted, register the package in +the currently active project or in the current directory in case the +active project is not a package. + +If `registry` is not specified: +* For registration of a new version, automatically locate the registry + where `package` is available. +* For registration of a new package, fail unless exactly one registry + other than General is installed, in which case that registry is + used. Notes: * By default this will, in all cases, `git push` the updated registry @@ -116,19 +116,30 @@ Notes: specified by starting with `"./"`. * By module. It needs to first be loaded by `using` or `import`. -`registry` can be specified by name or by path in the same way as -`package`. If omitted or `nothing`, it will be automatically located -by `package`. +`registry` can be specified in the following ways: +* By registry name. This must be an exact match to the name of one of + the installed registries. +* By path. This must be an existing local path. +* By URL to its remote location. Everything which doesn't match one of + the previous options is assumed to be a URL. + +If `registry` is specified by URL, or the found registry is not a git +clone (i.e. obtained from a package server), a temporary git clone +will be used to perform the registration. In this case `push` must be +`true`. *Keyword arguments* register(package; registry = nothing, commit = true, push = true, - repo = nothing, gitconfig = Dict()) + branch = nothing, repo = nothing, ignore_reregistration = false, + gitconfig = Dict()) -* `registry`: Name or path of registry. -* `commit`: If `false`, only make the changes to the registry but do not commit. +* `registry`: Name, path, or URL of registry. +* `commit`: If `false`, only make the changes to the registry but do not commit. Additionally the registry is allowed to be dirty in the `false` case. * `push`: If `true`, push the changes to the registry repository automatically. Ignored if `commit` is false. +* `branch`: Branch name to use for the registration. * `repo`: Specify the package repository explicitly. Otherwise looked up as the `git remote` of the package the first time it is registered. +* `ignore_reregistration`: If `true`, do not raise an error if a version has already been registered (with different content), only an informational message. * `gitconfig`: Optional configuration parameters for the `git` command. """ function register(package::Union{Nothing, Module, AbstractString} = nothing; @@ -142,7 +153,8 @@ end # `registry`. Also returns false if there was nothing new to register # and true if something new was registered. function do_register(package, registry; - commit = true, push = true, repo = nothing, + commit = true, push = true, branch = nothing, + repo = nothing, ignore_reregistration = false, gitconfig::Dict = Dict()) # Find and read the `Project.toml` for the package. First look for # the alternative `JuliaProject.toml`. @@ -165,8 +177,16 @@ function do_register(package, registry; end registry_path = find_registry_path(registry, pkg) + registry_path, is_temporary = check_git_registry(registry_path, gitconfig) + if is_temporary && (!commit || !push) + error("Need to use a temporary git clone of the registry, but commit or push is set to false.") + end if is_dirty(registry_path, gitconfig) - error("Registry directory is dirty. Stash or commit files.") + if commit + error("Registry directory is dirty. Stash or commit files.") + else + @info("Note: registry directory is dirty.") + end end # Compute the tree hash for the package and the subdirectory @@ -175,11 +195,16 @@ function do_register(package, registry; # string. tree_hash, subdir = get_tree_hash(package_path, gitconfig) - # Check if this exact package has already been registered. Do - # nothing and don't error in that case. - if find_registered_version(pkg, registry_path) == tree_hash + # Check if this version has already been registered. Note, if it + # was already registered and the contents has changed and + # `ignore_reregistration` is false, this will be caught later. + registered_version = find_registered_version(pkg, registry_path) + if registered_version == tree_hash @info "This version has already been registered and is unchanged." return false + elseif !isempty(registered_version) && ignore_reregistration + @info "This version has already been registered. Registration request is ignored. Update the version number to register a new version." + return false end # Use the `repo` argument or, if this is a new package @@ -201,6 +226,8 @@ function do_register(package, registry; git = gitcmd(registry_path, gitconfig) HEAD = readchomp(`$git rev-parse --verify HEAD`) + saved_branch = readchomp(`$git rev-parse --abbrev-ref HEAD`) + remote = readchomp(`$git remote`) status = ReturnStatus() try check_and_update_registry_files(pkg, package_repo, tree_hash, @@ -208,10 +235,18 @@ function do_register(package, registry; subdir = subdir) if !haserror(status) if commit + if !isnothing(branch) + run(`$git checkout -b $branch`) + end commit_registry(pkg, package_path, package_repo, tree_hash, git) if push - run(`$git push`) + if isnothing(branch) + run(`$git push`) + else + run(`$git push --set-upstream $remote $branch`) + end end + run(`$git checkout $(saved_branch)`) end clean_registry = false end @@ -219,6 +254,7 @@ function do_register(package, registry; if clean_registry run(`$git reset --hard $(HEAD)`) run(`$git clean -f -d`) + run(`$git checkout $(saved_branch)`) end end @@ -264,10 +300,11 @@ function is_dirty(path, gitconfig) return !isempty(read(`$git diff-index -u HEAD -- .`)) end -# If the package is omitted, the active project must correspond to a -# package. +# If the package is omitted, +# * use the active project if it corresponds to a package, +# * otherwise use the current directory. function find_package_path(::Nothing) - path = "" + path = pwd() if VERSION < v"1.4" env = Pkg.Types.EnvCache() if !isnothing(env.pkg) @@ -283,10 +320,6 @@ function find_package_path(::Nothing) end end - if path == "" - error("The active project is not a package.") - end - return path end @@ -337,17 +370,21 @@ function find_registry_path(registry::AbstractString, ::Pkg.Types.Project) end function find_registry_path(registry::AbstractString) - if length(splitpath(registry)) > 1 - return abspath(expanduser(registry)) - end - + # 1. Does `registry` match the name of one of the installed registries? all_registries = collect_registries() matching_registries = filter(r -> r.name == registry, all_registries) - if isempty(matching_registries) - error("Registry $(registry) not found.") + if !isempty(matching_registries) + return first(matching_registries).path end - return first(matching_registries).path + # 2. Is `registry` an existing path? + path = abspath(expanduser(registry)) + if checked_ispath(path) + return path + end + + # 3. If not, assume it is a URL. + return registry end function find_registry_path(::Nothing, pkg::Pkg.Types.Project) @@ -373,7 +410,81 @@ function find_registry_path(::Nothing, pkg::Pkg.Types.Project) return first(matching_registries).path end -# This replaces the use of `Pkg.Types.collect_registries` which was +# Starting with Julia 1.4, a registry can either be obtained as a git +# clone of a remote git repository or be downloaded from a Julia +# package server. Starting with Julia 1.7, in the latter case the +# registry can also be stored as a tar archive that hasn't been +# unpacked. +# +# Either way, LocalRegistry must have a git clone to work with, so if +# the registry is not in that form, make a temporary git clone. +function check_git_registry(registry_path_or_url, gitconfig) + if !checked_ispath(registry_path_or_url) + # URL given. Use this to make a git clone. + url = registry_path_or_url + elseif isdir(joinpath(registry_path_or_url, ".git")) + # Path is already a git clone. Nothing left to do. + return registry_path_or_url, false + else + # Registry is given as a path but is not a git clone. Find the + # URL of the registry from Registry.toml. + if VERSION >= v"1.7-" + # This handles both packed and unpacked registries. + try + url = Pkg.Registry.RegistryInstance(registry_path_or_url).repo + catch + error("Bad registry path: $(registry_path_or_url)") + end + else + if looks_like_tar_registry(registry_path_or_url) + error("Non-unpacked registries require Julia 1.7 or later.") + elseif !isdir(registry_path_or_url) + error("Bad registry path: $(registry_path_or_url)") + end + url = Pkg.TOML.parsefile(joinpath(registry_path_or_url, "Registry.toml"))["repo"] + end + end + + # Make a temporary clone of the registry at `url`. For Julia 1.3 + # and later this will be automatically removed when Julia exits. + # For older Julia it will linger around. Upgrade your Julia if you + # don't like that. + path = mktempdir() + git = gitcmd(path, gitconfig) + try + # Note, the output directory `.` effectively means `path`. + run(`$git clone -q $url .`) + catch + error("Failed to make a temporary git clone of $url") + end + return path, true +end + +# On sufficiently old Julia versions (including 1.1 but not 1.5) and +# Windows, `ispath` errors instead of returning false for (at least +# some) invalid paths, like e.g. "file://path". +function checked_ispath(path) + if Sys.iswindows() + try + return ispath(path) + catch + return false + end + end + return ispath(path) +end + +function looks_like_tar_registry(path) + endswith(path, ".toml") || return false + isfile(path) || return false + try + return haskey(Pkg.TOML.parsefile(path), "git-tree-sha1") + catch + return false + end +end + +# This replaces the use of `Pkg.Types.collect_registries`, which was # removed in Julia 1.7. # # TODO: Once Julia versions before 1.7 are no longer supported, @@ -387,8 +498,17 @@ function collect_registries() isdir(reg_dir) || continue for name in readdir(reg_dir) file = joinpath(reg_dir, name, "Registry.toml") - isfile(file) || continue - push!(registries, (name = name, path = joinpath(reg_dir, name))) + if isfile(file) + push!(registries, (name = name, path = joinpath(reg_dir, name))) + else + # Packed registry in Julia 1.7+. + file = joinpath(reg_dir, "$(name).toml") + if isfile(file) + push!(registries, + (name = name, path = joinpath(reg_dir, + "$(name).toml"))) + end + end end end return registries diff --git a/test/check_git_registry.jl b/test/check_git_registry.jl new file mode 100644 index 0000000..62bbdc5 --- /dev/null +++ b/test/check_git_registry.jl @@ -0,0 +1,50 @@ +with_testdir() do testdir + registry_dir = joinpath(testdir, "TestRegistry") + upstream_dir = joinpath(dirname(registry_dir), "upstream") + upstream_url = "file:///$(upstream_dir)" + create_registry(registry_dir, upstream_url, + description = "For testing purposes only.", + uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369", + gitconfig = TEST_GITCONFIG, push = false) + + reg_path, is_temp = check_git_registry(registry_dir, TEST_GITCONFIG) + @test reg_path == registry_dir + @test !is_temp + + mkpath(upstream_dir) + upstream_git = gitcmd(upstream_dir, TEST_GITCONFIG) + run(`$(upstream_git) clone -q --bare $(registry_dir) .`) + + reg_path, is_temp = check_git_registry(upstream_url, TEST_GITCONFIG) + @test isdir(joinpath(reg_path, ".git")) + @test is_temp + + # Emulate a registry downloaded from a package server. + downstream_git = gitcmd(registry_dir, TEST_GITCONFIG) + tree_hash = readchomp(`$(downstream_git) rev-parse HEAD:`) + rm(joinpath(registry_dir, ".git"), recursive = true) + write(joinpath(registry_dir, ".tree_info.toml"), + "git-tree-sha1 = \"$(tree_hash)\"") + reg_path, is_temp = check_git_registry(registry_dir, TEST_GITCONFIG) + @test isdir(joinpath(reg_path, ".git")) + @test is_temp + + # Emulate a registry downloaded from a package server without unpacking. + tar = read(`$(upstream_git) -c core.autocrlf=false archive $(tree_hash)`) + gzip = transcode(GzipCompressor, tar) + write(joinpath(testdir, "TestRegistry.tar.gz"), gzip) + registry_toml = joinpath(testdir, "TestRegistry.toml") + write(registry_toml, + """git-tree-sha1 = "$(tree_hash)" + uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369" + path = "TestRegistry.tar.gz" + """) + if VERSION < v"1.7-" + @test_throws ErrorException check_git_registry(registry_toml, + TEST_GITCONFIG) + else + reg_path, is_temp = check_git_registry(registry_toml, TEST_GITCONFIG) + @test isdir(joinpath(reg_path, ".git")) + @test is_temp + end +end diff --git a/test/find_package_path.jl b/test/find_package_path.jl new file mode 100644 index 0000000..6ae40ab --- /dev/null +++ b/test/find_package_path.jl @@ -0,0 +1,45 @@ +# Additional tests of `find_package_path`. Many of these have the +# purpose to cover error cases, making them somewhat contrived. + +# Not a developed package. +@test_throws ErrorException find_package_path("AutoHashEquals") + +# Find package by module and path. +using Multibreak +package_path = find_package_path(Multibreak) +@test find_package_path(package_path) == package_path + +# Find package by name. +if Base.Sys.islinux() + @test find_package_path("Multibreak") == package_path +else + # Workaround for CI path weirdnesses on Windows and Mac. + @test splitpath(package_path)[end-2:end] == splitpath(find_package_path("Multibreak"))[end-2:end] +end + +# Not a package path. +corrupt_path = joinpath(package_path, "no_such_dir") +@test_throws ErrorException find_package_path(corrupt_path) + +# Unknown package. +@test_throws ErrorException find_package_path("ZeroethTest") + +# Current active environment is not a package. Return the current directory. +@test find_package_path(nothing) == pwd() + +# Activate a package directory and find it with `find_package_path`. +Pkg.activate("Multibreak") +if Base.Sys.islinux() + @test find_package_path(nothing) == package_path +else + # Workaround for CI path weirdnesses on Windows and Mac. + @test splitpath(package_path)[end-2:end] == splitpath(find_package_path(nothing))[end-2:end] +end +Pkg.activate() + +# Early Julia 1.x versions insist on installing the General registry +# when doing `activate`. It is expected not to be there in the +# LocalRegistry tests, so remove it again if it has been installed. +if isdir(joinpath(first(DEPOT_PATH), "registries", "General")) + Pkg.Registry.rm("General") +end diff --git a/test/find_registry_path.jl b/test/find_registry_path.jl new file mode 100644 index 0000000..8db84cc --- /dev/null +++ b/test/find_registry_path.jl @@ -0,0 +1,69 @@ +# Additional tests of `find_registry_path` and `check_registry`. Many +# of these have the purpose to cover error cases, making them somewhat +# contrived. Another complicating factor is that some of the call +# variants have to interact with the package environment, including +# registries, of the running Julia process. + +# Not a registered package. +pkg = Pkg.Types.Project(Dict("name" => "UUIDs", + "uuid" => "cf7118a7-6976-5b1a-9a39-7adc72f591a4")) +@test_throws ErrorException find_registry_path(nothing, pkg) + + +with_empty_registry() do registry_dir, packages_dir + Pkg.Registry.add(RegistrySpec(path = registry_dir)) + + # Use Multibreak as Guinea pig. The sleep is a Travis workaround. See + # a later comment. This also tests automatically choosing the only + # installed registry for a new package. + sleep(1) + register("Multibreak", push = false, gitconfig = TEST_GITCONFIG) + + # Directory already exists. Also tests code handling a trailing slash. + create_registry("TestRegistry2", "", gitconfig = TEST_GITCONFIG, + push = false) + @test_throws ErrorException create_registry("TestRegistry2/", "", + gitconfig = TEST_GITCONFIG, + push = false) + + # Find a registry by name. + package_path = find_package_path("Multibreak") + pkg = Pkg.Types.read_project(joinpath(package_path, "Project.toml")) + @test find_registry_path("TestRegistry") == joinpath(first(DEPOT_PATH), + "registries", + "TestRegistry") + + # The named registry does not exist. In this case it is assumed to + # be a local path if it exists, otherwise a URL, regardless how + # much it doesn't look like a URL. + saved_dir = pwd() + tempdir = mktempdir() + cd(tempdir) + @test find_registry_path("General", pkg) == "General" + mkdir("General") + @test find_registry_path("General", pkg) == abspath("General") + cd(saved_dir) + rm(tempdir, recursive = true) + + # Find which registry contains a package. + @test find_registry_path(nothing, pkg) == joinpath(first(DEPOT_PATH), + "registries", + "TestRegistry") + + # Workaround for bad `mtime` resolution of 1 second on MacOS workers + # on Travis. + # + # The issue is that `read_registry` caches its results with respect to + # the file `mtime`. Since `read_registry` is called from within + # `register`, the old data will be read into the cache. If the new + # data is written close enough to the previous registry update so that + # `mtime` does not change, subsequent `read_registry` will keep using + # the old data from the cache. + sleep(1) + + # More than one registry contains the package. + register("Multibreak", registry = "TestRegistry2", + repo = "file://$(packages_dir)/FirstTest", + gitconfig = TEST_GITCONFIG, push = false) + @test_throws ErrorException find_registry_path(nothing, pkg) +end diff --git a/test/register.jl b/test/register.jl new file mode 100644 index 0000000..08a7459 --- /dev/null +++ b/test/register.jl @@ -0,0 +1,245 @@ +# Try to register an already existing version with different content. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux24.toml") + register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + prepare_package(packages_dir, "Flux30.toml") + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + # This should do nothing more than give an informational message. + @test do_register(joinpath(packages_dir, "Flux"), registry_dir, + gitconfig = TEST_GITCONFIG, push = false, + ignore_reregistration = true) == false +end + +# Parse error in compat section. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Broken1.toml") + if VERSION < v"1.2" + @test_throws ErrorException register(joinpath(packages_dir, "Broken"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + else + @test_throws Pkg.Types.PkgError register(joinpath(packages_dir, "Broken"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + end +end + +# Try to change name (UUID remains). +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + prepare_package(packages_dir, "Fluxx1.toml") + @test_throws ErrorException register(joinpath(packages_dir, "Fluxx"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +# Try to change UUID. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + prepare_package(packages_dir, "Flux31.toml") + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +# Depends on itself. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Broken2.toml") + @test_throws ErrorException register(joinpath(packages_dir, "Broken"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +# Incorrect name of dependency. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + prepare_package(packages_dir, "Broken3.toml") + @test_throws ErrorException register(joinpath(packages_dir, "Broken"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +# TODO: This should really be an error but RegistryTools 1.3.0 doesn't catch it. +# Incorrect UUID of dependency. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Broken4.toml") + register(joinpath(packages_dir, "Broken"), registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) +end + +# Incorrect UUID of stdlib. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Broken5.toml") + @test_throws ErrorException register(joinpath(packages_dir, "Broken"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + # Change the git remote before registration and verify that the + # registered repo is not changed. + prepare_package(packages_dir, "Flux32.toml") + package_dir = joinpath(packages_dir, "Flux") + git = gitcmd(package_dir, TEST_GITCONFIG) + package_file = joinpath(registry_dir, "F", "Flux", "Package.toml") + old_repo = TOML.parsefile(package_file)["repo"] + new_repo = "https://example.com/Julia/Flux.jl.git" + run(`$git remote set-url origin $(new_repo)`) + register(joinpath(packages_dir, "Flux"), registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) + @test TOML.parsefile(package_file)["repo"] == old_repo + + # Register with explicit repo argument and verify that the registered + # repo is updated. + prepare_package(packages_dir, "Flux33.toml") + register(joinpath(packages_dir, "Flux"), registry = registry_dir, + repo = new_repo, gitconfig = TEST_GITCONFIG, push = false) + @test TOML.parsefile(package_file)["repo"] == new_repo +end + +# Register a package in a subdirectory of a git repository. Also add +# some dirt outside the subdirectory to verify that it is ignored. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "SubdirTest1.toml", "subdir") + write(joinpath(packages_dir, "SubdirTest", "README.md"), "dirty") + register(joinpath(packages_dir, "SubdirTest", "subdir"), + registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false) + package_file = joinpath(registry_dir, "S", "SubdirTest", "Package.toml") + @test TOML.parsefile(package_file)["subdir"] == "subdir" +end + +# Register a package with a JuliaProject.toml rather than a Project.toml. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "JuliaProjectTest1.toml", + use_julia_project = true) + register(joinpath(packages_dir, "JuliaProjectTest"), registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) + @test isfile(joinpath(registry_dir, "J", "JuliaProjectTest", "Package.toml")) +end + +# Remove Project.toml from a package and try to register. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + rm(joinpath(packages_dir, "Flux", "Project.toml")) + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +# Dirty the package repository and try to register the package. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + readme = joinpath(packages_dir, "Flux", "README.md") + open(readme, "a") do io + write(io, "\n") + end + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) +end + +# Dirty the registry repository and try to register a package. +with_empty_registry() do registry_dir, packages_dir + prepare_package(packages_dir, "Flux1.toml") + filename = joinpath(registry_dir, "Registry.toml") + open(filename, "a") do io + write(io, "\n") + end + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false) + # Allowed with `commit = false`. + register(joinpath(packages_dir, "Flux"), registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false, commit = false) +end + + +# Test automatic push functionality. The sequence of events is: +# 1. Create a bare "upstream" repository. +# 2. Create a new registry with the upstream as repo and `push = true`. +# 3. Register a package with `push = true`. +# 4. Verify that the registry and the upstream repo has the same two commits. +with_testdir() do testdir + upstream_dir = joinpath(testdir, "upstream") + mkpath(upstream_dir) + upstream_git = gitcmd(upstream_dir, TEST_GITCONFIG) + run(`$(upstream_git) init --bare`) + registry_push_dir = joinpath(testdir, "TestRegistryPush") + create_registry(registry_push_dir, "file://$(upstream_dir)", push = true, + gitconfig = TEST_GITCONFIG) + downstream_git = gitcmd(registry_push_dir, TEST_GITCONFIG) + packages_dir = joinpath(testdir, "packages") + prepare_package(packages_dir, "FirstTest1.toml") + register(joinpath(packages_dir, "FirstTest"), registry = registry_push_dir, + push = true, gitconfig = TEST_GITCONFIG) + @test readchomp(`$(downstream_git) log`) == readchomp(`$(upstream_git) log`) + @test length(readlines(`$(upstream_git) log --format=oneline`)) == 2 + + # Now duplicate the upstream repo. Then register the same package + # * like before via downstream repo with push, + # * directly against the second upstream, internally using a + # temporary clone. + upstream2_dir = joinpath(testdir, "upstream2") + mkpath(upstream2_dir) + upstream2_git = gitcmd(upstream2_dir, TEST_GITCONFIG) + run(`$(upstream2_git) clone --bare file://$(upstream_dir) .`) + prepare_package(packages_dir, "Flux1.toml") + register(joinpath(packages_dir, "Flux"), registry = registry_push_dir, + push = true, gitconfig = TEST_GITCONFIG) + # Can't have `push = false` when using a temporary git clone. + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = "file://$(upstream2_dir)", + push = false, + gitconfig = TEST_GITCONFIG) + register(joinpath(packages_dir, "Flux"), registry = "file://$(upstream2_dir)", + push = true, gitconfig = TEST_GITCONFIG) + @test readchomp(`$(downstream_git) log`) == readchomp(`$(upstream_git) log`) + # Can't use standard log format here since the time stamps will be different. + @test readchomp(`$(downstream_git) log --format=%T:%s`) == readchomp(`$(upstream2_git) log --format=%T:%s`) + @test length(readlines(`$(upstream2_git) log --format=%T:%s`)) == 3 + + # Register one more package, this time using a branch. + prepare_package(packages_dir, "Images1.toml") + register(joinpath(packages_dir, "Images"), registry = registry_push_dir, + push = true, branch = "images", gitconfig = TEST_GITCONFIG) + register(joinpath(packages_dir, "Images"), + registry = "file://$(upstream2_dir)", + push = true, branch = "images", gitconfig = TEST_GITCONFIG) + @test readchomp(`$(downstream_git) log`) == readchomp(`$(upstream_git) log`) + # Can't use standard log format here since the time stamps will be different. + @test readchomp(`$(upstream_git) log --format=%T:%s images`) == readchomp(`$(upstream2_git) log --format=%T:%s images`) + @test length(readlines(`$(upstream2_git) log --format=%T:%s images`)) == 4 +end diff --git a/test/regression.jl b/test/regression.jl new file mode 100644 index 0000000..cfed508 --- /dev/null +++ b/test/regression.jl @@ -0,0 +1,86 @@ + +# The following tests are primarily regression tests - checking that +# the results are the same as when the tests were written, regardless +# of correctness. +# +# The general strategy is that a number of project files have been +# stored. These are read and expanded to minimal stub packages, which +# are then registered in a newly created registry. The resulting +# registries after some selections of packages have been added have +# also been stored and are compared against. +# +# The project files have been extracted from the git history of the +# Flux and Images packages. The patch numbers have been faked to get +# more version samples out of their git histories. The FirstTest1 +# project file is derived from this package. + +# Set up packages and registry directories in a temporary location. +if VERSION >= v"1.2" + testdir = mktempdir(prefix = "LocalRegistryTests") +else + testdir = mktempdir() +end +packages_dir = joinpath(testdir, "packages") +if packages_dir ∉ LOAD_PATH + push!(LOAD_PATH, packages_dir) +end +registry_dir = joinpath(testdir, "TestRegistry") + +# Create a new registry. +create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git", + description = "For testing purposes only.", + uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369", + gitconfig = TEST_GITCONFIG, push = false) + +# Add the FirstTest1 package and check against the stored `registry1`. +prepare_package(packages_dir, "FirstTest1.toml") +using FirstTest +register(FirstTest, registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) +@test check_result(registry_dir, "registry1") + +# Reregister the same version of FirstTest to verify that nothing +# happens, +@test_logs (:info, "This version has already been registered and is unchanged.") register(FirstTest, registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false) +@test check_result(registry_dir, "registry1") + +# Add 29 versions of the Flux project files and check against `registry2`. +for n = 1:29 + prepare_package(packages_dir, "Flux$(n).toml") + using Flux + register(Flux, registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) +end +@test check_result(registry_dir, "registry2") + +# Add 15 versions of the Images project files and check against `registry3`. +for n = 1:15 + prepare_package(packages_dir, "Images$(n).toml") + using Images + register(Images, registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) +end +@test check_result(registry_dir, "registry3") + +# Start over with a fresh registry and add all 46 project files but in +# shuffled order. Check that this also matches `registry3`. +registry_dir = joinpath(testdir, "test2", "TestRegistry") +create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git", + description = "For testing purposes only.", + uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369", + gitconfig = TEST_GITCONFIG, push = false) +project_files = vcat("FirstTest1.toml", + ["Flux$(n).toml" for n = 1:29], + ["Images$(n).toml" for n = 1:15]) +Random.seed!(13) +shuffle!(project_files) +for project_file in project_files + prepare_package(packages_dir, project_file) + package = match(r"[a-zA-Z]+", project_file).match + # Register by path instead of module in this test. + register(joinpath(packages_dir, package), registry = registry_dir, + gitconfig = TEST_GITCONFIG, push = false) +end +@test check_result(registry_dir, "registry3") + +pop!(LOAD_PATH) diff --git a/test/runtests.jl b/test/runtests.jl index fd957fd..1a3416b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,10 @@ using LocalRegistry -using LocalRegistry: find_package_path, find_registry_path +using LocalRegistry: find_package_path, find_registry_path, check_git_registry, + do_register using Test using Random using Pkg +using CodecZlib const TEST_GITCONFIG = Dict( "user.name" => "LocalRegistryTests", @@ -15,8 +17,9 @@ include("utils.jl") # want interference from, e.g. the General registry, use a temporary # DEPOT_PATH. But first add some packages while we have the General # registry available. These will be used for some tests later. -pkg"add AutoHashEquals" -pkg"dev --local Multibreak" +Pkg.add("AutoHashEquals") +# Same as `pkg"dev --local Multibreak"` but properly using the API function. +Pkg.develop("Multibreak", shared = false) empty!(DEPOT_PATH) depot_path = mktempdir(@__DIR__) push!(DEPOT_PATH, depot_path) @@ -25,328 +28,24 @@ push!(DEPOT_PATH, depot_path) # contain fake URLs. Pkg.UPDATED_REGISTRY_THIS_SESSION[] = true -# The following tests are primarily regression tests - checking that -# the results are the same as when the tests were written, regardless -# of correctness. -# -# The general strategy is that a number of project files have been -# stored. These are read and expanded to minimal stub packages, which -# are then registered in a newly created registry. The resulting -# registries after some selections of packages have been added have -# also been stored and are compared against. -# -# The project files have been extracted from the git history of the -# Flux and Images packages. The patch numbers have been faked to get -# more version samples out of their git histories. The FirstTest1 -# project file is derived from this package. - -# Set up packages and registry directories in a temporary location. -if VERSION >= v"1.2" - testdir = mktempdir(prefix = "LocalRegistryTests") -else - testdir = mktempdir() -end -packages_dir = joinpath(testdir, "packages") -if packages_dir ∉ LOAD_PATH - push!(LOAD_PATH, packages_dir) -end -registry_dir = joinpath(testdir, "TestRegistry") - -# Create a new registry. -create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git", - description = "For testing purposes only.", - uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369", - gitconfig = TEST_GITCONFIG, push = false) - -# Add the FirstTest1 package and check against the stored `registry1`. -prepare_package(packages_dir, "FirstTest1.toml") -using FirstTest -register(FirstTest, registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) -@test check_result(registry_dir, "registry1") - -# Reregister the same version of FirstTest to verify that nothing -# happens, -@test_logs (:info, "This version has already been registered and is unchanged.") register(FirstTest, registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false) -@test check_result(registry_dir, "registry1") - -# Add 29 versions of the Flux project files and check against `registry2`. -for n = 1:29 - prepare_package(packages_dir, "Flux$(n).toml") - using Flux - register(Flux, registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) +@testset "Regression tests" begin + include("regression.jl") end -@test check_result(registry_dir, "registry2") -# Add 15 versions of the Images project files and check against `registry3`. -for n = 1:15 - prepare_package(packages_dir, "Images$(n).toml") - using Images - register(Images, registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) +@testset "Register tests" begin + include("register.jl") end -@test check_result(registry_dir, "registry3") -# Start over with a fresh registry and add all 46 project files but in -# shuffled order. Check that this also matches `registry3`. -registry_dir = joinpath(testdir, "test2", "TestRegistry") -create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git", - description = "For testing purposes only.", - uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369", - gitconfig = TEST_GITCONFIG, push = false) -project_files = vcat("FirstTest1.toml", - ["Flux$(n).toml" for n = 1:29], - ["Images$(n).toml" for n = 1:15]) -Random.seed!(13) -shuffle!(project_files) -for project_file in project_files - prepare_package(packages_dir, project_file) - package = match(r"[a-zA-Z]+", project_file).match - # Register by path instead of module in this test. - register(joinpath(packages_dir, package), registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) +@testset "Find package path" begin + include("find_package_path.jl") end -@test check_result(registry_dir, "registry3") - -# Trying to register an already existing version with different content. -prepare_package(packages_dir, "Flux30.toml") -@test_throws ErrorException register(joinpath(packages_dir, "Flux"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) -# Parse error in compat section. -prepare_package(packages_dir, "Broken1.toml") -if VERSION < v"1.2" - @test_throws ErrorException register(joinpath(packages_dir, "Broken"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) -else - @test_throws Pkg.Types.PkgError register(joinpath(packages_dir, "Broken"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) +@testset "Find registry path" begin + include("find_registry_path.jl") end -# Trying to change name (UUID remains). -prepare_package(packages_dir, "Fluxx1.toml") -@test_throws ErrorException register(joinpath(packages_dir, "Fluxx"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) - -# Trying to change UUID. -prepare_package(packages_dir, "Flux31.toml") -@test_throws ErrorException register(joinpath(packages_dir, "Flux"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) - -# Depends on itself. -prepare_package(packages_dir, "Broken2.toml") -@test_throws ErrorException register(joinpath(packages_dir, "Broken"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) - -# Incorrect name of dependency. -prepare_package(packages_dir, "Broken3.toml") -@test_throws ErrorException register(joinpath(packages_dir, "Broken"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) - -# TODO: This should really be an error but RegistryTools 1.3.0 doesn't catch it. -# Incorrect UUID of dependency. -prepare_package(packages_dir, "Broken4.toml") -register(joinpath(packages_dir, "Broken"), registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) - -# Incorrect UUID of stdlib. -prepare_package(packages_dir, "Broken5.toml") -@test_throws ErrorException register(joinpath(packages_dir, "Broken"), - registry = registry_dir, - gitconfig = TEST_GITCONFIG, - push = false) - -# Change the git remote before registration and verify that the -# registered repo is not changed. -prepare_package(packages_dir, "Flux32.toml") -package_dir = joinpath(packages_dir, "Flux") -git = gitcmd(package_dir, TEST_GITCONFIG) -package_file = joinpath(registry_dir, "F", "Flux", "Package.toml") -old_repo = TOML.parsefile(package_file)["repo"] -new_repo = "https://example.com/Julia/Flux.jl.git" -run(`$git remote set-url origin $(new_repo)`) -register(joinpath(packages_dir, "Flux"), registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) -@test TOML.parsefile(package_file)["repo"] == old_repo - -# Register with explicit repo argument and verify that the registered -# repo is updated. -prepare_package(packages_dir, "Flux33.toml") -register(joinpath(packages_dir, "Flux"), registry = registry_dir, - repo = new_repo, gitconfig = TEST_GITCONFIG, push = false) -@test TOML.parsefile(package_file)["repo"] == new_repo - -pop!(LOAD_PATH) - -# Register a package in a subdirectory of a git repository. Also add -# some dirt outside the subdirectory to verify that it is ignored. -prepare_package(packages_dir, "SubdirTest1.toml", "subdir") -write(joinpath(packages_dir, "SubdirTest", "README.md"), "dirty") -register(joinpath(packages_dir, "SubdirTest", "subdir"), - registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false) -package_file = joinpath(registry_dir, "S", "SubdirTest", "Package.toml") -@test TOML.parsefile(package_file)["subdir"] == "subdir" - -# Register a package with a JuliaProject.toml rather than a Project.toml. -prepare_package(packages_dir, "JuliaProjectTest1.toml", - use_julia_project = true) -register(joinpath(packages_dir, "JuliaProjectTest"), registry = registry_dir, - gitconfig = TEST_GITCONFIG, push = false) -@test isfile(joinpath(registry_dir, "J", "JuliaProjectTest", "Package.toml")) - -# Test automatic push functionality. The sequence of events is: -# 1. Create a bare "upstream" repository. -# 2. Create a new registry with the upstream as repo and `push = true`. -# 3. Register a package with `push = true`. -# 4. Verify that the registry and the upstream repo has the same two commits. -upstream_dir = joinpath(testdir, "upstream") -mkpath(upstream_dir) -upstream_git = gitcmd(upstream_dir, TEST_GITCONFIG) -run(`$(upstream_git) init --bare`) -registry_push_dir = joinpath(testdir, "TestRegistryPush") -create_registry(registry_push_dir, "file://$(upstream_dir)", push = true, - gitconfig = TEST_GITCONFIG) -downstream_git = gitcmd(registry_push_dir, TEST_GITCONFIG) -register(joinpath(packages_dir, "FirstTest"), registry = registry_push_dir, - push = true, gitconfig = TEST_GITCONFIG) -@test readchomp(`$(downstream_git) log`) == readchomp(`$(upstream_git) log`) -@test length(readlines(`$(upstream_git) log --format=oneline`)) == 2 - - - -# Additional tests of `find_package_path` and `find_registry_path`. -# Many of these have the purpose to cover error cases, making them -# somewhat contrived. Another complicating factor is that some of the -# call variants have to interact with the package environment, -# including registries, of the running Julia process. - -# Prepare by adding the registry used in previous tests. -# TODO: Needed in Julia 1.7.0-DEV.1046. Check if the `mkdir` can be -# removed for the final Julia 1.7. -mkdir(joinpath(depot_path, "registries")) -Pkg.Registry.add(RegistrySpec(path = registry_dir)) - -# Use Multibreak as Guinea pig. The sleep is a Travis workaround. See -# a later comment. This also tests automatically choosing the only -# installed registry for a new package. -sleep(1) -register("Multibreak", push = false, gitconfig = TEST_GITCONFIG) - -# Directory already exists. Also tests code handling a trailing slash. -create_registry("TestRegistry2", "", gitconfig = TEST_GITCONFIG, push = false) -@test_throws ErrorException create_registry("TestRegistry2/", "", - gitconfig = TEST_GITCONFIG, - push = false) - -# Not a developed package. -@test_throws ErrorException find_package_path("AutoHashEquals") - -# Not a registered package. -pkg = Pkg.Types.Project(Dict("name" => "UUIDs", - "uuid" => "cf7118a7-6976-5b1a-9a39-7adc72f591a4")) -@test_throws ErrorException find_registry_path(nothing, pkg) - -# Find package by module and path. -using Multibreak -package_path = find_package_path(Multibreak) -@test find_package_path(package_path) == package_path - -# Find package by name. -if Base.Sys.islinux() - @test find_package_path("Multibreak") == package_path -else - # Workaround for CI path weirdnesses on Windows and Mac. - @test splitpath(package_path)[end-2:end] == splitpath(find_package_path("Multibreak"))[end-2:end] -end - -# Not a package path. -corrupt_path = joinpath(package_path, "no_such_dir") -@test_throws ErrorException find_package_path(corrupt_path) - -# Unknown package. -@test_throws ErrorException find_package_path("ZeroethTest") - -# Find a registry by name. -pkg = Pkg.Types.read_project(joinpath(package_path, "Project.toml")) -@test find_registry_path("TestRegistry") == joinpath(first(DEPOT_PATH), - "registries", - "TestRegistry") - -# The named registry does not exist. -@test_throws ErrorException find_registry_path("General", pkg) - -# Find which registry contains a package. -@test find_registry_path(nothing, pkg) == joinpath(first(DEPOT_PATH), - "registries", "TestRegistry") - -# Workaround for bad `mtime` resolution of 1 second on MacOS workers -# on Travis. -# -# The issue is that `read_registry` caches its results with respect to -# the file `mtime`. Since `read_registry` is called from within -# `register`, the old data will be read into the cache. If the new -# data is written close enough to the previous registry update so that -# `mtime` does not change, subsequent `read_registry` will keep using -# the old data from the cache. -sleep(1) - -# More than one registry contains the package. -register("Multibreak", registry = "TestRegistry2", - repo = "file://$(packages_dir)/FirstTest", - gitconfig = TEST_GITCONFIG, push = false) -@test_throws ErrorException find_registry_path(nothing, pkg) - -# Dirty the registry repository and try to register a package. -registry_path = find_registry_path("TestRegistry2") -filename = joinpath(registry_path, "Registry.toml") -open(filename, "a") do io - write(io, "\n") -end -@test_throws ErrorException register("Multibreak", registry = "TestRegistry2", - gitconfig = TEST_GITCONFIG, push = false) - -# Remove Project.toml from a package and try to register. -mv(joinpath(package_path, "Project.toml"), - joinpath(package_path, "Project.txt")) -@test_throws ErrorException register("Multibreak", registry = "TestRegistry2", - gitconfig = TEST_GITCONFIG, push = false) -mv(joinpath(package_path, "Project.txt"), - joinpath(package_path, "Project.toml")) - -# Dirty the package repository and try to register the package. -package_path = find_package_path("Multibreak") -filename = joinpath(package_path, "README.md") -open(filename, "a") do io - write(io, "\n") -end -@test_throws ErrorException register("Multibreak", registry = "TestRegistry2", - gitconfig = TEST_GITCONFIG, push = false) - -# Current active environment is not a package. -@test_throws ErrorException find_package_path(nothing) - -# Activate a package directory and find it with `find_package_path`. -Pkg.activate("Multibreak") -if Base.Sys.islinux() - @test find_package_path(nothing) == package_path -else - # Workaround for CI path weirdnesses on Windows and Mac. - @test splitpath(package_path)[end-2:end] == splitpath(find_package_path(nothing))[end-2:end] +@testset "Check git registry" begin + include("check_git_registry.jl") end if VERSION < v"1.2" diff --git a/test/utils.jl b/test/utils.jl index 255830f..af265f0 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -150,3 +150,27 @@ function sanity_check_registry(path) return true end + +function with_testdir(f::Function) + if VERSION >= v"1.2" + testdir = mktempdir(prefix = "LocalRegistryTests") + else + testdir = mktempdir() + end + f(testdir) + rm(testdir, recursive = true) +end + +function with_empty_registry(f::Function) + with_testdir() do testdir + registry_dir = joinpath(testdir, "TestRegistry") + packages_dir = joinpath(testdir, "packages") + + # Create a new registry. + create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git", + description = "For testing purposes only.", + uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369", + gitconfig = TEST_GITCONFIG, push = false) + f(registry_dir, packages_dir) + end +end