# Precompiled Script Plugin in buildSrc Sample

version 6.5-milestone-1

- Groovy DSL

- Kotlin DSL

| 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 a multi module project produces multiple Java libraries that use shared internal modules as an implementation detail. We want to apply a set of code quality checking rules to all the submodules and configure some aspects specific to library artifacts.

This is achieved by layering two separate plugins in project’s `buildSrc` module:

- `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 and checks for mandatory content in a README.

All plugins created in this sample contain functional tests that use TestKit to verify their behavior.

This sample does not have any project source code and only lays out a hypothetical project structure where two library modules depend on a shared internal module.

The internal module uses `com.example.java-convention` plugin:

internal-module/build.gradle

    plugins {
        id 'com.example.java-convention'
    }

    dependencies {
        // internal module dependencies
    }

internal-module/build.gradle.kts

    plugins {
        id("com.example.java-convention")
    }

    dependencies {
        // internal module dependencies
    }

The two libraries use `com.example.library` plugin that in turn uses `com.example.java-convention`.

library-a/build.gradle

    plugins {
        id 'com.example.library'
    }

    dependencies {
        implementation project(':internal-module')
    }

library-b/build.gradle

    plugins {
        id 'com.example.library'
    }

    dependencies {
        implementation project(':internal-module')
    }

library-a/build.gradle.kts

    plugins {
        id("com.example.library")
    }

    dependencies {
        implementation(project(":internal-module"))
    }

library-b/build.gradle.kts

    plugins {
        id("com.example.library")
    }

    dependencies {
        implementation(project(":internal-module"))
    }

## 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:

buildSrc/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'
    }

buildSrc/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.13")
    }

- 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:

buildSrc/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'
    }

buildSrc/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` plugin applies the `com.example.java-convention` plugin:

buildSrc/src/main/groovy/com.example.library.gradle

    plugins {
        id 'java-library'
        id 'maven-publish'
        id 'com.example.java-convention'
    }

buildSrc/src/main/kotlin/com.example.library.gradle.kts

    plugins {
        `java-library`
        `maven-publish`
        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.library` plugin uses a custom task class from `buildSrc/src/main/java` to configure library README checks:

buildSrc/src/main/groovy/com.example.library.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 = ['^## API$', '^## Changelog$']
    }

buildSrc/src/main/kotlin/com.example.library.gradle.kts

    val readmeCheck by tasks.registering(com.example.ReadmeVerificationTask::class) {
        readme.set(layout.projectDirectory.file("README.md"))
        readmePatterns.set(listOf("^## API$", "^## Changelog$"))
    }

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