The Asciidoctor Gradle Plugin Suite is the official means of using Asciidoctor to convert all your AsciiDoc documentation using Gradle.

This started as a port of the Asciidoctor Maven Plugin project founded by Jason Porter and relies on AsciidoctorJ which was founded by Alex Soto. In fact the 1.5.x series of the Asciidoctor Gradle plugin can still be considered a port. However the 2.x series and beyond is a complete departure with functionality far exceeding any lightweight markup plugins for any other build tool. This new series allows for the creation of a true DocuOps pipeline by bringing together Gradle as a powerful and generic build tool, and Asciidoctor as an agile and lightweight document generator.

Compatibility

This collection of plugins requires at least Gradle 4.0, JDK 8.0 and AsciidoctorJ 1.6.0 to run. If you need prior Gradle, JDK or AsciidoctorJ support please use a plugin from the 1.5.x or 1.6.x release series.

Quick Start

To start you need to use one of the plugins from the following Gradle snippet

build.gradle
plugins {
    id 'org.asciidoctor.jvm.convert' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.convert") version "2.4.0"
}

Task Configuration

All Asciidoctor tasks will have the following methods and properties:

Properties and methods common all AsciidoctorJ tasks
asciidoctorj

a task extension which allows a task to extend of override global configuration for Asciidoctor tasks. This allow extensive flexibility. Any thing that can be configured in the global asciidoctorj extension can also be configured here.

attributes

A shortcut for asciidoctorj.attributes.

baseDir

Base directory for asciidoctor document conversion and root document inclusion. The base directory will be the project directory by default, but can be set to any other directory.

baseDirFollowsSourceDir

The base directory should be the same as the source directory even if the source directory is located within an intermediate working directory.

baseDirIsProjectDir

The base directory is always the current project directory.

baseDirIsRootProjectDir

The base directory is always the root project directory.

configurations

Specify additional configurations These configurations will be added to the classpath when the task is executed.

copyAllResources

Copy all resources to the output directory

copyNoResources

Do not copy any resources to the output directory

copyResourcesOnlyIf

Only copy resources if the backend matches the listed backend.

inProcess

Specifies whether Asciidoctor conversions should be run in-process or out-of-process. Default: true (in-process).

logDocuments

Specifies if documents being processed should be logged on console. Type: boolean. Default: false.

options

A shortcut to`asciidoctorj.options`.

outputDir

where generated docs go. Use either outputDir path, setOutputDir path or outputDir=path Type: File, but any object convertible with project.file can be passed. Default: $buildDir/asciidoc.

parallelMode

Specifies whether each backend or other variant of a converting tasks huodl be run in parallel or sequential. Sequential conversions might have less initialisation overhead, but may suffer from gemPath and extension pollution. Default: true (parallel).

resources

specify which additional files (image etc.) must be copied to output directory using a CopySpec. secondarySources: Specify which source files should be monitor for change. These are typically files which are included by top-level files as well as doctype files. Default: All files in sourceDir which matches getDefaultSourceDocumentPattern() as well as doctype files.

sourceDir

where the asciidoc sources are. Use either sourceDir path, setSourceDir path or sourceDir=path Type: File, but any object convertible with project.file can be passed. Default: src/docs/asciidoc.

sources

Specify which Asciidoctor source files to include as toplevel documents. It uses an Ant-style PatternSet.

useIntermediateWorkDir

Use an intermediate work directory for sources ances. Some extensions such as ditaa will write content into the source directory. In order to keep the project source directory pristine an intermediate work directory can be used. All sources and resources will be copied there prior the executing Asciidoctor.

withIntermediateArtifacts

Add intermediate artifacts to oputput directory If the document conversion process creates intermediate artifacts which needs to be added to the output directory, then the pattern set with a closure or Action. This implies useIntermediateWorkDir. An example of such a case is the use of ditaa.

The org.asciidoctor.jvm.convert plugin has a conversion task type of org.asciidoctor.gradle.jvm.AsciidoctorTask which, in addition the aforementioned will also have the following properties and methods which are configured via an outputOptions closure or action:

Properties & methods for configuring generic AsciidoctorTask
backends

the backends to use. Use backends to append. Use setBackends or backends=[] to overwrite Type: Set<String>, but any type can be converted to String can be used. Default: [html5].

separateOutputDirs

specifies whether each backend should use a separate subfolder under outputDir. Default: true

Defining Sources

The plugin will search for sources under sourceDir. Sources may have any of the following extensions in order to be discovered:

  • .adoc (preferred)

  • .asciidoc

  • .ad

  • .asc

To select only certain files, use the sources method. This method takes a closure or an Action as an argument, which in turn configures an org.asciidoctor.gradle.jvm.epub.internal PatternSet.

