I have a multi module Java / Gradle project where each module has identical configuration, so I would like to move that to a convention plugin as a pre-compiled script plugin. The problem is that all of the modules use the liquibase-gradle-plugin, which seems non-trivial to implement.
First, the liquibase plugin implements its own dependency scope liquibaseRuntime
, but my plugin does not know that scope. Here's my dependencies block (using a version catalog):
dependencies {
implementation libs.plugins.jooq.liquibase
implementation libs.plugins.gradle.liquibase
liquibaseRuntime libs.postgresql
liquibaseRuntime libs.liquibase
liquibaseRuntime libs.jooq
liquibaseRuntime libs.picocli
}
but that generates the error
Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method liquibaseRuntime() for arguments [map(valueof(DependencyValueSource))] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
at org.gradle.internal.metaobject.AbstractDynamicObject$CustomMissingMethodExecutionFailed.<init>(AbstractDynamicObject.java:190)
at org.gradle.internal.metaobject.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:184)
at org.gradle.internal.metaobject.ConfigureDelegate.invokeMethod(ConfigureDelegate.java:80)
If I change liquibaseRuntime
to implementation
the error goes away, but I don't want to export these dependencies, they're just for the liquibase plugin.
Second, the actual plugin configuration requires a configuration closure like this:
liquibase{
activities {
main {
changeLogFile "src/main/liquibase/changelog.xml"
// more config
}
}
}
If I write this in my plugin, I get the error
Caused by: java.lang.RuntimeException:
org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException:
Could not find method liquibase() for arguments [precompiled_EsrJooqLiquibase$_run_closure3@664b65b8] on project ':moduleA' of type org.gradle.api.Project.
How can I programmatically create such a configuration closure from the outside?
Update
The accepted answer works nicely, with one caveat:
to get the liquibaseRuntime
scope to work, I had to register it myself, the way the gradle liquibase plugin does:
project.configure(project) {
configurations.maybeCreate("liquibaseRuntime")
}
dependencies {
liquibaseRuntime(libs.postgresql) // etc
}
In order to use external plugins in a pre-compiled script plugin, you need to add the JARs containing those plugins to the classpath of the plugin in the plugin's build script, much like for normal code (documentation).
If you are writing the plugins in buildSrc
, this would be in the file buildSrc/build.gradle
.
The Maven coordinates1 of the plugin JAR are used for this purpose, as for a regular library. These should be added to the implementation
configuration:
// buildSrc/build.gradle
repositories {
gradlePluginPortal()
}
dependencies {
implementation 'org.liquibase:liquibase-gradle-plugin:2.2.1'
}
We have also registered the Gradle Plugin Portal as a repository so Gradle knows where to find the JAR, since this plugin is available there.
Now you can apply the plugin in your pre-compiled script plugin and you should have access to all the usual configuration options:
// Precompiled script plugin code
plugins {
id 'org.liquibase.gradle'
}
The plugin version is not necessary here since the plugin code is already on the classpath by virtue of the previous setup.
1 The Maven coordinates (ie, the groupId:artifactId:version) are different to the plugin id (the latter being the identifier used to apply a plugin in Gradle). The Maven coordinates of a plugin published at the Gradle Plugin Portal are declared on the plugin's page (eg for Liquibase) as the coordinates used for 'legacy plugin application'.