diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0cc4413c..46fd9c4d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ * ![Enhancement][badge-enhancement] Documenter now support Azure DevOps Repos URL scheme when generating edit and source links pointing to the repository. ([#1462][github-1462], [#1463][github-1463], [#1471][github-1471]) +## Version `v0.25.4` + +* ![Feature][badge-feature] Documenter can now deploy from Buildkite CI to GitHub Pages with `Documenter.Buildkite`. ([#1469][github-1469]) + ## Version `v0.25.3` * ![Feature][badge-feature] Documenter can now deploy from GitLab CI to GitHub Pages with `Documenter.GitLab`. ([#1448][github-1448]) @@ -682,6 +686,7 @@ [github-1462]: https://github.com/JuliaDocs/Documenter.jl/issues/1462 [github-1463]: https://github.com/JuliaDocs/Documenter.jl/pull/1463 [github-1468]: https://github.com/JuliaDocs/Documenter.jl/pull/1468 +[github-1469]: https://github.com/JuliaDocs/Documenter.jl/pull/1469 [github-1471]: https://github.com/JuliaDocs/Documenter.jl/pull/1471 [julia-38079]: https://github.com/JuliaLang/julia/issues/38079 diff --git a/docs/src/man/hosting.md b/docs/src/man/hosting.md index 13d0ec0bfc..a59cbe4cc8 100644 --- a/docs/src/man/hosting.md +++ b/docs/src/man/hosting.md @@ -498,9 +498,9 @@ It is possible to customize Documenter to use other systems then the ones descri the sections above. This is done by passing a configuration (a [`DeployConfig`](@ref Documenter.DeployConfig)) to `deploydocs` by the `deploy_config` keyword argument. Documenter supports [`Travis`](@ref Documenter.Travis), -[`GitHubActions`](@ref Documenter.GitHubActions), and [`GitLab`](@ref Documenter.GitLab) -natively, but it is easy to define your own by following the simple interface -described below. +[`GitHubActions`](@ref Documenter.GitHubActions), [`GitLab`](@ref Documenter.GitLab), and +[`Buildkite`](@ref Documenter.Buildkite) natively, but it is easy to define your own by +following the simple interface described below. ```@docs Documenter.DeployConfig @@ -513,4 +513,5 @@ Documenter.documenter_key_previews Documenter.Travis Documenter.GitHubActions Documenter.GitLab +Documenter.Buildkite ``` diff --git a/src/deployconfig.jl b/src/deployconfig.jl index cab787c035..24bf96bdc9 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -637,6 +637,149 @@ authentication_method(::GitLab) = Documenter.SSH documenter_key(::GitLab) = ENV["DOCUMENTER_KEY"] +############# +# Buildkite # +############# + +""" + Buildkite <: DeployConfig + +Buildkite implementation of `DeployConfig`. + +The following environment variables influence the build when using the +`Buildkite` configuration: + + - `DOCUMENTER_KEY`: must contain the Base64-encoded SSH private key for the + repository. This variable should be somehow set in the CI environment, e.g., + provisioned by an agent environment plugin. + + - `BUILDKITE_BRANCH`: the name of the commit branch. + + - `BUILDKITE_PULL_REQUEST`: Pull Request ID from GitHub if the pipelines + are for external pull requests. + + - `BUILDKITE_TAG`: The commit tag name. Present only when building tags. + +The `BUILDKITE_*` variables are set automatically on GitLab. More information on how +Buildkite sets the `BUILDKITE_*` variables can be found in the +[Buildkite documentation](https://buildkite.com/docs/pipelines/environment-variables). +""" +struct Buildkite <: DeployConfig + commit_branch::String + pull_request::String + commit_tag::String +end + +function Buildkite() + commit_branch = get(ENV, "BUILDKITE_BRANCH", "") + pull_request = get(ENV, "BUILDKITE_PULL_REQUEST", "false") + commit_tag = get(ENV, "BUILDKITE_TAG", "") + Buildkite(commit_branch, pull_request, commit_tag) +end + +function deploy_folder( + cfg::Buildkite; + repo, + repo_previews = repo, + devbranch, + push_preview, + devurl, + branch = "gh-pages", + branch_previews = branch, + kwargs..., +) + + marker(x) = x ? "✔" : "✘" + + io = IOBuffer() + all_ok = true + + println(io, "\nBuildkite config:") + println(io, " Commit branch: \"", cfg.commit_branch, "\"") + println(io, " Pull request: \"", cfg.pull_request, "\"") + println(io, " Commit tag: \"", cfg.commit_tag, "\"") + + build_type = if cfg.pull_request != "false" + :preview + elseif cfg.commit_tag != "" + :release + else + :devbranch + end + + println(io, "Detected build type: ", build_type) + + if build_type == :release + tag_nobuild = version_tag_strip_build(cfg.commit_tag) + ## If a tag exist it should be a valid VersionNumber + tag_ok = tag_nobuild !== nothing + + println( + io, + "- $(marker(tag_ok)) ENV[\"BUILDKITE_TAG\"] contains a valid VersionNumber", + ) + all_ok &= tag_ok + + is_preview = false + subfolder = tag_nobuild + deploy_branch = branch + deploy_repo = repo + elseif build_type == :preview + pr_number = tryparse(Int, cfg.pull_request) + pr_ok = pr_number !== nothing + all_ok &= pr_ok + println( + io, + "- $(marker(pr_ok)) ENV[\"BUILDKITE_PULL_REQUEST\"]=\"$(cfg.pull_request)\" is a number", + ) + btype_ok = push_preview + all_ok &= btype_ok + is_preview = true + println( + io, + "- $(marker(btype_ok)) `push_preview` keyword argument to deploydocs is `true`", + ) + ## deploy to previews/PR + subfolder = "previews/PR$(something(pr_number, 0))" + deploy_branch = branch_previews + deploy_repo = repo_previews + else + branch_ok = !isempty(cfg.commit_tag) || cfg.commit_branch == devbranch + all_ok &= branch_ok + println( + io, + "- $(marker(branch_ok)) ENV[\"BUILDKITE_BRANCH\"] matches devbranch=\"$(devbranch)\"", + ) + is_preview = false + subfolder = devurl + deploy_branch = branch + deploy_repo = repo + end + + key_ok = haskey(ENV, "DOCUMENTER_KEY") + println(io, "- $(marker(key_ok)) ENV[\"DOCUMENTER_KEY\"] exists") + all_ok &= key_ok + + print(io, "Deploying to folder $(repr(subfolder)): $(marker(all_ok))") + @info String(take!(io)) + + if all_ok + return DeployDecision(; + all_ok = true, + branch = deploy_branch, + repo = deploy_repo, + subfolder = subfolder, + is_preview = is_preview, + ) + else + return DeployDecision(; all_ok = false) + end +end + +authentication_method(::Buildkite) = Documenter.SSH + +documenter_key(::Buildkite) = ENV["DOCUMENTER_KEY"] + ################## # Auto-detection # ################## @@ -647,6 +790,8 @@ function auto_detect_deploy_system() return GitHubActions() elseif haskey(ENV, "GITLAB_CI") return GitLab() + elseif haskey(ENV, "BUILDKITE") + return Buildkite() else return nothing end diff --git a/test/deployconfig.jl b/test/deployconfig.jl index 7d1e119278..8ad1e67efc 100644 --- a/test/deployconfig.jl +++ b/test/deployconfig.jl @@ -383,6 +383,90 @@ end end end end end +@testset "Buildkite CI deploy configuration" begin; with_logger(NullLogger()) do + # Regular tag build + withenv("BUILDKITE" => "true", + "BUILDKITE_BRANCH" => "master", + "BUILDKITE_PULL_REQUEST" => "false", + "BUILDKITE_TAG" => "v1.2.3", + "DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==", + ) do + cfg = Documenter.Buildkite() + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="master", devurl="dev", push_preview=true) + @test d.all_ok + @test d.subfolder == "v1.2.3" + @test d.repo == "github.com/JuliaDocs/Documenter.jl.git" + @test d.branch == "gh-pages" + @test Documenter.documenter_key(cfg) === "SGVsbG8sIHdvcmxkLg==" + @test Documenter.authentication_method(cfg) === Documenter.SSH + end + # Broken tag build + withenv("BUILDKITE" => "true", + "BUILDKITE_BRANCH" => "master", + "BUILDKITE_PULL_REQUEST" => "false", + "BUILDKITE_TAG" => "not-a-version", + "DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==", + ) do + cfg = Documenter.Buildkite() + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="master", devurl="dev", push_preview=true) + @test !d.all_ok + end + # Regular/broken devbranch build + withenv( + "BUILDKITE" => "true", + "BUILDKITE_BRANCH" => "master", + "BUILDKITE_PULL_REQUEST" => "false", + "BUILDKITE_TAG" => nothing, + "DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==", + ) do + cfg = Documenter.Buildkite() + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="master", devurl="hello-world", push_preview=true) + @test d.all_ok + @test d.subfolder == "hello-world" + @test d.repo == "github.com/JuliaDocs/Documenter.jl.git" + @test d.branch == "gh-pages" + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="not-master", devurl="hello-world", push_preview=true) + @test !d.all_ok + @test Documenter.documenter_key(cfg) === "SGVsbG8sIHdvcmxkLg==" + end + # Regular pull request build + withenv("BUILDKITE" => "true", + "BUILDKITE_BRANCH" => "something", + "BUILDKITE_PULL_REQUEST" => "42", + "BUILDKITE_TAG" => nothing, + "DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==", + ) do + cfg = Documenter.Buildkite() + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="master", devurl="hello-world", push_preview=true) + @test d.all_ok + @test d.subfolder == "previews/PR42" + @test d.repo == "github.com/JuliaDocs/Documenter.jl.git" + @test d.branch == "gh-pages" + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="master", devurl="hello-world", push_preview=false) + @test !d.all_ok + @test Documenter.documenter_key(cfg) === "SGVsbG8sIHdvcmxkLg==" + end + # Missing/broken environment variables + withenv( + "BUILDKITE" => "true", + "BUILDKITE_BRANCH" => "master", + "BUILDKITE_PULL_REQUEST" => "false", + "BUILDKITE_TAG" => "v1.2.3", + "DOCUMENTER_KEY" => nothing, + ) do + cfg = Documenter.Buildkite() + d = Documenter.deploy_folder(cfg; repo="github.com/JuliaDocs/Documenter.jl.git", + devbranch="master", devurl="hello-world", push_preview=false) + @test !d.all_ok + end +end end + struct CustomConfig <: Documenter.DeployConfig end Documenter.deploy_folder(::CustomConfig; kwargs...) = Documenter.DeployDecision(; all_ok = true, subfolder = "v1.2.3") struct BrokenConfig <: Documenter.DeployConfig end