I have a settings plugin which is applying a proje...
# community-support
j
I have a settings plugin which is applying a project plugin to each project:
Copy code
public class SemverSettingsPlugin : Plugin<Settings> {

    override fun apply(target: Settings) {
        target.gradle.beforeProject { project ->
            project.pluginManager.apply(SemverProjectPlugin::class)
        }
    }
}
As I am applying it via
SemverProjectPlugin::class
, any try to use
plugin.manager.withPlugin("com.javiersc.semver")
is not working. Am I forced to apply the plugin via ID? Is it possible to apply it in both ways or link the ID somehow?
v
Should work either way. Gradle knows which class an ID is mapping to. So it should work, no matter how you apply it.
j
This is a repro: • https://github.com/Reproducers/semver-repro-175/tree/id-not-found The plugin is explicitly applied to the root and lib-1 projects; it is not applied explicitly to lib-2. The settings plugin is applying the plugin to all projects, something is working as all projects have registered the task
printSemver
Copy code
gradle.afterProject { project ->
    println("Project: ${project.name}")
    project.pluginManager.withPlugin('com.javiersc.semver') {
        println("Plugin: com.javiersc.semver is applied")
        project.extensions.configure(SemverExtension) { semver ->
            semver.mapVersion Map.per
        }
    }
}
The
Plugin: com.javiersc.semver is applied
is only shown for the projects that explicitly apply the plugin. Can the implementation break the mapping? • https://github.com/JavierSegoviaCordoba/semver-gradle-plugin/blob/c402c81e05b77cb34315c23c89e2ee312a218b8d/semver-settings-gradle-plugin/main/kotlin/com/javiersc/semver/settings/gradle/plugin/SemverSettingsPlugin.kt#L8-L15 • https://github.com/JavierSegoviaCordoba/semver-gradle-plugin/blob/c402c81e05b77cb34315c23c89e2ee312a218b8d/semver-gradle-plugin/main/kotlin/com/javiersc/semver/gradle/plugin/SemverPlugin.kt#L13-L17
v
SemverPlugin
does have that ID, not
SemverProjectPlugin
But the latter is what you apply directly from your
SemverSettingsPlugin
j
You are right, I am going to try to find a workaround for this as the ids for settings and project are just there because, I think, I cannot reuse the same ID on two plugins.
The only way to have only one ID is by removing applying a different plugin and just put directly the logic there, right?
Copy code
public class SemverPlugin : Plugin<PluginAware> {
    override fun apply(target: PluginAware) {
        when (target) {
            is Project -> target.pluginManager.apply(SemverProjectPlugin::class)
            is Settings -> target.pluginManager.apply(SemverSettingsPlugin::class)
            else -> error("Semver cannot be applied to ${target::class}")
        }
    }
}
v
No, just apply the
SemverPlugin
in your
SemverSettingsPlugin
j
Could it not be a problem that the callback
pluginManager::withPlugin
would be for
SemverPlugin
which is applying other plugins but not doing anything itself? No weird race conditions or something so?
v
The
SemverProjectPlugin
and
SemverSettingsPlugin
don't necessarily need own plugin IDs, unless you want to be able to apply them directly using the respective ID or react to those being applied. If you just consider them an implementation detail, you should also be fine.
Could it not be a problem that the callback
pluginManager::withPlugin
would be for
SemverPlugin
which is applying other plugins but not doing anything itself?
No weird race conditions or something so?
Well, if you apply one of the sub-plugins directly without applying the delegating plugin, you cannot react using the delegating plugin id. But if you consider them an implementation detail and maybe even make the sub-plugins
internal
, I don't think there should be any problems.
j
Perfect! Thank you šŸ™ Currently I would have a circular dependency issue as the semver plugin module is depending on settings one to do
Copy code
when (target) {
            is Project -> target.pluginManager.apply(SemverProjectPlugin::class)
            is Settings -> target.pluginManager.apply(SemverSettingsPlugin::class)
            else -> error("Semver cannot be applied to ${target::class}")
        }
So I think I need to merge those two into one
v
I don't see where you would have a circle
You apply the context is a different one
j
SemverPlugin
belongs to the project
semver-gradle-plugin
, and it applies
SemverSettingsPlugin
which belongs to the project
semver-settings-gradle-plugin
As the first one needs the second one to do the
when
I mentioned above, the settings project cannot depend on the project that contains the
SemverPlugin
I need to merge
semver-gradle-plugin
and
semver-settings-gradle-plugin
into one module to avoid that problem
v
Ah, yeah, that might be true if it is in different projects. Unless you apply using the ID of course, that could work.
j
I think I will go with the ID as it is better to have it separated, thanks!
On similar setups, the "synthetic" ID is useful or it is better to remove them to catch issues earlier?
v
That's really fully dependent on what you want
šŸ‘ 1
j
In the past, I had issues related to using the same name on an extension that can be provided by the project and the settings plugin. That led me to use
hubdle
and
hubdleSettings
and I think I can have this issue again if try to do the same with
semver
. I am not sure if the problem was that
hubdle
was indeed a Kotlin extension function too and not a Gradle extension itself. Have you seen that issue before? Creating the Kotlin extension for the settings plugin can be problematic on Groovy? I do not use Groovy at all but some users of my plugin are using it so I need to take care with this topic.
v
Yes, using Kotlin extensions functions is of course always a problem. • you leave behind anyone not using Kotlin • the extension function is always present, even if you do not apply the plugin but just have it in the classpath, so it fails at runtime instead of compile time for Kotlin DSL You should always prefer to use proper Gradle extensions instead, as those work seemlessly and the same on all DSLs and are only available if the plugin really is applied. But even if you use Kotlin extension functions it should be possible in a way that you do not need different extension functions, as the receiver should be different. Actually imho using Kotlin or Groovy in a public plugin is seldomly a good idea, especially when it comes to compatibility. I'd always prefer to use the lowest Java supported by the lowest Gradle version I want to support to maximize compatibililty.
j
But is it possible to use Gradle extensions on settings plugins?
I was meaning about the accessor, look like the accessor is only a problem on Kotlin and as I am not creating adding the custom function extension with the same signature as I was doing in Hubdle, the problem is not happening
v
Yes, you can use extensions in settings plugins. If Gradle is too old you need to configure by class like
configure<SemverSettingsExtension> { ... }
or use an extension function the plugin provided as no accessors were generated, but since some time you should even get type-safe accessors generated.
j
Nice one! I am going to try to remove the extension. Thank you!
šŸ‘Œ 1
It works šŸ‘
šŸ‘Œ 1