To specify a custom output folder, use the outputDir method.

build.gradle
asciidoctor {
  sourceDir  file('docs')
  sources {
    include 'toplevel.adoc', 'another.adoc', 'third.adoc'
  }
  outputDir  file('build/docs')
}
build.gradle.kts
tasks {
  "asciidoctor"(AsciidoctorTask::class) {
    sourceDir = file("docs")
    sources(delegateClosureOf<PatternSet> {
      include("toplevel.adoc", "another.adoc", "third.adoc")
    })
    outputDir = file("build/docs")
  }
}

Paths defined in this PatternSet are resolved relative to the sourceDir.

Processing Auxiliary Files

Some backends require that additional files be copied across. The most common example are images for HTML backends. For this the resources method is used. It is provided with a closure that configures an org.asciidoctor.gradle.jvm.epub.internal CopySpec

build.gradle
resources {
  from('src/resources/images') {
    include 'images/**/*.png'
    exclude 'images/**/notThisOne.png'
  }

  from( "${buildDir}/downloads" ) {
    include 'deck.js/**'
  }

  into './images'
}
build.gradle.kts
resources(delegateClosureOf<CopySpec> {
  from("src/resources/images") {
    include("images/**/*.png")
    exclude("images/**/notThisOne.png")
  }

  from("$buildDir/downloads") {
    include("deck.js/**")
  }

  into("./images")
})

Files will be copied to below ${outputDir}/${backend} (or just ${outputDir} if separateOutputDirs=false)

Unlike sourceDir files can be copied from anywhere in the filesystem.

If resources is never set, the default behaviour is as if the following was called

build.gradle
resources {
  from(sourceDir) {
    include 'images/**'
  }
}

If you do not want this behaviour, then it can be turned off by doing

build.gradle
copyNoResources()

Include directives and base directory

These plugins do not change the way include:: directive works, but it is important to note how setting baseDir will affect top level includes. It is recommended that you always use {includedir} as a prefix for the file path. This attribute is always set to the correct top-level folder where the sources will be located.

However it is not practical for everyone to use {includedir} and as from 2.2.0 it is possible to add a strategy for controlling the base directory:

build.gradle
asciidoctor {
    baseDirIsRootProjectDir() (1)
    baseDirIsProjectDir() (2)
    baseDirFollowsSourceDir() (3)
}
1 The base directory is the root project directory.
2 The base directory is the current subproject directory.
3 The base directory will always the the same as the source directory. If an intermediate working directory is being used, the base directory will automatically point to that.

Docinfo processing

When using the docinfo attribute with html and docbook backends, it is recommended that baseDirFollowsSourceDir() is always set. This will ensure that the docinfo files are picked up correctly from the same directory that is the source directory.

Choosing a Process Mode for AsciidoctorJ

All AsciidoctorJ-based tasks can control how Asciidoctor conversions are being run via the inProcess property. This is early days, and a choice for your build will depend very much on your context, but the following has already become clear:

  • IN_PROCESS and OUT_OF_PROCESS should theoretically run faster, especially if you continuously rebuild the same documentation. Gradle workers are the underlying implementation for these two options

  • The safe option is always JAVA_EXEC. For lower memory consumption this is by far the safer option. (It is also the only way we can get the Windows-based tests for this plugin to complete on Appveyor & Travis CI). It you run a lot of builds the penalty start-up time might become an issue for you.

In certain cases the plugin will overrule your choice as it has some built-in rules for special cases. In such cases it will log a warning that it has done that.

AsciidoctorJ Base Plugin

This plugin is automatically applied by all AsciidoctorJ-based plugins.

Adds an extension for configuring which version of AsciidoctorJ and various other AsciidoctorJ backends.

This is very much similar to the one used in older versions of the Asciidoctor Gradle plugin, but now it also offers the ability to add the same functionality to a task thus allowing a task to override the default versions that has been set.

asciidoctorj {
  version = '1.5.6' (1)
  groovyDslVersion = '1.0.0.Alpha2' (2)

  options doctype: 'book', ruby: 'erubis' (3)

  attributes toclevel : 2 (4)
}
1 Set the default version of AsciidoctorJ for all Asciidoctor tasks in a project.
2 Set the default version of the Groovy extensions DSL for all Asciidoctor tasks in a project.
3 Add options for all Asciidoctor tasks
4 Add attributes for all Asciidoctor tasks

You can also override or extend select settings within a task using the same extension i.e.

asciidoctor {
  asciidoctorj {
      setOptions = [ doctype: 'article' ] (1)

      attributes toc : left (2)
  }
}
1 Override any global options
2 Use these attributes in addition to the globally specified ones.

