Chapter 20. Gradle Plugins

Gradle at its core intentionally provides very little for real world automation. All of the useful features, like the ability to compile Java code, are added by plugins. Plugins add new tasks (e.g. JavaCompile), domain objects (e.g. SourceSet), conventions (e.g. Java source is located at src/main/java) as well as extending core objects and objects from other plugins.

In this chapter we will discuss how to use plugins and the terminology and concepts surrounding plugins.

20.1. What plugins do

Applying a plugin to a project allows the plugin to extend the project's capabilities. It can do things such as:

  • Extend the Gradle model (e.g. add new DSL elements that can be configured)
  • Configure the project according to conventions (e.g. add new tasks or configure sensible defaults)
  • Apply specific configuration (e.g. add organizational repositories or enforce standards)

By applying plugins, rather than adding logic to the project build script, we can reap a number of benefits. Applying plugins:

  • Promotes reuse and reduces the overhead of maintaining similar logic across multiple projects
  • Allows a higher degree of modularization, enhancing comprehensibility and organization
  • Encapsulates imperative logic and allows build scripts to be as declarative as possible

20.2. Types of plugins

There are two general types of plugins in Gradle, script plugins and binary plugins. Script plugins are additional build scripts that further configure the build and usually implement a declarative approach to manipulating the build. They are typically used within a build although they can be externalized and accessed from a remote location. Binary plugins are classes that implement the Plugin interface and adopt a programmatic approach to manipulating the build. Binary plugins can reside within a build script, within the project hierarchy or externally in a plugin jar.

20.3. Applying plugins

Plugins are said to be applied, which is done via the Project.apply() method. The application of plugins is idempotent. That is, the same plugin can be applied multiple times. If the plugin has previously been applied, any further applications are safe and will have no effect.

20.3.1. Script plugins

Example 20.1. Applying a script plugin

build.gradle

apply from: 'other.gradle'

Script plugins can be applied from a script on the local filesystem or at a remote location. Filesystem locations are relative to the project directory, while remote script locations are specified with an HTTP URL. Multiple script plugins (of either form) can be applied to a given build.

20.3.2. Binary plugins

Example 20.2. Applying a binary plugin

build.gradle

apply plugin: 'java'

Plugins can be applied using a plugin id. The plugin id serves as a unique identifier for a given plugin. Core plugins register a short name that can be used as the plugin id. In the above case, we are using the short name ‘java’ to apply the JavaPlugin. Community plugins, on the other hand, use a fully qualified form for the plugin id (e.g. com.github.foo.bar), although some legacy plugins may still utilize a short, unqualified form.

Rather than using a plugin id, plugins can also be applied by simply specifying the class of the plugin:

Example 20.3. Applying a binary plugin by type

build.gradle

apply plugin: JavaPlugin

The JavaPlugin symbol in the above sample refers to the the JavaPlugin. This class does not strictly need to be imported as the org.gradle.api.plugins package is automatically imported in all build scripts (see Appendix E, Existing IDE Support and how to cope without it). Furthermore, it is not necessary to append .class to identify a class literal in Groovy as it is in Java.

20.3.2.1. Locations of binary plugins

A plugin is simply any class that implements the Plugin interface. Gradle provides the core plugins as part of its distribution so simply applying the plugin as above is all you need to do. However, non-core binary plugins need to be available to the build classpath before they can be applied. This can be achieved in a number of ways, including:

For more on defining your own plugins, see Chapter 58, Writing Custom Plugins.

20.4. Applying plugins with the buildscript block

Binary plugins that have been published as external jar files can be added to a project by adding the plugin to the build script classpath and then applying the plugin. External jars can be added to the build script classpath using the buildscript {} block as described in Section 59.6, “External dependencies for the build script”.

Example 20.4. Applying a plugin with the buildscript block

build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
    }
}

apply plugin: "com.jfrog.bintray"

20.5. Applying plugins with the plugins DSL

The plugins DSL is currently incubating. Please be aware that the DSL and other configuration may change in later Gradle versions.

The new plugins DSL provides a more succinct and convenient way to declare plugin dependencies. It works with the new Gradle plugin portal to provide easy access to both core and community plugins. The plugins script block configures an instance of PluginDependenciesSpec.

To apply a core plugin, the short name can be used:

Example 20.5. Applying a core plugin

build.gradle

plugins {
    id 'java'
}

To apply a community plugin from the portal, the fully qualified plugin id must be used:

Example 20.6. Applying a community plugin

build.gradle

plugins {
    id "com.jfrog.bintray" version "0.4.1"
}

No further configuration is necessary. Specifically, there is no need to configure the buildscript classpath. Gradle will resolve the plugin in the plugin portal, locate it, and make it available to the build.

See PluginDependenciesSpec for more information on using the Plugin DSL.

20.5.1. Limitations of the plugins DSL

The new way to add plugins to a project is much more than a more convenient syntax. The new DSL is processed very differently to the old one. The new mechanism allows Gradle to determine the plugins in use very early and very quickly. This allows Gradle to do smart things such as:

  • Optimize the loading and reuse of plugin classes.
  • Allow different plugins to use different versions of dependencies.
  • Provide editors detailed information about the potential properties and values in the buildscript for editing assistance.

This requires that plugins be specified in a way that Gradle can easily and quickly extract, before executing the rest of the build script. It also requires that the definition of plugins to use be somewhat static.

There are some key differences between the new plugin mechanism and the “traditional” apply() method mechanism. There are also some constraints, some of which are temporary limitations while the mechanism is still being developed and some are inherent to the new approach.

20.5.1.1. Constrained Syntax

The new plugins {} block does not support arbitrary Groovy code. It is constrained, in order to be idempotent (produce the same result every time) and side effect free (safe for Gradle to execute at any time).

The form is:

plugins {
    id «plugin id» version «plugin version»
}
                

Where «plugin version» and «plugin id» must be constant, literal, strings. No other statements are allowed; their presence will cause a compilation error.

The plugins {} block must also be a top level statement in the buildscript. It cannot be nested inside another construct (e.g. an if-statement or for-loop).

20.5.1.2. Can only be used in build scripts

The plugins {} block can currently only be used in a project's build script. It cannot be used in script plugins, the settings.gradle file or init scripts.

Future versions of Gradle will remove this restriction.

20.5.1.3. Cannot be used in conjunction with subprojects {}, allprojects {}, etc

It is not possible to use the familiar pattern of applying a plugin to multiple projects at once using subprojects {}, etc at the moment. There is currently no mechanism for applying a plugin to multiple projects at once. At the moment, each project that requires a plugin must declare so in the plugins {} block in its buildscript.

Future versions of Gradle will remove this restriction.

If the restrictions of the new syntax are prohibitive, the recommended approach is to apply plugins using the buildscript {} block.

20.6. Finding community plugins

Gradle has a vibrant community of plugin developers who contribute plugins for a wide variety of capabilities. The Gradle plugin portal provides an interface for searching and exploring community plugins.

20.7. More on plugins

This chapter aims to serve as an introduction to plugins and Gradle and the role they play. For more information on the inner workings of plugins, see Chapter 58, Writing Custom Plugins.