Writing custom Gradle plugins, part 1
Gradle is a plugin-oriented build system. Each plugin provides a set of tasks and conventions, and the code required to run the build process. Although many plugins are already provided in the core distribution (java, groovy, ant, maven, jetty…), the need may arise to develop your own. As this feature is currently not documented, we will write a series of blog posts demonstrating, step by step, how to create a plugin participating in the build lifecycle.
First steps
Of course, our plugin itself shall be built with Gradle.
Ours will use a Groovy layout, although the standard Java structure is also supported – this may be the subject of a future blog post.
Create the following directory layout :
firstplugin +-- build.gradle +-- libs | +--- gradle-0.6.jar | +--- groovy-all-1.5.6.jar | +--- slf4j-api-1.5.3.jar +-- src/main/groovy/com/zenika/plugins/FirstPlugin.java
Here is the related build script :
-
usePlugin(‘groovy’)
-
version=1.0
-
repositories {
-
flatDir(dirs: file(‘lib’))
-
}
-
dependencies {
-
groovy “:groovy-all:1.5.6”
-
groovy “:gradle:0.6”
-
groovy “:slf4j-api:1.5.3”
-
}
For now, the plugin consists of a single class “FirstPlugin.java” :
-
package com.zenika.gradle.plugins;
-
import org.gradle.api.Plugin;
-
import org.gradle.api.Project;
-
import org.gradle.api.internal.project.PluginRegistry;
-
import java.util.Map;
-
public class FirstPlugin implements Plugin {
-
public void apply(Project project, PluginRegistry pluginRegistry, final Map<String, ?> customValues) {
-
System.out.println(“Hello World!”);
-
}
-
}
Compiling and packaging it is as easy as :
-
gradle clean libs
Using the plugin
To use our brand new plugin, it must be first registered in Gradle through a “settings.gradle” descriptor :
-
flatDir(dirs:“C:/dev/gradle/firstplugin/build/libs”)
-
dependencies(“:firstplugin:1.0”)
Please note that, for the sake of simplicity, we used a physical path on the local hard drive. In an enterprise environment, the plugin would rather be deployed on a remote repository like Nexus.
Now, let’s import the plugin in a build script :
-
usePlugin(com.zenika.gradle.plugins.FirstPlugin)
-
task test <<{
-
println “Testing plugin”
-
}
The “test” task doesn’t do much, but is required to allow our plugin to be loaded and executed, as it doesn’t define custom Gradle tasks on its own.
Let’s see what happens when the script gets executed :
-
gradle test
The result should be :
Hello World! :test Testing plugin
A side note on plugin descriptors
Requiring a “settings.gradle” descriptor file seems a bit laborious for a simple user-defined plugin. The forthcoming versions of Gradle will take it into account and simplify the process.
On the other hand, if your plugin gets packaged in the core distribution, the plugin descriptor is not required any more.
you can even declare a custom shortcut notation by editing the “plugin.properties” file :
-
java=org.gradle.api.plugins.JavaPlugin
-
groovy=org.gradle.api.plugins.GroovyPlugin
-
war=org.gradle.api.plugins.WarPlugin
-
osgi=org.gradle.api.plugins.osgi.OsgiPlugin
-
jetty=org.gradle.api.plugins.jetty.JettyPlugin
-
maven=org.gradle.api.plugins.MavenPlugin
-
project–reports=org.gradle.api.plugins.ProjectReportsPlugin
-
ant=org.gradle.api.plugins.ant.AntPlugin
-
firstplugin=com.zenika.gradle.plugins.FirstPlugin
and use it like any other core plugin :
-
usePlugin(‘firstplugin’)
Conclusion
In this article, we have seen how to develop a simple custom Gradle plugin.
In the next installments of this series, we will show how to pass properties to our plugin, how to write custom tasks, and how to integrate them in the build lifecycle.
I believe the Gradle 0.7 API for plugins changes dramatically compared to 0.6. When 0.7 gets release, you may want to update this piece.