gradle

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


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?


Solution

  • 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'.