-
Notifications
You must be signed in to change notification settings - Fork 40.7k
Antora
Spring Boot 3.3 and later uses Antora to generate documentation. Antora is a site generator that is built on top of Asciidoctor. It provides us the ability to create a single documentation site for multiple different versions of Spring Boot.
To build the documentation locally so you can preview it, run the either the full ./gradlew build`
or the following command:
$ ./gradlew spring-boot-project:spring-boot-docs:antora
Once complete, the documentation will be available under build/site
.
You can also run the same antora
task to generate partial documentation on any module that has an src/docs/antora/antora.yml
file.
For example, to build just the REST API documentation you can run:
$ ./gradlew spring-boot-project:spring-boot-actuator-autoconfigure:antora
Antora has three main concepts that can be used to structure documentation.
-
Components
-
Modules
-
Content Sources
Components collections of documentation create from one or more content sources. Typically a versioned instance of a component created from a branch or tag in a git repository.
Spring Boot has a single component named spring-boot
.
A module is a collection of content in a component version that’s related by some kind of grouping. It is primarily an organization tool for the writer.
Spring Boot has the following modules:
-
`ROOT - The root module and navigation
-
tutorial
- Tutorials for how to use Spring Boot -
reference
- The main Reference documentation -
how-to
- How-to style question and answer documentation -
build-tool-plugins
- General information about the build tool plugins -
gradle-plugin
- Gradle plugin documentation -
maven-plugin
- Maven plugin documentation -
cli
- CLI documentations -
specification
- Specification docs (e.g. the uber jar format) -
appendix
- Appendix information (with a lot of auto-generated content) -
api
- REST API and Javadoc
A lot of inspiration for the modules comes from the Divio Documentation System.
Content from a git repository is located by specifying a content source.
Each content source contains an antora.yml
file which provides the information Antora needs to create a component.
Spring Boot uses a src/docs/antora
directory under our existing Gradle modules as content sources.
The following modules contain Antora sources:
-
spring-boot-docs
-
spring-boot-actuator-autoconfigure
-
spring-boot-gradle-plugin
-
spring-boot-maven-plugin
The Antora playbook controls what content is included in the documentation site. There is a playbook file used to generate the real site which lists the branches and tags to include. There is also a local playbook file that is generated on-the-fly by Gradle whenever a documentation module is built.
The file can be inspected by looking at build/generated/docs/antora-playbook/antora-playbook.yml
.
If you need to change the generated content you’ll need to update the GenerateAntoraPlaybook
class under buildSrc
.
Navigation files are special .adoc
files used to create the navigation tree on the left of the site.
Spring Boot composes navigation files from distinct files located with each module.
Navigation files are name nav-<module>.adoc
and placed in the partials
directory.
The main navigation file that includes the partials is at spring-boot-project/spring-boot-docs/src/docs/antora/nav.adoc
.
In addition to the main navigation, modules may also include a src/docs/antora/local-nav.adoc
file.
This file is not used on the final site, but provides a way to generate navigation for a single module so that its documentation can be viewed without generating the entire site.
Antora typically works by generating a documentation site from content contained in a git repository. Using git content alone isn’t sufficient for Spring Boot since some of our documentation is generated automatically during the build.
For example, we generate an appendix containing the configuration properties we support.
We also generate link and version attributes from the spring-boot-dependencies
module.
These can be used in any .adoc
file.
To support contents that is generated during a build, but not committed to git, we use the zip contents collector extension. This extension allows us to publish a zip file to artifactory containing all the generated content required to build the documentation site.
Individual antora.yml
files need to declare the zip contents that they expect to be included.
Includes are defined using the module name
and a classifier
.
The classifier is either:
-
aggregate-content
- Generated.adoc
files etc. -
catalog-content
- Generated HTML (e.g. Javadoc).
Here’s a typical configuration:
ext:
zip_contents_collector:
include:
- name: root
classifier: aggregate-content
- name: api
classifier: catalog-content
module: api
destination: content-catalog
During a local build, zip contents are picked up directly from the /build
directory.
Note
|
It is critical that content zips are actually published to Artifactory.
If new zips are added, the spring-boot-docs modules will need to be updated to ensure publishing occurs.
|
The main spring-boot-docs
site includes zip content that provides an antora.yml
file.
This file contains generated attributes and additional configuration that Antora needs to generate a correct site.
Because our build is modular, we also need to include this generated content when building other documentation modules.
In these cases, we cannot declare the include in the antora.yml
file because we only want the include for the local build.
We don’t want our main documentation playbook to find these includes and attempt to download them.
To deal with this, special configuration is applied to the generateAntoraPlaybook
task.
Here’s a typical example:
tasks.named("generateAntoraPlaybook") {
alwaysInclude = [name: "actuator-rest-api", classifier: "local-aggregate-content"]
dependsOn antoraActuatorRestApiLocalAggregateContent
}
In the example above, the local-aggregate-content
will be included for the local build but never actually published.
The antoraActuatorRestApiLocalAggregateContent
task is responsible for creating the zip file.
It typically delegates to generateAntoraYml
.
Generating the site during the regular project build is a helpful way of previewing the documentation, but it’s not suitable for publishing the real site. The real documentation site needs to collect content sources from multiple branches and present them in a unified way.
To do this, we have an orphan branch named docs-build
.
This branch contains a GitHub workflow that builds the real site.
The workflow is run whenever a commit is made to the docs-build
branch.
It’s also run after after a successful CI build to publish snapshot docs.
By default Antora does not validate that the fragment part of an xref actually exists in the target document. To deal with this, we use the xref extension.
This extension ensure fragments actually exist in the target document. It also allows us to stub out references for content that isn’t yet available.
Stubbing is important due to the modular nature of our build.
For example, our Maven plugin documentation may have xrefs to sections in the reference
modules.
These can only be validated when spring-boot-docs
is built.
When the spring-boot-maven-plugin
is built, we need to stub out these xrefs so they don’t fail.
Stubbing is configure on the generated local playbook file. Here’s a typical Gradle configuration:
tasks.named("generateAntoraPlaybook") {
xrefStubs = ["appendix:.*", "api:.*", "reference:.*"]
...
}
There are few differences from the aciidoctor generation that we used in earlier versions of Spring Boot.
The Asciidoctor extensions used in Antora are written in Javascript. This means our previous extensions cannot be used.
A replacement set of extensions have been developed which offer equivalent features. As the underlying code is different, there may be subtle issues when migrating.
During the migration to Antora we’ve taken the opportunity to follow the best practices for Asciidoctor attribute naming. This means that attributes will be different and may need to change during a forward-merge.
Antora .adoc
files continue to use our standard formatting rule of three spaces before a section header.
However, we now also include a line after the header.
This is done to ensure that attribute are always read correctly.
We no longer need to specify indent=0
in source blocks or indent the code.
Most source blocks should now just need [source,<language>]
.
For example:
[source,xml] ---- <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> ----
We now use standard asciidoctor tabs rather than our own extension. This mean that markup will need to change when forward-merging.
Here some typical tab markup:
[tabs]
======
Maven::
+
[source,shell]
----
$ target/myproject
----
Gradle::
+
[source,shell]
----
$ build/native/nativeCompile/myproject
----
======
We now use @springio/asciidoctor-extensions/include-code-extension
to include code fragments.
This uses a slightly different syntax of:
include-code::SomeCode[]
We now use @springio/asciidoctor-extensions/configuration-properties-extension
for configuration properties.
This uses a slightly different syntax of:
[configprops,yaml]
----
spring:
datasource:
url: jdbc:mysql://localhost/test
username: dbuser
password: dbpass
----