The entities that can be set are:

attributes

Asciidoctorj-EPUB attributes. Use attributes to append and setAttributes to replace any current attributes with a new set. Attribute values are lazy-evaluated to strings.

attributeProvider

Register an additional provider of attributes. Attribute providers are a means of adding attributes that will not affect the up-to-date status of tasks.

docExtensions

Groovy DSL extensions. Use docExtensions to add one or more extensions. Use setDocExtensions to replace the current set of extensions with a new set. Extensions can be any kind of object that is serialisable, although in most cases they will be strings or files. If extensions are detached dependencies, they will not be serialised, but rather will be placed on the classpath in order that AsciidoctorJ can pick them up automatically.

fatalWarnings

Patterns for AsciidoctorJ log messages that should be treated as fatal errors. The list is empty be default. Use setFatalWarnings to clear any existing patterns or to decouple a task’s configuration from the global configuration. Use fatalWarnings to add more patterns. Pass missingIncludes() to add the common use-case of missing include files.

gemPaths

One or more gem installation directories (separated by the system path separator). Use gemPaths to append. Use setGemPaths or gemPaths=['path1','path2'] to overwrite. Use asGemPath to obtain a path string, separated by platform-specific separator. Type: FileCollection, but any collection of objects convertible with project.files can be passed Default: empty

jrubyVersion

Minimum version of JRuby to be used. The exact version that will be used could be higher due to AsciidoctorJ having a transitive dependency that is newer.

logLevel

The log level at which AsciidoctorJ will log. This is specified as a Gradle logging level. The plugin will translate it to the appropriate AsciidoctorJ logging level. Default is project.logger.level.

modules

Configuration for version of specific compoenents and converters that can be used.

options

AsciidoctorJ options. Use options to append and setOptions to replace any current options with a new set. Options are evaluated as late as possible.

requires

The set of Ruby modules to be included. Use requires to append. Use setRequires or requires=['name'] to overwrite. Default: empty.

resolutionStrategy

Strategies for resolving Asciidoctorj-related dependencies. Asciidoctor dependencies are held in a detached configuration. If for some special reason, you need to modify the way the dependency set is resolved, you can modify the behaviour by adding one or more strategies.

safeMode

AsciidoctorJ safe mode. Set the Safe mode as either UNSAFE, SAFE, SERVER, SECURE. Can be a number (0, 1, 10, 20), a string, or the entity name

version

Asciidoctorj version. If not specified a version will be used.

Options & Attributes

The following options may be set using the extension’s options property

  • header_footer - boolean

  • template_dirs - List<String>

  • template_engine - String

  • doctype - String

Any key/values set on attributes is sent as is to Asciidoctor. You may use this Map to specify a stylesheet for example. The following snippet shows a sample configuration defining attributes.

build.gradle
asciidoctorj { (1)
    options doctype: 'book', ruby: 'erubis'

    attributes 'source-highlighter': 'coderay',
                toc                 : '',
                idprefix            : '',
                idseparator         : '-'
}
1 This can be globally on the project extension or locally on the task’s extension.

Or in the Gradle Kotlin DSL:

build.gradle.kts
tasks {
  "asciidoctor"(AsciidoctorTask::class) { (1)
    options(mapOf("doctype" to "book", "ruby" to "erubis"))

    attributes(
      mapOf(
        "source-highlighter" to "coderay",
        "toc"                to "",
        "idprefix            to "",
        "idseparator"        to "-"
      )
    )
  }
}
1 This is an example of setting it on the task extension in Kotlin.

The following attributes are automatically set by the asciidoctorj extension:

  • project-name : matches $project.name

  • project-version: matches $project.version (if defined). Empty String value if undefined

  • project-group: matches $project.group (if defined). Empty String value if undefined

These attributes may be overridden by explicit user input.

You may need to include extra content into the head of the exported document. For example, you might want to include jQuery inside the <head> element of the HTML export. To do so, first create a docinfo file src/docs/asciidoc/docinfo.html containing the content to include, in this case the <script> tag to load jQuery.

src/docs/asciidoc/docinfo.html
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.js"></script>

Then, add the docinfo1 attribute to the attributes list in the previous example:

build.gradle
attributes docinfo1: ''

Refer to the Asciidoctor documentation to learn more about these options and attributes.

Note

Attribute values defined on the build file will win over values defined on the documents themselves. You can change this behavior by appending an @ at the end of the value when defined in the build file. Please refer to Attribute assignment precedence for more information.

Versions of components

The modules block currently supports four elements

