Skip to content

Commit ef38eb7

Browse files
tz-lomtz-lom
authored andcommitted
Support self-hosted github installations
1 parent 76e83a1 commit ef38eb7

File tree

4 files changed

+74
-17
lines changed

4 files changed

+74
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
## Version [v1.14.1] - 2025-07-09
1313

14+
### Added
15+
16+
* Support self-hosted GitHub instances.
17+
1418
### Fixed
1519

1620
* Fixed the `GITHUB_EVENT_NAME` message to include `release` as one of the options. ([#2750])

src/deployconfig.jl

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -318,12 +318,35 @@ struct GitHubActions <: DeployConfig
318318
github_repository::String
319319
github_event_name::String
320320
github_ref::String
321+
github_host::String
322+
github_api::String
323+
github_pages_url::String
321324
end
325+
322326
function GitHubActions()
323327
github_repository = get(ENV, "GITHUB_REPOSITORY", "") # "JuliaDocs/Documenter.jl"
324328
github_event_name = get(ENV, "GITHUB_EVENT_NAME", "") # "push", "pull_request" or "cron" (?)
325329
github_ref = get(ENV, "GITHUB_REF", "") # "refs/heads/$(branchname)" for branch, "refs/tags/$(tagname)" for tags
326-
return GitHubActions(github_repository, github_event_name, github_ref)
330+
github_api = get(ENV, "GITHUB_API_URL", "") # https://api.github.com
331+
332+
# Compute GitHub Pages URL from repository
333+
parts = split(github_repository, "/")
334+
github_pages_url = if length(parts) == 2
335+
owner, repo = parts
336+
"https://$(owner).github.io/$(repo)/"
337+
else
338+
""
339+
end
340+
341+
return GitHubActions(github_repository, github_event_name, github_ref, "github.com", github_api, github_pages_url)
342+
end
343+
344+
function GitHubActions(host, pages_url)
345+
github_repository = get(ENV, "GITHUB_REPOSITORY", "") # "JuliaDocs/Documenter.jl"
346+
github_event_name = get(ENV, "GITHUB_EVENT_NAME", "") # "push", "pull_request" or "cron" (?)
347+
github_ref = get(ENV, "GITHUB_REF", "") # "refs/heads/$(branchname)" for branch, "refs/tags/$(tagname)" for tags
348+
github_api = get(ENV, "GITHUB_API_URL", "") # https://api.github.com
349+
return GitHubActions(github_repository, github_event_name, github_ref, host, github_api, pages_url)
327350
end
328351

329352
# Check criteria for deployment
@@ -393,7 +416,7 @@ function deploy_folder(
393416
all_ok &= pr_ok
394417
println(io, "- $(marker(pr_ok)) ENV[\"GITHUB_REF\"] corresponds to a PR number")
395418
if pr_ok
396-
pr_origin_matches_repo = verify_github_pull_repository(cfg.github_repository, pr_number)
419+
pr_origin_matches_repo = verify_github_pull_repository(cfg, pr_number)
397420
all_ok &= pr_origin_matches_repo
398421
println(io, "- $(marker(pr_origin_matches_repo)) PR originates from the same repository")
399422
end
@@ -452,7 +475,7 @@ end
452475

453476
authentication_method(::GitHubActions) = env_nonempty("DOCUMENTER_KEY") ? SSH : HTTPS
454477
function authenticated_repo_url(cfg::GitHubActions)
455-
return "https://$(ENV["GITHUB_ACTOR"]):$(ENV["GITHUB_TOKEN"])@github.com/$(cfg.github_repository).git"
478+
return "https://$(ENV["GITHUB_ACTOR"]):$(ENV["GITHUB_TOKEN"])@$(cfg.github_host)/$(cfg.github_repository).git"
456479
end
457480

458481
function version_tag_strip_build(tag; tag_prefix = "")
@@ -469,7 +492,7 @@ function version_tag_strip_build(tag; tag_prefix = "")
469492
return "$s0$s1$s2$s3$s4"
470493
end
471494

472-
function post_status(::GitHubActions; type, repo::String, subfolder = nothing, kwargs...)
495+
function post_status(cfg::GitHubActions; type, repo::String, subfolder = nothing, kwargs...)
473496
try # make this non-fatal and silent
474497
# If we got this far it usually means everything is in
475498
# order so no need to check everything again.
@@ -489,17 +512,18 @@ function post_status(::GitHubActions; type, repo::String, subfolder = nothing, k
489512
sha = get(ENV, "GITHUB_SHA", nothing)
490513
end
491514
sha === nothing && return
492-
return post_github_status(type, repo, sha, subfolder)
515+
return post_github_status(cfg, type, repo, sha, subfolder)
493516
catch
494517
@debug "Failed to post status"
495518
end
496519
end
497520

498-
function post_github_status(type::S, deploydocs_repo::S, sha::S, subfolder = nothing) where {S <: String}
521+
522+
function post_github_status(cfg::GitHubActions, type::S, deploydocs_repo::S, sha::S, subfolder = nothing) where {S <: String}
499523
try
500524
Sys.which("curl") === nothing && return
501525
## Extract owner and repository name
502-
m = match(r"^github.com\/(.+?)\/(.+?)(.git)?$", deploydocs_repo)
526+
m = match(Regex("^(?:https?://)?$(cfg.github_host)\\/(.+?)\\/(.+?)(.git)?\$"), deploydocs_repo)
503527
m === nothing && return
504528
owner = String(m.captures[1])
505529
repo = String(m.captures[2])
@@ -517,9 +541,9 @@ function post_github_status(type::S, deploydocs_repo::S, sha::S, subfolder = not
517541
json["description"] = "Documentation build in progress"
518542
elseif type == "success"
519543
json["description"] = "Documentation build succeeded"
520-
target_url = "https://$(owner).github.io/$(repo)/"
521-
if subfolder !== nothing
522-
target_url *= "$(subfolder)/"
544+
target_url = cfg.github_pages_url
545+
if !isempty(target_url) && subfolder !== nothing
546+
target_url = rstrip(target_url, '/') * "/$(subfolder)/"
523547
end
524548
json["target_url"] = target_url
525549
elseif type == "error"
@@ -530,7 +554,7 @@ function post_github_status(type::S, deploydocs_repo::S, sha::S, subfolder = not
530554
error("unsupported type: $type")
531555
end
532556
push!(cmd.exec, "-d", JSON.json(json))
533-
push!(cmd.exec, "https://api.github.com/repos/$(owner)/$(repo)/statuses/$(sha)")
557+
push!(cmd.exec, "$(cfg.github_api)/repos/$(owner)/$(repo)/statuses/$(sha)")
534558
# Run the command (silently)
535559
io = IOBuffer()
536560
res = run(pipeline(cmd; stdout = io, stderr = devnull))
@@ -541,7 +565,8 @@ function post_github_status(type::S, deploydocs_repo::S, sha::S, subfolder = not
541565
return nothing
542566
end
543567

544-
function verify_github_pull_repository(repo, prnr)
568+
function verify_github_pull_repository(cfg::GitHubActions, prnr)
569+
repo = cfg.github_repository
545570
github_token = get(ENV, "GITHUB_TOKEN", nothing)
546571
if github_token === nothing
547572
@warn "GITHUB_TOKEN is missing, unable to verify if PR comes from destination repository -- assuming it doesn't."
@@ -552,7 +577,7 @@ function verify_github_pull_repository(repo, prnr)
552577
push!(cmd.exec, "-H", "Authorization: token $(github_token)")
553578
push!(cmd.exec, "-H", "User-Agent: Documenter.jl")
554579
push!(cmd.exec, "--fail")
555-
push!(cmd.exec, "https://api.github.com/repos/$(repo)/pulls/$(prnr)")
580+
push!(cmd.exec, "$(cfg.github_api)/repos/$(repo)/pulls/$(prnr)")
556581
try
557582
# Run the command (silently)
558583
response = run_and_capture(cmd)

src/utilities/Remotes.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ function repofile(remote::Remote, ref, filename, linerange = nothing)
102102
return fileurl(remote, ref, filename, isnothing(linerange) ? nothing : Int(first(linerange)):Int(last(linerange)))
103103
end
104104

105+
106+
const GITHUB_HOST = "github.com"
107+
105108
"""
106109
GitHub(user :: AbstractString, repo :: AbstractString)
107110
GitHub(remote :: AbstractString)
@@ -121,12 +124,15 @@ a slash (e.g. `JuliaDocs/Documenter.jl`).
121124
struct GitHub <: Remote
122125
user::String
123126
repo::String
127+
host::String
128+
129+
GitHub(user::AbstractString, repo::AbstractString, host::AbstractString = GITHUB_HOST) = new(user, repo, host)
124130
end
125-
function GitHub(remote::AbstractString)
131+
function GitHub(remote::AbstractString; host::AbstractString = GITHUB_HOST)
126132
user, repo = split(remote, '/')
127-
return GitHub(user, repo)
133+
return GitHub(user, repo, host)
128134
end
129-
repourl(remote::GitHub) = "https://github.com/$(remote.user)/$(remote.repo)"
135+
repourl(remote::GitHub) = "https://$(remote.host)/$(remote.user)/$(remote.repo)"
130136
function fileurl(remote::GitHub, ref::AbstractString, filename::AbstractString, linerange)
131137
url = "$(repourl(remote))/blob/$(ref)/$(filename)"
132138
isnothing(linerange) && return url

test/deployconfig.jl

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,28 @@ end
493493
)
494494
@test !d.all_ok
495495
end
496+
# Self-hosted GitHub installation
497+
# Regular tag build with GITHUB_TOKEN
498+
withenv(
499+
"GITHUB_EVENT_NAME" => "push",
500+
"GITHUB_REPOSITORY" => "JuliaDocs/Documenter.jl",
501+
"GITHUB_REF" => "refs/tags/v1.2.3",
502+
"GITHUB_ACTOR" => "github-actions",
503+
"GITHUB_TOKEN" => "SGVsbG8sIHdvcmxkLg==",
504+
"DOCUMENTER_KEY" => nothing,
505+
) do
506+
cfg = Documenter.GitHubActions("github.selfhosted", "pages.selfhosted/something/JuliaDocs/Documenter.jl")
507+
d = Documenter.deploy_folder(
508+
cfg; repo = "github.selfhosted/JuliaDocs/Documenter.jl.git",
509+
devbranch = "master", devurl = "dev", push_preview = true
510+
)
511+
@test d.all_ok
512+
@test d.subfolder == "v1.2.3"
513+
@test d.repo == "github.selfhosted/JuliaDocs/Documenter.jl.git"
514+
@test d.branch == "gh-pages"
515+
@test Documenter.authentication_method(cfg) === Documenter.HTTPS
516+
@test Documenter.authenticated_repo_url(cfg) === "https://github-actions:[email protected]/JuliaDocs/Documenter.jl.git"
517+
end
496518
end
497519
end
498520

@@ -1396,7 +1418,7 @@ end
13961418
"CI" => "woodpecker",
13971419
"GITHUB_REPOSITORY" => nothing
13981420
) do
1399-
@test_throws KeyError cfg = Documenter.auto_detect_deploy_system()
1421+
@test_throws KeyError cfg = Documenter.auto_detect_deploy_system()
14001422
end
14011423
# Drone compatibility ends post-1.0.0
14021424
withenv(

0 commit comments

Comments
 (0)