You can open this sample inside an IDE using the IntelliJ native importer or Eclipse Buildship.

This sample shows how precompiled script plugins can be used to compose build logic using built-in Gradle plugins, external Gradle plugins and other utility classes.

Use case

As an example, let’s say an organization produces two types of Java software - services and libraries. We want to apply a set of code quality checking rules to both types of projects and configure some aspects specific to each type.

This is achieved by layering three separate plugins:

  • com.example.java-convention - configures conventions that are generic for any Java project in the organization.

  • com.example.library - adds publishing configuration to publish to the organization’s repository.

  • com.example.service - adds integration tests and checks for mandatory content in a README.

We’ve put the plugins in the plugins directory in the sample. All plugins created in this sample contain functional tests that use TestKit to verify their behavior.

This root of this sample contains a consumer project that demonstrates how the plugins can be consumed using a composite build:

settings.gradle
rootProject.name = 'consumer-service'

includeBuild('plugin')
build.gradle
plugins {
    id 'com.example.service' version '1.0'
}
settings.gradle.kts
rootProject.name = "consumer-service"

includeBuild("plugin")
build.gradle.kts
plugins {
    id("com.example.service") version "1.0"
}

Things to note

Applying an external plugin in precompiled script plugin

The com.example.java-convention plugin uses SpotBugs plugin to perform static code analysis.

SpotBugs is an external plugin - external plugins need to be added as implementation dependencies before they can be applied in a precompiled script plugin:

plugin/build.gradle
repositories {
    gradlePluginPortal() // so that external plugins can be resolved in dependencies section
}

dependencies {
    implementation 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.0.5'
    testImplementation 'org.spockframework:spock-core:1.3-groovy-2.5'
}
plugin/build.gradle.kts
repositories {
    gradlePluginPortal() // so that external plugins can be resolved in dependencies section
}

dependencies {
    implementation("gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.0.5")
    testImplementation("junit:junit:4.12")
}
  • The dependency artifact coordinates (GAV) for a plugin can be different from the plugin id.

  • The Gradle Plugin Portal (gradlePluginPortal()) is added as a repository for plugin dependencies.

  • The plugin version is determined from the dependency version. Precompiled script plugins cannot supply a different version for now.

Once the dependency is added, the external plugin can be applied in precompiled script plugin by id:

plugin/src/main/groovy/com.example.java-convention.gradle
plugins {
    id 'java'
    id 'checkstyle'

    // NOTE: external plugin version is specified in implementation dependency artifact of the project's build file
    id 'com.github.spotbugs'
}
plugin/src/main/kotlin/com.example.java-convention.gradle.kts
plugins {
    java
    checkstyle

    // NOTE: external plugin version is specified in implementation dependency artifact of the project's build file
    id("com.github.spotbugs")
}

Applying other precompiled script plugins

Precompiled script plugins can apply other precompiled script plugins.

The com.example.library and com.example.service plugins both apply the com.example.java-convention plugin:

plugin/src/main/groovy/com.example.library.gradle
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'com.example.java-convention'
}
plugin/src/main/groovy/com.example.service.gradle
plugins {
    id 'com.example.java-convention'
}
plugin/src/main/kotlin/com.example.library.gradle.kts
plugins {
    `java-library`
    `maven-publish`
    id("com.example.java-convention")
}
plugin/src/main/kotlin/com.example.service.gradle.kts
plugins {
    id("com.example.java-convention")
}

Using classes from the main source set

Precompiled script plugins can use classes defined in the main source set of the plugins project.

In this sample, com.example.service plugin uses a custom task class from src/main/java to configure service README checks:

plugin/src/main/groovy/com.example.service.gradle
def readmeCheck = tasks.register('readmeCheck', com.example.ReadmeVerificationTask) {
    // Expect the README in the project directory
    readme = layout.projectDirectory.file("README.md")
    // README must contain a Service API header
    readmePatterns = ['^## Service API$']
}
plugin/src/main/kotlin/com.example.service.gradle.kts
val readmeCheck by tasks.registering(com.example.ReadmeVerificationTask::class) {
    readme.set(layout.projectDirectory.file("README.md"))
    readmePatterns.set(listOf("^## Service API$"))
}

For more details on authoring custom Gradle plugins, consult the user manual.