build.gradle
asciidoctorj {
  modules {
    pdf { (1)
      version '1.2.3'
    }
    epub { (2)
      version '1.2.3'
    }
    diagram { (3)
      version '1.2.3'
    }
    groovyDsl { (4)
      version '1.2.3'
    }
  }
}
1 Asciidoctorj-EPUB version. If not specified asciidoctorj-epub will not be on the classpath. If you plan to use the EPUB backend and not using the EPUB plugin, then you need to set a version here.
2 Asciidoctorj-PDF version. If not specified asciidoctorj-pdf will not be on the classpath. If you plan to use the PDF backend and not using the PDF plugin, then you need to set a version here.
3 See AsciidoctorJ Diagram,
4 Version of Groovy Extensions DSL. If not specified and no extensions are specified, Groovy DSL will not be used. However, if any extensions are added without setting an explicit version and default version will be used.

When using the {kotlin-dsl} the same settings can be achieved use something similar getModules().getPdf().version("1.2.3"). In a similar fashion shortcuts can be achived in the {groovy-dsl}:

asciidoctorj {
  modules {
    pdf.version '1.2.3'
  }

  modules.pdf.version '1.2.3'
}

Applying the AsciidoctorJ Base plugin on its own

If none of the default conventions work for you, the base plugin can be applied on its own.

build.gradle
plugins {
    id 'org.asciidoctor.jvm.base' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.base") version "2.4.0"
}

The New AsciidoctorJ Plugin

build.gradle
plugins {
    id 'org.asciidoctor.jvm.convert' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.convert") version "2.4.0"
}

When applying org.asciidoctor.jvm.convert it creates a single task of type org.asciidoctor.gradle.jvm.AsciidoctorTask called asciidoctor.

By convention it sets the * sourceDir to src/docs/asciidoc * outputDir to ${buildDir}/docs/asciidoc

The AsciidoctorPdf Plugin

build.gradle
plugins {
    id 'org.asciidoctor.jvm.pdf' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.pdf") version "2.4.0"
}

When applying org.asciidoctor.jvm.pdf it creates a single task of type org.asciidoctor.gradle.jvm.AsciidoctorPdfTask an extension called pdfThemes

The default task is named asciidoctorPdf and is configured to:

  • Output source to "${buildDir}/docs/asciidocPdf"

  • Not to copy any resources to the output directory

  • It will set also a default version for asciidoctorj-pdf artifact. To override set asciidoctorj.pdfVersion or asciidoctorPdf.asciidoctorj.pdfVersion.

The AsciidoctorPdfTask task type has the following additional methods:

fontsDir

Directory for custom PDF fonts. Specify a directory in any form acceptable to project.file. Using this instead of directly setting the pdf-fontsdir attribute means that Gradle will be able to check out of date status dependent on the content of this folder.

theme

Name of the theme to use. Optional. When specifying a theme name it must match one registered via pdfThemes.

The pdfThemes extension allows for themes to be registered from local copies or downloaded from GitHub or GitLab and has been inspired by earlier work of Florian Wilhelm (@fwilhe).

Registering a local theme
pdfThemes {
    local 'basic', { (1)
        styleDir = file('themes/basic') (2)
        styleName = 'very-basic' (3)
    }
}
1 Local themes are registered using the local keyword and must be provided with a name
2 Directory for finding the theme. Specify a directory in any form acceptable to project.file.
3 Optional setting of the style name. If this is not set, the theme name provided previously will be used.
Registering a GitHub or GitLab theme
pdfThemes {
    github 'basic', { (1)
        organisation = 'fwilhe2' (2)
        repository = 'corporate-theme' (3)
        relativePath = 'resources/themes' (4)

        branch = 'master' (5)
        tag = '1.0.1' (6)
        commit = '4910271e8c3964b60e186a62f3e4339ed0752714' (7)
    }
}
1 Specify a GitHub repository which contains one or more themes. (For GitLab replace github with gitlab).
2 GitHub/GitLab Organisation (or user).
3 Name of repository containing the theme(s).
4 Relative path inside the repository to where the theme is located. If not speciified the theme is assumed to be in the root of the repository.
5 Specify the branch
6 Instead of a branch a tag can be used.
7 Instead of a branch or a tag, a very specific commit can be used.

If a repository contains more than one theme, then the block will need to be repeated for each theme and the name and relativePath adjusted accordingly. Gradle will however, only downlaod the repository once.

Kotlin users can use equivalent Action-based configurations.

The AsciidoctorEpub Plugin

build.gradle
plugins {
    id 'org.asciidoctor.jvm.epub' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.epub") version "2.4.0"
}

