From ed705802a387f8209511dfce66acb8e37327ce8e Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Tue, 16 Mar 2021 22:10:42 +0000 Subject: [PATCH 1/5] Implement `fixup` function --- src/PkgTemplates.jl | 12 +++++++++++- src/fixup.jl | 14 ++++++++++++++ src/plugin.jl | 11 +++++++++++ src/plugins/documenter.jl | 3 +++ src/plugins/git.jl | 10 ++++++++++ src/plugins/license.jl | 4 ++++ src/plugins/project_file.jl | 4 ++++ src/plugins/src_dir.jl | 3 +++ 8 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/fixup.jl diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 8c9ae6d8..29d06f22 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -38,7 +38,8 @@ export SrcDir, TagBot, Tests, - TravisCI + TravisCI, + fixup """ Plugins are PkgTemplates' source of customization and extensibility. @@ -48,10 +49,19 @@ When implementing a new plugin, subtype this type to have full control over its """ abstract type Plugin end +""" + isfixable(::Plugin, pkg_dir) -> Bool + +Determines whether or not the plugin can be updated on an existing project via +[`fixup`](@ref). +""" +isfixable(::Plugin, pkg_dir) = false + include("template.jl") include("plugin.jl") include("show.jl") include("interactive.jl") +include("fixup.jl") include("deprecated.jl") # Run some function with a project activated at the given path. diff --git a/src/fixup.jl b/src/fixup.jl new file mode 100644 index 00000000..85282be1 --- /dev/null +++ b/src/fixup.jl @@ -0,0 +1,14 @@ +function fixup(tpl::Template, pkg_dir::AbstractString) + ispath(pkg_dir) || throw(ArgumentError("Not a directory.")) + isdir(joinpath(pkg_dir, "src")) || throw(ArgumentError("No `src/` directory.")) + + fixable = filter(p -> isfixable(p, pkg_dir), tpl.plugins) + foreach((prehook, hook, posthook)) do h + @info "Running $(nameof(h))s" + foreach(sort(fixable; by=p -> priority(p, h), rev=true)) do p + @info p + h(p, tpl, pkg_dir) + end + end + # TODO: some magic to add badges to an existing Readme?! +end diff --git a/src/plugin.jl b/src/plugin.jl index c6c6eed4..ba2a59a7 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -210,6 +210,17 @@ This function **must** be implemented. """ function destination end +""" + isfixable(p::FilePlugin) -> Bool + +Determines whether or not [`fixup`](@ref) should update the files created by `p`. + +By default, returns `true` if the [`destination(p)`](@ref) file does not exist. +Subtype of [`FilePlugin`](@ref) should implement their own method if they require +different behaviour. +""" +isfixable(p::FilePlugin, pkg_dir) = !isfile(joinpath(pkg_dir, destination(p))) + """ Badge(hover::AbstractString, image::AbstractString, link::AbstractString) diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index 2f321659..359a6660 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -161,6 +161,9 @@ function validate(p::Documenter{T}, t::Template) where T <: YesDeploy end end +# Do not edit existing docs. +isfixable(::Documenter, pkg_dir) = !isdir(joinpath(pkg_dir, "docs")) + function hook(p::Documenter, t::Template, pkg_dir::AbstractString) pkg = basename(pkg_dir) docs_dir = joinpath(pkg_dir, "docs") diff --git a/src/plugins/git.jl b/src/plugins/git.jl index 5b235d56..be15f781 100644 --- a/src/plugins/git.jl +++ b/src/plugins/git.jl @@ -54,6 +54,16 @@ function validate(p::Git, t::Template) end end +# fixup only if pkg_dir not a git repo +function isfixable(::Git, pkg_dir) + try + r = GitRepo(pkg_dir) + return !isa(r, GitRepo) + catch + return true + end +end + # Set up the Git repository. function prehook(p::Git, t::Template, pkg_dir::AbstractString) LibGit2.with(LibGit2.init(pkg_dir)) do repo diff --git a/src/plugins/license.jl b/src/plugins/license.jl index 656fb16b..e5bbf248 100644 --- a/src/plugins/license.jl +++ b/src/plugins/license.jl @@ -40,6 +40,10 @@ view(::License, t::Template, ::AbstractString) = Dict( "YEAR" => year(today()), ) +function isfixable(::License, pkg_dir) + return !any(isfile, joinpath.(pkg_dir, ("LICENSE", "LICENSE.md"))) +end + function prompt(::Type{License}, ::Type, ::Val{:name}) options = readdir(default_file("licenses")) # Move MIT to the top. diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 28efd583..665e9035 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -38,3 +38,7 @@ function compat_version(v::VersionNumber) "$(v.major).$(v.minor).$(v.patch)" end end + +function isfixable(::ProjectFile, pkg_dir) + return !any(isfile, joinpath.(pkg_dir, ("Project.toml", "JuliaProject.toml"))) +end diff --git a/src/plugins/src_dir.jl b/src/plugins/src_dir.jl index e6004e08..41fb2a57 100644 --- a/src/plugins/src_dir.jl +++ b/src/plugins/src_dir.jl @@ -29,3 +29,6 @@ view(::SrcDir, ::Template, pkg::AbstractString) = Dict("PKG" => pkg) function prehook(p::SrcDir, t::Template, pkg_dir::AbstractString) p.destination = joinpath("src", basename(pkg_dir) * ".jl") end + +# TODO: should this return `true` if `src/` exists but `src/pkg_name.jl` doesn't? +isfixable(p::SrcDir, pkg_dir) = false From 03edd6087cf72b2590ea8c67a872733f06c73be3 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Fri, 4 Jun 2021 16:27:41 +0100 Subject: [PATCH 2/5] Handle directory having `.jl` suffix --- src/fixup.jl | 5 +++-- src/plugins/project_file.jl | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/fixup.jl b/src/fixup.jl index 85282be1..78e6dfbb 100644 --- a/src/fixup.jl +++ b/src/fixup.jl @@ -1,4 +1,5 @@ -function fixup(tpl::Template, pkg_dir::AbstractString) +function fixup(tpl::Template, pkg_dir) + pkg_dir = realpath(pkg_dir) ispath(pkg_dir) || throw(ArgumentError("Not a directory.")) isdir(joinpath(pkg_dir, "src")) || throw(ArgumentError("No `src/` directory.")) @@ -6,9 +7,9 @@ function fixup(tpl::Template, pkg_dir::AbstractString) foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" foreach(sort(fixable; by=p -> priority(p, h), rev=true)) do p - @info p h(p, tpl, pkg_dir) end end + @info "Fixed up package at $pkg_dir" # TODO: some magic to add badges to an existing Readme?! end diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 665e9035..ff78b892 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -15,7 +15,9 @@ priority(::ProjectFile, ::typeof(hook)) = typemax(Int) - 5 function hook(p::ProjectFile, t::Template, pkg_dir::AbstractString) toml = Dict( - "name" => basename(pkg_dir), + "name" => let pkg = basename(pkg_dir) + endswith(pkg, ".jl") ? pkg[1:end-3] : pkg + end, "uuid" => string(uuid4()), "authors" => t.authors, "version" => string(p.version), From 6620e7264254cc873a541a9ad7ea9b62751aceb3 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 11:55:04 +0200 Subject: [PATCH 3/5] added backup for existing package --- src/fixup.jl | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/fixup.jl b/src/fixup.jl index 78e6dfbb..2eea774a 100644 --- a/src/fixup.jl +++ b/src/fixup.jl @@ -1,8 +1,47 @@ +""" + fixup(tpl::Template, pkg_dir) + +Fixes up the package at `pkg_dir` according to the template `tpl`. Returns the path to the fixed package and the path to the backup folder. + +## Example + +```julia +using PkgTemplates + +# Original package: +t = Template(user="my-username", dir="~") +pkg_dir = t("MyPkg.jl") + +# Fixup the package (with Documenter plugin): +t = Template( + user="my-username", dir="~", + authors="Acme Corp", + plugins=[ + Documenter{GitHubActions}(), + ] +) +pkg_dir, backup = fixup(t, pkg_dir) +``` +""" function fixup(tpl::Template, pkg_dir) + + # Assertions: pkg_dir = realpath(pkg_dir) ispath(pkg_dir) || throw(ArgumentError("Not a directory.")) isdir(joinpath(pkg_dir, "src")) || throw(ArgumentError("No `src/` directory.")) + # Back up in temporary directory: + backup = joinpath(tempdir(), splitpath(pkg_dir)[end]) + if !isdir(backup) + @info "Fixing up the package at $pkg_dir might require overwriting files.\nThe current state of the package is backed up at $backup. Hit ENTER to continue." + readline() + run(`cp -r $pkg_dir $backup`) + else + @warn "Existing backup for $pkg_dir found at $backup. Skipping backup. If you are sure that you want to apply the fix-up again, hit ENTER to continue." + readline() + end + + # Fix all plugins that are fixable: fixable = filter(p -> isfixable(p, pkg_dir), tpl.plugins) foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" @@ -10,6 +49,8 @@ function fixup(tpl::Template, pkg_dir) h(p, tpl, pkg_dir) end end - @info "Fixed up package at $pkg_dir" + @info "Fixed up package at $pkg_dir. The old state of the package is backed up at $backup." # TODO: some magic to add badges to an existing Readme?! + + return pkg_dir, backup end From 947023f49738903edf6172bffa11c5dc009e7f2c Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 13:26:48 +0200 Subject: [PATCH 4/5] dealign with existing README --- src/plugins/readme.jl | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/plugins/readme.jl b/src/plugins/readme.jl index 35fa2f15..38a6e545 100644 --- a/src/plugins/readme.jl +++ b/src/plugins/readme.jl @@ -23,9 +23,30 @@ Creates a `README` file that contains badges for other included plugins. badge_off::Vector{typeof(Plugin)} = [] end + +isfixable(p::Readme, pkg_dir) = true source(p::Readme) = p.file destination(p::Readme) = p.destination +""" + hook(p::Readme, t::Template, pkg_dir::AbstractString) + +Overloads the `hook` function for the `Readme` file plugin. In case `fixup` is used and there is an existing README, a new README is proposed that complies with the template, but it the existing one is not overwritten. +""" +function hook(p::Readme, t::Template, pkg_dir::AbstractString) + source(p) === nothing && return + pkg = pkg_name(pkg_dir) + path = joinpath(pkg_dir, destination(p)) + text = render_plugin(p, t, pkg) + if isfile(path) + path_fixed = replace(path, ".md" => "_fixed.md") + @warn "README file already exists at $path. Generating a fixed but empty version from template at $path_fixed. You will most likely just have to copy and paste the content from the existing README into the fixed version and then overwrite $path with $path_fixed." + gen_file(path_fixed, text) + else + gen_file(path, text) + end +end + function view(p::Readme, t::Template, pkg::AbstractString) # Explicitly ordered badges go first. strings = String[] @@ -63,5 +84,5 @@ default_badge_order() = [ CirrusCI, Codecov, Coveralls, - subtypes(BadgePlugin)... -] + subtypes(BadgePlugin)..., +] \ No newline at end of file From 62f9ed483fa3fda73381ac8a0c031e9101776c6b Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 13:27:31 +0200 Subject: [PATCH 5/5] formatting --- src/PkgTemplates.jl | 6 ++--- src/deprecated.jl | 4 +-- src/fixup.jl | 4 +-- src/interactive.jl | 37 ++++++++++++++----------- src/plugin.jl | 23 +++++++++------- src/plugins/badges.jl | 2 +- src/plugins/ci.jl | 6 ++--- src/plugins/codeowners.jl | 12 ++++++--- src/plugins/coverage.jl | 12 ++++----- src/plugins/develop.jl | 2 +- src/plugins/documenter.jl | 54 ++++++++++++++++++------------------- src/plugins/formatter.jl | 8 ++++-- src/plugins/git.jl | 12 +++++---- src/plugins/license.jl | 14 +++++----- src/plugins/project_file.jl | 5 +++- src/plugins/readme.jl | 2 +- src/plugins/tagbot.jl | 20 +++++++------- src/plugins/tests.jl | 16 ++++++----- src/show.jl | 4 +-- src/template.jl | 38 +++++++++++++------------- 20 files changed, 152 insertions(+), 129 deletions(-) diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 1013a41c..5311797c 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -1,5 +1,4 @@ -@doc read(joinpath(dirname(@__DIR__), "README.md"), String) -module PkgTemplates +@doc read(joinpath(dirname(@__DIR__), "README.md"), String) module PkgTemplates using Base: active_project, contractuser @@ -15,8 +14,7 @@ using Parameters: @with_kw_noshow using Mocking -export - Template, +export Template, AppVeyor, BlueStyleBadge, CirrusCI, diff --git a/src/deprecated.jl b/src/deprecated.jl index 9c640256..217c0a02 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1,6 +1,6 @@ @deprecate generate(t::Template, pkg::AbstractString) t(pkg) @deprecate generate(pkg::AbstractString, t::Template) t(pkg) -@deprecate interactive_template() Template(; interactive=true) -@deprecate generate_interactive(pkg::AbstractString) Template(; interactive=true)(pkg) +@deprecate interactive_template() Template(; interactive = true) +@deprecate generate_interactive(pkg::AbstractString) Template(; interactive = true)(pkg) @deprecate GitHubPages(; kwargs...) Documenter{TravisCI}(; kwargs...) @deprecate GitLabPages(; kwargs...) Documenter{GitLabCI}(; kwargs...) diff --git a/src/fixup.jl b/src/fixup.jl index 2eea774a..50d8a286 100644 --- a/src/fixup.jl +++ b/src/fixup.jl @@ -32,7 +32,7 @@ function fixup(tpl::Template, pkg_dir) # Back up in temporary directory: backup = joinpath(tempdir(), splitpath(pkg_dir)[end]) - if !isdir(backup) + if !isdir(backup) @info "Fixing up the package at $pkg_dir might require overwriting files.\nThe current state of the package is backed up at $backup. Hit ENTER to continue." readline() run(`cp -r $pkg_dir $backup`) @@ -45,7 +45,7 @@ function fixup(tpl::Template, pkg_dir) fixable = filter(p -> isfixable(p, pkg_dir), tpl.plugins) foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" - foreach(sort(fixable; by=p -> priority(p, h), rev=true)) do p + foreach(sort(fixable; by = p -> priority(p, h), rev = true)) do p h(p, tpl, pkg_dir) end end diff --git a/src/interactive.jl b/src/interactive.jl index 7f003a8f..60d07d54 100644 --- a/src/interactive.jl +++ b/src/interactive.jl @@ -4,8 +4,8 @@ Shortcut for `Template(; interactive=true)(pkg)`. If no package name is supplied, you will be prompted for one. """ -function generate(pkg::AbstractString=prompt(Template, String, :pkg)) - t = Template(; interactive=true) +function generate(pkg::AbstractString = prompt(Template, String, :pkg)) + t = Template(; interactive = true) t(pkg) return t end @@ -17,7 +17,7 @@ Interactively create a plugin of type `T`. Implement this method and ignore othe related functions only if you want completely custom behaviour. """ function interactive(T::Type) - pairs = Vector{Pair{Symbol, Type}}(interactive_pairs(T)) + pairs = Vector{Pair{Symbol,Type}}(interactive_pairs(T)) # There must be at least 2 MultiSelectMenu options. # If there are none, return immediately. @@ -34,13 +34,13 @@ function interactive(T::Type) "$k" end end - menu = MultiSelectMenu(opts; pagesize=length(pairs)) + menu = MultiSelectMenu(opts; pagesize = length(pairs)) customize = sort!(collect(request(menu))) # If the "None" option was selected, don't customize anything. just_one && lastindex(pairs) in customize && return T() - kwargs = Dict{Symbol, Any}() + kwargs = Dict{Symbol,Any}() foreach(pairs[customize]) do (name, F) kwargs[name] = prompt(T, F, name) end @@ -64,7 +64,7 @@ function pretty_message(s::AbstractString) r"Array{(.*?),1}" => s"Vector{\1}", r"Union{Nothing, (.*?)}" => s"Union{\1, Nothing}", ] - return reduce((s, p) -> replace(s, p), replacements; init=s) + return reduce((s, p) -> replace(s, p), replacements; init = s) end """ @@ -73,12 +73,12 @@ end Provide some extra tips to users on how to structure their input for the type `T`, for example if multiple delimited values are expected. """ -input_tips(::Type{Vector{T}}) where T = [input_tips(T)..., "comma-delimited"] -input_tips(::Type{Union{T, Nothing}}) where T = [input_tips(T)..., input_tips(Nothing)...] +input_tips(::Type{Vector{T}}) where {T} = [input_tips(T)..., "comma-delimited"] +input_tips(::Type{Union{T,Nothing}}) where {T} = [input_tips(T)..., input_tips(Nothing)...] input_tips(::Type{Nothing}) = ["'nothing' for nothing"] input_tips(::Type{Secret}) = ["name only"] # Show expected input type as a tip if it's anything other than `String` -input_tips(::Type{T}) where T = String[string(T)] +input_tips(::Type{T}) where {T} = String[string(T)] input_tips(::Type{String}) = String[] input_tips(::Type{<:Signed}) = ["Int"] # Specific Int type likely not important @@ -91,7 +91,7 @@ A default implementation of `T(s)` exists. convert_input(::Type, T::Type{<:Real}, s::AbstractString) = parse(T, s) convert_input(::Type, T::Type, s::AbstractString) = T(s) -function convert_input(P::Type, ::Type{Union{T, Nothing}}, s::AbstractString) where T +function convert_input(P::Type, ::Type{Union{T,Nothing}}, s::AbstractString) where {T} # This is kind of sketchy because technically, there might be some other input # whose value we want to instantiate with the string "nothing", # but I think that would be a pretty rare occurrence. @@ -99,11 +99,15 @@ function convert_input(P::Type, ::Type{Union{T, Nothing}}, s::AbstractString) wh return s == "nothing" ? nothing : convert_input(P, T, s) end -function convert_input(P::Type, ::Type{Union{T, Symbol, Nothing}}, s::AbstractString) where T +function convert_input( + P::Type, + ::Type{Union{T,Symbol,Nothing}}, + s::AbstractString, +) where {T} # Assume inputs starting with ':' char are intended as Symbols, if a plugin accept symbols. # i.e. assume the set of valid Symbols the plugin expects can be spelt starting with ':'. return if startswith(s, ":") - Symbol(chop(s, head=1, tail=0)) # remove ':' + Symbol(chop(s, head = 1, tail = 0)) # remove ':' else convert_input(P, Union{T,Nothing}, s) end @@ -140,7 +144,7 @@ Implement this method to customize particular fields of particular types. prompt(P::Type, T::Type, name::Symbol) = prompt(P, T, Val(name)) # The trailing `nothing` is a hack for `fallback_prompt` to use, ignore it. -function prompt(P::Type, ::Type{T}, ::Val{name}, ::Nothing=nothing) where {T, name} +function prompt(P::Type, ::Type{T}, ::Val{name}, ::Nothing = nothing) where {T,name} default = defaultkw(P, name) tips = join([input_tips(T); "default: $(input_string(default))"], ", ") input = Base.prompt(pretty_message("Enter value for '$name' ($tips)")) @@ -170,8 +174,9 @@ function prompt(P::Type, ::Type{T}, ::Val{name}, ::Nothing=nothing) where {T, na end # Compute all the concrete subtypes of T. -concretes_rec(T::Type) = isabstracttype(T) ? vcat(map(concretes_rec, subtypes(T))...) : Any[T] -concretes(T::Type) = sort!(concretes_rec(T); by=nameof) +concretes_rec(T::Type) = + isabstracttype(T) ? vcat(map(concretes_rec, subtypes(T))...) : Any[T] +concretes(T::Type) = sort!(concretes_rec(T); by = nameof) # Compute name => type pairs for T's interactive options. function interactive_pairs(T::Type) @@ -181,7 +186,7 @@ function interactive_pairs(T::Type) prepend!(pairs, reverse(customizable(T))) uniqueby!(first, pairs) filter!(p -> last(p) !== NotCustomizable, pairs) - sort!(pairs; by=first) + sort!(pairs; by = first) return pairs end diff --git a/src/plugin.jl b/src/plugin.jl index ac465d3c..92f00a51 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -1,5 +1,6 @@ const DEFAULT_PRIORITY = 1000 -const DEFAULT_TEMPLATE_DIR = Ref{String}(joinpath(dirname(dirname(pathof(PkgTemplates))), "templates")) +const DEFAULT_TEMPLATE_DIR = + Ref{String}(joinpath(dirname(dirname(pathof(PkgTemplates))), "templates")) """ @plugin struct ... end @@ -64,7 +65,11 @@ macro plugin(ex::Expr) msg = "Run `using PkgTemplates: @with_kw_noshow` before using this macro" @assert isdefined(__module__, Symbol("@with_kw_noshow")) msg - block = :(begin @with_kw_noshow $ex end) + block = :( + begin + @with_kw_noshow $ex + end + ) foreach(filter(arg -> arg isa Expr, ex.args[3].args)) do field @assert field.head === :(=) "Field must have a default value" @@ -77,7 +82,7 @@ macro plugin(ex::Expr) return esc(block) end -function Base.:(==)(a::T, b::T) where T <: Plugin +function Base.:(==)(a::T, b::T) where {T<:Plugin} return all(n -> getfield(a, n) == getfield(b, n), fieldnames(T)) end @@ -122,7 +127,7 @@ but you can always call it yourself as part of your [`hook`](@ref) implementatio By default, an empty `Dict` is returned. """ -view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() +view(::Plugin, ::Template, ::AbstractString) = Dict{String,Any}() """ user_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any} @@ -132,7 +137,7 @@ The same as [`view`](@ref), but for use by package *users* for extension. Values returned by this function will override those from [`view`](@ref) when the keys are the same. """ -user_view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() +user_view(::Plugin, ::Template, ::AbstractString) = Dict{String,Any}() """ combined_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any} @@ -296,7 +301,7 @@ At this point, both the [`prehook`](@ref)s and [`hook`](@ref)s have run. """ posthook(::Plugin, ::Template, ::AbstractString) = nothing -function validate(p::T, ::Template) where T <: FilePlugin +function validate(p::T, ::Template) where {T<:FilePlugin} src = source(p) src === nothing && return isfile(src) || throw(ArgumentError("$(nameof(T)): The file $src does not exist")) @@ -333,7 +338,7 @@ Render a template file with the data in `view`. `tags` should be a tuple of two strings, which are the opening and closing delimiters, or `nothing` to use the default delimiters. """ -function render_file(file::AbstractString, view::Dict{<:AbstractString}, tags=nothing) +function render_file(file::AbstractString, view::Dict{<:AbstractString}, tags = nothing) return render_text(read(file, String), view, tags) end @@ -344,8 +349,8 @@ Render some text with the data in `view`. `tags` should be a tuple of two strings, which are the opening and closing delimiters, or `nothing` to use the default delimiters. """ -function render_text(text::AbstractString, view::Dict{<:AbstractString}, tags=nothing) - return tags === nothing ? render(text, view) : render(text, view; tags=tags) +function render_text(text::AbstractString, view::Dict{<:AbstractString}, tags = nothing) + return tags === nothing ? render(text, view) : render(text, view; tags = tags) end """ diff --git a/src/plugins/badges.jl b/src/plugins/badges.jl index 075a24fe..562e1118 100644 --- a/src/plugins/badges.jl +++ b/src/plugins/badges.jl @@ -46,7 +46,7 @@ function badges(::PkgEvalBadge) return Badge( "PkgEval", "https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/{{{PKG1}}}/{{{PKG}}}.svg", - "https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/{{{PKG1}}}/{{{PKG}}}.html" + "https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/{{{PKG1}}}/{{{PKG}}}.html", ) end diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index 129d98b9..14b43cc8 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -73,7 +73,7 @@ function view(p::GitHubActions, t::Template, pkg::AbstractString) p.osx && push!(os, "macOS-latest") p.windows && push!(os, "windows-latest") arch = filter(a -> getfield(p, Symbol(a)), ["x64", "x86"]) - excludes = Dict{String, String}[] + excludes = Dict{String,String}[] p.osx && p.x86 && push!(excludes, Dict("E_OS" => "macOS-latest", "E_ARCH" => "x86")) v = Dict( @@ -149,7 +149,7 @@ function view(p::TravisCI, t::Template, pkg::AbstractString) versions = collect_versions(t, p.extra_versions) allow_failures = filter(in(versions), ALLOWED_FAILURES) - excludes = Dict{String, String}[] + excludes = Dict{String,String}[] p.x86 && p.osx && push!(excludes, Dict("E_OS" => "osx", "E_ARCH" => "x86")) if p.arm64 p.osx && push!(excludes, Dict("E_OS" => "osx", "E_ARCH" => "arm64")) @@ -416,7 +416,7 @@ function collect_versions(t::Template, versions::Vector) return sort(unique(vs)) end -const AllCI = Union{AppVeyor, GitHubActions, TravisCI, CirrusCI, GitLabCI, DroneCI} +const AllCI = Union{AppVeyor,GitHubActions,TravisCI,CirrusCI,GitLabCI,DroneCI} """ is_ci(::Plugin) -> Bool diff --git a/src/plugins/codeowners.jl b/src/plugins/codeowners.jl index 44244f8d..4eb8b002 100644 --- a/src/plugins/codeowners.jl +++ b/src/plugins/codeowners.jl @@ -29,10 +29,16 @@ end function PkgTemplates.validate(p::CodeOwners, ::Template) for (pattern, subowners) in p.owners - contains(pattern, r"\s") && throw(ArgumentError(("Pattern ($pattern) must not contain whitespace"))) + contains(pattern, r"\s") && + throw(ArgumentError(("Pattern ($pattern) must not contain whitespace"))) for subowner in subowners - contains(subowner, r"\s") && throw(ArgumentError("Owner name ($subowner) must not contain whitespace")) - '@' ∈ subowner || throw(ArgumentError("Owner name ($subowner) must be `@user` or `email@domain.com`")) + contains(subowner, r"\s") && + throw(ArgumentError("Owner name ($subowner) must not contain whitespace")) + '@' ∈ subowner || throw( + ArgumentError( + "Owner name ($subowner) must be `@user` or `email@domain.com`", + ), + ) end end end diff --git a/src/plugins/coverage.jl b/src/plugins/coverage.jl index ae9fb5ec..c0460796 100644 --- a/src/plugins/coverage.jl +++ b/src/plugins/coverage.jl @@ -10,7 +10,7 @@ Sets up code coverage submission from CI to [Codecov](https://codecov.io). or `nothing` to create no file. """ @plugin struct Codecov <: FilePlugin - file::Union{String, Nothing} = nothing + file::Union{String,Nothing} = nothing end source(p::Codecov) = p.file @@ -32,7 +32,7 @@ Sets up code coverage submission from CI to [Coveralls](https://coveralls.io). or `nothing` to create no file. """ @plugin struct Coveralls <: FilePlugin - file::Union{String, Nothing} = nothing + file::Union{String,Nothing} = nothing end source(p::Coveralls) = p.file @@ -44,8 +44,8 @@ badges(::Coveralls) = Badge( "https://coveralls.io/github/{{{USER}}}/{{{PKG}}}.jl?branch={{{BRANCH}}}", ) -gitignore(::Union{Codecov, Coveralls}) = COVERAGE_GITIGNORE -view(::Union{Codecov, Coveralls}, t::Template, pkg::AbstractString) = Dict( +gitignore(::Union{Codecov,Coveralls}) = COVERAGE_GITIGNORE +view(::Union{Codecov,Coveralls}, t::Template, pkg::AbstractString) = Dict( "BRANCH" => something(default_branch(t), DEFAULT_DEFAULT_BRANCH), "PKG" => pkg, "USER" => t.user, @@ -58,6 +58,6 @@ Determine whether or not a plugin is a coverage plugin. If you are adding a coverage plugin, you should implement this function and return `true`. """ is_coverage(::Plugin) = false -is_coverage(::Union{Codecov, Coveralls}) = true +is_coverage(::Union{Codecov,Coveralls}) = true -needs_username(::Union{Codecov, Coveralls}) = true +needs_username(::Union{Codecov,Coveralls}) = true diff --git a/src/plugins/develop.jl b/src/plugins/develop.jl index 835f2717..eb1628cb 100644 --- a/src/plugins/develop.jl +++ b/src/plugins/develop.jl @@ -9,5 +9,5 @@ for more details. struct Develop <: Plugin end function posthook(::Develop, ::Template, pkg_dir::AbstractString) - Pkg.develop(PackageSpec(; path=pkg_dir)) + Pkg.develop(PackageSpec(; path = pkg_dir)) end diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index eb67ce60..72682ce5 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -1,11 +1,9 @@ -const DOCUMENTER_DEP = PackageSpec(; - name="Documenter", - uuid="e30172f5-a6a5-5a46-863b-614d45cd2de4", -) +const DOCUMENTER_DEP = + PackageSpec(; name = "Documenter", uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4") struct NoDeploy end -const YesDeploy = Union{TravisCI, GitHubActions, GitLabCI} -const GitHubPagesStyle = Union{TravisCI, GitHubActions} +const YesDeploy = Union{TravisCI,GitHubActions,GitLabCI} +const GitHubPagesStyle = Union{TravisCI,GitHubActions} """ Logo(; light=nothing, dark=nothing) @@ -17,8 +15,8 @@ Logo information for documentation. - `dark::AbstractString`: Path to a logo file for the dark theme. """ @with_kw_noshow struct Logo - light::Union{String, Nothing} = nothing - dark::Union{String, Nothing} = nothing + light::Union{String,Nothing} = nothing + dark::Union{String,Nothing} = nothing end """ @@ -76,23 +74,23 @@ struct Documenter{T} <: Plugin assets::Vector{String} logo::Logo makedocs_kwargs::Dict{Symbol} - canonical_url::Union{Function, Nothing} + canonical_url::Union{Function,Nothing} make_jl::String index_md::String - devbranch::Union{String, Nothing} - edit_link::Union{String, Symbol, Nothing} + devbranch::Union{String,Nothing} + edit_link::Union{String,Symbol,Nothing} end # Can't use @plugin because we're implementing our own no-arguments constructor. function Documenter{T}(; - assets::Vector{<:AbstractString}=String[], - logo::Logo=Logo(), - makedocs_kwargs::Dict{Symbol}=Dict{Symbol, Any}(), - canonical_url::Union{Function, Nothing}=make_canonical(T), - make_jl::AbstractString=default_file("docs", "make.jl"), - index_md::AbstractString=default_file("docs", "src", "index.md"), - devbranch::Union{AbstractString, Nothing}=nothing, - edit_link::Union{AbstractString, Symbol, Nothing}=:devbranch, + assets::Vector{<:AbstractString} = String[], + logo::Logo = Logo(), + makedocs_kwargs::Dict{Symbol} = Dict{Symbol,Any}(), + canonical_url::Union{Function,Nothing} = make_canonical(T), + make_jl::AbstractString = default_file("docs", "make.jl"), + index_md::AbstractString = default_file("docs", "src", "index.md"), + devbranch::Union{AbstractString,Nothing} = nothing, + edit_link::Union{AbstractString,Symbol,Nothing} = :devbranch, ) where {T} return Documenter{T}( assets, @@ -146,12 +144,14 @@ function view(p::Documenter, t::Template, pkg::AbstractString) "AUTHORS" => join(t.authors, ", "), "CANONICAL" => p.canonical_url === nothing ? nothing : p.canonical_url(t, pkg), "HAS_ASSETS" => !isempty(p.assets), - "MAKEDOCS_KWARGS" => map(((k, v),) -> k => repr(v), sort(collect(p.makedocs_kwargs), by=first)), + "MAKEDOCS_KWARGS" => + map(((k, v),) -> k => repr(v), sort(collect(p.makedocs_kwargs), by = first)), "PKG" => pkg, "REPO" => "$(t.host)/$(t.user)/$pkg.jl", "USER" => t.user, "BRANCH" => devbranch, - "EDIT_LINK" => p.edit_link == :devbranch ? _quoted(devbranch) : _quoted(p.edit_link), + "EDIT_LINK" => + p.edit_link == :devbranch ? _quoted(devbranch) : _quoted(p.edit_link), ) end @@ -160,7 +160,7 @@ _quoted(s::AbstractString) = string('"', s, '"') _quoted(s::Symbol) = repr(s) function view(p::Documenter{<:GitHubPagesStyle}, t::Template, pkg::AbstractString) - base = invoke(view, Tuple{Documenter, Template, AbstractString}, p, t, pkg) + base = invoke(view, Tuple{Documenter,Template,AbstractString}, p, t, pkg) return merge(base, Dict("HAS_DEPLOY" => true)) end @@ -176,8 +176,8 @@ function validate(p::Documenter, ::Template) end end -function validate(p::Documenter{T}, t::Template) where T <: YesDeploy - invoke(validate, Tuple{Documenter, Template}, p, t) +function validate(p::Documenter{T}, t::Template) where {T<:YesDeploy} + invoke(validate, Tuple{Documenter,Template}, p, t) if !hasplugin(t, T) name = nameof(T) s = "Documenter: The $name plugin must be included for docs deployment to be set up" @@ -214,7 +214,7 @@ function hook(p::Documenter, t::Template, pkg_dir::AbstractString) # Create the documentation project. with_project(docs_dir) do Pkg.add(DOCUMENTER_DEP) - cd(() -> Pkg.develop(PackageSpec(; path="..")), docs_dir) + cd(() -> Pkg.develop(PackageSpec(; path = "..")), docs_dir) end end @@ -233,7 +233,7 @@ end function interactive(::Type{Documenter}) styles = [NoDeploy, TravisCI, GitLabCI, GitHubActions] - menu = RadioMenu(map(string, styles); pagesize=length(styles)) + menu = RadioMenu(map(string, styles); pagesize = length(styles)) println("Documenter deploy style:") idx = request(menu) return interactive(Documenter{styles[idx]}) @@ -242,5 +242,5 @@ end function prompt(::Type{<:Documenter}, ::Type{Logo}, ::Val{:logo}) light = Base.prompt("Enter value for 'logo.light' (default: nothing)") dark = Base.prompt("Enter value for 'logo.dark' (default: nothing)") - return Logo(; light=light, dark=dark) + return Logo(; light = light, dark = dark) end diff --git a/src/plugins/formatter.jl b/src/plugins/formatter.jl index afaace9f..ce5fcaa5 100644 --- a/src/plugins/formatter.jl +++ b/src/plugins/formatter.jl @@ -19,7 +19,11 @@ end function validate(p::Formatter, t::Template) if p.style ∉ ("nostyle", "blue", "sciml", "yas") - throw(ArgumentError("""JuliaFormatter style must be either "nostyle", "blue", "sciml" or "yas".""")) + throw( + ArgumentError( + """JuliaFormatter style must be either "nostyle", "blue", "sciml" or "yas".""", + ), + ) end end @@ -38,7 +42,7 @@ end function prompt(::Type{Formatter}, ::Type{String}, ::Val{:style}) options = ["nostyle", "blue", "sciml", "yas"] - menu = RadioMenu(options; pagesize=length(options)) + menu = RadioMenu(options; pagesize = length(options)) println("Select a JuliaFormatter style:") idx = request(menu) return options[idx] diff --git a/src/plugins/git.jl b/src/plugins/git.jl index 6550728a..fd006a93 100644 --- a/src/plugins/git.jl +++ b/src/plugins/git.jl @@ -30,8 +30,8 @@ Creates a Git repository and a `.gitignore` file. """ @plugin struct Git <: Plugin ignore::Vector{String} = String[] - name::Union{String, Nothing} = nothing - email::Union{String, Nothing} = nothing + name::Union{String,Nothing} = nothing + email::Union{String,Nothing} = nothing branch::String = @mock(LibGit2.getconfig("init.defaultBranch", DEFAULT_DEFAULT_BRANCH)) ssh::Bool = false jl::Bool = true @@ -51,7 +51,9 @@ function validate(p::Git, t::Template) foreach((:name, :email)) do k user_k = "user.$k" if getproperty(p, k) === nothing && isempty(@mock LibGit2.getconfig(user_k, "")) - throw(ArgumentError("Git: Global Git config is missing required value '$user_k'")) + throw( + ArgumentError("Git: Global Git config is missing required value '$user_k'"), + ) end end end @@ -128,7 +130,7 @@ end function commit(p::Git, repo::GitRepo, pkg_dir::AbstractString, msg::AbstractString) if p.gpgsign - run(pipeline(`git -C $pkg_dir commit -S --allow-empty -m $msg`; stdout=devnull)) + run(pipeline(`git -C $pkg_dir commit -S --allow-empty -m $msg`; stdout = devnull)) else LibGit2.commit(repo, msg) end @@ -138,7 +140,7 @@ needs_username(::Git) = true function git_is_installed() return try - run(pipeline(`git --version`; stdout=devnull)) + run(pipeline(`git --version`; stdout = devnull)) true catch false diff --git a/src/plugins/license.jl b/src/plugins/license.jl index fc82da8e..a5baa7ed 100644 --- a/src/plugins/license.jl +++ b/src/plugins/license.jl @@ -18,9 +18,9 @@ struct License <: FilePlugin end function License(; - name::AbstractString="MIT", - path::Union{AbstractString, Nothing}=nothing, - destination::AbstractString="LICENSE", + name::AbstractString = "MIT", + path::Union{AbstractString,Nothing} = nothing, + destination::AbstractString = "LICENSE", ) if path === nothing path = default_file("licenses", name) @@ -35,10 +35,8 @@ defaultkw(::Type{License}, ::Val{:destination}) = "LICENSE" source(p::License) = p.path destination(p::License) = p.destination -view(::License, t::Template, ::AbstractString) = Dict( - "AUTHORS" => join(t.authors, ", "), - "YEAR" => year(today()), -) +view(::License, t::Template, ::AbstractString) = + Dict("AUTHORS" => join(t.authors, ", "), "YEAR" => year(today())) function isfixable(::License, pkg_dir) return !any(isfile, joinpath.(pkg_dir, ("LICENSE", "LICENSE.md"))) @@ -49,7 +47,7 @@ function prompt(::Type{License}, ::Type, ::Val{:name}) # Move MIT to the top. deleteat!(options, findfirst(==("MIT"), options)) pushfirst!(options, "MIT") - menu = RadioMenu(options; pagesize=length(options)) + menu = RadioMenu(options; pagesize = length(options)) println("Select a license:") idx = request(menu) return options[idx] diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 7e5b5918..197c23c8 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -29,7 +29,10 @@ end function project_key_order(key::String) _project_key_order = ["name", "uuid", "keywords", "license", "desc", "deps", "compat"] - return something(findfirst(x -> x == key, _project_key_order), length(_project_key_order) + 1) + return something( + findfirst(x -> x == key, _project_key_order), + length(_project_key_order) + 1, + ) end write_project(path::AbstractString, dict) = diff --git a/src/plugins/readme.jl b/src/plugins/readme.jl index 38a6e545..2c7c763c 100644 --- a/src/plugins/readme.jl +++ b/src/plugins/readme.jl @@ -85,4 +85,4 @@ default_badge_order() = [ Codecov, Coveralls, subtypes(BadgePlugin)..., -] \ No newline at end of file +] diff --git a/src/plugins/tagbot.jl b/src/plugins/tagbot.jl index 190c3399..11734e1b 100644 --- a/src/plugins/tagbot.jl +++ b/src/plugins/tagbot.jl @@ -39,16 +39,16 @@ Adds GitHub release support via [TagBot](https://github.com/JuliaRegistries/TagB destination::String = "TagBot.yml" trigger::String = "JuliaTagBot" token::Secret = Secret("GITHUB_TOKEN") - ssh::Union{Secret, Nothing} = Secret("DOCUMENTER_KEY") - ssh_password::Union{Secret, Nothing} = nothing - changelog::Union{String, Nothing} = nothing - changelog_ignore::Union{Vector{String}, Nothing} = nothing - gpg::Union{Secret, Nothing} = nothing - gpg_password::Union{Secret, Nothing} = nothing - registry::Union{String, Nothing} = nothing - branches::Union{Bool, Nothing} = nothing - dispatch::Union{Bool, Nothing} = nothing - dispatch_delay::Union{Int, Nothing} = nothing + ssh::Union{Secret,Nothing} = Secret("DOCUMENTER_KEY") + ssh_password::Union{Secret,Nothing} = nothing + changelog::Union{String,Nothing} = nothing + changelog_ignore::Union{Vector{String},Nothing} = nothing + gpg::Union{Secret,Nothing} = nothing + gpg_password::Union{Secret,Nothing} = nothing + registry::Union{String,Nothing} = nothing + branches::Union{Bool,Nothing} = nothing + dispatch::Union{Bool,Nothing} = nothing + dispatch_delay::Union{Int,Nothing} = nothing end source(p::TagBot) = p.file diff --git a/src/plugins/tests.jl b/src/plugins/tests.jl index 0aa06eff..5f4bccaf 100644 --- a/src/plugins/tests.jl +++ b/src/plugins/tests.jl @@ -1,11 +1,11 @@ const TEST_UUID = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -const TEST_DEP = PackageSpec(; name="Test", uuid=TEST_UUID) +const TEST_DEP = PackageSpec(; name = "Test", uuid = TEST_UUID) const AQUA_UUID = "4c88cf16-eb10-579e-8560-4a9242c79595" -const AQUA_DEP = PackageSpec(; name="Aqua", uuid=AQUA_UUID) +const AQUA_DEP = PackageSpec(; name = "Aqua", uuid = AQUA_UUID) const JET_UUID = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" -const JET_DEP = PackageSpec(; name="JET", uuid=JET_UUID) +const JET_DEP = PackageSpec(; name = "JET", uuid = JET_UUID) """ Tests(; @@ -76,7 +76,9 @@ end function validate(p::Tests, t::Template) invoke(validate, Tuple{FilePlugin,Template}, p, t) - p.project && t.julia < v"1.2" && @warn string( + 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 ($(t.julia)) is supported by the template", ) @@ -127,7 +129,7 @@ function add_test_dependency(p::Tests, pkg_dir::AbstractString) # Add the dependency manually since there's no programmatic way to add to [extras]. path = joinpath(pkg_dir, "Project.toml") toml = TOML.parsefile(path) - + get!(toml, "extras", Dict())["Test"] = TEST_UUID if p.aqua get!(toml, "extras", Dict())["Aqua"] = AQUA_UUID @@ -135,7 +137,7 @@ function add_test_dependency(p::Tests, pkg_dir::AbstractString) if p.jet get!(toml, "extras", Dict())["JET"] = JET_UUID end - + targets = String[] if p.aqua push!(targets, "Aqua") @@ -145,7 +147,7 @@ function add_test_dependency(p::Tests, pkg_dir::AbstractString) end push!(targets, "Test") get!(toml, "targets", Dict())["test"] = targets - + write_project(path, toml) # Generate the manifest by updating the project. diff --git a/src/show.jl b/src/show.jl index 85f2b83e..95e3e591 100644 --- a/src/show.jl +++ b/src/show.jl @@ -7,14 +7,14 @@ function Base.show(io::IO, m::MIME"text/plain", t::Template) print(io, " plugins: None") else print(io, repeat(' ', 2), "plugins:") - foreach(sort(t.plugins; by=string)) do p + foreach(sort(t.plugins; by = string)) do p println(io) show(IOContext(io, :indent => 4), m, p) end end end -function Base.show(io::IO, ::MIME"text/plain", p::T) where T <: Plugin +function Base.show(io::IO, ::MIME"text/plain", p::T) where {T<:Plugin} indent = get(io, :indent, 0) print(io, repeat(' ', indent), nameof(T)) ns = fieldnames(T) diff --git a/src/template.jl b/src/template.jl index f60f6dba..fed09936 100644 --- a/src/template.jl +++ b/src/template.jl @@ -22,7 +22,7 @@ function default_authors() end struct MissingUserException{T} <: Exception end -function Base.showerror(io::IO, ::MissingUserException{T}) where T +function Base.showerror(io::IO, ::MissingUserException{T}) where {T} s = """$(nameof(T)): Git hosting service username is required, set one with keyword `user=""`""" print(io, s) end @@ -80,7 +80,7 @@ struct Template user::String end -Template(; interactive::Bool=false, kwargs...) = Template(Val(interactive); kwargs...) +Template(; interactive::Bool = false, kwargs...) = Template(Val(interactive); kwargs...) Template(::Val{true}; kwargs...) = interactive(Template; kwargs...) function Template(::Val{false}; kwargs...) @@ -102,7 +102,7 @@ function Template(::Val{false}; kwargs...) !(typeof(p) in vcat(typeof.(plugins), disabled)) end append!(plugins, defaults) - plugins = Vector{Plugin}(sort(plugins; by=string)) + plugins = Vector{Plugin}(sort(plugins; by = string)) if isempty(user) foreach(plugins) do p @@ -135,12 +135,12 @@ function (t::Template)(pkg::AbstractString) try foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" - foreach(sort(t.plugins; by=p -> priority(p, h), rev=true)) do p + foreach(sort(t.plugins; by = p -> priority(p, h), rev = true)) do p h(p, t, pkg_dir) end end catch - rm(pkg_dir; recursive=true, force=true) + rm(pkg_dir; recursive = true, force = true) rethrow() end @@ -159,23 +159,23 @@ end function Base.:(==)(a::Template, b::Template) return a.authors == b.authors && - a.dir == b.dir && - a.host == b.host && - a.julia == b.julia && - a.user == b.user && - all(map(==, a.plugins, b.plugins)) + a.dir == b.dir && + a.host == b.host && + a.julia == b.julia && + a.user == b.user && + all(map(==, a.plugins, b.plugins)) end # Does the template have a plugin that satisfies some predicate? hasplugin(t::Template, f::Function) = any(f, t.plugins) -hasplugin(t::Template, ::Type{T}) where T <: Plugin = hasplugin(t, p -> p isa T) +hasplugin(t::Template, ::Type{T}) where {T<:Plugin} = hasplugin(t, p -> p isa T) """ getplugin(t::Template, ::Type{T<:Plugin}) -> Union{T, Nothing} Get the plugin of type `T` from the template `t`, if it's present. """ -function getplugin(t::Template, ::Type{T}) where T <: Plugin +function getplugin(t::Template, ::Type{T}) where {T<:Plugin} i = findfirst(p -> p isa T, t.plugins) return i === nothing ? nothing : t.plugins[i] end @@ -184,7 +184,7 @@ end getkw!(kwargs, k) = pop!(kwargs, k, defaultkw(Template, k)) # Default Template keyword values. -defaultkw(::Type{T}, s::Symbol) where T = defaultkw(T, Val(s)) +defaultkw(::Type{T}, s::Symbol) where {T} = defaultkw(T, Val(s)) defaultkw(::Type{Template}, ::Val{:authors}) = default_authors() defaultkw(::Type{Template}, ::Val{:dir}) = contractuser(Pkg.devdir()) defaultkw(::Type{Template}, ::Val{:host}) = "github.com" @@ -194,7 +194,7 @@ defaultkw(::Type{Template}, ::Val{:user}) = default_user() function interactive(::Type{Template}; kwargs...) # If the user supplied any keywords themselves, don't prompt for them. - kwargs = Dict{Symbol, Any}(kwargs) + kwargs = Dict{Symbol,Any}(kwargs) options = [:user, :authors, :dir, :host, :julia, :plugins] customizable = setdiff(options, keys(kwargs)) @@ -205,8 +205,8 @@ function interactive(::Type{Template}; kwargs...) try println("Template keywords to customize:") - opts = map(k -> "$k ($(repr(defaultkw(Template, k))))" , customizable) - menu = MultiSelectMenu(opts; pagesize=length(customizable)) + opts = map(k -> "$k ($(repr(defaultkw(Template, k))))", customizable) + menu = MultiSelectMenu(opts; pagesize = length(customizable)) customize = customizable[sort!(collect(request(menu)))] just_one && last(customizable) in customize && return Template(; kwargs...) @@ -245,7 +245,7 @@ end function prompt(::Type{Template}, ::Type, ::Val{:host}) hosts = ["github.com", "gitlab.com", "bitbucket.org", "Other"] - menu = RadioMenu(hosts; pagesize=length(hosts)) + menu = RadioMenu(hosts; pagesize = length(hosts)) println("Select Git repository hosting service:") idx = request(menu) return if idx == lastindex(hosts) @@ -258,7 +258,7 @@ end function prompt(::Type{Template}, ::Type, ::Val{:julia}) versions = map(format_version, VersionNumber.(1, 0:VERSION.minor)) push!(versions, "Other") - menu = RadioMenu(map(string, versions); pagesize=length(versions)) + menu = RadioMenu(map(string, versions); pagesize = length(versions)) println("Select minimum Julia version:") idx = request(menu) return if idx == lastindex(versions) @@ -276,7 +276,7 @@ function prompt(::Type{Template}, ::Type, ::Val{:plugins}) ndefaults = length(defaults) # Put the defaults first. options = unique!([defaults; concretes(Plugin)]) - menu = MultiSelectMenu(map(T -> string(nameof(T)), options); pagesize=length(options)) + menu = MultiSelectMenu(map(T -> string(nameof(T)), options); pagesize = length(options)) println("Select plugins:") # Pre-select the default plugins and move the cursor to the first non-default. # To make this better, we need julia#30043.