Making use of a third Birthday party Gradle Plugin as a Composite Plugin

This submit displays you tips on how to wrap a third birthday celebration Gradle plugin to your personal plugin, as a way to interactive with it programmatically. We’ll use Gradle composite builds to permit us to construct unexpectedly, lowering the construct, take a look at, unlock cycle.

Ever used a gradle plugin and sought after to make some tweaks to it, however don’t need the trouble of forking it, or deploying any other model to rely on? The usage of Gradle composite builds you’ll be able to create a Gradle Plugin that your construct can rely on. Then inside of that plugin, have it follow the 3rd birthday celebration plugin you need to make use of / adjust.

Notice: A third birthday celebration plugin way one evolved one by one out of your repository. It doesn’t essentially imply one written through folks. Instance’s of such plugins might be ktlint, android gradle plugin, affected module detector, anything else you’ve written your self or through your crew/corporate that sits in a separate Gradle root.

What’s a composite construct?

A composite construct is solely a construct that comes with different builds. In some ways a composite construct is very similar to a Gradle multi-project construct, except for that as a substitute of together with unmarried initiatives, entire builds are integrated.

Composite builds will let you:
– mix builds which might be generally evolved independently, as an example when checking out a trojan horse repair in a library that your software makes use of

– decompose a big multi-project construct into smaller, extra remoted chunks that may be labored in independently or in combination as wanted

For this case we’re going to use the Affected Module Detector (AMD) Gradle plugin from Dropbox. We will be able to create a Gradle plugin of our personal, come with it as a composite construct after which have that plugin follow the AMD plugin.

The result will likely be that our multi-module task is determined by the AMD plugin and we can run AMD duties, while additionally with the ability to increase the AMD plugin behaviour then again we adore as a result of its wrapped in our personal plugin.

All code for this submit is to be had at the repo right here. One thing we aren’t going to hide is tips on how to follow the AMD plugin in a standard gradle method, then again this is coated within the repo, and is to be had in this department. If you wish to skip instantly to the composite resolution, then this is to be had in this department.

Very first thing when short of to create a composite construct is developing the folder and Gradle construction. Our task is a elementary new Android task from the Android Studio IDE clean template. It has an app module and we’ve got additionally added an Android library module (mylibrary) in order that it’s multi-module. Supplying you with a folder construction like so:

/ 
 construct.gradle
 settings.gradle
 app/
    src/
    construct.gradle
 mylibrary/
    src/
    construct.gradle

We’re going to have our app rely on a plugin we create as a composite plugin. To create a composite plugin, you get started with a folder containing a construct.gradle a settings.gradle and the opposite standard Gradle recordsdata. (You’ll be able to use the gradle init command to create those, or reproduction them from a prior task.) In addition to the Gradle root folder recordsdata simply mentioned, we upload a sub-project referred to as ‘plugin’ and this additionally has a construct.gradle. Supplying you with an up to date folder construction like so:

/ 
 amd-plugin/
    gradle/
    construct.gradle
    gradlew
    settings.gradle
    plugin/
      construct.gradle
      src/
 app/
    src/ 
    construct.gradle
 mylibrary/
    src/
    construct.gradle
 construct.gradle
 settings.gradle

Reminder, you’ll be able to see this folder construction setup, right here on GitHub.

Filling out /amd-plugin/settings.gradle seems like this:

