diff --git a/Project.toml b/Project.toml index ac0ddbf..5f61b62 100644 --- a/Project.toml +++ b/Project.toml @@ -5,17 +5,15 @@ version = "0.7.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] -julia = "1" Mustache = ">= 0.5.13" +julia = "1" [extras] Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/README.md b/README.md index 5232e88..8ede901 100644 --- a/README.md +++ b/README.md @@ -47,16 +47,10 @@ t = Template(; Codecov(), TravisCI(; x86=true), Documenter{TravisCI}(), -o ], + ], ) ``` -You can also create a `Template` interactively by following a set of prompts: - -```jl -julia> t = Template(; interactive=true) -``` - --- For a much more detailled overview, please see the documentation. diff --git a/docs/src/developer.md b/docs/src/developer.md index e1f7147..a049b15 100644 --- a/docs/src/developer.md +++ b/docs/src/developer.md @@ -19,7 +19,6 @@ BasicPlugin ## Template + Package Creation Pipeline - The [`Template`](@ref) constructor basically does this: ``` @@ -76,7 +75,7 @@ To understand how they're implemented, let's look at simplified versions of two ### Example: `Documenter` ```julia -@with_defaults struct Documenter <: Plugin +@with_kw_noshow struct Documenter <: Plugin make_jl::String = default_file("docs", "make.jl") <- "Path to make.jl template" index_md::String = default_file("docs", "src", "index.md") <- "Path to index.md template" end @@ -118,14 +117,8 @@ function hook(p::Documenter, t::Template, pkg_dir::AbstractString) end ``` -The first thing you'll notice is the strange struct definition with [`@with_defaults`](@ref). - -```@docs -@with_defaults -interactive -``` - -Inside of our struct definition we're using [`default_file`](@ref) to refer to files in this repository. +The `@with_kw_noshow` macro defines keyword constructors for us. +Inside of our struct definition, we're using [`default_file`](@ref) to refer to files in this repository. ```@docs default_file diff --git a/docs/src/migrating.md b/docs/src/migrating.md index fd9f1f0..f2d0e5b 100644 --- a/docs/src/migrating.md +++ b/docs/src/migrating.md @@ -43,16 +43,11 @@ One less name to remember! ## Interactive Templates -Two less names to remember! - -| Old | New | -| :--------------------: | :---------------------------------: | -| `interactive_template` | `Template(; interactive=true)` | -| `generate_interactive` | `Template(; interactive=true)(pkg)` | +Currently not implemented, but will be in the future. ## Other Functions -Another two less names to remember! +Two less names to remember! Although it's unlikely that anyone used these. | Old | New | diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 2f22247..5221245 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -4,14 +4,12 @@ using Base: active_project using Base.Filesystem: contractuser using Dates: month, today, year -using InteractiveUtils: subtypes using LibGit2: LibGit2, GitRemote, GitRepo using Pkg: Pkg, TOML, PackageSpec -using REPL.TerminalMenus: MultiSelectMenu, RadioMenu, request using UUIDs: uuid4 using Mustache: render -using Parameters: with_kw +using Parameters: @with_kw_noshow export Template, @@ -43,7 +41,6 @@ abstract type Plugin end include("template.jl") include("plugin.jl") include("show.jl") -include("interactive.jl") # Run some function with a project activated at the given path. function with_project(f::Function, path::AbstractString) diff --git a/src/interactive.jl b/src/interactive.jl deleted file mode 100644 index a26414a..0000000 --- a/src/interactive.jl +++ /dev/null @@ -1,172 +0,0 @@ -""" - interactive(::Type{T<:Plugin}) -> T - -Create a [`Plugin`](@ref) of type `T` interactively from user input. -""" -function interactive(::Type{T}) where T <: Plugin - kwargs = Dict{Symbol, Any}() - - foreach(fieldnames(T)) do name - F = fieldtype(T, name) - v = Val(name) - required = !applicable(defaultkw, T, v) - default = required ? defaultkw(F) : defaultkw(T, v) - kwargs[name] = if applicable(prompt, T, v) - prompt(F, "$T: $(prompt(T, v))", default, required=required) - elseif required - prompt(F, "$T: Value for field '$name' ($F)", default; required=required) - else - default - end - end - - return T(; kwargs...) -end - -leaves(T::Type) = isconcretetype(T) ? [T] : vcat(map(leaves, subtypes(T))...) - -function plugin_types() - Ts = leaves(Plugin) - # Hack both Documenter types into the list. - # Unfortunately there's no way to do this automatically, - # but it's unlikely for more parametric plugin types to exist. - push!(Ts, Documenter{TravisCI}, Documenter{GitLabCI}) - return Ts -end - -function Template(::Val{true}; kwargs...) - opts = Dict{Symbol, Any}(kwargs) - - if !haskey(opts, :user) - default = defaultkw(Template, :user) - opts[:user] = prompt(String, "Git hosting service username", default) - end - - if !haskey(opts, :host) - default = defaultkw(Template, :host) - opts[:host] = prompt(String, "Git hosting service URL", default) - end - - if !haskey(opts, :authors) - default = defaultkw(Template, :authors) - opts[:authors] = prompt(String, "Package author(s)", default) - end - - if !haskey(opts, :dir) - default = defaultkw(Template, :dir) - opts[:dir] = prompt(String, "Path to package parent directory", default) - end - - if !haskey(opts, :julia) - default = defaultkw(Template, :julia) - opts[:julia] = prompt(VersionNumber, "Supported Julia version", default) - end - - if !haskey(opts, :disable_defaults) - available = map(typeof, default_plugins()) - initial = defaultkw(Template, :disable_defaults) - opts[:disable_defaults] = select("Select defaults to disable:", available, initial) - end - - if !haskey(opts, :plugins) - # Don't offer any disabled plugins as options. - available = setdiff(sort(plugin_types(); by=string), opts[:disable_defaults]) - initial = setdiff(map(typeof, default_plugins()), opts[:disable_defaults]) - chosen = select("Select plugins", available, initial) - opts[:plugins] = map(interactive, chosen) - end - - return Template(Val(false); opts...) -end - -defaultkw(::Type{String}) = "" -defaultkw(::Type{Union{T, Nothing}}) where T = nothing -defaultkw(::Type{T}) where T <: Number = zero(T) -defaultkw(::Type{Vector{T}}) where T = T[] - -function prompt( - ::Type{<:Union{String, Nothing}}, s::AbstractString, default; - required::Bool=false, -) - default isa AbstractString && (default = contractuser(default)) - default_display = if required - "REQUIRED" - elseif default === nothing - "None" - else - repr(default) - end - - print("$s [$default_display]: ") - input = strip(readline()) - - return if isempty(input) && required - println("This option is required") - prompt(String, s, default; required=required) - elseif isempty(input) - default - else - input - end -end - -function prompt( - ::Type{VersionNumber}, s::AbstractString, default::VersionNumber; - required::Bool=false, -) - v = prompt(String, s, default; required=required) - return if v isa VersionNumber - v - else - startswith(v, "v") && (v = v[2:end]) - v = replace(v, "\"" => "") - VersionNumber(v) - end -end - -function prompt(::Type{Bool}, s::AbstractString, default::Bool; required::Bool=false) - b = prompt(String, s, default; required=required) - return b === default ? default : uppercase(b) in ("Y", "YES", "T", "TRUE") -end - -function prompt(::Type{Vector}, s::AbstractString, default::Vector; required::Bool=false) - return prompt(Vector{String}, s, default; required=required) -end - -function prompt( - ::Type{Vector{String}}, s::AbstractString, default::Vector{<:AbstractString}; - required::Bool=false, -) - s = prompt(String, "$s (comma-delimited)", join(default, ", "); required=required) - return convert(Vector{String}, map(strip, split(s, ","; keepempty=false))) -end - -function prompt(::Type{<:Dict}, s::AbstractString, default::Dict, required::Bool=false) - default_display = join(map(p -> "$(p.first)=$(p.second)", collect(default)), ", ") - s = prompt(String, "$s (k=v, comma-delimited)", default_display; required=required) - return if isempty(s) - Dict{String, String}() - else - Dict{String, String}(Pair(split(strip(kv), "=")...) for kv in split(s, ",")) - end -end - -# TODO: These can be made simpler when this is merged: -# https://github.com/JuliaLang/julia/pull/30043 - -select(s::AbstractString, xs::Vector, initial) = select(string, s, xs, initial) - -# Select any number of elements from a collection. -function select(f::Function, s::AbstractString, xs::Vector, initial::Vector) - m = MultiSelectMenu(map(f, xs); pagesize=length(xs)) - foreach(x -> push!(m.selected, findfirst(==(x), xs)), initial) - selection = request("$s:", m) - return map(i -> xs[i], collect(selection)) -end - -# Select one item frm oa collection. -function select(f::Function, s::AbstractString, xs::Vector, initial) - print(stdin.buffer, repeat("\e[B", findfirst(==(initial), xs) - 1)) - selection = request("$s:", RadioMenu(map(f, xs); pagesize=length(xs))) - return xs[selection] -end diff --git a/src/plugin.jl b/src/plugin.jl index 2eefa86..00fddc9 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -1,47 +1,6 @@ const TEMPLATES_DIR = normpath(joinpath(@__DIR__, "..", "templates")) const DEFAULT_PRIORITY = 1000 -""" - @with_defaults struct T #= ... =# end - -Creates keyword constructors and generates methods needed to interactively create instances with [`interactive`](@ref). - -## Example - -```julia -struct Foo <: Plugin - file::String = "/the/default/value" <- "This is the interactive prompt" - n::Int <- "This one has no default, so it's a required keyword" - abc::String = "No prompt, so the default is always taken in interactive mode" - xyz::String # Required keyword, with a generic interactive prompt. -end -``` -""" -macro with_defaults(ex::Expr) - T = esc(ex.args[2].args[1]) # This assumes T <: U. - - # This is a bit nasty. - funcs = Expr[] - foreach(filter(arg -> arg isa Expr, ex.args[3].args)) do arg - if iscall(arg, :<) && iscall(arg.args[3], :-) # x::T <- "prompt" - name = QuoteNode(arg.args[2].args[1]) - prompt = arg.args[2] - push!(funcs, :(PkgTemplates.prompt(::Type{$T}, ::Val{$name}) = $(esc(prompt)))) - elseif arg.head === :(=) - rhs = arg.args[2] - name = QuoteNode(arg.args[1].args[1]) - if iscall(rhs, :<) && iscall(rhs.args[3], :-) # x::T = "foo" <- "prompt" - prompt = rhs.args[3].args[2] - push!(funcs, :(PkgTemplates.prompt(::Type{$T}, ::Val{$name}) = $(esc(prompt)))) - end - default = arg.args[2] = rhs.args[2] - push!(funcs, :(PkgTemplates.defaultkw(::Type{$T}, ::Val{$name}) = $(esc(default)))) - end - end - - return Expr(:block, esc(with_kw(ex, __module__, false)), funcs...) -end - """ A simple plugin that, in general, creates a single file. """ @@ -276,11 +235,6 @@ If you are implementing a plugin that uses the `user` field of a [`Template`](@r """ needs_username(::Plugin) = false -function prompt end - -iscall(x, ::Symbol) = false -iscall(ex::Expr, s::Symbol) = ex.head === :call && ex.args[1] === s - include(joinpath("plugins", "project_file.jl")) include(joinpath("plugins", "src_dir.jl")) include(joinpath("plugins", "tests.jl")) diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index a9ce0fc..23d3e21 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -9,6 +9,7 @@ format_version(v::AbstractString) = string(v) const ALLOWED_FAILURES = ["1.3", "nightly"] # TODO: Update this list with new RCs. const DEFAULT_CI_VERSIONS = map(format_version, [default_version(), VERSION, "nightly"]) +const DEFAULT_CI_VERSIONS_NO_NIGHTLY = map(format_version, [default_version(), VERSION]) const EXTRA_VERSIONS_DOC = "- `extra_versions::Vector`: Extra Julia versions to test, as strings or `VersionNumber`s." """ @@ -44,14 +45,14 @@ Integrates your packages with [Travis CI](https://travis-ci.com). - `coverage::Bool`: Whether or not to publish code coverage (another code coverage plugin such as [`Codecov`](@ref) must also be included). $EXTRA_VERSIONS_DOC """ -@with_defaults struct TravisCI <: BasicPlugin - file::String = default_file("travis.yml") <- "Path to .travis.yml template" - linux::Bool = true <- "Enable Linux bulds" - osx::Bool = true <- "Enable OSX builds" - windows::Bool = true <- "Enable Windows builds" - x86::Bool = false <- "Enable 32-bit builds" - coverage::Bool = true <- "Enable code coverage submission" - extra_versions::Vector = DEFAULT_CI_VERSIONS <- "Extra Julia versions to test" +@with_kw_noshow struct TravisCI <: BasicPlugin + file::String = default_file("travis.yml") + linux::Bool = true + osx::Bool = true + windows::Bool = true + x86::Bool = false + coverage::Bool = true + extra_versions::Vector = DEFAULT_CI_VERSIONS end source(p::TravisCI) = p.file @@ -113,11 +114,11 @@ Integrates your packages with [AppVeyor](https://appveyor.com) via [AppVeyor.jl] - `coverage::Bool`: Whether or not to publish code coverage ([`Codecov`](@ref) must also be included). $EXTRA_VERSIONS_DOC """ -@with_defaults struct AppVeyor <: BasicPlugin - file::String = default_file("appveyor.yml") <- "Path to .appveyor.yml template" - x86::Bool = false <- "Enable 32-bit builds" - coverage::Bool = true <- "Enable code coverage submission" - extra_versions::Vector = DEFAULT_CI_VERSIONS <- "Extra Julia versions to test" +@with_kw_noshow struct AppVeyor <: BasicPlugin + file::String = default_file("appveyor.yml") + x86::Bool = false + coverage::Bool = true + extra_versions::Vector = DEFAULT_CI_VERSIONS end source(p::AppVeyor) = p.file @@ -166,11 +167,11 @@ $EXTRA_VERSIONS_DOC !!! note Code coverage submission from Cirrus CI is not yet supported by [Coverage.jl](https://github.com/JuliaCI/Coverage.jl). """ -@with_defaults struct CirrusCI <: BasicPlugin - file::String = default_file("cirrus.yml") <- "Path to .cirrus.yml template" - image::String = "freebsd-12-0-release-amd64" <- "FreeBSD image" - coverage::Bool = true <- "Enable code coverage submission" - extra_versions::Vector = DEFAULT_CI_VERSIONS <- "Extra Julia versions to test" +@with_kw_noshow struct CirrusCI <: BasicPlugin + file::String = default_file("cirrus.yml") + image::String = "freebsd-12-0-release-amd64" + coverage::Bool = true + extra_versions::Vector = DEFAULT_CI_VERSIONS end source(p::CirrusCI) = p.file @@ -198,7 +199,7 @@ end GitLabCI(; file="$(contractuser(default_file("gitlab-ci.yml")))", coverage=true, - extra_versions=$(map(format_version, [default_version(), VERSION])), + extra_versions=$DEFAULT_CI_VERSIONS_NO_NIGHTLY, ) Integrates your packages with [GitLab CI](https://docs.gitlab.com/ce/ci/). @@ -215,11 +216,11 @@ See [`Documenter`](@ref) for more information. !!! note Nightly Julia is not supported. """ -@with_defaults struct GitLabCI <: BasicPlugin - file::String = default_file("gitlab-ci.yml") <- "Path to .gitlab-ci.yml template" - coverage::Bool = true <- "Enable code coverage submission" +@with_kw_noshow struct GitLabCI <: BasicPlugin + file::String = default_file("gitlab-ci.yml") + coverage::Bool = true # Nightly has no Docker image. - extra_versions::Vector = map(format_version, [default_version(), VERSION]) <- "Extra Julia versions to test" + extra_versions::Vector = DEFAULT_CI_VERSIONS_NO_NIGHTLY end gitignore(p::GitLabCI) = p.coverage ? COVERAGE_GITIGNORE : String[] @@ -252,7 +253,6 @@ function view(p::GitLabCI, t::Template, pkg::AbstractString) ) end - """ is_ci(::Plugin) -> Bool diff --git a/src/plugins/citation.jl b/src/plugins/citation.jl index 68b6f25..805d446 100644 --- a/src/plugins/citation.jl +++ b/src/plugins/citation.jl @@ -7,9 +7,9 @@ Creates a `CITATION.bib` file for citing package repositories. - `file::AbstractString`: Template file for `CITATION.bib`. - `readme::Bool`: Whether or not to include a section about citing in the README. """ -@with_defaults struct Citation <: BasicPlugin - file::String = default_file("CITATION.bib") <- "Path to CITATION.bib template" - readme::Bool = false <- """Enable "Citing" README section""" +@with_kw_noshow struct Citation <: BasicPlugin + file::String = default_file("CITATION.bib") + readme::Bool = false end tags(::Citation) = "<<", ">>" diff --git a/src/plugins/coverage.jl b/src/plugins/coverage.jl index 26d11df..448cc36 100644 --- a/src/plugins/coverage.jl +++ b/src/plugins/coverage.jl @@ -8,8 +8,8 @@ Sets up code coverage submission from CI to [Codecov](https://codecov.io). ## Keyword Arguments - `file::Union{AbstractString, Nothing}`: Template file for `.codecov.yml`, or `nothing` to create no file. """ -@with_defaults struct Codecov <: BasicPlugin - file::Union{String, Nothing} = nothing <- "Path to .codecov.yml template" +@with_kw_noshow struct Codecov <: BasicPlugin + file::Union{String, Nothing} = nothing end source(p::Codecov) = p.file @@ -29,8 +29,8 @@ Sets up code coverage submission from CI to [Coveralls](https://coveralls.io). ## Keyword Arguments - `file::Union{AbstractString, Nothing}`: Template file for `.coveralls.yml`, or `nothing` to create no file. """ -@with_defaults struct Coveralls <: BasicPlugin - file::Union{String, Nothing} = nothing <- "Path to .coveralls.yml template" +@with_kw_noshow struct Coveralls <: BasicPlugin + file::Union{String, Nothing} = nothing end source(p::Coveralls) = p.file diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index 5c23223..291639f 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -38,7 +38,7 @@ struct Documenter{T<:Union{TravisCI, GitLabCI, Nothing}} <: Plugin make_jl::String index_md::String - # Can't use @with_defaults due to some weird precompilation issues. + # Can't use @with_kw_noshow due to some weird precompilation issues. function Documenter{T}(; assets::Vector{<:AbstractString}=String[], makedocs_kwargs::Dict{Symbol}=Dict{Symbol, Any}(), @@ -52,28 +52,6 @@ end Documenter(; kwargs...) = Documenter{Nothing}(; kwargs...) -function interactive(::Type{Documenter}) - kwargs = Dict{Symbol, Any}() - - default = default_file("docs", "make.jl") - kwargs[:make_jl] = prompt(String, "Documenter: Path to make.jl template", default) - - default = default_file("docs", "src", "index.md") - kwargs[:index_md] = prompt(String, "Documenter: Path to make.jl template", default) - - kwargs[:assets] = prompt(Vector{String}, "Documenter: Extra asset files", String[]) - - md_kw = prompt(Dict{String, String}, "Documenter: makedocs keyword arguments", Dict()) - parsed = Dict{Symbol, Any}(Symbol(p.first) => eval(Meta.parse(p.second)) for p in md_kw) - kwargs[:makedocs_kwargs] = parsed - - available = [Nothing, TravisCI, GitLabCI] - f = T -> string(nameof(T)) - T = select(f, "Documenter: Documentation deployment strategy", available, Nothing) - - return Documenter{T}(; kwargs...) -end - gitignore(::Documenter) = ["/docs/build/"] badges(::Documenter) = Badge[] diff --git a/src/plugins/droneci.jl b/src/plugins/droneci.jl deleted file mode 100644 index 5ce2027..0000000 --- a/src/plugins/droneci.jl +++ /dev/null @@ -1,45 +0,0 @@ -""" - DroneCI(; config_file::Union{AbstractString, Nothing}="") -> DroneCI - -Add `DroneCI` to a template's plugins to add a `.drone.yml` configuration file to -generated repositories, and an appropriate badge to the README. The default configuration -file supports Linux on ARM32 and ARM64. - -# Keyword Arguments -* `config_file::Union{AbstractString, Nothing}=""`: Path to a custom `.drone.yml`. - If `nothing` is supplied, no file will be generated. -""" -struct DroneCI <: GenericPlugin - gitignore::Vector{String} - src::Union{String, Nothing} - dest::String - badges::Vector{Badge} - view::Dict{String, Any} - - function DroneCI(; config_file::Union{AbstractString, Nothing}="") - if config_file !== nothing - config_file = if isempty(config_file) - joinpath(DEFAULTS_DIR, "drone.yml") - elseif isfile(config_file) - abspath(config_file) - else - throw(ArgumentError("File $(abspath(config_file)) does not exist")) - end - end - return new( - [], - config_file, - ".drone.yml", - [ - Badge( - "Build Status", - "https://cloud.drone.io/api/badges/{{USER}}/{{PKGNAME}}.jl/status.svg", - "https://cloud.drone.io/{{USER}}/{{PKGNAME}}.jl", - ), - ], - Dict{String, Any}(), - ) - end -end - -interactive(::Type{DroneCI}) = interactive(DroneCI; file="drone.yml") diff --git a/src/plugins/git.jl b/src/plugins/git.jl index 8ba5718..aaea917 100644 --- a/src/plugins/git.jl +++ b/src/plugins/git.jl @@ -12,11 +12,11 @@ Creates a Git repository and a `.gitignore` file. - `gpgsign::Bool`: Whether or not to sign commits with your GPG key. This option requires that the Git CLI is installed, and for you to have a GPG key associated with your committer identity. """ -@with_defaults struct Git <: Plugin - ignore::Vector{String} = String[] <- "Gitignore entries" - ssh::Bool = false <- "Enable SSH Git remote" - manifest::Bool = false <- "Commit Manifest.toml" - gpgsign::Bool = false <- "GPG-sign commits" +@with_kw_noshow struct Git <: Plugin + ignore::Vector{String} = String[] + ssh::Bool = false + manifest::Bool = false + gpgsign::Bool = false end # Try to make sure that no files are created after we commit. diff --git a/src/plugins/license.jl b/src/plugins/license.jl index 5a2fc20..be8314a 100644 --- a/src/plugins/license.jl +++ b/src/plugins/license.jl @@ -34,15 +34,3 @@ view(::License, t::Template, ::AbstractString) = Dict( "AUTHORS" => join(t.authors, ", "), "YEAR" => year(today()), ) - -function interactive(::Type{License}) - destination = prompt(String, "License: License file destination", "LICENSE") - return if prompt(Bool, "License: Use custom license file", false) - path = prompt(String, "License: Path to custom license file", ""; required=true) - License(; path=path, destination=destination) - else - available = sort(readdir(joinpath(TEMPLATES_DIR, "licenses"))) - name = select("License: Select a license", available, "MIT") - License(; name=name, destination=destination) - end -end diff --git a/src/plugins/readme.jl b/src/plugins/readme.jl index f982fab..97ec228 100644 --- a/src/plugins/readme.jl +++ b/src/plugins/readme.jl @@ -5,8 +5,7 @@ inline_badges=false, ) -Creates a `README` file. -By default, it includes badges for other included plugins +Creates a `README` file that contains badges for other included plugins. ## Keyword Arguments - `file::AbstractString`: Template file for the `README`. @@ -14,10 +13,10 @@ By default, it includes badges for other included plugins For example, values of `"README"` or `"README.rst"` might be desired. - `inline_badges::Bool`: Whether or not to put the badges on the same line as the package name. """ -@with_defaults struct Readme <: BasicPlugin - file::String = default_file("README.md") <- "Path to README.md template" - destination::String = "README.md" <- "README file destination" - inline_badges::Bool = false <- "Enable inline badges" +@with_kw_noshow struct Readme <: BasicPlugin + file::String = default_file("README.md") + destination::String = "README.md" + inline_badges::Bool = false end source(p::Readme) = p.file diff --git a/src/plugins/src_dir.jl b/src/plugins/src_dir.jl index d23fda2..be90d19 100644 --- a/src/plugins/src_dir.jl +++ b/src/plugins/src_dir.jl @@ -6,9 +6,9 @@ Creates a module entrypoint. ## Keyword Arguments - `file::AbstractString`: Template file for `src/.jl`. """ -@with_defaults mutable struct SrcDir <: BasicPlugin - file::String = default_file("src", "module.jl") <- "Path to .jl template" - destination::String = joinpath("src", ".jl") +@with_kw_noshow mutable struct SrcDir <: BasicPlugin + file::String = default_file("src", "module.jl") + destination::String = "" end Base.:(==)(a::SrcDir, b::SrcDir) = a.file == b.file diff --git a/src/plugins/tests.jl b/src/plugins/tests.jl index e125ee1..8281be6 100644 --- a/src/plugins/tests.jl +++ b/src/plugins/tests.jl @@ -14,9 +14,9 @@ Sets up testing for packages. !!! note Managing test dependencies with `test/Project.toml` is only supported in Julia 1.2 and later. """ -@with_defaults struct Tests <: BasicPlugin - file::String = default_file("test", "runtests.jl") <- "Path to runtests.jl template" - project::Bool = false <- "Enable test/Project.toml" +@with_kw_noshow struct Tests <: BasicPlugin + file::String = default_file("test", "runtests.jl") + project::Bool = false end source(p::Tests) = p.file diff --git a/src/template.jl b/src/template.jl index fa19018..9b7dc3e 100644 --- a/src/template.jl +++ b/src/template.jl @@ -34,9 +34,6 @@ A configuration used to generate packages. The default plugins are [`ProjectFile`](@ref), [`SrcDir`](@ref), [`Tests`](@ref), [`Readme`](@ref), [`License`](@ref), and [`Git`](@ref). To override a default plugin instead of disabling it altogether, supply it via `plugins`. -### Interactive Usage -- `interactive::Bool=false`: When set, the template is created interactively, filling unset keywords with user input. - --- To create a package from a `Template`, use the following syntax: @@ -56,7 +53,7 @@ struct Template user::String end -Template(; interactive::Bool=false, kwargs...) = Template(Val(interactive); kwargs...) +Template(; kwargs...) = Template(Val(false); kwargs...) # Non-interactive constructor. function Template(::Val{false}; kwargs...) diff --git a/test/fixtures/AllPlugins/drone.yml b/test/fixtures/AllPlugins/drone.yml deleted file mode 100644 index 90f3f82..0000000 --- a/test/fixtures/AllPlugins/drone.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -kind: pipeline -name: linux - arm - Julia {{VERSION}} - -platform: - os: linux - arch: arm - -steps: -- name: build - image: julia:{{VERSION}} - commands: - - "julia --project=. --check-bounds=yes --color=yes -e 'using InteractiveUtils; versioninfo(verbose=true); using Pkg; Pkg.build(); Pkg.test(coverage=true)'" - ---- -kind: pipeline -name: linux - arm64 - Julia {{VERSION}} - -platform: - os: linux - arch: arm64 - -steps: -- name: build - image: julia:{{VERSION}} - commands: - - "julia --project=. --check-bounds=yes --color=yes -e 'using InteractiveUtils; versioninfo(verbose=true); using Pkg; Pkg.build(); Pkg.test(coverage=true)'" - -... diff --git a/test/plugins/droneci.jl b/test/plugins/droneci.jl deleted file mode 100644 index 5b7fc6f..0000000 --- a/test/plugins/droneci.jl +++ /dev/null @@ -1,41 +0,0 @@ -t = Template(; user=me) -pkg_dir = joinpath(t.dir, test_pkg) - -@testset "DroneCI" begin - @testset "Plugin creation" begin - p = DroneCI() - @test isempty(p.gitignore) - @test p.src == joinpath(DEFAULTS_DIR, "drone.yml") - @test p.dest == ".drone.yml" - @test p.badges == [ - Badge( - "Build Status", - "https://cloud.drone.io/api/badges/{{USER}}/{{PKGNAME}}.jl/status.svg", - "https://cloud.drone.io/{{USER}}/{{PKGNAME}}.jl", - ), - ] - @test isempty(p.view) - p = DroneCI(; config_file=nothing) - @test p.src === nothing - p = DroneCI(; config_file=test_file) - @test p.src == test_file - @test_throws ArgumentError DroneCI(; config_file=fake_path) - end - - @testset "Badge generation" begin - p = DroneCI() - @test badges(p, me, test_pkg) == ["[![Build Status](https://cloud.drone.io/api/badges/$me/$test_pkg.jl/status.svg)](https://cloud.drone.io/$me/$test_pkg.jl)"] - end - - @testset "File generation" begin - # Without a coverage plugin in the template, there should be no coverage step. - p = DroneCI() - @test gen_plugin(p, t, test_pkg) == [".drone.yml"] - @test isfile(joinpath(pkg_dir, ".drone.yml")) - drone = read(joinpath(pkg_dir, ".drone.yml"), String) - @test !occursin("coverage_script", drone) - rm(joinpath(pkg_dir, ".drone.yml")) - end -end - -rm(pkg_dir; recursive=true) diff --git a/test/template.jl b/test/template.jl index 260f34e..11a2e21 100644 --- a/test/template.jl +++ b/test/template.jl @@ -6,7 +6,7 @@ @test isempty(Template(; disable_defaults=[Git]).user) end mock(PT.default_user => () -> "username") do _du - @test Template().user == PT.default_user() + @test Template().user == "username" end end