Euan's Blog

How I Write Documentation: AsciiDoctor Built With GitLab CI

I spend quite a lot of my time writing documentation for both end users and other developers alike. Over the years, I've experimented with many approaches including Markdown and LaTeX.

In the end though, I've settled on an approach: documentation is written using AsciiDoctor, and lives in a repository of its own. GitLab CI is used to automatically build documentation upon commit to the main branch, pushing the resulting HTML and PDF files to the build artefact server.

I chose AsciiDoctor due to its ease of writing and the array of supported output formats such as HTML 5, DocBook 5, and PDF. Many customers tend to expect PDFs for their end-user documentation and I like to use HTML when writing documentation for web pages. The basic syntax is also relatively easy to grasp (though when I've not written any recently I do tend to find myself having to refer back to the AsciiDoc Language Reference). There's built in support for all of the common content that we require such as images, lists, code blocks, keyboard macros and menu macros. It being based upon plain text also means that diffing between revisions is very easy compared to something such as a Microsoft Word file.

Custom stylesheets can be used when building both HTML and PDF documents, and I use embedded CSS and data URIs for images so that I can ship a single HTML file for a document that contains everything required to display properly. The HTML styling uses standard CSS and will be familiar to anybody with experience working with HTML and CSS. Unfortunately, the same cannot be said for PDF styling which has its own theming guide. My theming requirements aren't particularly complex, but even so styling was a case of trial and error which took a while to resolve.

Once finished writing a document, I commit and push to our GitLab server. From here, GitLab CI takes over and builds all of the documents. I keep multiple documents in a single repository so GitLab builds them all on every commit. The official AsciiDoctor Docker image is used to build the documents. The pipeline looks a little like the following:

stages:
  - build

build-html:
  artifacts:
    paths:
      - output/**/*.html
  image: asciidoctor/docker-asciidoctor
  script:
    - >
      asciidoctor -a data-uri \
        -a toc=left \
        -a sectnums \
        -a reproducible \
        -a icons=font \
        -a source-highlighter=Pygments \
        -a experimental \
        -D output \
        -R src '**/*.adoc'
  stage: build

build-pdf:
  artifacts:
    paths:
      - output/**/*.pdf
  image: asciidoctor/docker-asciidoctor
  script:
    - >
      asciidoctor-pdf -a toc \
        -a sectnums \
        -a reproducible \
        -a icons=font \
        -a source-highlighter=Pygments \
        -a experimental \
        -D output \
        -R src '**/*.adoc'
  stage: build

Documents are stored in a src directory, and the CI pipeline creates an output directory containing all of the built documents. The directory structure from the src directory is preserved in the output. We then create a build artefact from our output directory.

Overall this approach seems to be working out pretty well so far. The only current downside that I have is how long it takes to actually build the PDFs. The HTML build stage completes in a matter of a few seconds, but the PDF build stage tends to take several minutes and this is only getting worse as more and more documents are created. The PDF build stage also consumes a lot of memory which is also increasing with the more documents that is added.

The next thing I need to investigate is AsciiDoctor Diagram for any diagraming needs, though that may be more of a challenge to both learn and to teach to other team members!

#Asciidoctor