This is a simple guide on how to best build your documentation in Julia v1.0 if you are using Documenter
.
The old way
If you are using Documenter
you probably have something like the following in your .travis.yml
file for building your documentation:
after_success:
- julia -e 'Pkg.add("Documenter")'
- julia -e 'cd(Pkg.dir("PACKAGE_NAME")); include(joinpath("docs", "make.jl"))'
Why is this bad? Here are some reasons:
- There is no good way to add doc-build dependencies, you have to add them manually (like we
Pkg.add("Documenter")
above). - Code in the
after_success:
part of the build does not fail the build. This makes it difficult to verify that (i) the doc build works and (ii) that doctest etc. still passes. For this reason some package have chosen to build the docs as part of the test suite instead. - Doc building runs in the global environment, and is thus affected by the surroundings.
So, maybe we can use this new Pkg
thing, that apparently should solve all our problems. Absolutely!
The new way
In Julia v1.0 we can instead use a designated doc-build project with a Project.toml
in the docs/
directory. The project includes Documenter
and all your other doc-build dependencies. If Documenter
is the only dependency, then the Project.toml
file should include the following:
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
[compat]
Documenter = "~0.19"
Here we also added a compatibility constraint for Documenter
, since I happen to know that Documenter
0.20 will break everything.
Instead of creating the Project.toml
file manually we could have started Julia with julia --project=docs/
(alternatively just start Julia and then using Pkg; Pkg.activate("docs")
) and then used the Pkg
REPL to add
our doc-build dependencies.
Next we need to configure the .travis.yml
to use this project. For this we will utilize Travis Build Stages that have just been released (see Build Stages - Travis CI). Add the following to your .travis.yml
file:
jobs:
include:
- stage: "Documentation"
julia: 1.0
os: linux
script:
- julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd()));
Pkg.instantiate()'
- julia --project=docs/ docs/make.jl
after_success: skip
This adds a new build stage, called Documentation
, that will run after the default test
stage. It will look something like this. The julia:
and os:
entries control from which worker we build the docs, for example Julia 1.0
and linux
. What happens on the three lines in the script:
part?
- The first line
Pkg.instantiate()
s the project, meaning thatDocumenter
and the other dependencies will be installed. - The second line adds our package to the doc-build environment.
- The third line builds the docs.
Lastly, commit the files (the Manifest.toml
can be .gitignored
) and push!
Why is this better?
- Using a custom docs projects gives full control over the environment where the docs build.
- We can have documentation dependencies.
- A failed doc build now fails CI.
In my opinion this is a pretty nice example of how to utilize the new Pkg
environments.
If you need some inspiration, have a look at the following packages that already uses projects and build stages for doc-building:
Some gotchas
-
Make sure that the
julia
andos
arguments toDocumenter.deploydocs
match the configuration you define for the build stage in.travis.yml
. Note that this is something that will change in the next Documenter release, where thejulia
andos
arguments are removed and the deployment is essentially governed by the.travis.yml
configuration. So the annoyance of keeping those in sync is temporary. EDIT: This does not apply to Documenter v0.20. -
If you are using doctests, you will run into absolutify --project path by fredrikekre · Pull Request #28625 · JuliaLang/julia · GitHub (you will see something like
ERROR: LoadError: ArgumentError: Package Foo not found in current path
) which is a bug in Juliav0.7
,v1.0
(but fixed onnightly
and the upcoming Juliav1.0.1
). You can add the following lines at the top ofdocs/make.jl
to workaround it:# Workaround for JuliaLang/julia/pull/28625 if Base.HOME_PROJECT[] !== nothing Base.HOME_PROJECT[] = abspath(Base.HOME_PROJECT[]) end
Feel free to ping me (@fredrikekre
) for any questions from your PRs. Happy upgrading!