How to build and consume gradle plugin inside a multi-module project?
Asked Answered
C

1

7

The big picture

I have a library which is used as a dependency in other projects. The library has some configuration requirements related to test suites for each project depending on it. This is why I have created a plugin that configures those for me so that I could just add the plugin and be done with it:

plugins {
   id("org.my.gradle.plugin") version "internal"
}

Project structure

+ root
  + my-api/... (self-sustained; doesn't depend on anything, pretty much interfaces)
  + my-implementation/... (depends on my-api and `my-gradle-plugin` via `plugins { id("org.my.plugin") }`)
  + my-gradle-plugin/... (the plugin itself)
    + build.gradle.kts
      plugins {
        `java-gradle-plugin`
        `maven-publish`
      }

      gradlePlugin {
          plugins {
              create("org.my.gradle.plugin") {
                  id = "org.my.gradle.plugin"
                  group = "org.my.gradle.plugin"
                  implementationClass = "org.my.gradle.plugin.MyGradlePlugin"
                  version = project.version
              }
          }
      }


  + build.gradle.kts // a bunch of shared task configurations and some repository configuration (mavenLocal, maven(xyz), mavenCentral())
  + gradle.properties - contains only "version=0.0.3-SNAPSHOT"
  + settings.gradle.kts
    pluginManagement {
        repositories {
            mavenLocal()
            maven { url = uri("https://xyz") }
            gradlePluginPortal()
            mavenCentral()
        }
        resolutionStrategy {
            val version: String by settings
            eachPlugin {
                if (requested.id.id == "org.my.gradle.plugin") {
                    useVersion(version)
                }
            }
        }
    }

The problem

The plugin works fine if it's a separate stand alone project. This, unfortunately, complicates my workflow so I thought I could possibly have it within the same multi-module project.

Unfortunately I am running into problems, because gradle doesn't seem to know it needs to build the plugin in order to use it inside one of the modules and therefore I get:

* Where:
Build file '/workspace/my-implementation/build.gradle.kts' line: 3

* What went wrong:
Plugin [id: 'org.my.gradle.plugin', version: '0.0.3-SNAPSHOT'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'org.my.gradle.plugin:org.my.gradle.plugin.gradle.plugin:0.0.3-SNAPSHOT')
  Searched in the following repositories:
    MavenLocal(file:/home/jenkins/.m2/repository/)
    maven(https://xyz)
    Gradle Central Plugin Repository
    MavenRepo


Why does it fail?

I know that spring-boot-gralde-plugin is part of the spring boot multi-module gradle project and is consumed within the project itself. Unfortunately I haven't been able to figure out what's the "magic trick" to make it work.

Any ideas what I'm missing here?

Chinchilla answered 11/12, 2022 at 14:47 Comment(1)
You've already figured out the solution, but for reference here's the relevant bit in the docs.Fruity
C
10

Well, this took me the better half of the day, but I finally figured it out.

In order to consume the plugin inside the same repository, you must place a settings.gradle.kts file inside your plugin. This separates the plugin build from the rest of your modules. Then you can use includeBuild() inside the pluginManagement to enforce the building of the plugin before everything else:

// ./root/settings.kotlin.kts

rootProject.name = "root-project"

include("my-api", "my-implementation")

pluginManagement {
    includeBuild("my-gradle-plugin")
    repositories {
        mavenLocal()
        maven { url = uri("https://xyz") }
        gradlePluginPortal()
        mavenCentral()
    }
    resolutionStrategy {
        val version: String by settings
        eachPlugin {
            if (requested.id.id == "org.my.gradle.plugin") {
                useVersion(version)
            }
        }
    }
}

Then you can just use the plugin without any issues:

plugins {
   id("org.my.gradle.plugin") version "internal"
}

I'm using gradle 7.5+ so not sure if this works for older versions.

The docs also mention this here: https://docs.gradle.org/7.6/userguide/composite_builds.html#included_plugin_builds

Chinchilla answered 11/12, 2022 at 16:48 Comment(1)
Great answer! I think Stackoverflow needs a "pat yourself on the back button" for this sort of cases where nobody else has even commented, or attempted to help and you end up answering your own complex question.Erymanthus

© 2022 - 2024 — McMap. All rights reserved.