Remote repository links
Documenter, if set up appropriately, can automatically generate links to publicly hosted Git repositories (such as source and edit links to e.g. repositories hosted on GitHub). Usually this is for linking back to the main package repository or the project source code.
The Remotes
API is used to specify remote repositories and generate the URLs. It is also designed to be extended, to support additional Git repository hosting services.
Remote link types
There are two categories of remote repositories that (may) need to be configured for Documenter to be able to determine remote URLs:
Project repository remote, specified with the
repo
keyword tomakedocs
. This refers to the project as a whole (rather than specific files), and is used for the repository landing page link, issue references etc.File link remotes, specified by the
remotes
keyword tomakedocs
. These are used to link a file system file to the corresponding file in the remote repository. In particular, these are used to generate the edit links for manual pages, and Julia source file links for docstrings.
For the most common case – a repository of a simple Julia package – there is usually only one remote repository that one links to, and the distinction between file links and repository links is not relevant. However, in more complex setups it may be necessary to distinguish between the two cases. The defaults to the two keywords try to cater for the most common use case, and as is explained below, this means that there has to be some interaction between these two arguments.
Remotes for files
When Documenter has to determine the URL of a file in the hosted repository, it gets a local filesystem absolute path as an input.[1] In the case of Markdown files, those local paths are determined by makedocs
when it reads them. The links to Julia files are determined from the docsystem, and point to where the code was loaded from (e.g. for a development dependency of the environment, they come from the Pkg.develop
ed path; but for normal Pkg.add
dependencies the source files are usually in ~/.julia/packages
).
In most cases, for both Markdown and Julia files, the files Documenter is concerned about are located in the currently checked out Git repository that contains the Documenter make.jl
script (e.g. the locally checked out package repository). However, sometimes they may also be in a different repository (either in a subdirectory of or outside of the primary repository), or even in a non-Git directory outside of the primary repository (e.g. if you're trying to build the documentation of a release tarball).
To handle those cases, the remotes
keyword to makedocs
can be used to set up a local directory => remote repository
mapping for local file system paths. The local directory is assumed to correspond to the root of the Git repository, and any subpath within that directory is then resolved to the corresponding path in the remote repository. If there are nested remotes
configured, Documenter will use the one that matches first as it walks up the directory tree from the original path.
As the common cases are a locally checked out Git repository (added with Pkg.develop
to the docs environment), or a released package which is hosted on GitHub (Pkg.add
ed to the environment), Documenter will also try to determine such remotes automatically.
- When Documenter walks up the directory tree, it checks whether the directory is a root of a Git repository (by looking for the presence of a
.git
directory or file). Once it finds a valid local repository root, it tries to read itsorigin
remote URL.- If that matches a GitHub repository[2], Documenter automatically sets up a mapping from that directory, and then uses that to determine the remote URLs.
- If Documenter is unable to determine the remote from the repository's
origin
(e.g.origin
is not set up, or it is hosted somewhere else), it will error, as it will not be able to determine the remote URLs. In this case, the remote should be configured explicitly withremotes
.
You can think of it as Documenter automatically populating remotes
with any cloned GitHub repositories it finds.[3]
For released packages (those added using Pkg.add(...)
rather than Pkg.develop(...)
), the version and repository can be determined from the package metadata, but a commit hash is not readily available. In this case, Documenter will guess that a tag v$VERSION
exists in the repository on GitHub. Note that these tags are created automatically by the widely used JuliaRegistries/TagBot action. Since this is sometimes not the case, and could cause dead or incorrect links, setting the linkcheck
keyword to true
to makedocs
will check these guessed links have an existing target and that the existing target matches the published package. (Note this will also all other external links from your documentation.) Note that enabling this option can cause documentation builds to fail due to network errors or intermittent downtime of external services.
The Remotes
API can be used to implement the methods to compute the remote URLs (for now, Documenter only supports GitHub and GitLab natively).
repo
& remotes
interaction
Since Documenter is primarily used to generate documentation for Julia packages, there is some interaction between the repo
and remotes
keyword arguments, to automagically determine their defaults. This means that usually it is not necessary to specify either explicitly in the make.jl
script.
The rules are as follows:
If
repo
is not specified, it is essentially determined like any other remote link, by trying to figure out the repository that contains theroot
path argument ofmakedocs
(defaulting to the directory of themake.jl
script; usually thedocs/
directory). TheRemote
object will one of theremotes
, which in turn may have been determined automatically via theorigin
URL of the containing Git repository.If
repo
is specified, but theremotes
for the repository root is not,repo
will function as aremotes
entry for the repository root. This is so that it would not be necessary to specify the same argument twice (i.e. once for general repository links, once for file links).If both
repo
and aremotes
for the repository root are configured, Documenter will throw an error, as it does not really make sense for them to point to two different remotes.[4]
Remotes API
Documenter.Remotes
— ModuleTypes and functions for handling repository remotes.
Documenter.Remotes.GitHub
— TypeGitHub(user :: AbstractString, repo :: AbstractString)
GitHub(remote :: AbstractString)
Represents a remote Git repository hosted on GitHub. The repository is identified by the names of the user (or organization) and the repository: GitHub(user, repository)
. E.g.:
makedocs(
repo = GitHub("JuliaDocs", "Documenter.jl")
)
The single-argument constructor assumes that the user and repository parts are separated by a slash (e.g. JuliaDocs/Documenter.jl
).
Documenter.Remotes.GitLab
— TypeGitLab(host, user, repo)
GitLab(user, repo)
GitLab(remote)
Represents a remote Git repository hosted on GitLab. The repository is identified by the host, name of the user (or organization), and the repository. For example:
makedocs(
repo = GitLab("JuliaDocs", "Documenter.jl")
)
The single argument constructor assumes that the end user and repository parts are separated by a slash (e.g., JuliaDocs/Documenter.jl
).
The following types and functions and relevant when creating custom Remote
types:
Documenter.Remotes.Remote
— Typeabstract type Remote
Abstract supertype for implementing additional remote repositories that Documenter can use when generating links to files hosted on Git hosting service (such as GitHub, GitLab etc). For custom or less common Git hosting services, the user can create their own Remote
subtype and pass that as the repo
argument to makedocs
.
When implementing a new type T <: Remote
, the following functions must be extended for that type:
Additionally, it may also extend the following functions:
Documenter.Remotes.repourl
— FunctionRemotes.repourl(remote::T) -> String
An internal Documenter function that must be extended when implementing a user-defined Remote
. It should return a string pointing to the landing page of the remote repository. E.g. for GitHub
it returns "https://github.com/USER/REPO/"
.
Documenter.Remotes.fileurl
— FunctionRemotes.fileurl(remote::T, ref, filename, linerange) -> String
An internal Documenter function that must be extended when implementing a user-defined Remote
. Should return the full remote URL to the source file filename
, optionally including the line numbers.
ref
is string containing the Git reference, such as a commit SHA, branch name or a tag name.filename
is a string containing the full path of the file in the repository without any leading/
characters.linerange
either specifies a range of integers or isnothing
. In the former case it either specifies a line number (iffirst(linerange) == last(linerange)
) or a range of lines (first(linerange) < last(linerange)
). The line information should be accessed only with thefirst
andlast
functions (no other interface guarantees are made).If
linerange
isnothing
, the line numbers should be omitted and the returned URL should refer to the full file.It is also acceptable for an implementation to completely ignore the value of the
linerange
argument, e.g. when the remote repository does not support direct links to particular line numbers.
E.g. for GitHub
, depending on the input arguments, it would return the following strings:
ref | filename | linerange | returned string |
---|---|---|---|
"master" | "foo/bar.jl" | nothing | "https://github.com/USER/REPO/blob/master/foo/bar.jl" |
"v1.2.3" | "foo/bar.jl" | 12:12 | "https://github.com/USER/REPO/blob/v1.2.3/foo/bar.jl#L12" |
"xyz/foo" | "README.md" | 10:15 | "https://github.com/USER/REPO/blob/xyz/foo/README.md#L10-L15" |
Documenter.Remotes.issueurl
— FunctionRemotes.issueurl(remote::T, issuenumber)
An internal Documenter function that can be extended when implementing a user-defined Remote
. It should return a string with the full URL to an issue referenced by issuenumber
, or nothing
if it is not possible to determine such a URL.
issuenumber
is a string containing the issue number.
It is not mandatory to define this method for a custom Remote
. In this case it just falls back to always returning nothing
.
E.g. for GitHub
when issuenumber = "123"
, it would return "https://github.com/USER/REPO/issues/123"
.
- 1There is an exception to this: links to Julia
Base
module source files. But Documenter already known how to handle those correctly, and they are really only relevant to the Julia main manual build. - 2GitHub is the most common case, but this could be extended to cover other Git hosting services in the future (as long as the remote can reliably determined from the
origin
URL). - 3One thing to be aware here is that Documenter builds up a cache of the Git repositories it finds on every
makedocs
call. This is for performance reasons, to reduce the number of file system accesses and, in particular,git
calls, which are relatively slow. - 4If there is a use case for this, this limitation could be relaxed in the future.