Developing a Custom Gradle Plugin
Join the DZone community and get the full member experience.
Join For FreeGradle allows you to implement your own plugins in any languages like Java, Groovy, or Kotlin, so you can reuse your build logic, and share it with others, which can be used across many different projects and builds.
In our example, we are going to use Kotlin as the implementation language for a standalone plugin project and Kotlin in the build script plugin examples. In the following example, we will create a plugin with two tasks: task with command-line option and task with extension.
Plugin Setup
Setup build.gradle.kts
Let's create a plugin as a standalone project so that we can publish it and share it with others, which we are going to package and publish a plugin is to use the Java Gradle Plugin Development Plugin. It's a is simply a Java project that produces a JAR containing the plugin classes, it's will automatically apply the Java Plugin, add the gradleApi()
dependency to the implementation configuration, generate the required plugin descriptors in the resulting JAR file, and configure the Plugin Marker Artifact to be used when publishing.
Here is a simple build script for the project build.gradle.kts
:
xxxxxxxxxx
plugins {
`kotlin-dsl`
`java-gradle-plugin`
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
compileOnly(gradleApi())
testImplementation("junit:junit:4.13")
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
gradlePlugin {
(plugins) {
register("my_plugin") {
id = "com.example.my_plugin"
implementationClass = "com.example.MyPlugin"
}
}
}
Plugin
To create a Gradle plugin, you need to write a class that implements the Plugin interface. When the plugin is applied to a project, Gradle creates an instance of the plugin class and calls the instance’s Plugin.apply() method. Handling user input from the script we will do through an extension and command option.
xxxxxxxxxx
package com.example
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create("greeting", MyExtension::class.java)
val task = project.tasks.create("hello", MyTask::class.java)
task.group = "welcome"
}
}
Create src/resource/META-INF/plugin.properties
file and set reference to your plugin class:
xxxxxxxxxx
implementation-class=com.example.MyPlugin
Extension
For using extension the Gradle Project has an associated ExtensionContainer object that contains all the settings and properties for the plugins that have been applied to the project. You can provide a configuration for your plugin by adding an extension object to this container. An extension object is simply an object with Java Bean properties that represent the configuration.
xxxxxxxxxx
package com.example
open class MyExtension {
var message: String? = null
}
Task
Task classes from the Gradle API can be used in specific circumstances, extending DefaultTask
is the most common scenario. Annotate the default task action as @TaskAction
.
xxxxxxxxxx
package com.example
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
open class MyTask : DefaultTask() {
@Input
@Optional
@Option(description = "Message from command line", option = "message")
var message: String? = null
@TaskAction
fun run() {
val extension = project.extensions.findByName("greeting") as MyExtension
extension.message?.let {
println("Hello from extension ${extension.message}")
}
message?.let {
println("Hello from command line $message")
}
}
}
Test
You can use the ProjectBuilder class to create Project instances to use when you test your plugin implementation.
xxxxxxxxxx
package com.example
import org.gradle.api.Project
import org.gradle.testfixtures.ProjectBuilder
import org.junit.Assert.*
import org.junit.Test
class MyPluginTest {
@Test
fun test() {
val pluginProject: Project = ProjectBuilder.builder().build()
pluginProject.pluginManager.apply("com.example.my_plugin")
val task = pluginProject.tasks.findByName("hello")
assertNotNull(task)
assertTrue(task is MyTask)
assertEquals("welcome", task!!.group)
}
}
Plugin publishing
Register in Gradle Plugin Portal. See more: publishing tutorial
Add the Plugin Publishing Plugin to the project
Add plugin from plugin-publishing (use the latest version):
xxxxxxxxxx
plugins {
...
id("com.gradle.plugin-publish") version "0.12.0"
}
Configure the Plugin Publishing Plugin
Create a pluginBundle
block in build.gradle.kts
and specify global information regarding your plugin. This helps other people browsing the portal find more information about your plugin and learn how to contribute to its development.
xxxxxxxxxx
pluginBundle {
website = "https://your_project_web_site"
vcsUrl = "https://your_project_source"
tags = listOf("hello", "greeting")
}
Publish your plugin
Run validate plugin command:
./gradlew validatePlugins
Run publishing, if you're not authorized use login
command:
./gradlew publishPlugins
Usage
Apply your plugin to project:
xxxxxxxxxx
plugins {
...
id "com.example.my_plugin" version "1.0.0"
}
Output of gradle hello --message = "My Gradle Plugin"
xxxxxxxxxx
> Task :hello
Hello from command line My Gradle plugin
Add extension in your build.gradle:
xxxxxxxxxx
greeting {
message = "My Gradle plugin"
}
Output of gradle hello:
xxxxxxxxxx
> Task :hello
Hello from extension My Gradle plugin
Opinions expressed by DZone contributors are their own.
Comments