Catch missing user exception in interactive mode and prompt for it (#180)

This commit is contained in:
Chris de Graaf 2020-06-04 10:09:20 -05:00 committed by GitHub
parent 6db8ffdefc
commit 1c8030be89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 10 deletions

View File

@ -1,7 +1,7 @@
name = "PkgTemplates" name = "PkgTemplates"
uuid = "14b8a8f1-9102-5b29-a752-f990bacb7fe1" uuid = "14b8a8f1-9102-5b29-a752-f990bacb7fe1"
authors = ["Chris de Graaf", "Invenia Technical Computing Corporation"] authors = ["Chris de Graaf", "Invenia Technical Computing Corporation"]
version = "0.7.2" version = "0.7.3"
[deps] [deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"

View File

@ -19,6 +19,12 @@ function default_authors()
return "$authors and contributors" return "$authors and contributors"
end end
struct MissingUserException{T} <: Exception end
function Base.showerror(io::IO, ::MissingUserException{T}) where T
s = """$(nameof(T)): Git hosting service username is required, set one with keyword `user="<username>"`"""
print(io, s)
end
""" """
Template(; kwargs...) Template(; kwargs...)
@ -95,11 +101,7 @@ function Template(::Val{false}; kwargs...)
if isempty(user) if isempty(user)
foreach(plugins) do p foreach(plugins) do p
if needs_username(p) needs_username(p) && throw(MissingUserException{typeof(p)}())
T = nameof(typeof(p))
s = """$T: Git hosting service username is required, set one with keyword `user="<username>"`"""
throw(ArgumentError(s))
end
end end
end end
@ -184,7 +186,7 @@ function interactive(::Type{Template}; kwargs...)
just_one = length(customizable) == 1 just_one = length(customizable) == 1
just_one && push(customizable, "None") just_one && push(customizable, "None")
return try try
println("Template keywords to customize:") println("Template keywords to customize:")
menu = MultiSelectMenu(map(string, customizable); pagesize=length(customizable)) menu = MultiSelectMenu(map(string, customizable); pagesize=length(customizable))
customize = customizable[sort!(collect(request(menu)))] customize = customizable[sort!(collect(request(menu)))]
@ -195,17 +197,34 @@ function interactive(::Type{Template}; kwargs...)
kwargs[k] = prompt(Template, fieldtype(Template, k), k) kwargs[k] = prompt(Template, fieldtype(Template, k), k)
end end
Template(; kwargs...) while true
try
return Template(; kwargs...)
catch e
e isa MissingUserException || rethrow()
kwargs[:user] = prompt(Template, String, :user)
end
end
catch e catch e
e isa InterruptException || rethrow() e isa InterruptException || rethrow()
println() println()
@info "Cancelled" @info "Cancelled"
nothing return nothing
end end
end end
prompt(::Type{Template}, ::Type, ::Val{:pkg}) = Base.prompt("Package name") prompt(::Type{Template}, ::Type, ::Val{:pkg}) = Base.prompt("Package name")
function prompt(::Type{Template}, ::Type, ::Val{:user})
return if isempty(default_user())
input = Base.prompt("Enter value for 'user' (String, required)")
input === nothing && throw(InterruptException())
return input
else
fallback_prompt(String, :user)
end
end
function prompt(::Type{Template}, ::Type, ::Val{:host}) function prompt(::Type{Template}, ::Type, ::Val{:host})
hosts = ["github.com", "gitlab.com", "bitbucket.org", "Other"] hosts = ["github.com", "gitlab.com", "bitbucket.org", "Other"]
menu = RadioMenu(hosts; pagesize=length(hosts)) menu = RadioMenu(hosts; pagesize=length(hosts))

View File

@ -9,6 +9,7 @@ const DOWN = "\eOB"
const ALL = "a" const ALL = "a"
const NONE = "n" const NONE = "n"
const DONE = "d" const DONE = "d"
const SIGINT = "\x03"
# Because the plugin selection dialog prints directly to stdin in the same way # Because the plugin selection dialog prints directly to stdin in the same way
# as we do here, and our input prints happen first, we're going to need to insert # as we do here, and our input prints happen first, we're going to need to insert
@ -206,6 +207,25 @@ end
@test PT.interactive(Codecov) == Codecov() @test PT.interactive(Codecov) == Codecov()
end end
@testset "Missing user" begin
print(
stdin.buffer,
DONE, # Customize nothing
"username", LF, # Enter user after it's prompted
)
mock(PT.default_user => () -> "") do _du
@test Template(; interactive=true) == Template(; user="username")
end
end
@testset "Interrupts" begin
print(
stdin.buffer,
SIGINT, # Send keyboard interrupt
)
@test Template(; interactive=true) === nothing
end
println() println()
end end
end end

View File

@ -3,8 +3,10 @@
@testset "Template" begin @testset "Template" begin
@testset "Template constructor" begin @testset "Template constructor" begin
@testset "user" begin @testset "user" begin
msg = sprint(showerror, PT.MissingUserException{TravisCI}())
@test startswith(msg, "TravisCI: ")
mock(PT.default_user => () -> "") do _du mock(PT.default_user => () -> "") do _du
@test_throws ArgumentError Template() @test_throws PT.MissingUserException Template()
@test isempty(Template(; plugins=[!Git]).user) @test isempty(Template(; plugins=[!Git]).user)
end end
mock(PT.default_user => () -> "username") do _du mock(PT.default_user => () -> "username") do _du