When applying org.asciidoctor.jvm.epub it creates a single task of type org.asciidoctor.gradle.jvm.epub.AsciidoctorEpubTask which is then configured to:

  • Output source to "${buildDir}/docs/asciidocEpub"

  • Not to copy any resources to the output directory

  • It will set also a default version for asciidoctorj-epub artifact. To override set asciidoctorj.epubVersion or asciidoctorPdf.asciidoctorj.epubVersion.

The AsciidoctorEpubTask task type has the following additional methods:

ebookFormats

The epub formats to generate. Specify one of more strings. Anything that is supported by the Asciidoctor EPUB backend can be used. Constants EPUB3 and KF8 are available for convenience. To override any previous set fomrats use setEbookFormats. To add to the existing list use eBookFormats.

KF8 formats cannot be generated under Windows at present.

The AsciidoctorJ Reveal.js Plugin

build.gradle
plugins {
    id 'org.asciidoctor.jvm.revealjs' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.revealjs") version "2.4.0"
}

When applying org.asciidoctor.jvm.revealjs support is added for creating slides using Asciidoctor & Reveal.js. The plugin configures:

  • Create a task called asciidoctorRevealJs.

  • Create an extension called revealjs which is used for configuring the version of Reveal.js as well as a template.

  • Create an extension called revealjsPlugins which will allow for downloading additional Reveal.js plugins.

  • Output source to "${buildDir}/docs/asciidocRevealJs"

  • Copy all resources to the output directory including Reveal.js templates.

  • Apply the org.asciidoctor.jvm.gems plugin as GEM support is required.

The AsciidoctorRevealJSTask task type has the following additional methods:

revealjsOptions

Configure special Reveal.js options. Can be configured via Closure or Action. See [RevealJSOptions] for more details.

templateDir

Location where the template directory will be located on disk before Asciidoctor processing starts.

theme

The Reveal.js theme to use. The theme must match one from the template.

The version of the Reveal.js GEM and the Reveal.js template is configured via the revealjs extension:

revealjs {
  version = '1.1.3' (1)

  templateGitHub {  (2)
    organisation = 'hakimel'
    repository = 'reveal.js'
    tag = '3.7.0'
  }
}
1 Reveal.js GEM version
2 Obtain the Reveal.js template from GitHub.

If not specified, sensible defaults are provided.

Reveal.js Options

Various options can be configured for Reveal.js. Although these can be set as attributes directly, it is far better to set them on the task as advantage can be taken of Gradle task caching and file resolving.

asciidoctorRevealJs {
  revealjsOptions { (1)
    controls = true
  }
}
1 Use revealjsOptions block for configuration with any of the below options.
autoslideInterval

Delay in milliseconds between automatically proceeding to the next slide. Disabled when set to 0 (the default). This value can still be overwritten on a per-slide basis by setting a data-autoslide attribute on a slide. Type is integer.

autoSlideStoppable

Stop auto-sliding after user input Type is boolean.

backgroundTransition

Transition style for full page slide backgrounds.. Can be a RevealJSOptions.Transition or string value.

controls

Display controls in the bottom right corner. Type is boolean.

customThemeLocation

A custom theme that is not in the template. Can be anything convertible to a file or URI.

hideAddressBarOnMobile

Hides the address bar on mobile devices. Type is boolean.

flagEmbedded

Flags if the presentation is running in an embedded mode ( contained within a limited portion of the screen ). Type is boolean.

fragments

Use fragments globally. Type is boolean.

highlightJsThemeLocation

Highlight.js theme location. Can be anything convertible to a file or URI.

keyboardShortcuts

Enable keyboard shortcuts for navigation. Type is boolean.

loop

Loop the presentation.. Type is boolean.

mouseWheel

Enable slide navigation via mouse wheel. Type is boolean.

overviewMode

Enable the slide overview mode. Type is boolean.

parallaxBackgroundImageLocation

Parallax background image. Can be anything convertible to a file or URI.

parallaxBackgroundSize

Parallax background size. Accepts any CSS syntax. Can be anything convertible to a string.

previewLinks

Opens links in an iframe preview overlay. Type is boolean.

processBar

Display a presentation progress bar. Type is boolean.

pushToHistory

Push each slide change to the browser history. Type is boolean.

righttoLeft

Change the presentation direction to be RTL. Type is boolean.

slideNumber

Display the slide number of the current slide. Type is boolean.

touchMode

Enables touch navigation on devices with touch input. Type is boolean.

transition

Slide transition mode. Can be a RevealJSOptions.Transition or string value.

transitionSpeed

Slide transition speed. Can be a RevealJSOptions.TransitionSpeed or string value.

verticalCenter

Vertical centering of slides. Type is boolean.

viewDistance

Number of slides away from the current that are visible. Type is integer.

Using AsciidoctorJ Diagram

