haelix
haelix

Reputation: 4555

With Gradle, how best to publish a multi-module project to an additional repository as a specific version?

I have this multi-module project structure

proj
├── subprojA
└── subprojB  [depends on subprojA]

Both subprojects are producing a java jar each. I want to do an extra publishing step where the 2 subproject jars would be given version "1.0.0-dev" and they would be pushed to MavenLocal.

It was relatively easy to publish using a new "publication" entity as these are designed to be able to override the project version (not shown, an additional trick to make each publication go to only their respective repo):

devlocal(MavenPublication) {
    from components.java
    version "1.0.0-dev"
    alias true // prevents error "Publishing is not able to resolve a dependency on a project with multiple publications that have different coordinates"
}

However - you guessed it - there is a problem with this. The new publication is "dumb" in the sense that subprojB would depend on the wrong version of subprojA - i.e. the actual project version not 1.0.0-dev. I want the extra publication jars to depend on one-another.

I discover this is not trivial, there are 2 approaches:

Which option is better and can anyone point to an example for either?

Edit: I did find an example for approach #1 here but after implementing it I realise it's not enough, as it only changes POM metadata whereas Gradle uses "Gradle module metadata". Not so lucky to find the same tweaks for Module metadata.

Upvotes: 5

Views: 2846

Answers (2)

Imad Salki
Imad Salki

Reputation: 656

Faced the same problem, I have a common project named Commun used by project A.

and this solved my problem :

tasks.withType(GenerateModuleMetadata) {
    enabled = false
}

When you declare this dependency in your build.gradle like this :

implementation (group: 'com.example', name: 'common', version: "${commonVersion}")

You always download the jar in you repository (Maven in your case).

If you want to have the flexibility between Local environement and Production, so that when you update the common library you can use it directly in project A without publishing it you can do this :

in the build.gradle :

dependencies {
        // Common
        if (project.hasProperty("production")) {
            implementation (group: 'com.example', name: 'common', version: "${commonVersion}")
        } else {
            implementation group: 'com.example', name: 'common'
        }
}

in your settings.gradle :

rootProject.name = 'projectA'
if (startParameter.projectProperties.get("production") == null) {
    includeBuild "../common"
}

don't forget to update the buil task in production environement :

./gradlew clean build -Pproduction=true

Upvotes: 1

haelix
haelix

Reputation: 4555

After much fighting with Gradle it turns out approach #1 requires to switch off "gradle module metadata" and have publication only publish POM files, which can be hacked to contain the right version for the deps. Starting Gradle 6, by default Gradle's own metadata is used instead of POM, which is retained for Maven interoperability. But this metadata seemingly cannot be edited during publication (it can only be edited during resolution in client projects - see this). So the (suboptimal) solution for now is to hack the POM like here and disable Gradle module metadata like this:

tasks.withType(GenerateModuleMetadata) {
    enabled = false
}

Upvotes: 2

Related Questions