pluginManagement { // Claim the place we wish to to find plugin dependencies
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement { // Claim the place we wish to to find code dependencies
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.identify = "blundell-amd-plugin" // Title this task

come with(":plugin") // Make sure our module (task) is used

Filling out /amd-plugin/construct.gradle seems like this:

plugins {
    // We wish to use Kotlin
    identity("org.jetbrains.kotlin.jvm") model "1.7.21" follow false
    // We would like in an effort to post the plugin
    identity("com.gradle.plugin-publish") model "1.1.0" follow false
}

Filling out /amd-plugin/plugin/construct.gradle seems like this:

plugins {
    identity("java-gradle-plugin")
    identity("org.jetbrains.kotlin.jvm")
    identity("com.gradle.plugin-publish")
}

dependencies {
    testImplementation("junit:junit:4.13.2")
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

The ones 3 recordsdata (settings.gradle, 2x construct.gradle) make up the infra of our new task. Gradle must now be capable to construct that task effectively, then again it doesn’t do anything else so isn’t a lot use but.

You’ll be able to optimistically realize that the whole lot underneath amd-plugin seems like a stand-alone gradle task, and that’s as a result of it’s. 🙂

Now let’s create a composite construct of our authentic task with this newly created one. Upon getting two Gradle initiatives, its a unmarried line to mix them right into a composite construct. Right here we’re composing a plugin so we’re together with it underneath pluginManagement, in case you sought after to compose supply code you might put it with the standard contains on the backside.

On your root task settings.gradle:

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
    includeBuild("amd-plugin") // This line permits our plugin task to be integrated as a composite construct
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.identify = "CompositePlugin"
come with ':app'
come with ':mylibrary'

Upon getting declared the composite construct like this, you must be capable to ‘sync’ your Android Studio IDE and the amd-plugin will begin to display as a multi-module task this is integrated.

The sync’d task (Challenge View) in Android Studio.

We’ve now hooked up two Gradle initiatives in combination to construct as a composite. The very last thing left is to fill our our plugin to if truth be told do one thing. Reminder; we’re going to wrap the Affected Module Detector Plugin from Dropbox, in order that we will be able to increase its capability.

To create a plugin we want to claim to Gradle, what our plugin is and the place it’s, this is helping Gradle create the jar that our plugin exists in. This implies converting our /amd-plugin/plugin/construct.gradle and including the gradlePlugin closure:

gradlePlugin {
    plugins {
        blundAffectedModsPlugin {
            identity = "com.blundell.amd.plugin" 
            implementationClass = "com.blundell.amd.BlundellAffectedModulesPlugin" // That is the absolutely certified identify and trail to the plugin ( we will be able to create subsequent )
        }
    }
} 

While we’re on this document, let’s upload a dependency at the third birthday celebration (AMD) plugin to our dependencies block:

dependencies {
  implementation(
    "com.dropbox.affectedmoduledetector:affectedmoduledetector:0.2.0"
  )
  testImplementation("junit:junit:4.13.2")
}

Now we’ve got a dependency at the AMD plugin, we will be able to get admission to its public api. We additionally declared our plugin magnificence, let’s create the corresponding supply code for that. Create a brand new document: amd-plugin/plugin/src/primary/kotlin/com/blundell/amd/BlundellAffectedModulesPlugin.kt

BlundellAffectedModulesPlugin.kt is our plugin due to this fact we lengthen from the Gradle org.gradle.api.Plugin:

bundle com.blundell.amd

import com.dropbox.affectedmoduledetector.AffectedModuleConfiguration
import com.dropbox.affectedmoduledetector.AffectedModuleDetectorPlugin
import org.gradle.api.Plugin
import org.gradle.api.Challenge

magnificence BlundellAffectedModulesPlugin : Plugin<Challenge> {

    override a laugh follow(task: Challenge) = task.run {
        task.plugins.follow(AffectedModuleDetectorPlugin::magnificence.java)
        pluginManager.withPlugin("com.dropbox.affectedmoduledetector") {
            val config = rootProject.extensions.findByType(AffectedModuleConfiguration::magnificence.java)!!
            config.logFolder = "${task.buildDir}/amd-output"
            config.logFilename = "output.log"
            logger.lifecycle("We will now have interaction with the plugin programmatically (as above).")
        }
    }
}

Here’s what this code does:

  • We follow the AffectedModuleDetectorPlugin so that anybody making use of this plugin, applies the third birthday celebration plugin
  • With the AMD plugin implemented, we get the AMD plugins config and configure it in order that it’s going to print out logs into our /construct folder when it’s operating

As soon as the plugin is created, the very last thing we want to do is have our primary task follow our BlundellAffectedModulesPlugin so it may be used. That is performed in the principle task’s root construct.gradle:

buildscript {
    ext {
        compose_ui_version = '1.3.2'
    }
}
// Most sensible-level construct document the place you'll be able to upload configuration choices commonplace to all sub-projects/modules.
plugins {
    identity 'com.android.software' model '7.3.1' follow false
    identity 'com.android.library' model '7.3.1' follow false
    identity 'org.jetbrains.kotlin.android' model '1.6.10' follow false
    identity 'com.blundell.amd.plugin' // This is applicable our composite plugin
}

And that’s it! Upon getting implemented the plugin you’ll be able to sync your IDE to select up the most recent adjustments. Then in case you run an AMD plugin command akin to:

./gradlew runAffectedUnitTests -Paffected_module_detector.allow

You’ll see your personal plugin operating and wrapping the third birthday celebration.

Congratulations for your composed construct. You’ll be able to take this additional and create your personal duties as a way to have much more regulate of what’s run and when, the primary level being, now that you’ve a composite construct, you’ll be able to programatically have interaction with different plugins and feature all that code to your IDE. Permitting you to debug in a single position, issues that the place in most cases exhausting to observe throughout a couple of initiatives, and decompose your paintings in smaller extra remoted chunks.

Leave a Reply

Your email address will not be published. Required fields are marked *