Publishing Maven relocations via Gradle

I am in a situation where I need to change the groupId for my project. To that end I want to setup a “Maven relocation”. The quick synopsis is that for this type of relocation, for each artifact published from my project I will need to now publish 2 poms:

  1. under the old groupId, artifactId and version (GAV) that “points to” the new GAV via a relocation element
  2. under the new GAV

But I am completely unclear how to do this with Gradle. Does Gradle have any support for this?

Bueller…? :slight_smile: Seriously, can noone even say that this is for sure not supported in any way in Gradle?

This issue is basically [GRADLE-2812] (https://issues.gradle.org/browse/GRADLE-2812) and the discussions surrounding it. There’s not a great way to change the group without some work in the dependent project.

If you are primarily concerned about your own transitive dependencies needing a transition period, that’s pretty easy to model if your versioning is still increasing. You’ll have some additional complexity (resolution rules) if your version numbers reset or if it’s more important to publish something at the old location in perpetuity, even for new versions. If you just care about transitive dependencies resolving to the correct version, this might be good enough:

dependencies {
    modules {
        module('oldGroup:oldArtifactId') { replacedBy('newGroup:newArtifactId') }
    }
}

If your project is a dependency for projects out of your control, there’s not a great way for things to just work for the dependent project without at least being aware and accounting for the change. You could wrap the needed changes in a plugin if you don’t think they’ll figure out exactly what is needed, but they’d still have to know to apply the plugin.

My project is HIbernate, which lots of people use of course. The only valid way for that to work is for there to be a relocation (per Maven terms) in place.

GRADLE-2812 is about resolving a relocation. That is one side of the equation. And yes it is sad that Gradle does not seem to handle that side of it very well.

My concern however is the other side of the equation: actually publishing the relocation.

If you’re using the ‘maven-publish’ plugin, this should be fairly easy. You’re basically just creating another publication for the relocation (called relocationPom below), customizing the POM, but not adding an artifact. You’ll need to add the relocation to the distributionManagement section using the pom.withXml capability. This is standalone, and should work with just the repository to publish to being configured, but I expect you would likely remove some of these hardcoded value and let the defaults flow through.

apply plugin: 'maven-publish'

publishing {
    publications {
        relocationPom(MavenPublication) {
            groupId 'old.group'
            artifactId 'old.artifact'
            version '1.0'
            pom.withXml {
                def relocation = asNode().appendNode('distributionManagement').appendNode('relocation')
                relocation.appendNode('groupId', 'new.group')
                relocation.appendNode('artifactId', 'new.artifact')
            }
        }
        // OTHER PUBLICATIONS HERE
    }
    repositories {
        // ADD REPOSITORY TO PUBLISH TO HERE
    }
}

If there’s a reason you need the older ‘maven’ plugin instead, I think things will be a bit trickier, but I’ll take a closer look if that’s what you really need.

Ah, that could work. I do in fact use maven-publish. I will try. Thanks James!

James unfortunately we run into a problem with this, essentially running into the following unresolved problem yet again:
https://issues.gradle.org/browse/GRADLE-2966

If your dependencies are such that you run into this issue, I don’t think you’re going to find a better solution than the one mentioned in the issue comments (except for a fix). If you can’t have multiple publications in the project and depend on it, then you’re going to need another project somewhere.

I suppose the only thing I can really add to that is a personal preference for using the GradleBuild task for situations where it doesn’t seem structurally correct to add a subproject. In this case it does seem like overkill, so I would probably just move the publication for the POM into a separate .gradle file and add a task to call it from the original project rather than create an actual subproject:

task publishRelocationPom(type: GradleBuild) {
    buildFile = 'publishRelocationPom.gradle'
    tasks = ['publishRelocationPom']
}

Either way though, it’s more complicated that it should be.