Issue with maven publish plugin within multiproject build

Project Structure

/build
build.gradle
gradle.properties
settings.gradle

/project1
build.gradle
/src

/project2
build.gradle
/src
.
.
.
/projectN


Problem

The build directory acts as the root project, with all other directories as subprojects with their own build.gradle for unique dependencies and tasks. As it stands, subprojects apply the maven-publish plugin in order to publish jars specific to their components (and this works fine). I currently have a task at the root project level (build) that wraps up the source within the subprojects into a zip file (this task works as expected).

My goal now is to apply the maven publish plugin at the root project level and add the zip artifact so that when I run publish, it publishes all subproject jars as well as the build project’s zip artifact.Though, when I apply the plugin at the root project level and run publish, it says that the publishToMavenLocal task is always up to date. Also, I don’t see the artifact specific publishing tasks when I run gradlew tasks --all.


Code

Through a custom plugin applied at the root project level, each subproject applies the maven plugin like so:

//When this base-plugin is applied:
p.subprojects.each {
    this.setupPublishing(it)
}

private void setupPublishing(final Project p) 
{
    p.apply plugin: 'maven-publish'
    
    p.publishing {
        publications {
            mavenJava(MavenPublication) {
                from p.components.java
                
                artifact p.sourceJar
                artifact p.testJar
                artifact p.javadocJar
            }
        }
        
        repositories {
            maven {
                url p.ext.publishUrl
            }
        }
    }
}

Where sourceJar, testJar, and javadocJars are my custom tasks the generate the necessary artifacts (this works fine). Now when I add the following code for the root project within the same plugin, the srcZip is never uploaded. The srcZip task artifact is created as expected.

this.setupRootPublishing(p)
private void setupRootPublishing(final Project p)
{

    p.apply plugin: 'maven-publish'

    def publishClosure = {
         mavenDefault(MavenPublication){
             artifact p.tasks.srcZip
         }
    }

    publishClosure.setDelegate(p)

    p.publishing {
            publications {
	   		    publishClosure
             }
        
            repositories {
                maven {
                    url p.ext.publishUrl
                }
            }
        }
}

Question

Does anyone see an issue here? Is there some limitation to the maven-publish plugin that doesn’t allow you to publish from both the root level and subproject level?

Thanks!

As a work-around, at the root project level (build), instead of applying the maven-publish plugin, I used the maven plugin. Thus forcing me to run uploadArchives when I want to upload the zip artifact. If anyone has any insight as to why the double maven-publish plugin apply didn’t work, I’d still be interested!

##Fix

this.setupRootPublishing(p)

private void setupRootPublishing(final Project p)
{
    p.apply plugin: 'maven'

    p.artifacts {
        archives p.srcZip
    }

    p.uploadArchives {
        repositories {
            mavenDeployer {
                repository(url: p.ext.publishUrl)
            }
        }
    }
}

I cannot test it out myself right now, but my gut feeling is that your issue is related to publishClosure somehow. Have you tried creating the publication directly inside publications instead of going through that extra closure?

Hey Chris,

Yes, I tried that initially and got the following error:

> Cannot create a Publication named ‘MavenPublication’ because this container does not support creating elements by name alone. Please specify which subtype of Publication to create. Known subtypes are: MavenPublication

A stack overflow post pointed me to the publishClosure above. I can’t recall the reasoning behind the custom closure and setting the delegate as the root project, and I can’t find the post again :expressionless:

Let me know if you end up testing this. Thanks!

My test of the suggestion to eliminate publishClosure seems to be working.
With your version of setupRootPublishing I got the up-to-date problem you described. I then changed the method to the following and everything worked as expected.

private void setupRootPublishing(final Project p)
{
    p.apply plugin: 'maven-publish'
    /*def publishClosure = {
        mavenDefault(MavenPublication){
            artifact( p.tasks.makeArtifact.outputs.files.singleFile ) {
                builtBy p.tasks.makeArtifact
            }
        }
    }
    publishClosure.setDelegate(p)*/
    p.publishing {
        publications {
            //publishClosure
            mavenDefault(MavenPublication){
                artifact( p.tasks.makeArtifact.outputs.files.singleFile ) {
                    builtBy p.tasks.makeArtifact
                }
            }
        }
        repositories {
            maven {
                url p.ext.publishUrl
            }
        }
    }
}

Output:

$ ./gradlew pTML
:generatePomFileForMavenDefaultPublication
:makeArtifact
:publishMavenDefaultPublicationToMavenLocal
:publishToMavenLocal

Chris, same issue. I receive the same error mentioned in my last comment with your solution. Then if I add my closure logic again, I don’t see the artifact.

It could potentially be a limitation in the version I use (2.8).

Any chance you can provide a more complete/working example that demonstrates the problem? I retested my code in Gradle 2.8, same successful results.

As for the closure logic, the code in the closure isn’t even being called. publishClosure is a NOOP. publishClosure() would cause the closure to be executed, but I can’t get it to work without further investigation.

Oh, I didn’t realize that about the closure. Even with that, I still receive that error mentioned previously.

As for a complete example, I’m not sure there is much else I can show. Though, maybe some additional context on how my build sets up publishing may uncover an issue, because I didn’t fully explain it in the initial post.

The /build project (root project), holds all of the build logic responsible for configuring the sub-projects where the source code actually lives. In build/build.gradle I apply my own custom plugin that is pulled down from a jar on our nexus repository. Code looks something like this:

buildscript{
    repositories{
        maven {
            url 'http://companyNexusServer/content/repositories/releases/'
        }
    }
}

dependencies{
    classpath "group.of.artifact:buildsystem:1.0.0"
}

apply plugin: 'plugin.id'

Now, within the apply method of the plugin, I have created this setUpRootPublishing() method that’s covered the scope of our conversation thus far. What I didn’t mention, was that at the end of the apply method, we apply a second plugin for all subprojects.

p.subprojects.each {
    it.apply plugin: 'another.plugin.id'
}

Within this additional plugin, we call the setupPlublishing() method at the beginning of this post. This is the only context I’ve left out of our conversation, that I feel could be useful. I’ve modeled my setUpRootPublishing() just as you did, with no success. I’m hoping this may uncover an issue or limitation.

Thanks!

I was hoping you could put together a zip of a working example that shows the issue rather than me trying to write my own. :slight_smile:

For proprietary reasons, I can’t give out the working build.

With that said, this isn’t that pressing for me as the use case I’m fulfilling isn’t really needed and I have a work-around. It’d be cool to understand the issue, but don’t feel a need slave over it.

Thanks for the help!