Add per-plugin validation at template construction time
This commit is contained in:
parent
385195c6b5
commit
fd995a05bc
@ -17,9 +17,25 @@ Plugin
|
||||
BasicPlugin
|
||||
```
|
||||
|
||||
## Package Generation Pipeline
|
||||
## Template + Package Creation Pipeline
|
||||
|
||||
The package generation process looks basically like this:
|
||||
|
||||
The [`Template`](@ref) constructor basically does this:
|
||||
|
||||
```
|
||||
- extract values from keyword arguments
|
||||
- create a Template from the values
|
||||
- validate each plugin against the constructed Template
|
||||
```
|
||||
|
||||
The plugin validation step uses the [`validate`](@ref) function.
|
||||
It lets us catch mistakes before we try to generate packages.
|
||||
|
||||
```@docs
|
||||
validate
|
||||
```
|
||||
|
||||
The package generation process looks like this:
|
||||
|
||||
```
|
||||
- create empty directory for the package
|
||||
@ -31,7 +47,6 @@ The package generation process looks basically like this:
|
||||
- run plugin posthook
|
||||
```
|
||||
|
||||
That's it!
|
||||
As you can tell, plugins play a central role in setting up a package.
|
||||
|
||||
The three main entrypoints for plugins to do work are the [`prehook`](@ref), the [`hook`](@ref), and the [`posthook`](@ref).
|
||||
@ -151,6 +166,14 @@ struct Git <: Plugin end
|
||||
|
||||
priority(::Git, ::typeof(posthook)) = 5
|
||||
|
||||
function validate(::Git, ::Template)
|
||||
foreach(("user.name", "user.email")) do k
|
||||
if isempty(LibGit2.getconfig(k, ""))
|
||||
throw(ArgumentError("Git: Global Git config is missing required value '$k'"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function prehook(::Git, t::Template, pkg_dir::AbstractString)
|
||||
LibGit2.with(LibGit2.init(pkg_dir)) do repo
|
||||
LibGit2.commit(repo, "Initial commit")
|
||||
@ -174,8 +197,9 @@ function posthook(::Git, ::Template, pkg_dir::AbstractString)
|
||||
end
|
||||
```
|
||||
|
||||
All three hooks are implemented:
|
||||
Validation and all three hooks are implemented:
|
||||
|
||||
- [`validate`](@ref) makes sure that all required Git configuration is present.
|
||||
- [`prehook`](@ref) creates the Git repository for the package.
|
||||
- [`hook`](@ref) generates the `.gitignore` file, using the special [`gitignore`](@ref) function.
|
||||
- [`posthook`](@ref) adds and commits all the generated files.
|
||||
@ -286,8 +310,8 @@ function hook(p::Tests, t::Template, pkg_dir::AbstractString)
|
||||
end
|
||||
```
|
||||
|
||||
There is also a default [`prehook`](@ref) implementation for [`BasicPlugin`](@ref)s, which checks that the plugin's [`source`](@ref) file exists, and throws an `ArgumentError` otherwise.
|
||||
If you want to extend the prehook but keep the file existence check, use the `invoke` method as described above.
|
||||
There is also a default [`validate`](@ref) implementation for [`BasicPlugin`](@ref)s, which checks that the plugin's [`source`](@ref) file exists, and throws an `ArgumentError` otherwise.
|
||||
If you want to extend the validation but keep the file existence check, use the `invoke` method as described above.
|
||||
|
||||
For more examples, see the plugins in the [Continuous Integration (CI)](@ref) and [Code Coverage](@ref) sections.
|
||||
|
||||
|
@ -134,6 +134,15 @@ function badges(p::Plugin, t::Template, pkg::AbstractString)
|
||||
return map(b -> render_text(string(b), combined_view(p, t, pkg)), bs)
|
||||
end
|
||||
|
||||
"""
|
||||
validate(::Plugin, ::Template)
|
||||
|
||||
Perform any required validation for a [`Plugin`](@ref).
|
||||
|
||||
It is preferred to do validation here instead of in [`prehook`](@ref), because this function is called at [`Template`](@ref) construction time, whereas the prehook is only run at package generation time.
|
||||
"""
|
||||
validate(::Plugin, ::Template) = nothing
|
||||
|
||||
"""
|
||||
prehook(::Plugin, ::Template, pkg_dir::AbstractString)
|
||||
|
||||
@ -168,7 +177,7 @@ At this point, both the [`prehook`](@ref)s and [`hook`](@ref)s have run.
|
||||
"""
|
||||
posthook(::Plugin, ::Template, ::AbstractString) = nothing
|
||||
|
||||
function prehook(p::T, ::Template, ::AbstractString) where T <: BasicPlugin
|
||||
function validate(p::T, ::Template) where T <: BasicPlugin
|
||||
src = source(p)
|
||||
src === nothing && return
|
||||
isfile(src) || throw(ArgumentError("$(nameof(T)): The file $src does not exist"))
|
||||
|
@ -89,6 +89,16 @@ function view(p::Documenter{TravisCI}, t::Template, pkg::AbstractString)
|
||||
return merge(base, Dict("HAS_DEPLOY" => true))
|
||||
end
|
||||
|
||||
foreach((TravisCI, GitLabCI)) do T
|
||||
@eval function validate(::Documenter{$T}, t::Template)
|
||||
if !hasplugin(t, $T)
|
||||
name = nameof($T)
|
||||
s = "Documenter: The $name plugin must be included for docs deployment to be set up"
|
||||
throw(ArgumentError(s))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function hook(p::Documenter, t::Template, pkg_dir::AbstractString)
|
||||
pkg = basename(pkg_dir)
|
||||
docs_dir = joinpath(pkg_dir, "docs")
|
||||
|
@ -30,11 +30,20 @@ function gitignore(p::Git)
|
||||
return ignore
|
||||
end
|
||||
|
||||
# Set up the Git repository.
|
||||
function prehook(p::Git, t::Template, pkg_dir::AbstractString)
|
||||
function validate(p::Git, t::Template)
|
||||
if p.gpgsign && try run(pipeline(`git --version`; stdout=devnull)); false catch; true end
|
||||
throw(ArgumentError("Git: gpgsign is set but the Git CLI is not installed"))
|
||||
end
|
||||
|
||||
foreach(("user.name", "user.email")) do k
|
||||
if isempty(LibGit2.getconfig(k, ""))
|
||||
throw(ArgumentError("Git: Global Git config is missing required value '$k'"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Set up the Git repository.
|
||||
function prehook(p::Git, t::Template, pkg_dir::AbstractString)
|
||||
LibGit2.with(LibGit2.init(pkg_dir)) do repo
|
||||
commit(p, repo, pkg_dir, "Initial commit")
|
||||
pkg = basename(pkg_dir)
|
||||
|
@ -24,6 +24,5 @@ view(::SrcDir, ::Template, pkg::AbstractString) = Dict("PKG" => pkg)
|
||||
# Update the destination now that we know the package name.
|
||||
# Kind of hacky, but oh well.
|
||||
function prehook(p::SrcDir, t::Template, pkg_dir::AbstractString)
|
||||
invoke(prehook, Tuple{BasicPlugin, Template, AbstractString}, p, t, pkg_dir)
|
||||
p.destination = joinpath("src", basename(pkg_dir) * ".jl")
|
||||
end
|
||||
|
@ -23,8 +23,8 @@ source(p::Tests) = p.file
|
||||
destination(::Tests) = joinpath("test", "runtests.jl")
|
||||
view(::Tests, ::Template, pkg::AbstractString) = Dict("PKG" => pkg)
|
||||
|
||||
function prehook(p::Tests, t::Template, pkg_dir::AbstractString)
|
||||
invoke(prehook, Tuple{BasicPlugin, Template, AbstractString}, p, t, pkg_dir)
|
||||
function validate(p::Tests, t::Template)
|
||||
invoke(validate, Tuple{BasicPlugin, Template}, p, t)
|
||||
p.project && t.julia < v"1.2" && @warn string(
|
||||
"Tests: The project option is set to create a project (supported in Julia 1.2 and later) ",
|
||||
"but a Julia version older than 1.2 is supported by the Template.",
|
||||
|
@ -85,7 +85,9 @@ function Template(::Val{false}; kwargs...)
|
||||
end
|
||||
end
|
||||
|
||||
return Template(authors, dir, host, julia, plugins, user)
|
||||
t = Template(authors, dir, host, julia, plugins, user)
|
||||
foreach(p -> validate(p, t), t.plugins)
|
||||
return t
|
||||
end
|
||||
|
||||
"""
|
||||
|
@ -46,13 +46,19 @@
|
||||
end
|
||||
|
||||
@testset "hasplugin" begin
|
||||
t = tpl(; plugins=[Documenter{TravisCI}()])
|
||||
t = tpl(; plugins=[TravisCI(), Documenter{TravisCI}()])
|
||||
@test PT.hasplugin(t, typeof(first(PT.default_plugins())))
|
||||
@test PT.hasplugin(t, Documenter)
|
||||
@test PT.hasplugin(t, PT.is_ci)
|
||||
@test PT.hasplugin(t, _ -> true)
|
||||
@test !PT.hasplugin(t, _ -> false)
|
||||
@test !PT.hasplugin(t, Citation)
|
||||
@test !PT.hasplugin(t, PT.is_ci)
|
||||
end
|
||||
|
||||
@testset "validate" begin
|
||||
mock(LibGit2.getconfig => (_k, _d) -> "") do _gc
|
||||
@test_throws ArgumentError tpl(; plugins=[Git()])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user