Gradle - configure subprojects based on plugin presence

I am fighting with a fairly simple gradle problem but despite searching I cannot find a solution. Very simple, in a multi project build, I need configure some subproject based on the plugins they load.
So If sub project has plugin ‘war’ or ‘ear’ do this… I have tried the following without success:

subprojects {
if (it.plugins.hasPlugin(‘war’) || (it.plugins.hasPlugin(‘ear’) {
apply plugin: ‘my super special plugin’


}
}

The above never apply plugin: ‘my super special plugin’

Any suggestion? Thanks

You’re looking for PluginManager.withPlugin:

https://docs.gradle.org/current/dsl/org.gradle.api.plugins.PluginManager.html#org.gradle.api.plugins.PluginManager:withPlugin(java.lang.String, org.gradle.api.Action)

(Sorry, Discourse seems to barf on this link)

subprojects {
    pluginManager.withPlugin("war") {
        apply plugin: 'my super special plugin'
    }
}

Thanks a lot!, that works perfectly!
I am having just a bit of problem selecting both war and ear ids. The following won’t work. Is it possible or Do I need to have to separate blocks pluginManager.withPlugin(“xxx”). I have quite some code to apply

subprojects {
    pluginManager.withPlugin("war") || pluginManager.withPlugin("ear") {
        apply plugin: 'my super special plugin'
    }
}

I think you want pluginManager.hasPlugin(id) which returns boolean rather than withPlugin(id, action) which executes an action and returns void

https://docs.gradle.org/current/dsl/org.gradle.api.plugins.PluginManager.html

I tried, it never returns true, I suspect that it evaluates before “war” plugins is applied?

Yep, likely a timing issue. You could use an afterEvaluate closure to delay evaluation

subprojects {
   afterEvaluate {
      if (pluginManager.hasPlugin('foo')) {
        ... 
      } 
   } 
} 

The configuration can be shared/passed around:

subprojects {
   def configurationForEarOrWar = { /* stuff */ }
   pluginManager.withPlugin("war", configurationForEarOrWar)
   pluginManager.withPlugin("ear", configurationForEarOrWar)
}
1 Like

@sterling Thanks. It works perfect and solves the problem

@Lance somehow afterEvaluate did not help. hasPlugin still returned false

No problem.

As a style/usability comment, if there are several plugins that your plugin knows how to configure, it would be better to unconditionally apply your special plugin and then have the plugin do withPlugin(...). That makes it easier for people who use your plugin to “do the right thing”.

Thanks for the good suggestion.
It is not really my plugin, it’s websphere deployment plug-in that can run on both war and ear projects.
Somehow (i don’t recall why) I found out that if I just applied it, the overall build and deploy would fail on some modules.
In this way you suggested works perfectly

@sterling do you have a recommended pattern for conditional plugin applications while still using withPlugin()? We have a use case where we have one configuration we want to run for, say, android library projects but only if the Kotlin kapt plugin is not applied. If kapt’s plugin is applied, then we’d want to apply something different

Right now we’re basically doing something like this:

if (project.pluginManager.hasPlugin("org.jetbrains.kotlin.kapt")) {
  // Apply kapt configuration
} else if (project.pluginManager.hasPlugin("com.android.application")) {
  // Do something different
}

The hasPlugin system works, but obviously has ordering concerns. Figuring this might be our only option, but hoping there’s maybe another mechanism for this case that I’m missing.