Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can plugin programmatically configure maven-publish publishing and allow build.gradle to modify it

Tags:

gradle

I have project wide settings in a plugin, called parent, that attempts to apply the maven-publish plugin and then programmatically configure the publishing extension. This seems to work but when I apply this plugin in a build.gradle script I can not configure publishing extension to set the project specific publications.

I receive the error:

  Cannot configure the 'publishing' extension after it has been accessed.

My intent was to set up the publishing repository in the parent plugin and then let each build.gradle script add the appropriate publications.

Is there a way to do this?

Currently ParentPlugin.groovy looks like:

def void apply(Project project) {
    project.getProject().apply plugin: 'maven-publish'

     def publishingExtension = project.extensions.findByName('publishing')

    publishingExtension.with {
        repositories {
            maven {
                mavenLocal()

                credentials {
                    username getPropertyWithDefault(project.getProject(), 'publishUserName', 'dummy')
                    password getPropertyWithDefault(project.getProject(), 'publishPassword', 'dummy')
                }

            }
        }
    }
}

My client build.gradle fails when it tries to configure the publishing extension.

apply plugin: 'parent'

publishing {
        publications {
            mavenJava(MavenPublication) {
                groupId 'agroup'
                artifactId 'anartifactid'
                version '1.0.0-SNAPSHOT'

                from components.java
            }
        }
}

Is this possible? Is there another way I should be approaching this?

like image 281
ditkin Avatar asked Jan 17 '14 15:01

ditkin


People also ask

Can Maven plugins be used in Gradle?

You can't use a Maven plugin as-is in Gradle; you'll have to port it to a Gradle plugin. How difficult this is depends on how many Maven APIs the plugin is using. Another strategy might be to call into Maven via Gradle's Exec task.

What is publishing in build Gradle?

Gradle automatically generates publishing tasks for all possible combinations of publication and repository, allowing you to publish any artifact to any repository.


2 Answers

NOTE regarding repositories{} and publications{} for plugin maven-publish:

Topic: How to workaround this perplexing gradle fatal error message: Cannot configure the 'publishing' extension after it has been accessed

First thing to try (deep magic): (note "project." prefix is optional) -- Configure publications and repositories not like this:

project.publishing {publications {...}}
project.publishing {repositories {...}}

but instead like this recommended style:

project.publishing.publications {...}
project.publishing.repositories {...}

It would be instructive for a gradle guru to explain why this trick works.

Another known workaround is to make sure that each apply of plugin maven-publish is in the same project code block as project.publishing.repositories and project.publishing.publications. But that is more complex and harder to do than the first thing to try, since by default the CBF applies maven-publish and a second apply of it may itself cause the same error. maven-publish is normally applied in pub/scripts/publish-maven.gradle, unless PUB_PUBLISH_MAVEN is set to override that file location, in which case the caller should apply plugin maven-publish. See https://orareview.us.oracle.com/29516818 for how this not-preferred workaround can be done (for project emcapms) while still using the CBF.

P.S. Someday I'll write this up with minimal code examples. But I'm putting this hard-won knowedge out there now to save other folks from wasting days on this common maven-publish issue.

like image 188
maven_publish_braindamaged Avatar answered Oct 03 '22 09:10

maven_publish_braindamaged


To deal with this, I wrote another plugin, which can delay modifications to the publication while also avoid a "reading" of the extension, which would put it in the "configured" state. The plugin is called nebula-publishing-plugin, the code for the "lazy" block can be found in the github repo. It looks like this:

/**
 * All Maven Publications
 */
def withMavenPublication(Closure withPubClosure) {
    // New publish plugin way to specify artifacts in resulting publication
    def addArtifactClosure = {

        // Wait for our plugin to be applied.
        project.plugins.withType(PublishingPlugin) { PublishingPlugin publishingPlugin ->
            DefaultPublishingExtension publishingExtension = project.getExtensions().getByType(DefaultPublishingExtension)
            publishingExtension.publications.withType(MavenPublication, withPubClosure)
        }
    }

    // It's possible that we're running in someone else's afterEvaluate, which means we need to run this immediately
    if (project.getState().executed) {
        addArtifactClosure.call()
    } else {
        project.afterEvaluate addArtifactClosure
    }
}

You would then call it like this:

withMavenPublication { MavenPublication t ->
        def webComponent = project.components.getByName('web')
        // TODO Include deps somehow
        t.from(webComponent)
    }

The plugin is available in jcenter() as 'com.netflix.nebula:nebula-publishing-plugin:1.9.1'.

like image 41
Justin Ryan Avatar answered Oct 03 '22 10:10

Justin Ryan