The new plugins have built-in support for asciidoctorj-diagram. Simply add the following to the project or task extension and diagramming will be available. If it is not set the asciidoctorj-diagram JAR will nto be added to the classpath.

asciidoctorj {
    modules {
       diagram.version '1.5.4.1'
    }
}

With this enhancement, there is also no longer a need to add requires 'asciidoctor-diagram'.

If you using OpenJDK 9/10 on MacOS you might find an error such as below
Caused by: java.lang.UnsatisfiedLinkError: /path/to/openjdk10/lib/libfontmanager.dylib: dlopen(/path/to/openjdk10/lib/libfontmanager.dylib, 1): Library not loaded: /Users/jenkins/workspace/openjdk10_build_x86-64_macos/openjdk/installedfreetype/lib/libfreetype.6.dylib
  Referenced from: /path/to/openjdk10/lib/libfontmanager.dylib
  Reason: image not found

The solution is to install freetype via HomeBrew or MacPorts. You might also need to do something (ridiculous) such as

$ sudo mkdir -p /Users/jenkins/workspace/openjdk10_build_x86-64_macos/openjdk/installedfreetype
$ sudo ln -s /opt/local/lib /Users/jenkins/workspace/openjdk10_build_x86-64_macos/openjdk/installedfreetype/lib (1)
1 opt/local/lib is the location for MacPorts. Change it accordingly for HomeBrew.

Ruby GEM support

GEM support is simplified via the org.asciidoctor.jvm.gems plugin.

build.gradle
plugins {
    id 'org.asciidoctor.jvm.gems' version '2.4.0'
}

repositories {
    maven { url 'http://rubygems-proxy.torquebox.org/releases' } (1)
}

dependencies {
    asciidoctorGems 'rubygems:asciidoctor-revealjs:1.1.3' (2)
}

asciidoctorj {
    requires 'asciidoctor-revealjs' (3)
}
1 Always specify a GEM proxy.
2 Specify GEMs as per usual.
3 Add the GEM to the project-wide (or task-specific) list of requires.
build.gradle.kts
plugins {
    id("org.asciidoctor.jvm.gems") version "2.4.0"
}

Kindlegen plugin

build.gradle
plugins {
    id 'org.asciidoctor.kindlegen.base' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.kindlegen.base") version "2.4.0"
}

Producing KF* formats via the EPUB extension requires kindlegen to be installed. This plugin provides the capability of bootstrapping kindlegen on Windows, Mac & Linux without the user having to do anything.

There is a base plugin org.asciidoctor.kindlegen.base which just provides a kindlegen extension. In order to use it you will need to agree to the Amazon terms of usage. To confirm this you need to configure

kindlegen {
  agreeToTermsOfUse = true
}

If you do not, then the plugin will refuse to bootstrap kindlegen.

The base plugin is automatically applied by the EPUB plugin. If you only produce EPUB3 formats with the EPUB plugin you do not have to agree to the usage of kindlegen.

Adding Custom Extensions

Starting with version 1.5.0 you were able to write your own Asciidoctor extensions in Groovy, or any other JVM language for that matter. Now with the 2.0.0 you have even more flexibility in that extensions can be applied on a per task basis on globally. There are several options available to make it happen.

As External Library

This is the most versatile option, as it allows you to reuse the same extension in different projects. An external library is just like any other Java/Groovy project. You simply define a dependency using the asciidoctor configuration.

build.gradle
configurations {
    asciidoctorExt
}

dependencies {
    asciidoctorExt 'com.acme:asciidoctor-extensions:x.y.z'
}

asciidoctor {
    configurations 'asciidoctorExt'
}

As Project Dependency

The next option is to host the extension project in a multi-project build. This allows for a much quicker development cycle as you don’t have to publish the jar to a repository every time you make adjustments to the code. Take for example the following setup:

.
├── build.gradle
├── core
│   ├── build.gradle
│   └── src
│       ├── asciidoc
│       │   └── index.adoc
│       └── main
│           └── java
├── extension
│   ├── build.gradle
│   └── src
│       └── main
│           ├── groovy
│           │   └── org
│           │       └── asciidoctor
│           │           └── example
│           │               ├── ExampleExtensionRegistry.groovy
│           │               └── YellBlock.groovy
│           └── resources
│               └── META-INF
│                   └── services
│                       └── org.asciidoctor.extension.spi.ExtensionRegistry
└── settings.gradle

The extension project is a sibling for core. The build file for the latter looks like this:

build.gradle
plugins {
   id 'org.asciidoctor.jvm.convert' version '2.4.0'
}

repositories {
    jcenter()
}

configuration {
    asciidoctorExtensions
}

dependencies {
    asciidoctorExtensions project(':extension')
}

