How to create subproject programmatically so that plugins can be added to it

Hello,

I am developing a plugin that adds subprojects to the project to which the plugin is applied.
Everything is fine except one thing: when applying other plugin to the subproject it fails, because the subproject is a DefaultProject instance (I use new DP() to create it) and the getPluginManager() is unimplemented. The comment in the source code claims that decorator takes care the implementation.

What is the appropriate way to create a subproject for being able to add plugins to it programmatically?

Thanks!
Zsolt

Hi Zslot,

The only place you can create new projects is in the settings.gradle. Have a look at the implementation of Settings.include() and Settings.includeFlat() regarding how to do this. Once your settings are evaluated, the project graph is frozen and you can’t add projects. The DefaultProject instances you create are not part of the project graph and will be ignored.

If you don’t want to copy/paste code between settings scripts, you can add a plugin to the Gradle object from an init.gradle script and use it from the settings.

Here are a few starting points:
https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html
https://docs.gradle.org/current/javadoc/org/gradle/api/initialization/Settings.html
https://docs.gradle.org/current/userguide/init_scripts.html#initScriptConfiguration (see also 42.2)

Let us know how it works out!

Hi Dimitar,

Before I react to your answer a quick side-question:
Plugin documentation claims T can be of any type. There is even an example for its usage in SettingsPluginIntegrationSpec in Gradle code.
So nice! Let’s try it and expect some magic so my subprojects can be easily set there. Nope! It fails deep in Gradle where expecting a Settings but getting a Project type instead (see stacktrace below).
Is it the regular testing setup (1) which is not suitable or something else?

(1) using ProjectBuilder and then adding via project.pluginManager.apply()

Thanks
Zsolt

at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:153)
at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:116)
at org.gradle.api.plugins.PluginManager$apply.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at hu.tinca.gradle.rioplugin.Rio2PluginTest.setUp(Rio2PluginTest.groovy:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:543)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:212)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:631)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:883)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1208)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:758)
at org.testng.TestRunner.run(TestRunner.java:613)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:87)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1137)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1062)
at org.testng.TestNG.run(TestNG.java:974)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:74)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassCastException: org.gradle.api.internal.project.DefaultProject_Decorated cannot be cast to org.gradle.api.initialization.Settings

Hi Zsolt,

You don’t give me much to work with :slight_smile:

Based on your stacktrace, I can see that you are trying to use the PluginManager directly from a TestNG test. From that and the questions you are asking, I dare say you are on the wrong path and are making it difficult for yourself. Try to use the Gradle Test Kit and have a look at a few other plugins before you continue adding code.

Not really any type - Plugin<Date> while syntactically correct is meaningless as the date object does not support plugins. In practice, you want to use Plugin<Project> (applied from within projects), Plugin<Gradle> (applied within init scripts), Plugin<Settings> (applied within settings - I have never used that one)

As your plugin needs to come from somewhere, unless you customize your distro, I’d suggest using Project or Gradle (you can not declare buildscript dependencies in the settings script).

I hope that helps

The stacktrace shows you are trying to apply a Settings plugin to a Project instance, which can obviously not work.