I’ve been trying to get my head around custom Gradle plugins throughout the week and I’ve run into a bit of a wall. My goal is basically to consolidate a lot of common configuration into a custom plugin. One thing this plugin should include is the ‘maven-publish’ configuration. This configuration is identicle across projects except for the artifact details (group ID, artifact ID, version). So, my idea is to define an extension which will allow configuration of only these changing properties, with the actual configuration taking place within my plugin. This would allow me to reduce a lot of repeated script code in all of my projects (I intend on adding other common stuff to the plugin too if I can get this to work).
The problem is that the commonConfig and repoConfig extension variables being access in the publishing configuration are all null. I gather this is due to the plugin code being executed before the extension configuration takes place in the project build script, and so these values have not been set at this stage. So to get around this I tried surrounding the configuration code in a project.afterEvaluate {} closure. This unfortunately results in the following error:
“Cannot configure the ‘publishing’ extension after it has been accessed.”
I’m not sure if this is a ‘maven-publish’ specific issue or if my approach is just wrong, so was hoping to get some clarification here. There doesn’t seem to be a lot of information out there (that I could find) on how to do this sort of thing so any help would be appreciated.
EDIT:
I’ll just add that If i add the afterEvaluate closure and remove the publishing configuration block from the plugin, I can confirm that I do have access to the commonConfig and repoConfig extension variables. So at least the extensions appear to be working.
You are not going to get very far with this solution. You should study the new rules based plugins and rewrite all this logic in the new scheme. The afterEvaluate is a hack that will not give you reliable results and eventually will stop working completely even if you manage to get it to work in the first place. The maven-publish plugin is a rules based plugin which would best to combine with another rules based plugin solution that you create.
As a suggestion what you are trying to do seems like a new @Mutate configuration rule supplying your desired configuration as values for the PublicationContainer model object. The PublicationContainer would be the subject of your rule and there you could use code like this to create and configure your publications:
@Mutate
void createMyPublications(PublicationContainer publications) {
publications.create('aar', MavenPublication) {
// Configure the maven publication here
}
}
And to complete this answer, I would probably migrate your commonConfig and repoConfig to ‘@Managed’ elements, and add them to the new model using '@Model’
These new model elements would then be used as inputs in the @Mutate rule suggested above by @Alex_Vol
The problem is the PublicationContainer model path seems to be unknown. I get the following error when attempting a build:
Error:A problem occurred configuring project ‘:testproject’.
> The following model rules could not be applied due to unbound inputs and/or subjects:
ConfigPlugin#createPublications
subject:
- PublicationContainer (parameter 1) []
inputs:
- commonConfig ConfigPlugin.CommonConfig (parameter 2)
[] - indicates that a model item could not be found for the path or type.
Is there some way I should be making the ‘maven-publish’ plugin model paths visible to my own config plugin other than applying it in the project build script or plugin?
You can use the gradle ‘model’ task to see what’s in the new model space.
You’ll see PublishingExtension
This should be the subject of your rule. From PublishingExtension you can access the publications container. See here
Ah, yes that did the trick. It’s all working now, and the end result is a very simple plugin which is nice to see. For reference here’s the final working plugin code (with sensitve credential info omitted)
This is compiled as a *.jar archive and published to my Maven repository. One of my projects can then utilise this plugin in its build.gradle script file like so (once the appropriate dependency and repository is added):
Note that this is part of a larger build script for an Android app. Publishing this project with gradle publish works as expected.
A couple of follow up questions while I’m at it:
1.When I use the gradle model task for my project which is using my plugin, the output seems to only show the tasks model, but none of my own plugin models or the publishing extension model. Is this a bug or am I missing something here? Here’s the actual output:
2.Currently I have applied the ‘maven-publish’ plugin in my project build.gradle script file, whereas ideally this would just be applied within my config plugin. If my plugin consists purely of a RuleSource subclass, is it possible to apply another plugin within this plugin? Or do I need to do this in the apply(..) method of a Plugin<Project> implementation, with the RuleSource sublass included as an inner class?
Taking the Gradle source code for new rules based core plugins as my guideline I would answer that creating a hybrid plugin with the RuleSource class an the inner class and the apply method applying the maven-plugin is the way to go.
Not sure what to say about the model task output. I use Gradle 2.9 and the model output is way more than you show here. What version of Gradle are you running this on?
Thanks Alex, I ended up going the hybrid route and it’s working well.
Regarding the model task output, this occurs using Gradle 2.9. Both Gradle and the wrapper behave the same way. I’ve tried using a Gradle 2.8 wrapper but again I get the same behaviour. This is on a 64-bit Windows 10 machine for my Android projects.
My iOS build scripts which use the same plugins, including my custom plugin of this topic, produce much more output with all of the expected models. This is on an OSX machine (10.10.5 Yosemite) using Gradle 2.8.
I’m at a bit of a loss as to what could be causing this issue. I’ll give Gradle 2.10 a shot this week as well to see if anything changes.