asciidoctor {
    configurations 'asciidoctorExtensions'
}

Alternatively you can add the project to the extension directly

build.gradle
plugins {
   id 'org.asciidoctor.jvm.convert' version '2.4.0'
}

asciidoctorj {
    docExtensions project(':extension')
}

In the less-common case where extension is not supplied via the default configuration, he latter shortcur will not work, and you will need to use the longer method described above.

As Inline Script

The next option is to define extensions directly in the build script. This approach is based on the project asciidoctorj-groovy-dsl that allows to define Asciidoctor extensions in Groovy. An extension is registered via the docExtensions element.

build.gradle
asciidoctorj {
    docExtensions {
        block(name: "BIG", contexts: [":paragraph"]) {
            parent, reader, attributes ->
            def upperLines = reader.readLines()
                .collect {it.toUpperCase()}
                .inject("") {a, b -> a + '\n' + b}

            createBlock(parent, "paragraph", [upperLines], attributes, [:])
        }
    }
}

http://github.com/asciidoctor/asciidoctorj-groovy-dsl contains a description of the DSL itself.

Groovy extensions can also be included as files.

build.gradle
asciidoctorj {
    docExtensions file('big.groovy')
}
big.groovy
block(name: "BIG", contexts: [":paragraph"]) {
    parent, reader, attributes ->
    def upperLines = reader.readLines()
        .collect {it.toUpperCase()}
        .inject("") {a, b -> a + '\n' + b}

    createBlock(parent, "paragraph", [upperLines], attributes, [:])
}

Upgrading From Older Versions of Asciidoctor

To help with migration the old plugin will print a number of messages to help with a conversion. The amount of text is controlled via --warning-mode in Gradle 4.5+. For Gradle 4.0-4.4 use --info to get the full list of recommendations. Use of --warning-mode=none (Gradle 4.5+) or --quiet (Gradle 4.0-4.4) will produce migration information.

Firstly replace plugin org.asciidoctor.convert with org.asciidoctor.jvm.convert.

If you used separateOutputDirs, yout need to change that to outputOptions.separateOutputDirs. If you only use one backend in the task you can delete this and it will default to false for single backends and true for multiple backends.

The base directory is now set to the directory of the root project. This may influence how your includes are processed. Either set baseDir to specific directory or or use the includedir which is automatically calculates to be the correct source directory.

Gradle injected a number of attributes into the build. Some of these names have been changed from 1.5/1.6. to indicate that they are injected:

Old name

New name

Substituable

Usage

projectdir

gradle-projectdir

No

The Gradle project directory which is running the Asciidoctor task.

rootdir

gradle-rootdir

No

The rootproject directory in a multi-project build.

project-name

gradle-project-name

Yes

The name of the current Gradle subproject. (Or the root project in case of a single project).

project-group

gradle-project-group

Yes

The project/artifact group if it is defined.

project-version

revnumber

Yes

The project version if it is defined.

-

gradle-relative-srcdir

No

The relative path from the parent of the current document that is being processed to the source document root. It is calcluated as moving from the current document towards the root. For instance src/docs/asciidoc/subdir/sample.adoc will set this attribute to .. if sourceDir == src/docs/asciidoc.

Substitutable attributes means that the build script author can change those attributes by setting them explicitly.

If you used external GEMs via the JRuby Gradle plugin, you should switch over to using org.asciidoctor.jvm.gems instead. You should also use the asciidoctorGems configuration rather than the gems configuration. Tasks should not depend on JRubyPrepare, but on AsciidoctorGemsPrepare instead.

Configurations

The asciidoctor configuration is no longer available. If you used that before to make artifacts available on the classpath you should use the configurations method on the task to add them. If you used it to manipulate versions of AsciidoctorJ and JRuby then you should rather use the explicit versions settings on asciidoctorj.

Multiple Asciidoctor tasks

If you have more than one Asciidoctor task, decide which options, attributes and requires should go in the asciidoctorj global project extension block and which should be customised within the tasks asciidoctor extension block.

Importantly, you probably did import org.asciidoctor.gradle.AsciidoctorTask. You will need to change that to import org.asciidoctor.gradle.jvm.AsciidoctorTask.

Extensions

Extensions on the Gradle classpath are no longer detected. You need to declare them explicitly. This includes any extensions created in buildSrc.

Asciidoctor Compatibility Plugin

In order to help people upgrade a compatibility plugin has been kept which mostly behaves in the same way as the AsciidoctorJ plugins in the 1.5.x series

build.gradle
plugins {
    id 'org.asciidoctor.convert' version '2.4.0'
}
build.gradle.kts
plugins {
    id("org.asciidoctor.convert") version "2.4.0"
}

