How to publish (to Maven Local) multi project java-library+gradle-plugin

I have taken over maintenance of a project which is built with Gradle. Up to now it was just a Gradle plugin but we are currently refactoring it. In the future it should have a core module which is used by the gradle plugin module. Then there should be more consumers of the core, i.e., CLI, Maven, perhaps something with UI (Java FX based?).

First action was to clean up the build. If anyone has a little bit of time, I am happy if you take a look and give feedback as I have not actively used Gradle for a long time. Note that any recent changes are on the develop branch (not on main) and that develop is not yet the default branch.

However, I have a strange problem and no idea to fix it. When I publish to MavenLocal (from develop branch) I get the following files:

org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.core/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.core/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.core-2.0.0-SNAPSHOT.module
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.core/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.core-2.0.0-SNAPSHOT.jar
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.core/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.core-2.0.0-SNAPSHOT.pom
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.core/2.0.0-SNAPSHOT/maven-metadata-local.xml
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/maven-metadata-local.xml
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/htmlSanityCheck-gradle-plugin-2.0.0-SNAPSHOT.jar
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/htmlSanityCheck-gradle-plugin-2.0.0-SNAPSHOT.pom
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/htmlSanityCheck-gradle-plugin-2.0.0-SNAPSHOT.module
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.jar
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.pom
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.module

I understand, that for the Gradle plugin the structure where the files are in org.aim42.htmlSanityCheck.gradle.plugin (beyond org/aim42/htmlSanityCheck) is necessary. I have a small integration test and it can find and use the plugin then. But the files in htmlSanityCheck-gradle-plugin have the very same contents. I would guess that I don’t need them. How can I prevent the installer from copying them?

In my wip/refactor-publishing branch I have tried a slightly different approach by dropping/migrating the publisher to the two modules. Nevertheless, I still get the Gradle plugin twice:

org/aim42/htmlSanityCheck/htmlSanityCheck-core/maven-metadata-local.xml
org/aim42/htmlSanityCheck/htmlSanityCheck-core/2.0.0-SNAPSHOT/htmlSanityCheck-core-2.0.0-SNAPSHOT.jar
org/aim42/htmlSanityCheck/htmlSanityCheck-core/2.0.0-SNAPSHOT/htmlSanityCheck-core-2.0.0-SNAPSHOT.pom
org/aim42/htmlSanityCheck/htmlSanityCheck-core/2.0.0-SNAPSHOT/htmlSanityCheck-core-2.0.0-SNAPSHOT.module
org/aim42/htmlSanityCheck/htmlSanityCheck-core/2.0.0-SNAPSHOT/maven-metadata-local.xml
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/maven-metadata-local.xml
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/htmlSanityCheck-gradle-plugin-2.0.0-SNAPSHOT.jar
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/htmlSanityCheck-gradle-plugin-2.0.0-SNAPSHOT.pom
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/htmlSanityCheck-gradle-plugin-2.0.0-SNAPSHOT.module
org/aim42/htmlSanityCheck/htmlSanityCheck-gradle-plugin/2.0.0-SNAPSHOT/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.jar
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.pom
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/maven-metadata-local.xml
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.module

I would like to keep this approach as the core module is then published as in Maven which would make consumption of the module more obvious to other users. But I still would like to get rid of the duplicate files in htmlSanityCheck-gradle-plugin.

Any ideas and feedback are appreciated, thanks in advance.

You are doing many very questionable things in those build scripts and something of it is causing this.
Just talking about the effect, org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin/2.0.0-SNAPSHOT/org.aim42.htmlSanityCheck.gradle.plugin-2.0.0-SNAPSHOT.jar should not exist at all.
org/aim42/htmlSanityCheck/org.aim42.htmlSanityCheck.gradle.plugin is (or better said should be) just the so-called marker artifact that is used to translate plugins { id("org.aim42.htmlSanityCheck") version "2.0.0-SNAPSHOT" } by naming convention to an actual Maven artifact which usually has just packaging = "pom", so no own artifact and just points to the actual code artifact that contains the plugin. One code artifact could contain any arbitrary amount of plugins and each that has an ID has its own marker artifact just pointing to the code artifact: Plugin Marker Artifacts

1 Like

Thanks a lot, this solved my issue.

I have no idea where I found this kind of code? I remember vaguely that in my first attempts only the module itself was published but was missing the marker interface

Additionally I was confused by having just a pom file in place with very little contents (not realizing that it had the real plugin as dependency).

Maybe the Gradle team wants to clarify in the long run in the documentation how the marker interface works and that it is normal to get both the marker artifact and the plugin itself in the Maven repo? In the samples there are arbitrary names like hello or goodbye (or simplePlugin) for the named domain objects (and their Closures). If you are not deep into the Groovy DSL behind Gradle it’s hard to figure, these are not specific configuration options (at least simplePlugin sounds like it is possible to generate misc. kinds of plugins and there are more options like complexPlugin or so)? At least I was confused going through the documentation.

If you think it is too unclear, I recommend you open a documentation issue on GitHub. Just writing it here in a comment will not bring any change as potentially none of the Gradle folks will ever see it. :slight_smile:
But imho it is pretty clear documented what the marker interface is for and how it works. But that is subjective of course.