Extending Publications

Hi,

I’ve been doing some experiments with different ways I can customize a MavenPublication. Ideally I’d like to create a plugin that provides our users the ability to do something like:

publishing {
    publications {
        pub1(MavenPublication /*or maybe MyPublication which extends from something?*/) {
            artifact(...)
            from(...)
            ...
            myCoolMethodsAndPropertiesHere
        }
    }
}

I would also be OK with adding an extension to the publication (and I think I like it more than the above):

publishing {
    publications {
        pub1(MavenPublication) {
            artifact(...)
            from(...)
            ...
            myExtension {
                myCoolMethodsAndPropertiesHere
            }
        }
    }
}

I can simulate the extension above but I have not been able to figure out how a plugin could integrate such a thing. My simulation:

class ExtClass {
    String something = 'hello'
}

publishing {
    publications {
        pub1(MavenPublication) {
            extensions.create('myExtension', ExtClass)
            artifact(...)
            from(...)
            ...
            myExtension {
                something 'world'
            }
        }
    }
}

Any help or ideas would be fantastic.

Thanks, Chris

The extra information will likely be used by a TaskActionListener to perform extra duties after a PublishToMavenRepository task is complete. I say “likely” because this is currently the only solution I have for hooking into the execution of the generated publishing tasks. For example:

gradle.addListener( new TaskActionListener() {
    void beforeActions( Task task ) {
    }
    void afterActions( Task task ) {
        if( task instanceof PublishToMavenRepository ) {
            MavenPublication p = task.publication
            ExtClass e = p.extensions.findByType( ExtClass )
            if( e ) {
                /* do work */
                println "something = ${e.something}"
            }
        }
    }
} )

Again, I welcome any other ideas on how something similar can be achieved.

Simplest solution would probably just to use the extra properties extension to decorate the publication.

pub1(MavenPublication) {
    from components.java
    
    ext.foo = 'bar'
}

Additionally, I think your other code example could be simplified to something like:

tasks.withType(PublishToMavenRepository) {
    doLast {
        if (publication.foo) {
            /* do work */
        }
    }
}
2 Likes

If a task of type PublishToMavenRepository is created after the call to tasks.withType(), will the doLast still be applied?

Yes, tasks.withType { } applies the configuration to all tasks now and in the future.

1 Like

In case it matters, I should have mentioned that I’m stuck using Gradle 1.12 for now.

It seems that the tasks.withType {} closure is applied before a task is fully configured. For example:

tasks.withType ( PublishToMavenRepository ) {
    println t.class
    println t.publication
    println t.repository
}

Results in:

$ ./gradlew tasks
class org.gradle.api.publish.maven.tasks.PublishToMavenLocal_Decorated
null
org.gradle.api.internal.artifacts.repositories.DefaultMavenLocalArtifactRepository_Decorated@1beea90
class org.gradle.api.publish.maven.tasks.PublishToMavenRepository_Decorated
null
null
class org.gradle.api.publish.maven.tasks.PublishToMavenLocal_Decorated
null
org.gradle.api.internal.artifacts.repositories.DefaultMavenLocalArtifactRepository_Decorated@16181be
class org.gradle.api.publish.maven.tasks.PublishToMavenRepository_Decorated
null
null

I could probably access these from doLast(), but I’m looking at doing some additional configuration as well (like creating more tasks), so doLast() is too late.

So, I’d like to create another task for each instance of PublishToMavenRepository and I’d like to access the publication and repository properties. Is there a way to accomplish that?

Sorry if it seems that I’m changing what this thread is about, but I’m evolving the possibilities as I dig deeper and learn more about some of the Gradle guts 

You are correct, using withType() the closure passed during creation of the publication has not yet been evaluated. If you want to access publications after they have finished being configured you can access it from within a model { } block.

model {
    publishing {
        publications.all {
            println foo
        }
    }
}

To do this inside a plugin, you’ll have to declare a RuleSource. You can see how the ‘maven-publish’ plugin itself does this here:

Also, we are beginning to document this in master.

http://gradle.org/docs/nightly/userguide/new_model.html

1 Like

Thanks for the RuleSource pointers @mark_vieira, it is quite interesting and in the future I’ll take a more detailed look. However, from my initial digging it doesn’t look like something I should even bother trying to use while stuck on Gradle 1.12. So for now, here’s the solution I’ve ended up with. It seems to be working very well so far and I appreciate your guidance.

class MyPublicationExtension
{
    String something = 'hello'
}

class MyPublishExtensionPlugin implements Plugin<Project>
{
    static final String PUBLICATION_EXTENSION_NAME = 'myExtension'

    @Override
    void apply( Project project )
    {
        project.plugins.withType( MavenPublishPlugin ) {
            project.extensions.configure( PublishingExtension, new Action<PublishingExtension>() {
                public void execute( PublishingExtension extension )
                {
                    extension.publications.withType( MavenPublication ) { MavenPublication mp ->
                        mp.extensions.create( PUBLICATION_EXTENSION_NAME, MyPublicationExtension )
                    }
                }
            } )
        }

        project.tasks.withType( PublishToMavenRepository ) {
            /*
             * In Gradle 1.12 PublishToMavenLocal extends
             * PublishToMavenRepository.
             * This means we'll get more tasks than we want.
             * This has been corrected sometime in Gradle 2.
             */
            if( !(it instanceof PublishToMavenLocal) )
            {
                doLast {
                    MyPublicationExtension e = publication.extensions.findByName( PUBLICATION_EXTENSION_NAME )
                    if( e ) {
                        /* do work */
                        println "something = ${e.something}"
                    }
                }
            }
        }
    }
}