The plugin adds a new task named asciidoctor. You can configure this task using the following configuration properties and methods.

Properties
logDocuments

a boolean specifying if documents being processed should be logged on console. Type: boolean. Default: false.

separateOutputDirs

specifies whether each backend should use a separate subfolder under outputDir. Default: true

Methods
attributes

a Map specifying various document attributes that can be sent to Asciidoctor Use attributes to append, Use setAttributes or attributes= to overwrite.

backends

the backends to use. Use backends to append. Use setBackends or backends=[] to overwrite Type: Set<String>, but any type can be converted to String can be used. Default: [html5].

gemPath

one or more gem installation directories (separated by the system path separator). Use gemPath to append. Use setGemPath or gemPath='path to overwrite. Use asGemPath to obtain a path string, separated by platform-specific separator. For backwards-compatibility, setGemPath and gePath='string' will accept a path string containing the platform-specific separator. Type: FileCollection, but any collection of objects convertible with project.files can be passed Default: empty

legacyAttributes

Insert legacy projectdir and rootdir attributes. This is a stop-gap and document authors should use gradle-rootdir gradle-projectdir` instead.

options

a Map specifying different options that can be sent to Asciidoctor. Use options to append, Use setOptions or options= to overwrite.

outputDir

where generated docs go. Use either outputDir path, setOutputDir path or outputDir=path Type: File, but any object convertible with project.file can be passed. Default: $buildDir/asciidoc.

resources

specify which additional files (image etc.) must be copied to output directory using a CopySpec.

requires

a set of Ruby modules to be included. Use requires to append. Use setRequires or requires='name' to overwrite. Type: Set<String>. Default: empty.

sourceDir

where the asciidoc sources are. Use either sourceDir path, setSourceDir path or sourceDir=path Type: File, but any object convertible with project.file can be passed. Default: src/docs/asciidoc.

sources

specify which Asciidoctor source files to include by using an Ant-style PatternSet.

Even though the DSL remains the same with this task, the internals have been changed to use the same JAVA_EXEC mechanism of the org.asciidoctor.jvm.convert plugins. The problems which the 1.5.x series suffered with classpaths anions disappearing should now be a thing of the past.

Appendix A: Tips & Tricks

Issues with plugins that modify project.version

Plugins such as Nebula Release and Reckon modify project.version with a non-serialisable object. This breaks the build.

The safest workaround is to set the revnumber attribute to a delayed evaluation of project.version in your build:

asciidoctorj {
    attributes revnumber : { project.version.toString() }
}

Pre-process and post-process

To make your own custom actions before or after asciidoctor processing, use doFirst and doLast. Check out chapters 14 and 17 in the Gradle docs to learn about the various actions you can perform.

build.gradle
asciidoctor.doFirst {
  // pre-process
}
asciidoctor.doLast {
  // post-process
}

As an example, here’s how to copy the generated index.html file to the root of the project. This is useful in Windows systems where asciidoctor can’t output directly to the root.

build.gradle
asciidoctor.doLast {
    copy {
        from 'build/docs/html5'
        into "$projectDir"
        include 'index.html'
    }
}

Using Pygments source highlighter

You need to have Python 2.x installed on a system or in a container for Pygments to work.
plugins {
  id 'org.asciidoctor.jvm.pdf' version '2.4.0'
  id 'org.asciidoctor.jvm.gems' version '2.4.0'
}

repositories {
    jcenter()
    maven { url 'http://rubygems-proxy.torquebox.org/releases' }
}

dependencies {
  asciidoctorGems 'rubygems:pygments:1.2.1'
}

asciidoctorPdf {
  dependsOn asciidoctorGemsPrepare
  sourceDir 'docs'

  asciidoctorj {
    requires 'pygments'
    attributes 'source-highlighter' : 'pygments'
  }
}

Appendix B: Known Issues

These are the main ones we know about:

  • EPUB3 + KF8 in one task. Both formats in one task is currently failing. The exact failure message depends on which order (KF8+EPUB3 or EPUB3+KF8) the conversion takes place in.

  • KF8 conversions fails under Windows. (Related to AsciidoctorJ #659 & JRuby #4943.

  • Does not work with JDK9 (but does with JDK10).

  • Not compatible with Gradle Kotlin DSL on Gradle 5.2.1 and 5.3. See KOTLIN-DSL-1353.

Appendix C: Development

The master branch represents the code for the latest 2.x release of these plugins. Development for for 2.x is against the development-2.0 branch. PRs are preferably taking against that branch. The 1.5.x & 1.6.x series of the plugin is now in maintenance only mode. PRs for these should be raised against the maintenance-1.5 and maintenance-1.6branch.