Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gitlab deployconfig. #1448

Merged
merged 9 commits into from
Oct 25, 2020
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Version `v0.25.3`

* ![Feature][badge-feature] Documenter can now deploy from Gitlab CI to GitHub Pages with `Documenter.Gitlab`.
mortenpi marked this conversation as resolved.
Show resolved Hide resolved

MichaelHatherly marked this conversation as resolved.
Show resolved Hide resolved
* ![Enhancement][badge-enhancement] The URL to the MathJax JS module can now be customized by passing the `url` keyword argument to the constructors (`MathJax2`, `MathJax3`). ([#1428][github-1428], [#1430][github-1430])

* ![Bugfix][badge-bugfix] `Documenter.doctest` now correctly accepts the `doctestfilters` keyword, similar to `Documenter.makedocs`. ([#1364][github-1364], [#1435][github-1435])
Expand Down
8 changes: 5 additions & 3 deletions docs/src/man/hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,10 @@ look at this package's repository for some inspiration.
It is possible to customize Documenter to use other systems then the ones described in
the sections above. This is done by passing a configuration
(a [`DeployConfig`](@ref Documenter.DeployConfig)) to `deploydocs` by the `deploy_config`
keyword argument. Documenter natively supports [`Travis`](@ref Documenter.Travis) and
[`GitHubActions`](@ref Documenter.GitHubActions) natively, but it is easy to define
your own by following the simple interface described below.
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.

```@docs
Documenter.DeployConfig
Expand All @@ -473,4 +474,5 @@ Documenter.documenter_key
Documenter.documenter_key_previews
Documenter.Travis
Documenter.GitHubActions
Documenter.Gitlab
```
154 changes: 154 additions & 0 deletions src/deployconfig.jl
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,160 @@ function post_github_status(type::S, deploydocs_repo::S, sha::S, subfolder=nothi
return nothing
end

##########
# Gitlab #
##########

"""
Gitlab <: DeployConfig

Gitlab implementation of `DeployConfig`.

The following environment variables influences the build when using the
mortenpi marked this conversation as resolved.
Show resolved Hide resolved
`Gitlab` configuration:

- `DOCUMENTER_KEY`: must contain the Base64-encoded SSH private key for the
repository. This variable should be set in the Gitlab settings. Make sure this
variable is marked **NOT** to be displayed in the build log.

- `CI_COMMIT_BRANCH`: the name of the commit branch.

- `CI_EXTERNAL_PULL_REQUEST_IID`: Pull Request ID from GitHub if the pipelines
are for external pull requests.

- `CI_PROJECT_PATH_SLUG`: The namespace with project name. All letters
lowercased and non-alphanumeric characters replaced with `-`.

- `CI_COMMIT_TAG`: The commit tag name. Present only when building tags.

- `CI_PIPELINE_SOURCE`: Indicates how the pipeline was triggered.

The `CI_*` variables are set automatically on Gitlab. More information on how Gitlab
sets the `CI_*` variables can be found in the
[Gitlab documentation](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html).
"""
struct Gitlab <: DeployConfig
mortenpi marked this conversation as resolved.
Show resolved Hide resolved
commit_branch::String
pull_request_iid::String
repo_slug::String
commit_tag::String
pipeline_source::String
end

function Gitlab()
commit_branch = get(ENV, "CI_COMMIT_BRANCH", "")
pull_request_iid = get(ENV, "CI_EXTERNAL_PULL_REQUEST_IID", "")
repo_slug = get(ENV, "CI_PROJECT_PATH_SLUG", "")
commit_tag = get(ENV, "CI_COMMIT_TAG", "")
pipeline_source = get(ENV, "CI_PIPELINE_SOURCE", "")
Gitlab(commit_branch, pull_request_iid, repo_slug, commit_tag, pipeline_source)
end

function deploy_folder(
cfg::Gitlab;
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, "\nGitlab config:")
println(io, " Commit branch: \"", cfg.commit_branch, "\"")
println(io, " Pull request IID: \"", cfg.pull_request_iid, "\"")
println(io, " Repo slug: \"", cfg.repo_slug, "\"")
println(io, " Commit tag: \"", cfg.commit_tag, "\"")
println(io, " Pipeline source: \"", cfg.pipeline_source, "\"")

build_type = if cfg.pull_request_iid != ""
: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[\"CI_COMMIT_TAG\"] contains a valid VersionNumber",
)
all_ok &= tag_ok

is_preview = false
subfolder = tag_nobuild
deploy_branch = branch
deploy_repo = repo

mortenpi marked this conversation as resolved.
Show resolved Hide resolved
elseif build_type == :preview
pr_number = tryparse(Int, cfg.pull_request_iid)
pr_ok = pr_number !== nothing
all_ok &= pr_ok
println(
io,
"- $(marker(pr_ok)) ENV[\"CI_EXTERNAL_PULL_REQUEST_IID\"]=\"$(cfg.pull_request_iid)\" 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[\"CI_COMMIT_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(::Gitlab) = Documenter.SSH

documenter_key(::Gitlab) = ENV["DOCUMENTER_KEY"]

##################
# Auto-detection #
Expand Down
94 changes: 94 additions & 0 deletions test/deployconfig.jl
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,100 @@ end end
end
end end

@testset "Gitlab CI deploy configuration" begin; with_logger(NullLogger()) do
# Regular tag build
withenv("GITLAB_CI" => "true",
"CI_COMMIT_BRANCH" => "master",
"CI_EXTERNAL_PULL_REQUEST_IID" => "",
"CI_PROJECT_PATH_SLUG" => "juliadocs-documenter-jl",
"CI_COMMIT_TAG" => "v1.2.3",
"CI_PIPELINE_SOURCE" => "push",
"DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==",
) do
cfg = Documenter.Gitlab()
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("GITLAB_CI" => "true",
"CI_COMMIT_BRANCH" => "master",
"CI_EXTERNAL_PULL_REQUEST_IID" => "",
"CI_PROJECT_PATH_SLUG" => "juliadocs-documenter-jl",
"CI_COMMIT_TAG" => "not-a-version",
"CI_PIPELINE_SOURCE" => "push",
"DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==",
) do
cfg = Documenter.Gitlab()
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(
"GITLAB_CI" => "true",
"CI_COMMIT_BRANCH" => "master",
"CI_EXTERNAL_PULL_REQUEST_IID" => "",
"CI_PROJECT_PATH_SLUG" => "juliadocs-documenter-jl",
"CI_COMMIT_TAG" => nothing,
"CI_PIPELINE_SOURCE" => "push",
"DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==",
) do
cfg = Documenter.Gitlab()
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("GITLAB_CI" => "true",
"CI_COMMIT_BRANCH" => "something",
"CI_EXTERNAL_PULL_REQUEST_IID" => "42",
"CI_PROJECT_PATH_SLUG" => "juliadocs-documenter-jl",
"CI_COMMIT_TAG" => nothing,
"CI_PIPELINE_SOURCE" => "push",
"DOCUMENTER_KEY" => "SGVsbG8sIHdvcmxkLg==",
) do
cfg = Documenter.Gitlab()
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(
"GITLAB_CI" => "true",
"CI_COMMIT_BRANCH" => "master",
"CI_EXTERNAL_PULL_REQUEST_IID" => "",
"CI_PROJECT_PATH_SLUG" => "juliadocs-documenter-jl",
"CI_COMMIT_TAG" => "v1.2.3",
"CI_PIPELINE_SOURCE" => "push",
"DOCUMENTER_KEY" => nothing,
) do
cfg = Documenter.Gitlab()
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
Expand Down