In my custom Gradle plugin I have the following logic, which is working OK when executed on a Gradle 2.3 distribution:
apply the ivy-publish plugin
automatically add some repositories to the ivy publish plugin repositories (repA, repB)
declare some publications in the build.gradle script where my plugin is applied (let’s say pubA, pubB)
the ivy publish plugin will create tasks publishPubAToRepA, publishPubBToRepA, publishPubAToRepB, publishPubBToRepB
declare custom tasks in my plugin (customA, customB)
Use a @RuleSource with @Finalize method to finalize my task by the regular tasks from the ivy publish plugin
Note that I add to do it in a @Finalize method, instead of a @Mutate method on the task container, because for this to work, the ivy publish plugin must have created its own tasks.
Anyway, this was working OK in 2.3.
When switching to 2.4, I recompiled my plugin, replacing the @RuleSource by extends RuleSource. That is the only thing I did.
And now, my custom tasks are not finalized by the original ivy plugin tasks.
Does anybody have a hint on what has changed between 2.3 and 2.4, that could lead to this behaviour ?
10:57:33.170 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Mutating tasks using org.gradle.api.publish.ivy.plugins.IvyPublishPlugin$Rules#createTasks(org.gradle.model.collection.CollectionBuilder<org.gradle.api.Task>, org.gradle.api.publish.PublishingExtension, java.io.File)
10:57:33.186 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Transitioning model element ‘tasks.generateDescriptorFileForIvyPublication’ from state Known to Initialized
10:57:33.201 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Transitioning model element ‘tasks.__instantiator’ from state GraphClosed to GraphClosed
10:57:33.201 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Transitioning model element ‘tasks.__instantiator’ from state GraphClosed to GraphClosed
10:57:33.217 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Creating tasks.generateDescriptorFileForIvyPublication using org.gradle.api.publish.ivy.plugins.IvyPublishPlugin$Rules#createTasks(org.gradle.model.collection.CollectionBuilder<org.gradle.api.Task>, org.gradle.api.publish.PublishingExtension, java.io.File) > create(generateDescriptorFileForIvyPublication)
10:57:33.233 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Mutating tasks.generateDescriptorFileForIvyPublication using org.gradle.api.publish.ivy.plugins.IvyPublishPlugin$Rules#createTasks(org.gradle.model.collection.CollectionBuilder<org.gradle.api.Task>, org.gradle.api.publish.PublishingExtension, java.io.File) > create(generateDescriptorFileForIvyPublication)
10:57:33.248 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Transitioning model element ‘tasks.__store’ from state Known to GraphClosed
10:57:33.264 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Creating tasks.__store using Project..tasks.__store()
10:57:33.264 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Finished transitioning model element tasks.__store from state Known to GraphClosed
10:57:33.279 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Transitioning model element ‘tasks.__store’ from state GraphClosed to GraphClosed
10:57:33.279 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Mutating tasks.generateDescriptorFileForIvyPublication using DefaultCollectionBuilder.createAndStoreVia() - tasks.generateDescriptorFileForIvyPublication
10:57:33.295 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Finished transitioning model element tasks.generateDescriptorFileForIvyPublication from state Known to Initialized
10:57:33.295 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Transitioning model element ‘tasks.publish’ from state Known to Initialized
My @Finalize method is called
10:57:33.389 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Mutating tasks using com.xxxx.gradle.plugins.jfdp.JfdpPlugin$Rule#addFinalizedTasks(org.gradle.api.tasks.TaskContainer)
10:57:33.404 [DEBUG] [com.xxxx.gradle.plugins.jfdp.JfdpPlugin] finalize publishIvyRelease
10:57:33.404 [DEBUG] [com.xxxx.gradle.plugins.jfdp.JfdpPlugin] finalize publishIvyShared
10:57:33.420 [DEBUG] [com.xxxx.gradle.plugins.jfdp.JfdpPlugin] finalize publishIvyWindows
10:57:33.451 [DEBUG] [org.gradle.model.internal.registry.DefaultModelRegistry] Finished transitioning model element tasks from state Created to SelfClosed
It seems that the ivy tasks are not in the task container when my @Finalize method is called (otherwise the wiring between my custom tasks and the ivy regular tasks would have occurred)
Mmmm, if I add logger.warn(tasks.toString()) at the beginning of my @Finalize method, I don’t see the regular ivy publish tasks publishPubAToRepA, publishPubBToRepA, publishPubAToRepB, publishPubBToRepB
This is strange.
As explained above, the publications are added in the consuming build.gradle file
publishing {
publications {
ivy(IvyPublication) {
from components.java
organisation “$myOrganisation”
module = “$myModule”
}
}
}
and the repositories are added by my plugin, from the project repositories:
project.repositories.all { repo ->
if (repo instanceof IvyArtifactRepository) {
project.getExtensions().configure(PublishingExtension, new ClosureBackedAction<PublishingExtension>({ repositories.add(repo) }))
}
}
In the 2.4 release note, in the ‘Potential Breaking Changes’ section, I see
The withType() method selects elements based on the public contract type rather than implementation type.
This might be the reason for my problem, but then I’m not sure how to understand this change of behavior and how to modify my RuleSource to cope with this change.
The basic problem here is that Gradle no longer creates all tasks. Part of the rules based mechanism is the ability to not create something unless it is needed. Where it’s falling down here is that the constructs you are using don’t actually express that it is needed. Unfortunately, there’s no way right now to express that all CustomTask objects depend on all PublishToIvyRepository tasks. That’s what you really need. It’s coming.
Your options for right now are to:
Call tasks.realize() at the end of your script to force the creation of all tasks (please note: this is an internal method)
Do you have a rough idea of the when ? (like one or two releases, or definitely not before 2016 …)
In the meantime, I think I will stick to 2.3.
I’m not a big fan of using hard-coded naming conventions for my build logic, and I don’t know the side effects that calling tasks.realize() can occur (and anyway, it’s not a real, lasting, solution)
One more thing:
If I understand you correctly, when the missing construct we’re talking about will be available, I will be able to create a rule directly between the tasks of type CustomTask and the tasks of type PublishToIvyRepository, without using the whole ModelMap<Task> as the rule subject ? If true, does this mean that I will be able to switch from @Finalize (required in 2.3 to be sure that the PublishToIvyRepository tasks were created) to @Mutate, right ?