Maven-publish: publish has no actions

(john) #1

I want to create a plugin that will publish artifacts from a task to a maven repository by means of the maven-publish plugin. I’m wanting to use the model rule approach. I want to remove as much boilerplate code as possible from build.gradle, hence my desire to move the publishing code into a plugin.

I have a task created in a plugin (that itself applies the maven-publish plugin) that will zip up files that are produced by a native build process. I need access to the Project class, so there is an extension container that I have created that has a project property that enables me to do this.

    public void createPackageNativeArtifactsTask(final ModelMap<Task> tasks, @Path("binaries") ModelMap<NativeBinarySpec> binaries,
            final ExtensionContainer extensionContainer) {

        // Get ProjectWrapper and enclosed Project object.
        final ProjectWrapper projectWrapper = extensionContainer.getByType(ProjectWrapper)
        final Project project = projectWrapper.project

        // these are the files we will package up
        def exportedBinaryList = binaries.findAll {                
                it instanceof StaticLibraryBinarySpec &&
                it.buildable  &&
       == 'export'

        // this is the repo I want to publish to
        def bktNexusPublishingRepository = (project.version.endsWith('-SNAPSHOT')) ? "snapshots" : "releases"

        project.publishing.repositories.maven {
            credentials {
                username = project.findProperty('bktNexusUser')
                password = project.findProperty('bktNexusPassword')
            url "${'bktNexusRepositoryUrlPrefix')}/${bktNexusPublishingRepository}"

        // this is the task that will zip everything up when the binaries are built
        tasks.create("packageNativeArtifacts", Zip) {
            outputs.upToDateWhen { false }
            group = "Publishing"
            description = "Zips all files defined in 'from' into 'destinationDir' in preparation for publishing by the publish* task(s)."
            baseName "${}"
            version "${project.version}"
            extension 'nar'

            exportedBinaryList.each { binary ->
                def binaryDir = + "/" + + "/" +
                def exportedHeaderDirs = binary.component.sources.cpp.exportedHeaders.getSrcDirs() as List
                from("${project.buildDir}/libs/${binary.component.baseName}/static/${binaryDir}") {
                exportedHeaderDirs.each { dir ->
                    from("${dir}") {

This works ok - it zips up binaries by their variant and puts them into a zip file. It also adds the exported header files and replicates them throughout the zip file. The rule that makes this task run after building and testing is not shown.

I have another rule that I want to have create the MavenPublication and set its artifact to be the output of the packageNativeArtifacts task that I just created. I can’t seem to add this step to the previous rule as the task doesn’t seem to be created when I call tasks.create(), it’s null. I’m guessing this is because the creation of the task is deferred. I annotate this new rule with @Finalize rule in order to have visibility of all tasks.

    public void finalizePackageNativeArtifactsTask(final ModelMap<Task> tasks, @Path("binaries") ModelMap<NativeBinarySpec> binaries,
            final ExtensionContainer extensionContainer) {

        // Get ProjectWrapper and enclosed Project object.
        final ProjectWrapper projectWrapper = extensionContainer.getByType(ProjectWrapper)
        final Project project = projectWrapper.project

        def packageNativeArtifacts = tasks.get('packageNativeArtifacts')
        project.publishing.publications.create("mavPub", MavenPublication) { publication ->

When I call the publish task, it runs through its dependencies ok, building all files as required. The packageNativeArtifacts task is set as a dependency too, so once the files are built, it then zips them up. However, nothing is uploaded to Nexus. When I run the task with --debug, I see the following:

17:37:50.134 [INFO] [org.gradle.execution.taskgraph.AbstractTaskPlanExecutor] :publish (Thread[Daemon worker Thread 79,5,main]) started.
17:37:50.134 [LIFECYCLE] [class org.gradle.internal.buildevents.TaskExecutionLogger] :publish
17:37:50.134 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Starting to execute task ':publish'
17:37:50.134 [INFO] [org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter] Skipping task ':publish' as it has no actions.
17:37:50.134 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':publish'
17:37:50.134 [INFO] [org.gradle.execution.taskgraph.AbstractTaskPlanExecutor] :publish (Thread[Daemon worker Thread 79,5,main]) completed. Took 0.0 secs.

The publish task seems to have no actions (whatever that means), and is therefore not executed. I have no idea why this is.

(Scott Palmer) #2

I’m having this exact same problem. (Using Gradle 3.4.1)

I have a multi-project build, and artifacts declared in three sub-projects. When I do a release (using ‘net.researchgate:gradle-release:2.5.0’) I want to publish the artifacts. I use the following code in my root project:

subprojects {
    apply from: rootProject.file('common.gradle')
	afterEvaluate { subProj ->
		rootProject.afterReleaseBuild.dependsOn subProj.tasks.getByName('publish')

It appears the ‘afteEvaluate’ is needed, because otherwise Gradle complains that there is no ‘publish’ task.
In the sub projects my artifacts are native installers. The publishing declaration is generally like this:

publishing {
	publications {
		designerApp(MavenPublication) {
			artifactId 'designer'
			artifact(files(runLight).asPath) {
				if (project.hasProperty('oemName')) {
					classifier "windows-${oemName}"
				} else {
					classifier 'windows'
				extension 'msi'
				builtBy runLight

runLight is a task that produces a .msi file using the WiX toolset.
When I run this, the “publish” task is skipped because it "has no actions."
It doesn’t even trigger the running of the ‘runLight’ task, which ripples through and basically causes almost nothing to happen in a release build other than bumping the version number.

Help Please.

(Scott Palmer) #3

I think I’ve figured some of this out, at least for my specific case.

I suspect when configuring the artifact with the closure, the builtBy attribute does not get set at the right time.
I think the task is skipped because the original filename of the artifact may not exist at the time publishing should occur. So if publishing was the only reason the buildBy task would run, nothing happens.

If the builtBy task does something like change the file name and call setArtifacts on the publication, things are even worse. The original file name isn’t what would be built anyway, so it may cause the skipping.

In my case the release plugin could have changed the filename because it removed “-SNAPSHOT” or a different version number was entered when prompted.

There is a very tricky issue with declaring task output files and having the release plugin effectively change the file name by bumping a version number part-way through the build.

(Scott Palmer) #4

Well apparently that isn’t it either. It looked like it was working, but I’m not getting consistent results. This time two out of three sub-projects properly published results. The one that didn’t work claimed to be up-to-date without ever even attempting to run the ‘builtBy’ task. I mean it didn’t even say that the builtBy task was up-to-date or skipped, it never considered it as part of the build.

It also doesn’t run the task: generatePomFileForPublication

Conclusion: maven-publish is likely broken