We recommend having a good understanding of the Gradle plugin development process explained in the core documentation. This chapter focuses on plugin development enhancement provided by dev.gradleplugins.* plugins and maintained by the Nokee team. It bridges a fundamental gap in the plugin development experience offered by the Gradle team. The plugins offer more modelling to ensure a more enjoyable development experience.

Introduction

We offer two Gradle plugin development plugins: dev.gradleplugins.java-gradle-plugin and dev.gradleplugins.groovy-gradle-plugin. The plugins support Gradle plugin development for the Java and Groovy languages, respectively. [1]

When we only require compatibility functionality of plugin development workflow, we recommend applying the dev.gradleplugins.gradle-plugin-development in the settings script. It offers global conveniences to all projects, such as creating versioned Gradle API dependencies with source access.

Finally, we also offer two test suite plugins: dev.gradleplugins.gradle-plugin-unit-test and dev.gradleplugins.gradle-plugins-functional-test. The plugins support unit and functional testing, respectively, for the Gradle plugin under development.

Minimum Gradle version

The plugins extend the familiar gradlePlugin extension by adding the nested compatibility extension. This new extension model the minimum Gradle version supported by the plugins under development. By default, it uses the current running Gradle version. However, you can set it to any globally available Gradle distribution after and including 2.14.

Example 1. Configuring minimum supported Gradle
build.gradle
gradlePlugin {
	compatibility {
		minimumGradleVersion = '4.9'
	}
}
build.gradle.kts
gradlePlugin {
	compatibility {
		minimumGradleVersion.set("4.9")
	}
}

The plugin uses this new information to automatically configure the Java source and target compatibility to the minimum supported Java version for the target Gradle. For example, setting a minimum Gradle version of 5.0 or newer, the plugin will configure the Java compatibilities to Java 8. Rest assured, the plugins honours any override to the Java compatibilities.

When developing a Gradle plugin implemented in Groovy using dev.gradleplugins.groovy-gradle-plugin, the plugin adds a dependency to groovy-all based on the minimum Gradle version to the compileOnly configuration. For example, by setting the minimum Gradle version to 6.2, the Groovy runtime will be set to 2.5.8.

Gradle runtime compatibility information

All the Gradle runtime compatibility knowledge is accessible via the GradleRuntimeCompatibility class. Developers can query the following information for any previously released Gradle distribution:

  • Minimum Java version supported by a specific Gradle distribution, and;

  • Groovy, as well as Kotlin, if available, version packaged in a specific Gradle distribution.

This information is particularly useful when developing a library targeting the Gradle distribution. For each of the JVM languages, we need to align the runtime to ensure maximum compatibility.

We extract the compatibility information for each version manually. We welcome any pull request that would automate this information gathering and/or include newer/older runtime information.

Redistributed Gradle API artifacts

The redistributed Gradle API serves the purpose of targeting a different Gradle version than the currently running Gradle. We host every redistributed Gradle API artifacts under the dev.gradleplugins:gradle-api coordinate. Each artifact includes a source JAR for improved IDE experience.

A developer can depend on dev.gradleplugins:gradle-api:4.9 to target Gradle API 4.9 while running its build using a newer (or older) Gradle distribution. The dev.gradleplugins.gradle-plugin-development settings plugin adds the gradleApi(version) extension method to the DependencyHandler instance of each project:

Example 2. Adding specific Gradle API dependency
build.gradle
dependencies {
   compileOnly gradleApi('4.9')
}
build.gradle.kts
dependencies {
   compileOnly(gradleApi("4.9"))
}
Always declare Gradle API dependency as compile only dependencies. If not, when executing the plugin inside Gradle, it will unnecessarily pull a complete copy of the Gradle classes. You should only every declare a runtime dependency on the Gradle API if you need to execute against Gradle runtime, such as using ProjectBuilder for unit testing. See the unit testing section to learn more.
We only redistribute the Gradle API artifact for Gradle 2.14 and newer. If you need access to older Gradle API artifacts, please open an issue on the GitHub project.

Gradle plugin testing

We offer two plugins for testing Gradle plugins: dev.gradleplugins.gradle-plugin-unit-test and dev.gradleplugin.gradle-plugin-functional-test. Both plugins have similar functionalities and differ in their testing goal.

We can select the testing framework for each test suites by adding a dependency. We recommend using the dependencies script block of each test suites. The test suite dependency block offers convenient methods to add common dependencies quickly. For example, we can use spockFramework() method to create a dependency on the Spock Framework. To specify a specific version for the Spock dependency, we can use spockFramework(version) method. By selecting the Spock Framework, the plugin automatically apply the groovy-base plugin to enable Groovy compilation on the project.

Unit testing (e.g. dev.gradleplugins.gradle-plugin-unit-test)

Unit tests for Gradle plugins focus on individual classes. It validates the configurations of the plugin. We usually use the ProjectBuilder for this validation. The unit test suite will automatically add an implementation dependency to the Gradle API. The test suite is configurable via the test extension on the project. We can execute the test suite via the Test task named test.

Functional testing (e.g. dev.gradleplugins.gradle-plugin-functional-test)

Functional tests for Gradle plugins focus on execution behaviours. It validates how the tasks behave during execution, among other runtime checks. We usually use the Gradle TestKit for this validation. The test suite is configurable via the functionalTest extension on the project. We can execute the test suite via the Test task named functionalTest.

Testing strategies

We configure the testing coverage of Gradle plugins regarding Gradle distribution through the testing strategies. The test suite plugins configure distinct Test tasks for each testing coverage. The plugin passes the selected Gradle distribution information to test against via the dev.gradleplugins.defaultGradleVersion system property. The value is a string representing a Gradle distribution version, i.e. 6.2.1.

There are three strategies available via the strategies factory method in each test suite extension:

At runtime, it’s up to the testing fixtures to honour the selected Gradle distribution under test as declared via the dev.gradleplugins.defaultGradleVersion system property. The Nokee team maintains testing strategies-aware Gradle fixtures, which automatically honour the distribution under test system property. We can add a dependency on the Gradle fixtures using gradleFixtures() method from inside the test suite dependencies script block. Other test fixtures, such as the plain Gradle TestKit, requires manual configurations of the distribution under test.

In the absence of testing strategies, the dev.gradleplugins.defaultGradleVersion system property is unset, thus defaulting to the test fixtures default distribution under test.

The Test task names will include a suffix differentiating each strategy when we configure multiple testing strategies. It allows quick and easy execution, even from the IDE:

Testing strategies task naming inside IntelliJ.

Gradle test fixtures

The Gradle fixtures maintained by the Nokee team is a set of commonly needed APIs for testing Gradle plugins. It supports multiple executer types (i.e. Gradle wrapper, TestKit Gradle runner) and provides better assertion for Gradle results such as asserting executed and skipped tasks as well as asserting failures. It provides better assertions for common artifacts produced by Gradle, such as files, archives, and published artifacts in Maven repositories. It includes source elements for composing samples to use during testing. It also provides fixtures for asserting native binaries produced by Gradle.

The fixtures are in beta and may not be forward binary compatible.

What’s next?

You should now have a grasp on the improvement offered by the dev.gradleplugins.* plugins. Head over the Gradle plugin development samples to see a demonstration of the plugins for common scenarios. You can learn more on each specific Gradle plugin development plugins in the plugin reference chapters.

Help improve this chapter

Have feedback or a question? Found a typo? Is something unclear? Help is just a GitHub issue away. Please open an issue or create a pull request, and we’ll get back to you.


1. The kotlin-dsl plugin behave differently, which prevents from adding supporting for Gradle plugins implemented in Kotlin.