From da5545c723fa1094c28ee25da3d40ac0ba3bf46a Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Mon, 18 Jul 2022 20:37:05 +0800 Subject: [PATCH 01/19] [enhancement] add woodpecker ci --- CHANGELOG.md | 3 + src/deployconfig.jl | 202 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 370a481c01..2cdbdb0acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ * ![Bugfix][badge-bugfix] Documenter now generates the correct source URLs for docstrings from other packages when the `repo` argument to `makedocs` is set (note: the source links to such docstrings only work if the external package is cloned from GitHub and added as a dev-dependency). However, this change **breaks** the case where the `repo` argument is used to override the main package/repository URL, assuming the repository is cloned from GitHub. ([#1808][github-1808]) +* ![Enhancement][badge-enhancement] Added Woodpecker CI as another CI solution for deploying docs. ([#1880][github-1880]) + ## Version `v0.27.21` * ![Bugfix][badge-bugfix] Fix a regression where Documenter throws an error on systems that do not have Git available. ([#1870][github-1870], [#1871][github-1871]) @@ -1102,6 +1104,7 @@ [github-1865]: https://github.com/JuliaDocs/Documenter.jl/pull/1865 [github-1870]: https://github.com/JuliaDocs/Documenter.jl/issues/1870 [github-1871]: https://github.com/JuliaDocs/Documenter.jl/pull/1871 +[github-1880]: https://github.com/JuliaDocs/Documenter.jl/pull/1880 [julia-38079]: https://github.com/JuliaLang/julia/issues/38079 diff --git a/src/deployconfig.jl b/src/deployconfig.jl index b5e5522dd8..48b848ad6c 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -843,6 +843,201 @@ authentication_method(::Buildkite) = Documenter.SSH documenter_key(::Buildkite) = ENV["DOCUMENTER_KEY"] +################# +# Woodpecker CI # +################# + +""" + Woodpecker <: DeployConfig + +Implementation of `DeployConfig` for deploying from Woodpecker CI. + +The following environmental variables are built-in from the Woodpecker pipeline +influences how `Documenter` works: + - `CI_REPO`: must match the full name of the repository / e.g. `JuliaDocs/Documenter.jl` + - `CI_BUILD_EVENT`: must be set to `push`, `tag`, `pull_request`, and `deployment` + - `CI_COMMIT_REF`: must match the `devbranch` keyword to [`deploydocs`](@ref), alternatively correspond to a git tag. + +User can define the `FORGE_URL` variable and add it to their Woodpecker pipeline definition: + +Example `.woodpecker.yml` +```yaml +pipeline: + docs: + image: julia + environment: + - FORGE_URL=https://github.com/JuliaDocs/Documenter.jl + ... +``` + +Or + +```yaml +pipeline: + docs: + image: julia + commands: + - export FORGE_URL=https://github.com/JuliaDocs/Documenter.jl + ... +``` + +More about pipeline syntax is documented here: https://woodpecker-ci.org/docs/usage/pipeline-syntax + +Lastly, another environment-variable used for authentication is +the `PROJECT_ACCESS_TOKEN` which is an access token you defined by +the forge you use e.g. GitHub, GitLab, Codeberg, and other gitea +instances. Check their documentation on how to create an access token. +This access token should be then added as a secret as documented in +https://woodpecker-ci.org/docs/usage/secrets. + +""" +struct Woodpecker <: DeployConfig + woodpecker_repo::String + woodpecker_event_name::String + woodpecker_ref::String +end + +""" + Woodpecker() + +Initialize woodpecker environment-variables. Further info of +environment-variables used are in https://woodpecker-ci.org/docs/usage/environment +""" +function Woodpecker() + woodpecker_repo = get(ENV, "CI_REPO", "") # repository full name / + woodpecker_event_name = get(ENV, "CI_BUILD_EVENT", "") # build event (push, pull_request, tag, deployment) + woodpecker_ref = get(ENV, "CI_COMMIT_REF", "") # commit ref + return Woodpecker(woodpecker_repo, woodpecker_event_name, woodpecker_ref) +end + +function deploy_folder( + cfg::Woodpecker; + repo, + repo_previews=repo, + branch="pages", + branch_previews=branch, + devbranch, + push_preview, + devurl, + kwargs...) + io = IOBuffer() + all_ok = true + if cfg.woodpecker_event_name == "pull_request" + build_type = :preview + elseif occursin(r"^refs\/tags\/(.*)$", cfg.woodpecker_ref) + build_type = :release + else + build_type = :devbranch + end + + println(io, "Deployment criteria for deploying $(build_type) build from Woodpecker-CI") + ## The deploydocs' repo should match CI_REPO + repo_ok = occursin(cfg.woodpecker_repo, repo) + all_ok &= repo_ok + println(io, "- $(marker(repo_ok)) ENV[\"CI_REPO\"]=\"$(cfg.woodpecker_repo)\" occursin in re + po=\"$(repo)\"") + + if build_type === :release + event_ok = in(cfg.woodpecker_event_name, ["push", "pull_request", "deployment", "tag"]) + all_ok &= event_ok + println(io, "- $(marker(event_ok)) ENV[\"CI_BUILD_EVENT\"]=\"$(cfg.woodpecker_event_name)\" is \"push\", \"deployment\" or \"tag\"") + ## If a tag exist it should be a valid VersionNumber + m = match(r"^refs\/tags\/(.*)$", cfg.woodpecker_ref) + tag_nobuild = version_tag_strip_build(m.captures[1]) + tag_ok = tag_nobuild !== nothing + all_ok &= tag_ok + println(io, "- $(marker(tag_ok)) ENV[\"CI_COMMIT_REF\"]=\"$(cfg.woodpecker_ref)\" contains a valid VersionNumber") + deploy_branch = branch + deploy_repo = repo + is_preview = false + ## Deploy to folder according to the tag + subfolder = m === nothing ? nothing : tag_nobuild + elseif build_type === :devbranch + ## Do not deploy for PRs + event_ok = in(cfg.woodpecker_event_name, ["push", "pull_request", "deployment", "tag"]) + all_ok &= event_ok + println(io, "- $(marker(event_ok)) ENV[\"CI_BUILD_EVENT\"]=\"$(cfg.woodpecker_event_name)\" is \"push\", \"deployment\" or \"tag\"") + ## deploydocs' devbranch should match the current branch + m = match(r"^refs\/heads\/(.*)$", cfg.woodpecker_ref) + branch_ok = m === nothing ? false : String(m.captures[1]) == devbranch + all_ok &= branch_ok + println(io, "- $(marker(branch_ok)) ENV[\"CI_COMMIT_REF\"] matches devbranch=\"$(devbranch)\"") + deploy_branch = branch + deploy_repo = repo + is_preview = false + ## Deploy to deploydocs devurl kwarg + subfolder = devurl + else # build_type === :preview + m = match(r"refs\/pull\/(\d+)\/merge", cfg.woodpecker_ref) + pr_number = tryparse(Int, m === nothing ? "" : m.captures[1]) + pr_ok = pr_number !== nothing + all_ok &= pr_ok + println(io, "- $(marker(pr_ok)) ENV[\"CI_COMMIT_REF\"] corresponds to a PR number") + if pr_ok + pr_origin_matches_repo = verify_github_pull_repository(cfg.woodpecker_repo, pr_number) + all_ok &= pr_origin_matches_repo + println(io, "- $(marker(pr_origin_matches_repo)) PR originates from the same repository") + end + btype_ok = push_preview + all_ok &= btype_ok + println(io, "- $(marker(btype_ok)) `push_preview` keyword argument to deploydocs is `true`") + deploy_branch = branch_previews + deploy_repo = repo_previews + is_preview = true + ## deploydocs to previews/PR + subfolder = "previews/PR$(something(pr_number, 0))" + end + + owner_ok = env_nonempty("CI_REPO_OWNER") + token_ok = env_nonempty("PROJECT_ACCESS_TOKEN") + auth_ok = owner_ok | token_ok + all_ok &= auth_ok + + if token_ok + println(io, "- $(marker(token_ok)) ENV[\"PROJECT_ACCESS_TOKEN\"] exists and is non-empty") + end + + if owner_ok + println(io, "- $(marker(owner_ok)) ENV[\"CI_REPO_OWNER\"] exists and is non-empty") + end + + print(io, "Deploying: $(marker(all_ok))") + @info String(take!(io)) + if build_type === :devbranch && !branch_ok && devbranch == "master" && cfg.woodpecker_ref == "refs/heads/main" + @warn """ + Possible deploydocs() misconfiguration: main vs master. Current branch (from \$CI_COMMIT_REF) is "main". + """ + end + + if all_ok + return DeployDecision(; all_ok=true, + branch=deploy_branch, + is_preview=is_preview, + repo=deploy_repo, + subfolder=subfolder + ) + else + return DeployDecision(; all_ok=false) + end +end + +authentication_method(::Woodpecker) = Documenter.HTTPS +function authenticated_repo_url(cfg::Woodpecker) + if !isnothing(get(ENV, "FORGE_URL", nothing)) + return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(ENV["FORGE_URL"])/$(cfg.woodpecker_repo).git" + else + # Regex will return the root of the URL e.g. https://github.com/JuliaDocs/Documenter.jl → github.com + # `CI_REPO_LINK` is an env var which returns a repository link e.g. https://github.com/JuliaDocs/Documenter.jl + m = match(r"https?:\/\/(?:.*\.)*(.+\..+?)\/", get(ENV, "CI_REPO_LINK", "")) + FORGE_URL=m.captures[1] + if !isempty(FORGE_URL) + return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(FORGE_URL)/$(cfg.woodpecker_repo).git" + end + end + # Otherwise, raise an error + error("No repository URL or link found. Please check link or your `FORGE_URL` environment-variable again.") +end + ################## # Auto-detection # ################## @@ -855,7 +1050,14 @@ function auto_detect_deploy_system() return GitLab() elseif haskey(ENV, "BUILDKITE") return Buildkite() + elseif get(ENV, "CI", nothing) in ["drone", "woodpecker"] + if ENV["CI"] == "drone" + @warn """Woodpecker is backward compatible to Drone + but *there will be breaking changes in the future*""" + end + return Woodpecker() else return nothing end end + From 5dd0f109ff6f19a4899560c9406158f9190a7390 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Tue, 19 Jul 2022 20:40:17 +0800 Subject: [PATCH 02/19] [enhancement] add woodpecker ci tests --- test/deployconfig.jl | 123 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/test/deployconfig.jl b/test/deployconfig.jl index 4a841556d8..bbba78d179 100644 --- a/test/deployconfig.jl +++ b/test/deployconfig.jl @@ -485,6 +485,111 @@ end end end end end +@testset "Woodpecker CI deploy configuration" begin; with_logger(NullLogger()) do + # Regular tag build with PROJECT_ACCESS_TOKEN + withenv( + "CI" => "woodpecker", + "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", + "CI_BUILD_EVENT" => "push", + "CI_REPO" => "JuliaDocs/Documenter.jl", + "CI_REPO_OWNER" => "JuliaDocs", + "CI_COMMIT_REF" => "refs/tags/v1.2.3", + "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", + "FORGE_URL" => nothing, + ) do + cfg = Documenter.Woodpecker() + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="master", devurl="dev", push_preview=true) + + @test d.all_ok + @test d.subfolder == "v1.2.3" + @test d.repo == "JuliaDocs/Documenter.jl" + @test d.branch == "pages" + @test Documenter.authentication_method(cfg) === Documenter.HTTPS + @test Documenter.authenticated_repo_url(cfg) === "https://JuliaDocs:SGVsbG8sIHdvcmxkLg==@github.com/JuliaDocs/Documenter.jl.git" + end + # Broken tag build + withenv( + "CI" => "woodpecker", + "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", + "CI_BUILD_EVENT" => "push", + "CI_REPO" => "JuliaDocs/Documenter.jl", + "CI_REPO_OWNER" => "JuliaDocs", + "CI_COMMIT_REF" => "refs/tags/not-a-version", + "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", + "FORGE_URL" => nothing, + ) do + cfg = Documenter.Woodpecker() + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="master", devurl="dev", push_preview=true) + @test !d.all_ok + end + # Regular devbranch build + withenv( + "CI" => "woodpecker", + "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", + "CI_BUILD_EVENT" => "pull_request", + "CI_REPO" => "JuliaDocs/Documenter.jl", + "CI_REPO_OWNER" => "JuliaDocs", + "CI_COMMIT_REF" => "refs/heads/master", + "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", + "FORGE_URL" => nothing, + ) do + cfg = Documenter.Woodpecker() + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="master", devurl="hello-world", push_preview=true) + @test d.all_ok + @test d.subfolder == "previews/PR42" + @test d.repo == "JuliaDocs/Documenter.jl" + @test d.branch == "pages" + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="not-master", devurl="hello-world", push_preview=true) + @test !d.all_ok + @test Documenter.authentication_method(cfg) === Documenter.HTTPS + @test Documenter.authenticated_repo_url(cfg) === "https://JuliaDocs:SGVsbG8sIHdvcmxkLg==@github.com/JuliaDocs/Documenter.jl.git" + end + # Regular pull request build + withenv( + "CI" => "woodpecker", + "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", + "CI_BUILD_EVENT" => "pull_request", + "CI_REPO" => "JuliaDocs/Documenter.jl", + "CI_REPO_OWNER" => "JuliaDocs", + "CI_COMMIT_REF" => "refs/pull/42/merge", + "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", + "FORGE_URL" => nothing, + ) do + cfg = Documenter.Woodpecker() + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="master", devurl="hello-world", push_preview=true) + @test d.all_ok + @test d.subfolder == "previews/PR42" + @test d.repo == "JuliaDocs/Documenter.jl" + @test d.branch == "pages" + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="not-master", devurl="hello-world", push_preview=true) + @test !d.all_ok + @test Documenter.authentication_method(cfg) === Documenter.HTTPS + @test Documenter.authenticated_repo_url(cfg) === "https://JuliaDocs:SGVsbG8sIHdvcmxkLg==@github.com/JuliaDocs/Documenter.jl.git" + end + # Missing environment variables + withenv( + "CI" => "woodpecker", + "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", + "CI_BUILD_EVENT" => "pull_request", + "CI_REPO" => "JuliaDocs/Documenter.jl", + "CI_REPO_OWNER" => "JuliaDocs", + "CI_COMMIT_REF" => "refs/pull/42/merge", + "PROJECT_ACCESS_TOKEN" => nothing, + "FORGE_URL" => nothing, + ) do + cfg = Documenter.Woodpecker() + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="master", devurl="hello-world", push_preview=true) + @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 @@ -519,6 +624,24 @@ end end cfg = Documenter.auto_detect_deploy_system() @test cfg === nothing end + withenv("CI" => "woodpecker", + "GITHUB_REPOSITORY" => nothing + ) do + cfg = Documenter.auto_detect_deploy_system() + @test cfg isa Documenter.Woodpecker + end + withenv("CI" => "drone", + "GITHUB_REPOSITORY" => nothing + ) do + cfg = Documenter.auto_detect_deploy_system() + @test cfg isa Documenter.Woodpecker + end + withenv("CI" => nothing, + "GITHUB_REPOSITORY" => nothing + ) do + cfg = Documenter.auto_detect_deploy_system() + @test cfg === nothing + end end ## @testset "Remote repository paths" begin From 710e78467ff7ff950e8ff7819d4f75cc75311938 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Wed, 20 Jul 2022 22:08:54 +0800 Subject: [PATCH 03/19] [fix] resolve some issues - PR should use built-in env vars `CI_COMMIT_REF` and `CI_COMMIT_PULL_REQUEST` - GitHub Actions and Woodpecker share similarities thus modified some stuff slightly. - `FORGE_URL` should be not a link but the root of a URL e.g. github.com, codeberg.org - `CI_REPO_LINK` should be used if `FORGE_URL` is not defined. --- src/deployconfig.jl | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 48b848ad6c..396d8948a9 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -513,7 +513,7 @@ function verify_github_pull_repository(repo, prnr) github_token === nothing && error("GITHUB_TOKEN missing") # Construct the curl call cmd = `curl -s` - push!(cmd.exec, "-S", "GET") + push!(cmd.exec, "-X", "GET") push!(cmd.exec, "-H", "Authorization: token $(github_token)") push!(cmd.exec, "-H", "User-Agent: Documenter.jl") push!(cmd.exec, "-H", "Content-Type: application/json") @@ -866,7 +866,7 @@ pipeline: docs: image: julia environment: - - FORGE_URL=https://github.com/JuliaDocs/Documenter.jl + - FORGE_URL=github.com ... ``` @@ -877,7 +877,7 @@ pipeline: docs: image: julia commands: - - export FORGE_URL=https://github.com/JuliaDocs/Documenter.jl + - export FORGE_URL=github.com ... ``` @@ -956,7 +956,7 @@ function deploy_folder( ## Do not deploy for PRs event_ok = in(cfg.woodpecker_event_name, ["push", "pull_request", "deployment", "tag"]) all_ok &= event_ok - println(io, "- $(marker(event_ok)) ENV[\"CI_BUILD_EVENT\"]=\"$(cfg.woodpecker_event_name)\" is \"push\", \"deployment\" or \"tag\"") + println(io, "- $(marker(event_ok)) ENV[\"CI_BUILD_EVENT\"]=\"$(cfg.woodpecker_event_name)\" is \"push\", \"deployment\", or \"tag\"") ## deploydocs' devbranch should match the current branch m = match(r"^refs\/heads\/(.*)$", cfg.woodpecker_ref) branch_ok = m === nothing ? false : String(m.captures[1]) == devbranch @@ -969,15 +969,15 @@ function deploy_folder( subfolder = devurl else # build_type === :preview m = match(r"refs\/pull\/(\d+)\/merge", cfg.woodpecker_ref) - pr_number = tryparse(Int, m === nothing ? "" : m.captures[1]) - pr_ok = pr_number !== nothing + pr_number1 = tryparse(Int, m === nothing ? "" : m.captures[1]) + pr_number2 = tryparse(Int, get(ENV, "CI_COMMIT_PULL_REQUEST", nothing) === nothing ? "" : ENV["CI_COMMIT_PULL_REQUEST"]) + # Check if both are Ints. If both are Ints, then check if they are equal, otherwise, return false + pr_numbers_ok = all(x -> x isa Int, [pr_number1, pr_number2]) ? (pr_number1 == pr_number2) : false + is_pull_request_ok = get(ENV, "CI_BUILD_EVENT", "") == "pull_request" + pr_ok = pr_numbers_ok == is_pull_request_ok all_ok &= pr_ok - println(io, "- $(marker(pr_ok)) ENV[\"CI_COMMIT_REF\"] corresponds to a PR number") - if pr_ok - pr_origin_matches_repo = verify_github_pull_repository(cfg.woodpecker_repo, pr_number) - all_ok &= pr_origin_matches_repo - println(io, "- $(marker(pr_origin_matches_repo)) PR originates from the same repository") - end + println(io, "- $(marker(pr_numbers_ok)) ENV[\"CI_COMMIT_REF\"] corresponds to a PR") + println(io, "- $(marker(is_pull_request_ok)) ENV[\"CI_BUILD_EVENT\"] matches built type: `pull_request`") btype_ok = push_preview all_ok &= btype_ok println(io, "- $(marker(btype_ok)) `push_preview` keyword argument to deploydocs is `true`") @@ -985,7 +985,7 @@ function deploy_folder( deploy_repo = repo_previews is_preview = true ## deploydocs to previews/PR - subfolder = "previews/PR$(something(pr_number, 0))" + subfolder = "previews/PR$(something(pr_number1, 0))" end owner_ok = env_nonempty("CI_REPO_OWNER") @@ -1023,19 +1023,17 @@ end authentication_method(::Woodpecker) = Documenter.HTTPS function authenticated_repo_url(cfg::Woodpecker) - if !isnothing(get(ENV, "FORGE_URL", nothing)) + if haskey(ENV, "FORGE_URL") return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(ENV["FORGE_URL"])/$(cfg.woodpecker_repo).git" else # Regex will return the root of the URL e.g. https://github.com/JuliaDocs/Documenter.jl → github.com - # `CI_REPO_LINK` is an env var which returns a repository link e.g. https://github.com/JuliaDocs/Documenter.jl - m = match(r"https?:\/\/(?:.*\.)*(.+\..+?)\/", get(ENV, "CI_REPO_LINK", "")) + # `CI_REPO_LINK` is a built-in env var which returns a repository link e.g. https://github.com/JuliaDocs/Documenter.jl + # See https://woodpecker-ci.org/docs/usage/environment to check the environment-variable + m = match(r"https?:\/\/(?:.*\.)*(.+\..+?)\/", get(ENV, "CI_REPO_LINK", "")) + isnothing(m) && @warn "Cannot get root of the URL. Please set a `FORGE_URL` environment-variable as a workaround" FORGE_URL=m.captures[1] - if !isempty(FORGE_URL) - return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(FORGE_URL)/$(cfg.woodpecker_repo).git" - end + return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(FORGE_URL)/$(cfg.woodpecker_repo).git" end - # Otherwise, raise an error - error("No repository URL or link found. Please check link or your `FORGE_URL` environment-variable again.") end ################## From 24c75df16a6dd7b657cb32b9a39b54ce8d24112c Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Wed, 20 Jul 2022 22:09:51 +0800 Subject: [PATCH 04/19] [enhancement] improve woodpecker ci tests --- test/deployconfig.jl | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/test/deployconfig.jl b/test/deployconfig.jl index bbba78d179..3f6446275d 100644 --- a/test/deployconfig.jl +++ b/test/deployconfig.jl @@ -488,9 +488,9 @@ end end @testset "Woodpecker CI deploy configuration" begin; with_logger(NullLogger()) do # Regular tag build with PROJECT_ACCESS_TOKEN withenv( + "CI_BUILD_EVENT" => "push", "CI" => "woodpecker", "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", - "CI_BUILD_EVENT" => "push", "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/tags/v1.2.3", @@ -510,9 +510,9 @@ end end end # Broken tag build withenv( + "CI_BUILD_EVENT" => "push", "CI" => "woodpecker", "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", - "CI_BUILD_EVENT" => "push", "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/tags/not-a-version", @@ -526,9 +526,9 @@ end end end # Regular devbranch build withenv( + "CI_BUILD_EVENT" => "push", "CI" => "woodpecker", "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", - "CI_BUILD_EVENT" => "pull_request", "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/heads/master", @@ -539,7 +539,7 @@ end end d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", devbranch="master", devurl="hello-world", push_preview=true) @test d.all_ok - @test d.subfolder == "previews/PR42" + @test d.subfolder == "hello-world" @test d.repo == "JuliaDocs/Documenter.jl" @test d.branch == "pages" d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", @@ -550,12 +550,14 @@ end end end # Regular pull request build withenv( + "CI_BUILD_EVENT" => "pull_request", + "CI_COMMIT_PULL_REQUEST" => "42", "CI" => "woodpecker", "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", - "CI_BUILD_EVENT" => "pull_request", "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/pull/42/merge", + "CI_BUILD_EVENT" => "pull_request", "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", "FORGE_URL" => nothing, ) do @@ -567,11 +569,29 @@ end end @test d.repo == "JuliaDocs/Documenter.jl" @test d.branch == "pages" d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", - devbranch="not-master", devurl="hello-world", push_preview=true) + devbranch="master", devurl="hello-world", push_preview=false) @test !d.all_ok @test Documenter.authentication_method(cfg) === Documenter.HTTPS @test Documenter.authenticated_repo_url(cfg) === "https://JuliaDocs:SGVsbG8sIHdvcmxkLg==@github.com/JuliaDocs/Documenter.jl.git" end + # Not a pull request + withenv( + "CI_BUILD_EVENT" => "push", + "CI_COMMIT_PULL_REQUEST" => "42", + "CI" => "woodpecker", + "CI_REPO_LINK" => "https://github.com/JuliaDocs/Documenter.jl", + "CI_REPO" => "JuliaDocs/Documenter.jl", + "CI_REPO_OWNER" => "JuliaDocs", + "CI_COMMIT_REF" => "refs/pull/42/merge", + "CI_BUILD_EVENT" => "push", + "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", + "FORGE_URL" => nothing, + ) do + cfg = Documenter.Woodpecker() + d = Documenter.deploy_folder(cfg; repo="JuliaDocs/Documenter.jl", + devbranch="master", devurl="hello-world", push_preview=true) + @test !d.all_ok + end # Missing environment variables withenv( "CI" => "woodpecker", From 3019cd0a438849a932228be309c7d62cd9056f80 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Wed, 20 Jul 2022 22:10:15 +0800 Subject: [PATCH 05/19] [docs] add woodpecker ci to documentation --- docs/src/man/hosting.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/src/man/hosting.md b/docs/src/man/hosting.md index 0a49fd838d..7daf929267 100644 --- a/docs/src/man/hosting.md +++ b/docs/src/man/hosting.md @@ -417,6 +417,37 @@ jobs: _This workflow was taken from [CliMA/ClimaTimeSteppers.jl](https://github.com/CliMA/ClimaTimeSteppers.jl/blob/0660ace688b4f4b8a86d3c459ab62ccf01d7ef31/.github/workflows/DocCleanup.yml) (Apache License 2.0)._ +## Woodpecker CI + +To run a documentation build from Woodpecker CI, one should create an access token +from their forge of choice: GitHub, GitLab, or Codeberg (or any Gitea instance). +This access token should be added to Woodpecker CI as a secret named as +`project_access_token` - all lowercase. Next, create a new pipeline configuration file +called `.woodpecker.yml` with the following contents: + +```yaml +pipeline: + docs: + when: + branch: main # update to match your development branch + image: julia + commands: + - julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - julia --project=docs/ docs/make.jl + secrets: [ project_access_token ] # access token is a secret + +``` + +This will pull an image of julia from docker and run the following commands from +`commands:` which instantiates the project for development and then runs the `make.jl` +file and builds and deploys the documentation to a branch which defaults to `pages` +which you can modify to something else e.g. GitHub → gh-pages, Codeberg → pages. + +!!! tip + The example above is a basic pipeline that suits most projects. Further information + on how to customize your pipelines can be found in the official woodpecker + documentation: [Woodpecker CI](https://woodpecker-ci.org/docs/intro). + ## Documentation Versions !!! note @@ -536,4 +567,5 @@ Documenter.Travis Documenter.GitHubActions Documenter.GitLab Documenter.Buildkite +Documenter.Woodpecker ``` From bc81ef60d4d3cf8512de0707756cd3c383ac0492 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Thu, 21 Jul 2022 09:47:59 +0800 Subject: [PATCH 06/19] [workaround] authenticated_repo_url handling - return an empty string if regex returns no match (which is a value of `nothing`. The error will be caught anyway in `deploydocs` --- src/deployconfig.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 396d8948a9..9ef3a5ef65 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -1028,11 +1028,12 @@ function authenticated_repo_url(cfg::Woodpecker) else # Regex will return the root of the URL e.g. https://github.com/JuliaDocs/Documenter.jl → github.com # `CI_REPO_LINK` is a built-in env var which returns a repository link e.g. https://github.com/JuliaDocs/Documenter.jl + # The variable is passed through the pipeline during the runs. # See https://woodpecker-ci.org/docs/usage/environment to check the environment-variable - m = match(r"https?:\/\/(?:.*\.)*(.+\..+?)\/", get(ENV, "CI_REPO_LINK", "")) - isnothing(m) && @warn "Cannot get root of the URL. Please set a `FORGE_URL` environment-variable as a workaround" - FORGE_URL=m.captures[1] - return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(FORGE_URL)/$(cfg.woodpecker_repo).git" + m = match(r"https?:\/\/(?:.+\.)*(.+\..+?)\/", get(ENV, "CI_REPO_LINK", "")) + forge_url = m !== nothing ? m.captures[1] : "" # if `nothing`, just give an empty string so deploydocs can use it + # even though we know that errors + return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(forge_url)/$(cfg.woodpecker_repo).git" end end From 6ac9b5bba4fbd2417fed04c4d0905fe9c386be93 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Thu, 21 Jul 2022 10:39:02 +0800 Subject: [PATCH 07/19] [docs] fix indentation --- docs/src/man/hosting.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/src/man/hosting.md b/docs/src/man/hosting.md index 7daf929267..7542443c21 100644 --- a/docs/src/man/hosting.md +++ b/docs/src/man/hosting.md @@ -427,14 +427,14 @@ called `.woodpecker.yml` with the following contents: ```yaml pipeline: - docs: - when: - branch: main # update to match your development branch - image: julia - commands: - - julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - - julia --project=docs/ docs/make.jl - secrets: [ project_access_token ] # access token is a secret + docs: + when: + branch: main # update to match your development branch + image: julia + commands: + - julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - julia --project=docs/ docs/make.jl + secrets: [ project_access_token ] # access token is a secret ``` From 324d1449745977e77e5d8e849d3d7a351851738f Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Thu, 21 Jul 2022 14:55:48 +0800 Subject: [PATCH 08/19] [misc] remove whitespace Co-authored-by: Morten Piibeleht --- src/deployconfig.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 9ef3a5ef65..a15603aeee 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -889,7 +889,6 @@ the forge you use e.g. GitHub, GitLab, Codeberg, and other gitea instances. Check their documentation on how to create an access token. This access token should be then added as a secret as documented in https://woodpecker-ci.org/docs/usage/secrets. - """ struct Woodpecker <: DeployConfig woodpecker_repo::String From 3394060d63185273b5227803d22c33a9a613349d Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Thu, 21 Jul 2022 14:57:01 +0800 Subject: [PATCH 09/19] [fix] let markdown parser pick up linkx properly Co-authored-by: Morten Piibeleht --- src/deployconfig.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index a15603aeee..16703041a2 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -881,14 +881,14 @@ pipeline: ... ``` -More about pipeline syntax is documented here: https://woodpecker-ci.org/docs/usage/pipeline-syntax +More about pipeline syntax is documented here: Lastly, another environment-variable used for authentication is the `PROJECT_ACCESS_TOKEN` which is an access token you defined by the forge you use e.g. GitHub, GitLab, Codeberg, and other gitea instances. Check their documentation on how to create an access token. This access token should be then added as a secret as documented in -https://woodpecker-ci.org/docs/usage/secrets. +. """ struct Woodpecker <: DeployConfig woodpecker_repo::String From 5d90dc0b8c7a0a6a7b1a74e818d814b213660161 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Thu, 21 Jul 2022 14:57:36 +0800 Subject: [PATCH 10/19] [fix] let markdown parser pickup links (2) Co-authored-by: Morten Piibeleht --- src/deployconfig.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 16703041a2..a4f95e141e 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -900,7 +900,7 @@ end Woodpecker() Initialize woodpecker environment-variables. Further info of -environment-variables used are in https://woodpecker-ci.org/docs/usage/environment +environment-variables used are in """ function Woodpecker() woodpecker_repo = get(ENV, "CI_REPO", "") # repository full name / From 73a2c9075909644200cbba61594a9cedaa736aed Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Thu, 21 Jul 2022 16:05:57 +0800 Subject: [PATCH 11/19] [enhancement] resolve reviews - handle `authenticated_repo_url` for woodpecker: * added more stuff into the `Woodpecker constructor`: - woodpecker_repo_link - woodpecker_forge_url - new constructor params are validated in `deploy_folder` - improve docstring for completeness - update Woodpecker constructor: - `CI_COMMIT_TAG` added to constructor - reducing logic if checking tag build is a valid version using `woodpecker_tag` - improve test --- src/deployconfig.jl | 61 ++++++++++++++++++++++++++++---------------- test/deployconfig.jl | 3 +++ 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index a4f95e141e..999cdff02b 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -855,8 +855,16 @@ Implementation of `DeployConfig` for deploying from Woodpecker CI. The following environmental variables are built-in from the Woodpecker pipeline influences how `Documenter` works: - `CI_REPO`: must match the full name of the repository / e.g. `JuliaDocs/Documenter.jl` + - `CI_REPO_LINK`: must match the full link to the project repo - `CI_BUILD_EVENT`: must be set to `push`, `tag`, `pull_request`, and `deployment` - `CI_COMMIT_REF`: must match the `devbranch` keyword to [`deploydocs`](@ref), alternatively correspond to a git tag. + - `CI_COMMIT_TAG`: must match to a tag. + - `CI_COMMIT_PULL_REQUEST`: must return the PR number. + - `CI_REPO_OWNER`: must return the value of the repo owner. Real names are not necessary. + +The following user-defined environmental variables influences how `Documenter` works: + - `PROJECT_ACCESS_TOKEN`: user generated access token from a forge e.g. GitHub, GitLab, Codeberg to be used as a secret. + - `FORGE_URL`: user-defined env var to be used for authentication. Optional. User can define the `FORGE_URL` variable and add it to their Woodpecker pipeline definition: @@ -891,7 +899,10 @@ This access token should be then added as a secret as documented in . """ struct Woodpecker <: DeployConfig + woodpecker_repo_link::String + woodpecker_forge_url::String woodpecker_repo::String + woodpecker_tag::String woodpecker_event_name::String woodpecker_ref::String end @@ -903,10 +914,16 @@ Initialize woodpecker environment-variables. Further info of environment-variables used are in """ function Woodpecker() + woodpecker_repo_link = get(ENV, "CI_REPO_LINK", "") + m = match(r"https?:\/\/(?:.+\.)*(.+\..+?)\/", woodpecker_repo_link) + # Get the forge URL, otherwise, if the value is `nothing`, + # Then use the woodpecker_repo_link + woodpecker_forge_url = isnothing(m) ? woodpecker_repo_link : m.captures[1] + woodpecker_tag = get(ENV, "CI_COMMIT_TAG", "") woodpecker_repo = get(ENV, "CI_REPO", "") # repository full name / woodpecker_event_name = get(ENV, "CI_BUILD_EVENT", "") # build event (push, pull_request, tag, deployment) woodpecker_ref = get(ENV, "CI_COMMIT_REF", "") # commit ref - return Woodpecker(woodpecker_repo, woodpecker_event_name, woodpecker_ref) + return Woodpecker(woodpecker_repo_link, woodpecker_forge_url, woodpecker_repo, woodpecker_tag, woodpecker_event_name, woodpecker_ref) end function deploy_folder( @@ -931,6 +948,12 @@ function deploy_folder( println(io, "Deployment criteria for deploying $(build_type) build from Woodpecker-CI") ## The deploydocs' repo should match CI_REPO + # + repo_link_ok = !isempty(cfg.woodpecker_repo_link) # if repo link is an empty string then it is not valid + all_ok &= repo_link_ok + forge_url_ok = !isempty(cfg.woodpecker_forge_url) # if the forge url is an empty string, it is not a valid url + all_ok &= forge_url_ok + repo_ok = occursin(cfg.woodpecker_repo, repo) all_ok &= repo_ok println(io, "- $(marker(repo_ok)) ENV[\"CI_REPO\"]=\"$(cfg.woodpecker_repo)\" occursin in re @@ -940,17 +963,15 @@ function deploy_folder( event_ok = in(cfg.woodpecker_event_name, ["push", "pull_request", "deployment", "tag"]) all_ok &= event_ok println(io, "- $(marker(event_ok)) ENV[\"CI_BUILD_EVENT\"]=\"$(cfg.woodpecker_event_name)\" is \"push\", \"deployment\" or \"tag\"") - ## If a tag exist it should be a valid VersionNumber - m = match(r"^refs\/tags\/(.*)$", cfg.woodpecker_ref) - tag_nobuild = version_tag_strip_build(m.captures[1]) + tag_nobuild = version_tag_strip_build(cfg.woodpecker_tag) tag_ok = tag_nobuild !== nothing all_ok &= tag_ok - println(io, "- $(marker(tag_ok)) ENV[\"CI_COMMIT_REF\"]=\"$(cfg.woodpecker_ref)\" contains a valid VersionNumber") + println(io, "- $(marker(tag_ok)) ENV[\"CI_COMMIT_TAG\"]=\"$(cfg.woodpecker_tag)\" contains a valid VersionNumber") deploy_branch = branch deploy_repo = repo is_preview = false ## Deploy to folder according to the tag - subfolder = m === nothing ? nothing : tag_nobuild + subfolder = tag_nobuild elseif build_type === :devbranch ## Do not deploy for PRs event_ok = in(cfg.woodpecker_event_name, ["push", "pull_request", "deployment", "tag"]) @@ -958,7 +979,7 @@ function deploy_folder( println(io, "- $(marker(event_ok)) ENV[\"CI_BUILD_EVENT\"]=\"$(cfg.woodpecker_event_name)\" is \"push\", \"deployment\", or \"tag\"") ## deploydocs' devbranch should match the current branch m = match(r"^refs\/heads\/(.*)$", cfg.woodpecker_ref) - branch_ok = m === nothing ? false : String(m.captures[1]) == devbranch + branch_ok = (m === nothing) ? false : String(m.captures[1]) == devbranch all_ok &= branch_ok println(io, "- $(marker(branch_ok)) ENV[\"CI_COMMIT_REF\"] matches devbranch=\"$(devbranch)\"") deploy_branch = branch @@ -968,7 +989,7 @@ function deploy_folder( subfolder = devurl else # build_type === :preview m = match(r"refs\/pull\/(\d+)\/merge", cfg.woodpecker_ref) - pr_number1 = tryparse(Int, m === nothing ? "" : m.captures[1]) + pr_number1 = tryparse(Int, (m === nothing) ? "" : m.captures[1]) pr_number2 = tryparse(Int, get(ENV, "CI_COMMIT_PULL_REQUEST", nothing) === nothing ? "" : ENV["CI_COMMIT_PULL_REQUEST"]) # Check if both are Ints. If both are Ints, then check if they are equal, otherwise, return false pr_numbers_ok = all(x -> x isa Int, [pr_number1, pr_number2]) ? (pr_number1 == pr_number2) : false @@ -987,19 +1008,14 @@ function deploy_folder( subfolder = "previews/PR$(something(pr_number1, 0))" end - owner_ok = env_nonempty("CI_REPO_OWNER") token_ok = env_nonempty("PROJECT_ACCESS_TOKEN") - auth_ok = owner_ok | token_ok + auth_ok = token_ok all_ok &= auth_ok if token_ok println(io, "- $(marker(token_ok)) ENV[\"PROJECT_ACCESS_TOKEN\"] exists and is non-empty") end - if owner_ok - println(io, "- $(marker(owner_ok)) ENV[\"CI_REPO_OWNER\"] exists and is non-empty") - end - print(io, "Deploying: $(marker(all_ok))") @info String(take!(io)) if build_type === :devbranch && !branch_ok && devbranch == "master" && cfg.woodpecker_ref == "refs/heads/main" @@ -1022,17 +1038,18 @@ end authentication_method(::Woodpecker) = Documenter.HTTPS function authenticated_repo_url(cfg::Woodpecker) + # `cfg.woodpecker_forge_url` should be just the root of the URL e.g. github.com, gitlab.com, codeberg.org + # otherwise, it will be equal to `cfg.woodpecker_repo_link` + # If so, we just split the `http(s)://` from the string we want + # e.g. `https://github.com/JuliaDocs/Documenter.jl` to `github.com/JuliaDocs/Documenter.jl`. if haskey(ENV, "FORGE_URL") return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(ENV["FORGE_URL"])/$(cfg.woodpecker_repo).git" else - # Regex will return the root of the URL e.g. https://github.com/JuliaDocs/Documenter.jl → github.com - # `CI_REPO_LINK` is a built-in env var which returns a repository link e.g. https://github.com/JuliaDocs/Documenter.jl - # The variable is passed through the pipeline during the runs. - # See https://woodpecker-ci.org/docs/usage/environment to check the environment-variable - m = match(r"https?:\/\/(?:.+\.)*(.+\..+?)\/", get(ENV, "CI_REPO_LINK", "")) - forge_url = m !== nothing ? m.captures[1] : "" # if `nothing`, just give an empty string so deploydocs can use it - # even though we know that errors - return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(forge_url)/$(cfg.woodpecker_repo).git" + if occursin(cfg.woodpecker_repo, cfg.woodpecker_forge_url) + return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(split(cfg.woodpecker_forge_url, r"https?://")[2]).git" + else + return "https://$(ENV["CI_REPO_OWNER"]):$(ENV["PROJECT_ACCESS_TOKEN"])@$(cfg.woodpecker_forge_url)/$(cfg.woodpecker_repo).git" + end end end diff --git a/test/deployconfig.jl b/test/deployconfig.jl index 3f6446275d..0e7ed784c3 100644 --- a/test/deployconfig.jl +++ b/test/deployconfig.jl @@ -494,6 +494,7 @@ end end "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/tags/v1.2.3", + "CI_COMMIT_TAG" => "v1.2.3", "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", "FORGE_URL" => nothing, ) do @@ -516,6 +517,7 @@ end end "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/tags/not-a-version", + "CI_COMMIT_TAG" => "not-a-version", "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", "FORGE_URL" => nothing, ) do @@ -532,6 +534,7 @@ end end "CI_REPO" => "JuliaDocs/Documenter.jl", "CI_REPO_OWNER" => "JuliaDocs", "CI_COMMIT_REF" => "refs/heads/master", + "CI_COMMIT_TAG" => nothing, "PROJECT_ACCESS_TOKEN" => "SGVsbG8sIHdvcmxkLg==", "FORGE_URL" => nothing, ) do From d4d506dd04192d88c6ad5dba980de27fdf56c7e7 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Fri, 22 Jul 2022 08:22:18 +0800 Subject: [PATCH 12/19] Update CHANGELOG.md Co-authored-by: Morten Piibeleht --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95670994e8..6c0d66e4c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,9 @@ **For upgrading:** the easiest way to fix the build is to remove the offending `@ref` links. Alternatively, the `repo` argument to `makedocs` can be set to the appropriate `Remotes.Remote` object that implements the `Remotes.issueurl` function, which would make sure that correct URLs are generated. +* ![Enhancement][badge-enhancement] Woodpecker CI is now automatically supported for documentation deployment. ([#1880][github-1880]) * ![Bugfix][badge-bugfix] Documenter now generates the correct source URLs for docstrings from other packages when the `repo` argument to `makedocs` is set (note: the source links to such docstrings only work if the external package is cloned from GitHub and added as a dev-dependency). However, this change **breaks** the case where the `repo` argument is used to override the main package/repository URL, assuming the repository is cloned from GitHub. ([#1808][github-1808]) * ![Bugfix][badge-bugfix] Documenter no longer uses the `TRAVIS_REPO_SLUG` environment variable to determine the Git remote of non-main repositories (when inferring it from the Git repository configuration has failed), which could previously lead to bad source links. ([#1881][github-1881]) - -* ![Enhancement][badge-enhancement] Added Woodpecker CI as another CI solution for deploying docs. ([#1880][github-1880]) - ## Version `v0.27.21` * ![Bugfix][badge-bugfix] Fix a regression where Documenter throws an error on systems that do not have Git available. ([#1870][github-1870], [#1871][github-1871]) From 8d6e37cdbdfee29dcffae2087d64f6a2eeb34fb2 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Fri, 22 Jul 2022 08:22:30 +0800 Subject: [PATCH 13/19] Update src/deployconfig.jl Co-authored-by: Morten Piibeleht --- src/deployconfig.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 999cdff02b..43a1105a0d 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -956,8 +956,7 @@ function deploy_folder( repo_ok = occursin(cfg.woodpecker_repo, repo) all_ok &= repo_ok - println(io, "- $(marker(repo_ok)) ENV[\"CI_REPO\"]=\"$(cfg.woodpecker_repo)\" occursin in re - po=\"$(repo)\"") + println(io, "- $(marker(repo_ok)) ENV[\"CI_REPO\"]=\"$(cfg.woodpecker_repo)\" occursin in repo=\"$(repo)\"") if build_type === :release event_ok = in(cfg.woodpecker_event_name, ["push", "pull_request", "deployment", "tag"]) From b73830bb126e0e7a3d907cb8ad09761240692c68 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Fri, 22 Jul 2022 09:00:24 +0800 Subject: [PATCH 14/19] Update CHANGELOG.md Co-authored-by: Morten Piibeleht --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0d66e4c8..a800fe4f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * ![Enhancement][badge-enhancement] Woodpecker CI is now automatically supported for documentation deployment. ([#1880][github-1880]) * ![Bugfix][badge-bugfix] Documenter now generates the correct source URLs for docstrings from other packages when the `repo` argument to `makedocs` is set (note: the source links to such docstrings only work if the external package is cloned from GitHub and added as a dev-dependency). However, this change **breaks** the case where the `repo` argument is used to override the main package/repository URL, assuming the repository is cloned from GitHub. ([#1808][github-1808]) * ![Bugfix][badge-bugfix] Documenter no longer uses the `TRAVIS_REPO_SLUG` environment variable to determine the Git remote of non-main repositories (when inferring it from the Git repository configuration has failed), which could previously lead to bad source links. ([#1881][github-1881]) + ## Version `v0.27.21` * ![Bugfix][badge-bugfix] Fix a regression where Documenter throws an error on systems that do not have Git available. ([#1870][github-1870], [#1871][github-1871]) From f94f3a552b6c879c92a2163e468b29e1989e09c9 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Sat, 23 Jul 2022 06:48:07 +0800 Subject: [PATCH 15/19] [docs] clarify secrets naming --- docs/src/man/hosting.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/man/hosting.md b/docs/src/man/hosting.md index 7542443c21..df9c9e4bbe 100644 --- a/docs/src/man/hosting.md +++ b/docs/src/man/hosting.md @@ -422,8 +422,9 @@ _This workflow was taken from [CliMA/ClimaTimeSteppers.jl](https://github.com/Cl To run a documentation build from Woodpecker CI, one should create an access token from their forge of choice: GitHub, GitLab, or Codeberg (or any Gitea instance). This access token should be added to Woodpecker CI as a secret named as -`project_access_token` - all lowercase. Next, create a new pipeline configuration file -called `.woodpecker.yml` with the following contents: +`project_access_token`. The case does not matter since this will be passed as +uppercase environment variables to your pipeline. Next, create a new pipeline +configuration file called `.woodpecker.yml` with the following contents: ```yaml pipeline: From c7c5bf1d0ba549a4d05ab32b77465daa568a2bba Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Sat, 23 Jul 2022 19:18:21 +0800 Subject: [PATCH 16/19] experiment if we can use ssh --- src/deployconfig.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 43a1105a0d..1181449e66 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -1035,7 +1035,7 @@ function deploy_folder( end end -authentication_method(::Woodpecker) = Documenter.HTTPS +authentication_method(::Woodpecker) = env_nonempty("DOCUMENTER_KEY") ? SSH : HTTPS function authenticated_repo_url(cfg::Woodpecker) # `cfg.woodpecker_forge_url` should be just the root of the URL e.g. github.com, gitlab.com, codeberg.org # otherwise, it will be equal to `cfg.woodpecker_repo_link` From 41c3f68cd40d00340e8e63e19349b077e173c338 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Sat, 23 Jul 2022 20:16:35 +0800 Subject: [PATCH 17/19] [docs] add woodpecker ci to documentation - also added a photo for a sample gitea repo - also added the manual way if not using julia to generate base64-encoded keys using `openssl` and `tr` --- .../hosting/gitea-codeberg-add-deploy-key.png | Bin 0 -> 82554 bytes docs/src/man/hosting/walkthrough.md | 33 +++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 docs/src/man/hosting/gitea-codeberg-add-deploy-key.png diff --git a/docs/src/man/hosting/gitea-codeberg-add-deploy-key.png b/docs/src/man/hosting/gitea-codeberg-add-deploy-key.png new file mode 100644 index 0000000000000000000000000000000000000000..eebf0f94f673b57ad7f85aaa274f9c817311e7d6 GIT binary patch literal 82554 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

r&v-|4O^?^P6P4 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

^;$tcUp(}L+fEvdKat7UA4Dtzu5y4`6uu)$bK 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 literal 0 HcmV?d00001 diff --git a/docs/src/man/hosting/walkthrough.md b/docs/src/man/hosting/walkthrough.md index 0cc68cda72..af111b0d57 100644 --- a/docs/src/man/hosting/walkthrough.md +++ b/docs/src/man/hosting/walkthrough.md @@ -102,27 +102,33 @@ set up automatic deployment of your documentation. The next steps are to add the GitHub and Travis. -## Adding the Public Key to GitHub +## Adding the Public Key to GitHub or Gitea such as Codeberg -In this section, we explain how to upload a public SSH key to GitHub. By this point, you -should have generated a public key and saved it to a file. If you haven't done this, go read +In this section, we explain how to upload a public SSH key to GitHub and Gitea such as Codeberg. By this point +, you should have generated a public key and saved it to a file. If you haven't done this, go read [Generating an SSH Key](@ref). -Go to `https://github.com/[YOUR_USER_NAME]/[YOUR_REPO_NAME]/settings/keys` and click "Add -deploy key". You should get to a page that looks like: +Go to `https://github.com/[YOUR_USER_NAME]/[YOUR_REPO_NAME]/settings/keys` for GitHub and `https://somegiteaname.org/[YOUR_USER_NAME]/[YOUR_REPO_NAME]/settings/keys` and click "Add +deploy key". You should get to a page that looks like,: -![](github-add-deploy-key.png) +**GitHub** + +![github-add-deploy-key](github-add-deploy-key.png) + +**Gitea** + +![gitea-codeberg-add-deploy-key](gitea-codeberg-add-deploy-key.png) Now we need to fill in three pieces of information. 1. Have "Title" be e.g. "Documenter". 2. Copy and paste the *public key* that we generated in the [Generating an SSH Key](@ref) - step into the "Key" field. + step into the "Key" or "Content" field. 3. Make sure that the "Allow write access" box is checked. Once you're done, click "Add key". Congratulations! You've added the public key -to GitHub. The next step is to add the private key to Travis or GitHub Secrets. - +to GitHub or your Gitea instance. The next step is to add the private key to Travis, GitHub, or +Woodpecker Secrets. ## Adding the Private Key @@ -138,6 +144,15 @@ julia> using Base64 julia> read("path/to/private/key", String) |> base64encode |> println ``` +If you are in a unix and unix-like system, you can just use `openssl` command with `tr` +(for truncate) to generate your base64-encoded-key. + +```bash +$ openssl enc -base64 -in path/to/your/private/key -out path/to/your/base/64/encoded/key +$ # We need to truncate the newlines +$ cat path/to/your/base/64/encoded/key | tr -d "\n" +``` + Copy the resulting output. Go to `https://travis-ci.com/[YOUR_USER_NAME]/[YOUR_REPO_NAME]/settings`. Scroll down From 9363be2c6c020f404964ef21e1de6b82b00ec147 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Sat, 23 Jul 2022 20:50:27 +0800 Subject: [PATCH 18/19] [enhancement] resolve reviews - add check if DOCUMENTER_KEY exists in woodpecker --- src/deployconfig.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/deployconfig.jl b/src/deployconfig.jl index 1181449e66..9992beaa4d 100644 --- a/src/deployconfig.jl +++ b/src/deployconfig.jl @@ -1008,11 +1008,16 @@ function deploy_folder( end token_ok = env_nonempty("PROJECT_ACCESS_TOKEN") - auth_ok = token_ok + key_ok = env_nonempty("DOCUMENTER_KEY") + auth_ok = token_ok | key_ok all_ok &= auth_ok - if token_ok + if key_ok + println(io, "- $(marker(key_ok)) ENV[\"DOCUMENTER_KEY\"] exists and is non-empty") + elseif token_ok println(io, "- $(marker(token_ok)) ENV[\"PROJECT_ACCESS_TOKEN\"] exists and is non-empty") + else + println(io, "- $(marker(auth_ok)) ENV[\"DOCUMENTER_KEY\"] or ENV[\"PROJECT_ACCESS_TOKEN\"] exists and is non-empty") end print(io, "Deploying: $(marker(all_ok))") From 7b1ae3bd59e569245965edb65a892671b68126d7 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Sat, 23 Jul 2022 21:36:36 +0800 Subject: [PATCH 19/19] [fix] wrong reference on markdown --- docs/src/man/hosting/walkthrough.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/man/hosting/walkthrough.md b/docs/src/man/hosting/walkthrough.md index af111b0d57..b03f6f1c63 100644 --- a/docs/src/man/hosting/walkthrough.md +++ b/docs/src/man/hosting/walkthrough.md @@ -5,7 +5,7 @@ If the instructions in [Authentication: SSH Deploy Keys](@ref) did not work for process. There are three main steps: 1. [Generating an SSH Key](@ref) -2. [Adding the Public Key to GitHub](@ref) +2. [Adding the Public Key to GitHub or Gitea such as Codeberg](@ref) 3. [Adding the Private Key](@ref) ## Generating an SSH Key @@ -55,7 +55,7 @@ julia> read("privatekey.pub", String) |> println ``` Copy and paste the output somewhere. This is your *public key* and is required for the step -[Adding the Public Key to GitHub](@ref). +[Adding the Public Key to GitHub or Gitea such as Codeberg](@ref). ### If you do not have `ssh-keygen` @@ -83,7 +83,7 @@ Now we need to save the public key somewhere. * Copy the text in the box titled "Public key for pasting into OpenSSH authorized_keys file" and paste it somewhere for later. This is your *public key* and is required for the step - [Adding the Public Key to GitHub](@ref) + [Adding the Public Key to GitHub or Gitea such as Codeberg](@ref) Finally, we need to save the private key somewhere.