From 369229d76fb0814e37aa9c65df92d768e395d91b Mon Sep 17 00:00:00 2001 From: Morten Piibeleht Date: Mon, 7 Jul 2025 15:08:24 +0300 Subject: [PATCH 1/3] chore: impose JuliaFormatter on the codebase --- .JuliaFormatter.toml | 25 +++ .github/workflows/format-julia.yaml | 34 ++++ bin/structure.jl | 52 +++--- src/PkgAuthentication.jl | 250 +++++++++++++++++----------- src/helpers.jl | 3 +- test/authserver.jl | 2 +- test/tests.jl | 12 +- test/util.jl | 6 +- test/utilities_test.jl | 38 ++++- 9 files changed, 283 insertions(+), 139 deletions(-) create mode 100644 .JuliaFormatter.toml create mode 100644 .github/workflows/format-julia.yaml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..3bc2277 --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,25 @@ +style = "blue" +indent = 4 +margin = 100 +always_for_in = "nothing" +whitespace_typedefs = true +whitespace_ops_in_indices = true +remove_extra_newlines = false +import_to_using = false +pipe_to_function_call = false +short_to_long_function_def = false +always_use_return = false +whitespace_in_kwargs = false +annotate_untyped_fields_with_any = false +format_docstrings = false +align_struct_field = true +align_assignment = true +align_conditional = true +align_pair_arrow = true +conditional_to_if = false +normalize_line_endings = "auto" +align_matrix = false +join_lines_based_on_source = true +trailing_comma = true +indent_submodule = true +ignore = [".git"] diff --git a/.github/workflows/format-julia.yaml b/.github/workflows/format-julia.yaml new file mode 100644 index 0000000..ab8773c --- /dev/null +++ b/.github/workflows/format-julia.yaml @@ -0,0 +1,34 @@ +name: "Format: Julia" +on: + push: + branches: + - main + paths: + - "**.jl" + - ".JuliaFormatter.toml" + - ".github/workflows/format-julia.yaml" + # Note: no path filtering when running on PRs, since the formatter + # is a required check, and therefore needs to always run. + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + - labeled + +env: + CI: true + +jobs: + format: + runs-on: ubuntu-latest + steps: + - uses: julia-actions/julia-format@v4 + with: + # Version compat for JuliaFormatter.jl (default: '1') + # E.g. set to '1.0.54' if you need to use JuliaFormatter.jl v1.0.54 + version: '1' + # GitHub PR label that enabled formatting suggestions. + # Leave this unset or empty to show suggestions for all PRs. + suggestion-label: 'format-suggest' diff --git a/bin/structure.jl b/bin/structure.jl index 8e4e560..a96ec6c 100644 --- a/bin/structure.jl +++ b/bin/structure.jl @@ -5,25 +5,28 @@ import InteractiveUtils, Markdown, TextWrap # Rather than generating the file directly, we'll write the output to a buffer # first, so that we wouldn't end up with a partial file if there is some error. -buffer = let buffer = IOBuffer(write=true) - write(buffer, """ - # Internal State Machine +buffer = let buffer = IOBuffer(; write=true) + write( + buffer, + """ + # Internal State Machine - The authentication control flow is implemented as the following state machine, starting from the `NeedAuthentication` - state (or `NoAuthentication` if `force=true` is passed to `authenticate`), and finishing in either `Success` or `Failure`. + The authentication control flow is implemented as the following state machine, starting from the `NeedAuthentication` + state (or `NoAuthentication` if `force=true` is passed to `authenticate`), and finishing in either `Success` or `Failure`. - ```mermaid - --- - title: PkgAuthentication state machine diagram - --- + ```mermaid + --- + title: PkgAuthentication state machine diagram + --- - stateDiagram-v2 + stateDiagram-v2 - [*] --> NeedAuthentication - [*] --> NoAuthentication - """) + [*] --> NeedAuthentication + [*] --> NoAuthentication + """, + ) - all_targets = Dict{String,Vector{String}}() + all_targets = Dict{String, Vector{String}}() ignore_errors = ( PkgAuthentication.Failure, PkgAuthentication.Success ) @@ -34,7 +37,7 @@ buffer = let buffer = IOBuffer(write=true) end end choice_index = 0 - for state in sort(InteractiveUtils.subtypes(PkgAuthentication.State), by=string) + for state in sort(InteractiveUtils.subtypes(PkgAuthentication.State); by=string) println(buffer) state_str = string(nameof(state)) # Generate the connecting arrows between the states @@ -64,8 +67,8 @@ buffer = let buffer = IOBuffer(write=true) docstr_text = docstr.meta[:results][1].text[1] println(buffer, " note left of $(state_str)") TextWrap.print_wrapped( - buffer, docstr_text, width=65, - initial_indent = 8, subsequent_indent = 8, + buffer, docstr_text; width=65, + initial_indent=8, subsequent_indent=8, ) println(buffer) println(buffer, " end note") @@ -76,13 +79,16 @@ buffer = let buffer = IOBuffer(write=true) end end - write(buffer, """ - Success --> [*] - Failure --> [*] - ``` + write( + buffer, + """ + Success --> [*] + Failure --> [*] + ``` - > **Note** This file is automatically generated by the `bin/structure.jl` script. - """) + > **Note** This file is automatically generated by the `bin/structure.jl` script. + """, + ) take!(buffer) end diff --git a/src/PkgAuthentication.jl b/src/PkgAuthentication.jl index 811bcd0..b61c42a 100644 --- a/src/PkgAuthentication.jl +++ b/src/PkgAuthentication.jl @@ -54,10 +54,10 @@ julia> PkgAuthentication.authenticate("my-pkg-server.example.com") """ function authenticate( server::AbstractString; - auth_suffix::Union{String, Nothing} = nothing, - force::Union{Bool, Nothing} = nothing, - tries::Union{Integer, Nothing} = nothing, - modify_environment::Bool = true, + auth_suffix::Union{String, Nothing}=nothing, + force::Union{Bool, Nothing}=nothing, + tries::Union{Integer, Nothing}=nothing, + modify_environment::Bool=true, )::Union{Success, Failure} if modify_environment ENV[pkg_server_env_var_name] = server @@ -66,9 +66,9 @@ function authenticate( # variable for the duration of the `authenticate` call. withenv(pkg_server_env_var_name => server) do authenticate(; - auth_suffix = auth_suffix, - force = force, - tries = tries, + auth_suffix=auth_suffix, + force=force, + tries=tries, ) end end @@ -89,9 +89,9 @@ julia> PkgAuthentication.authenticate() ``` """ function authenticate(; - auth_suffix::Union{String, Nothing} = nothing, - force::Union{Bool, Nothing} = nothing, - tries::Union{Integer, Nothing} = nothing, + auth_suffix::Union{String, Nothing}=nothing, + force::Union{Bool, Nothing}=nothing, + tries::Union{Integer, Nothing}=nothing, )::Union{Success, Failure} if auth_suffix === nothing # If the user does not provide the `auth_suffix` kwarg, we will append @@ -149,7 +149,8 @@ struct NeedAuthentication <: State server::String auth_suffix::String end -Base.show(io::IO, s::NeedAuthentication) = print(io, "NeedAuthentication($(s.server), $(s.auth_suffix))") +Base.show(io::IO, s::NeedAuthentication) = + print(io, "NeedAuthentication($(s.server), $(s.auth_suffix))") function step(state::NeedAuthentication)::Union{HasToken, NoAuthentication} path = token_path(state.server) @@ -173,7 +174,8 @@ struct NoAuthentication <: State server::String auth_suffix::String end -Base.show(io::IO, s::NoAuthentication) = print(io, "NoAuthentication($(s.server), $(s.auth_suffix))") +Base.show(io::IO, s::NoAuthentication) = + print(io, "NoAuthentication($(s.server), $(s.auth_suffix))") function device_client_id() return get(ENV, "JULIA_PKG_AUTHENTICATION_DEVICE_CLIENT_ID", "device") @@ -184,9 +186,9 @@ end # Returns an IOBuffer() object that can be passed to Downloads.download(input=...). function device_token_request_body(; client_id::AbstractString, - scope::Union{AbstractString, Nothing} = nothing, - device_code::Union{AbstractString, Nothing} = nothing, - grant_type::Union{AbstractString, Nothing} = nothing, + scope::Union{AbstractString, Nothing}=nothing, + device_code::Union{AbstractString, Nothing}=nothing, + grant_type::Union{AbstractString, Nothing}=nothing, ) b = IOBuffer() write(b, "client_id=", client_id) @@ -220,11 +222,11 @@ function get_auth_configuration(state::NoAuthentication) output = IOBuffer() auth_suffix = isempty(state.auth_suffix) ? "auth" : state.auth_suffix response = Downloads.request( - "$(state.server)/$(auth_suffix)/configuration", - method = "GET", - output = output, - throw = false, - headers = ["Accept" => "application/json"], + "$(state.server)/$(auth_suffix)/configuration"; + method="GET", + output=output, + throw=false, + headers=["Accept" => "application/json"], ) if response isa Downloads.Response && response.status == 200 @@ -238,7 +240,12 @@ function get_auth_configuration(state::NoAuthentication) end if body !== nothing - @assert !haskey(body, "auth_flows") || !("device" in body["auth_flows"]) || (haskey(body, "device_authorization_endpoint") && haskey(body, "device_token_endpoint") && haskey(body, "device_token_refresh_url")) + @assert !haskey(body, "auth_flows") || !("device" in body["auth_flows"]) || + ( + haskey(body, "device_authorization_endpoint") && + haskey(body, "device_token_endpoint") && + haskey(body, "device_token_refresh_url") + ) return body end end @@ -268,18 +275,24 @@ function step(state::NoAuthentication)::Union{RequestLogin, Failure} end end -function fetch_device_code(state::NoAuthentication, device_endpoint::AbstractString, device_scope::Union{AbstractString, Nothing}) +function fetch_device_code( + state::NoAuthentication, + device_endpoint::AbstractString, + device_scope::Union{AbstractString, Nothing}, +) output = IOBuffer() response = Downloads.request( - device_endpoint, - method = "POST", - input = device_token_request_body( - client_id = device_client_id(), - scope = device_scope, + device_endpoint; + method="POST", + input=device_token_request_body(; + client_id=device_client_id(), + scope=device_scope, + ), + output=output, + throw=false, + headers=Dict( + "Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded" ), - output = output, - throw = false, - headers = Dict("Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded"), ) if response isa Downloads.Response && response.status == 200 body = nothing @@ -302,11 +315,11 @@ function initiate_browser_challenge(state::NoAuthentication) output = IOBuffer() challenge = Random.randstring(32) response = Downloads.request( - "$(state.server)/$(state.auth_suffix)/challenge", + "$(state.server)/$(state.auth_suffix)/challenge"; method = "POST", - input = IOBuffer(challenge), + input = IOBuffer(challenge), output = output, - throw = false, + throw = false, ) if response isa Downloads.Response && response.status == 200 return true, challenge, String(take!(output)) @@ -327,7 +340,8 @@ struct HasToken <: State mtime::Float64 token::Dict{String, Any} end -Base.show(io::IO, s::HasToken) = print(io, "HasToken($(s.server), $(s.auth_suffix), $(s.mtime), )") +Base.show(io::IO, s::HasToken) = + print(io, "HasToken($(s.server), $(s.auth_suffix), $(s.mtime), )") function step(state::HasToken)::Union{NeedRefresh, Success} expiry = get(state.token, "expires_at", get(state.token, "expires", 0)) @@ -349,17 +363,18 @@ struct NeedRefresh <: State auth_suffix::String token::Dict{String, Any} end -Base.show(io::IO, s::NeedRefresh) = print(io, "NeedRefresh($(s.server), $(s.auth_suffix), )") +Base.show(io::IO, s::NeedRefresh) = + print(io, "NeedRefresh($(s.server), $(s.auth_suffix), )") function step(state::NeedRefresh)::Union{HasNewToken, NoAuthentication} refresh_token = state.token["refresh_token"] output = IOBuffer() response = Downloads.request( - state.token["refresh_url"], - method = "GET", - headers = ["Authorization" => "Bearer $refresh_token"], - output = output, - throw = false, + state.token["refresh_url"]; + method="GET", + headers=["Authorization" => "Bearer $refresh_token"], + output=output, + throw=false, ) # errors are recoverable by just getting a new token: if response isa Downloads.Response && response.status == 200 @@ -370,10 +385,12 @@ function step(state::NeedRefresh)::Union{HasNewToken, NoAuthentication} assert_dict_keys(body, "expires_in"; msg=msg) assert_dict_keys(body, "expires", "expires_at"; msg=msg) end - @info("Successfully refreshed token") + @info("Successfully refreshed token") return HasNewToken(state.server, body) catch err - @debug "invalid body received while refreshing token" exception=(err, catch_backtrace()) + @debug "invalid body received while refreshing token" exception = ( + err, catch_backtrace() + ) end @info "Did not refresh token, could not json parse ", response return NoAuthentication(state.server, state.auth_suffix) @@ -425,7 +442,7 @@ function step(state::HasNewToken)::Union{HasNewToken, Success, Failure} return HasNewToken(state.server, state.token, 0) end catch err - @debug "failed to write token" exception=(err, catch_backtrace()) + @debug "failed to write token" exception = (err, catch_backtrace()) return GenericError("Failed to write token.") end end @@ -443,7 +460,10 @@ struct RequestLogin <: State device_token_endpoint::String device_token_refresh_url::String end -Base.show(io::IO, s::RequestLogin) = print(io, "RequestLogin($(s.server), $(s.auth_suffix), , $(s.response), $(s.device_token_endpoint), $(s.device_token_refresh_url))") +Base.show(io::IO, s::RequestLogin) = print( + io, + "RequestLogin($(s.server), $(s.auth_suffix), , $(s.response), $(s.device_token_endpoint), $(s.device_token_refresh_url))", +) function step(state::RequestLogin)::Union{ClaimToken, Failure} is_device = !isempty(state.device_token_endpoint) @@ -477,7 +497,7 @@ function step(state::RequestLogin)::Union{ClaimToken, Failure} state.challenge, state.response, state.device_token_endpoint, - state.device_token_refresh_url + state.device_token_refresh_url, ) else # this can only happen for the browser hook return GenericError("Failed to execute open_browser hook.") @@ -503,13 +523,38 @@ struct ClaimToken <: State device_token_endpoint::String device_token_refresh_url::String end -Base.show(io::IO, s::ClaimToken) = print(io, "ClaimToken($(s.server), $(s.auth_suffix), , $(s.response), $(s.expiry), $(s.start_time), $(s.timeout), $(s.poll_interval), $(s.failures), $(s.max_failures), $(s.device_token_endpoint), $(s.device_token_refresh_url))") +Base.show(io::IO, s::ClaimToken) = print( + io, + "ClaimToken($(s.server), $(s.auth_suffix), , $(s.response), $(s.expiry), $(s.start_time), $(s.timeout), $(s.poll_interval), $(s.failures), $(s.max_failures), $(s.device_token_endpoint), $(s.device_token_refresh_url))", +) -ClaimToken(server, auth_suffix, challenge, response, device_token_endpoint, device_token_refresh_url, expiry = Inf, failures = 0) = - ClaimToken(server, auth_suffix, challenge, response, expiry, time(), 180, 2, failures, 10, device_token_endpoint, device_token_refresh_url) +ClaimToken( + server, + auth_suffix, + challenge, + response, + device_token_endpoint, + device_token_refresh_url, + expiry=Inf, + failures=0, +) = + ClaimToken( + server, + auth_suffix, + challenge, + response, + expiry, + time(), + 180, + 2, + failures, + 10, + device_token_endpoint, + device_token_refresh_url, + ) function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure} - if time() > state.expiry || (time() - state.start_time)/1e6 > state.timeout # server-side or client-side timeout + if time() > state.expiry || (time() - state.start_time) / 1e6 > state.timeout # server-side or client-side timeout return GenericError("Timeout waiting for user to authenticate in browser.") end @@ -524,16 +569,19 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure} if is_device output = IOBuffer() response = Downloads.request( - state.device_token_endpoint, - method = "POST", - input = device_token_request_body( - client_id = device_client_id(), - device_code = state.response["device_code"], - grant_type = "urn:ietf:params:oauth:grant-type:device_code", + state.device_token_endpoint; + method="POST", + input=device_token_request_body(; + client_id=device_client_id(), + device_code=state.response["device_code"], + grant_type="urn:ietf:params:oauth:grant-type:device_code", + ), + output=output, + throw=false, + headers=Dict( + "Accept" => "application/json", + "Content-Type" => "application/x-www-form-urlencoded", ), - output = output, - throw = false, - headers = Dict("Accept" => "application/json", "Content-Type" => "application/x-www-form-urlencoded"), ) else data = JSON.json(Dict( @@ -541,11 +589,11 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure} "response" => state.response, )) response = Downloads.request( - "$(state.server)/$(state.auth_suffix)/claimtoken", + "$(state.server)/$(state.auth_suffix)/claimtoken"; method = "POST", - input = IOBuffer(data), + input = IOBuffer(data), output = output, - throw = false, + throw = false, ) end @@ -599,7 +647,7 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure} state.failures + 1, state.max_failures, state.device_token_endpoint, - state.device_token_refresh_url + state.device_token_refresh_url, ) end elseif response isa Downloads.Response && response.status == 200 @@ -675,8 +723,10 @@ is_token_valid(toml) = get(toml, "id_token", nothing) isa AbstractString && get(toml, "refresh_token", nothing) isa AbstractString && get(toml, "refresh_url", nothing) isa AbstractString && - (get(toml, "expires_at", nothing) isa Union{Integer, AbstractFloat} || - get(toml, "expires", nothing) isa Union{Integer, AbstractFloat}) + ( + get(toml, "expires_at", nothing) isa Union{Integer, AbstractFloat} || + get(toml, "expires", nothing) isa Union{Integer, AbstractFloat} + ) @static if Base.VERSION >= v"1.4-" const pkg_server = Pkg.pkg_server @@ -694,29 +744,30 @@ end const _get_server_dir = Pkg.PlatformEngines.get_server_dir else function _get_server_dir( - url::AbstractString, - server::AbstractString, - ) - server === nothing && return - url == server || startswith(url, "$server/") || return + url::AbstractString, + server::AbstractString, + ) + server === nothing && return nothing + url == server || startswith(url, "$server/") || return nothing m = match(r"^\w+://(?:[^\\/@]+@)?([^\\/:]+)(?:$|/|:)", server) if m === nothing @warn "malformed Pkg server value" server - return + return nothing end joinpath(Pkg.depots1(), "servers", m.captures[1]) end end function get_server_dir( - url::AbstractString, - server::Union{AbstractString, Nothing} = pkg_server(), - ) + url::AbstractString, + server::Union{AbstractString, Nothing}=pkg_server(), +) server_dir_pkgauth = _get_server_dir(url, server) server_dir_pkg = Pkg.PlatformEngines.get_server_dir(url, server) if server_dir_pkgauth != server_dir_pkg - msg = "The PkgAuthentication server directory is not equal to the Pkg server directory." * - "Unexpected behavior may occur." + msg = + "The PkgAuthentication server directory is not equal to the Pkg server directory." * + "Unexpected behavior may occur." @warn msg server_dir_pkgauth server_dir_pkg end return server_dir_pkgauth @@ -749,18 +800,21 @@ end function open_browser(url::AbstractString) @debug "opening auth in browser" - printstyled(color = :yellow, bold = true, + printstyled(; color=:yellow, bold=true, "Authentication required: please authenticate in browser.\n") - printstyled(color = :yellow, """ - The authentication page should open in your browser automatically, but you may need to switch to the opened window or tab. If the authentication page is not automatically opened, you can authenticate by manually opening the following URL: """) - printstyled(color = :light_blue, "$url\n") + printstyled(; + color=:yellow, + """ +The authentication page should open in your browser automatically, but you may need to switch to the opened window or tab. If the authentication page is not automatically opened, you can authenticate by manually opening the following URL: """, + ) + printstyled(; color=:light_blue, "$url\n") try if OPEN_BROWSER_HOOK[] !== nothing try OPEN_BROWSER_HOOK[](url) return true catch err - @info "error executing browser hook" exception=(err, catch_backtrace()) + @info "error executing browser hook" exception = (err, catch_backtrace()) return false end elseif Sys.iswindows() || detectwsl() @@ -771,7 +825,8 @@ function open_browser(url::AbstractString) run(`xdg-open $url`; wait=false) end catch err - @warn "There was a problem opening the authentication URL in a browser, please try opening this URL manually to authenticate." url, error = err + @warn "There was a problem opening the authentication URL in a browser, please try opening this URL manually to authenticate." url, + error = err end return true end @@ -798,9 +853,9 @@ julia> PkgAuthentication.install("my-pkg-server.example.com") julia> PkgAuthentication.install("my-pkg-server.example.com"; maxcount = 5) ``` """ -function install(server::AbstractString; maxcount::Integer = 3) +function install(server::AbstractString; maxcount::Integer=3) ENV[pkg_server_env_var_name] = server - return install(; maxcount = maxcount) + return install(; maxcount=maxcount) end """ @@ -826,7 +881,7 @@ julia> PkgAuthentication.install() julia> PkgAuthentication.install(; maxcount = 5) ``` """ -function install(; maxcount::Integer = 3) +function install(; maxcount::Integer=3) if maxcount < 1 throw(ArgumentError("`maxcount` must be greater than or equal to one")) end @@ -842,23 +897,24 @@ function install(; maxcount::Integer = 3) end function generate_auth_handler(maxcount::Integer) - auth_handler = (url, server, err) -> begin - failed_auth_count = 0 - ret = authenticate(server; tries = 2) - if ret isa Success + auth_handler = + (url, server, err) -> begin failed_auth_count = 0 - @debug "Authentication successful." - else - failed_auth_count += 1 - if failed_auth_count >= maxcount - printstyled(color = :red, bold = true, "\nAuthentication failed.\n\n") - return true, false # handled, but Pkg shouldn't try again + ret = authenticate(server; tries=2) + if ret isa Success + failed_auth_count = 0 + @debug "Authentication successful." else - printstyled(color = :yellow, bold = true, "\nAuthentication failed. Retrying...\n\n") + failed_auth_count += 1 + if failed_auth_count >= maxcount + printstyled(; color=:red, bold=true, "\nAuthentication failed.\n\n") + return true, false # handled, but Pkg shouldn't try again + else + printstyled(; color=:yellow, bold=true, "\nAuthentication failed. Retrying...\n\n") + end end + return true, true # handled, and Pkg should try again now end - return true, true # handled, and Pkg should try again now - end return auth_handler end diff --git a/src/helpers.jl b/src/helpers.jl index c03ecc2..37d9b0c 100644 --- a/src/helpers.jl +++ b/src/helpers.jl @@ -8,7 +8,8 @@ else # We use the same approach as canonical/snapd do to detect WSL Sys.islinux() && ( isfile("/proc/sys/fs/binfmt_misc/WSLInterop") - || isdir("/run/WSL") + || + isdir("/run/WSL") ) end end diff --git a/test/authserver.jl b/test/authserver.jl index 07c01da..21e8463 100644 --- a/test/authserver.jl +++ b/test/authserver.jl @@ -47,7 +47,7 @@ function response_handler(req) "refresh_token" => refresh_token, "refresh_url" => "http://localhost:$(PORT)/auth/renew/token.toml/v2/", "expires_in" => EXPIRY, - "expires_at" => round(Int, time()) + EXPIRY + "expires_at" => round(Int, time()) + EXPIRY, ) @show response diff --git a/test/tests.jl b/test/tests.jl index 55a687a..faf9413 100644 --- a/test/tests.jl +++ b/test/tests.jl @@ -14,9 +14,9 @@ function delete_token() token_path = PkgAuthentication.token_path(test_pkg_server) servers_dir = joinpath(only(Pkg.depots()), "servers") @info "" token_path - rm(token_path; force = true, recursive = true) + rm(token_path; force=true, recursive=true) @info "" servers_dir - rm(servers_dir; force = true, recursive = true) + rm(servers_dir; force=true, recursive=true) end # Helper function to do the GET against /auth/configuration @@ -37,7 +37,7 @@ authserver_file = joinpath(@__DIR__, "authserver.jl") cmd = `$(Base.julia_cmd()) $(authserver_file)` env2 = copy(ENV) env2["JULIA_PROJECT"] = Base.active_project() -p = run(pipeline(setenv(cmd, env2), stdout=stdout, stderr=stdout), wait=false) +p = run(pipeline(setenv(cmd, env2); stdout=stdout, stderr=stdout); wait=false) atexit(() -> kill(p)) sleep(10) @@ -55,7 +55,7 @@ PkgAuthentication.register_open_browser_hook(url -> HTTP.get(url)) @test startswith(success.token["id_token"], "full-") @test !occursin("id_token", sprint(show, success)) - sleeptimer = ceil(Int, success.token["expires_at"] - time() + 1) + sleeptimer = ceil(Int, success.token["expires_at"] - time() + 1) @info "sleep for $(sleeptimer)s (until refresh necessary)" sleep(sleeptimer) @@ -86,7 +86,7 @@ end @test startswith(success.token["id_token"], "device-") @test !occursin("id_token", sprint(show, success)) - sleeptimer = ceil(Int, success.token["expires_at"] - time() + 1) + sleeptimer = ceil(Int, success.token["expires_at"] - time() + 1) @info "sleep for $(sleeptimer)s (until refresh necessary)" sleep(sleeptimer) @@ -116,7 +116,7 @@ end @test startswith(success.token["id_token"], "device-") @test !occursin("id_token", sprint(show, success)) - sleeptimer = ceil(Int, success.token["expires_at"] - time() + 1) + sleeptimer = ceil(Int, success.token["expires_at"] - time() + 1) @info "sleep for $(sleeptimer)s (until refresh necessary)" sleep(sleeptimer) diff --git a/test/util.jl b/test/util.jl index 1b90e15..f58a87c 100644 --- a/test/util.jl +++ b/test/util.jl @@ -1,4 +1,4 @@ -function with_depot(f::F, depot_path::AbstractString) where {F<:Function} +function with_depot(f::F, depot_path::AbstractString) where {F <: Function} original_depot_path = copy(Base.DEPOT_PATH) empty!(Base.DEPOT_PATH) pushfirst!(Base.DEPOT_PATH, depot_path) @@ -14,7 +14,7 @@ function with_depot(f::F, depot_path::AbstractString) where {F<:Function} end end -function with_temp_depot(f::F) where {F<:Function} +function with_temp_depot(f::F) where {F <: Function} mktempdir() do temp_depot with_depot(f, temp_depot) end @@ -26,7 +26,7 @@ end @boundscheck if i === nothing throw(ArgumentError("Collection is empty, must contain exactly 1 element")) end - (ret, state) = i::NTuple{2,Any} + (ret, state) = i::NTuple{2, Any} @boundscheck if iterate(x, state) !== nothing throw(ArgumentError("Collection has multiple elements, must contain exactly 1 element")) end diff --git a/test/utilities_test.jl b/test/utilities_test.jl index 0a1c448..91ebabc 100644 --- a/test/utilities_test.jl +++ b/test/utilities_test.jl @@ -3,20 +3,42 @@ @test PkgAuthentication.assert_dict_keys(Dict("foo" => 0), "foo"; msg="") === nothing @test_throws ErrorException PkgAuthentication.assert_dict_keys(Dict("bar" => 0), "foo"; msg="") - @test PkgAuthentication.assert_dict_keys(Dict("foo" => 0, "bar" => 0), "foo", "bar"; msg="") === nothing + @test PkgAuthentication.assert_dict_keys(Dict("foo" => 0, "bar" => 0), "foo", "bar"; msg="") === + nothing @test PkgAuthentication.assert_dict_keys(Dict("foo" => 0), "foo", "bar"; msg="") === nothing @test PkgAuthentication.assert_dict_keys(Dict("bar" => 0), "foo", "bar"; msg="") === nothing @test_throws ErrorException PkgAuthentication.assert_dict_keys(Dict(), "foo", "bar"; msg="") - @test_throws ErrorException PkgAuthentication.assert_dict_keys(Dict("baz" => 0), "foo", "bar"; msg="") + @test_throws ErrorException PkgAuthentication.assert_dict_keys( + Dict("baz" => 0), "foo", "bar"; msg="" + ) @test PkgAuthentication.detectwsl() isa Bool end @testset "device_token_request_body" begin - @test String(take!(PkgAuthentication.device_token_request_body(client_id="foo"))) == "client_id=foo" - @test String(take!(PkgAuthentication.device_token_request_body(client_id="foo", scope="bar"))) == "client_id=foo&scope=bar" - @test String(take!(PkgAuthentication.device_token_request_body(client_id="foo", device_code="bar"))) == "client_id=foo&device_code=bar" - @test String(take!(PkgAuthentication.device_token_request_body(client_id="foo", grant_type="bar"))) == "client_id=foo&grant_type=bar" - @test String(take!(PkgAuthentication.device_token_request_body(client_id="foo", scope="bar", device_code="baz", grant_type="qux"))) == "client_id=foo&scope=bar&device_code=baz&grant_type=qux" - @test String(take!(PkgAuthentication.device_token_request_body(client_id="foo", scope=nothing, device_code=nothing, grant_type=nothing))) == "client_id=foo" + @test String(take!(PkgAuthentication.device_token_request_body(; client_id="foo"))) == + "client_id=foo" + @test String( + take!(PkgAuthentication.device_token_request_body(; client_id="foo", scope="bar")) + ) == "client_id=foo&scope=bar" + @test String( + take!(PkgAuthentication.device_token_request_body(; client_id="foo", device_code="bar")) + ) == "client_id=foo&device_code=bar" + @test String( + take!(PkgAuthentication.device_token_request_body(; client_id="foo", grant_type="bar")) + ) == "client_id=foo&grant_type=bar" + @test String( + take!( + PkgAuthentication.device_token_request_body(; + client_id="foo", scope="bar", device_code="baz", grant_type="qux" + ), + ), + ) == "client_id=foo&scope=bar&device_code=baz&grant_type=qux" + @test String( + take!( + PkgAuthentication.device_token_request_body(; + client_id="foo", scope=nothing, device_code=nothing, grant_type=nothing + ), + ), + ) == "client_id=foo" end From 2ad4f3077f400fd802cd6a1b6e42d3e664c0fd53 Mon Sep 17 00:00:00 2001 From: Morten Piibeleht Date: Mon, 7 Jul 2025 15:32:54 +0300 Subject: [PATCH 2/3] fix printstyled --- src/PkgAuthentication.jl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/PkgAuthentication.jl b/src/PkgAuthentication.jl index b61c42a..711cd31 100644 --- a/src/PkgAuthentication.jl +++ b/src/PkgAuthentication.jl @@ -800,14 +800,17 @@ end function open_browser(url::AbstractString) @debug "opening auth in browser" - printstyled(; color=:yellow, bold=true, - "Authentication required: please authenticate in browser.\n") printstyled(; + "Authentication required: please authenticate in browser.\n"; color=:yellow, + bold=true, + ) + printstyled( """ -The authentication page should open in your browser automatically, but you may need to switch to the opened window or tab. If the authentication page is not automatically opened, you can authenticate by manually opening the following URL: """, + The authentication page should open in your browser automatically, but you may need to switch to the opened window or tab. If the authentication page is not automatically opened, you can authenticate by manually opening the following URL: """; + color=:yellow, ) - printstyled(; color=:light_blue, "$url\n") + printstyled("$url\n"; color=:light_blue) try if OPEN_BROWSER_HOOK[] !== nothing try @@ -907,10 +910,10 @@ function generate_auth_handler(maxcount::Integer) else failed_auth_count += 1 if failed_auth_count >= maxcount - printstyled(; color=:red, bold=true, "\nAuthentication failed.\n\n") + printstyled("\nAuthentication failed.\n\n"; color=:red, bold=true) return true, false # handled, but Pkg shouldn't try again else - printstyled(; color=:yellow, bold=true, "\nAuthentication failed. Retrying...\n\n") + printstyled("\nAuthentication failed. Retrying...\n\n"; color=:yellow, bold=true) end end return true, true # handled, and Pkg should try again now From 0551ee006ea2f345c5d9d1ac370ab86930abace6 Mon Sep 17 00:00:00 2001 From: Morten Piibeleht Date: Mon, 7 Jul 2025 15:48:15 +0300 Subject: [PATCH 3/3] fix --- src/PkgAuthentication.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PkgAuthentication.jl b/src/PkgAuthentication.jl index 711cd31..9c5f113 100644 --- a/src/PkgAuthentication.jl +++ b/src/PkgAuthentication.jl @@ -800,7 +800,7 @@ end function open_browser(url::AbstractString) @debug "opening auth in browser" - printstyled(; + printstyled( "Authentication required: please authenticate in browser.\n"; color=:yellow, bold=true,