Search code examples
kotlingradlegradle-plugingradle-kotlin-dsl

Understanding all the ways to apply a plugin in Gradle


I'm trying to understand all the ways you can apply a plugin in Gradle, Kotlin DSL. This question answers part of my question, but not all of it (I'm guessing methods have been added in the six years that have passed since them).

I've seen this exact scenario in one of my build.gradle.kts files.

plugins{
   `kotlin-dsl`
   kotlin("jvm") version "1.6.10"
   id("com.foo.bar.someplugin") version 1.2.3
}

apply("foo2.bar2.anotherplugin")

Wow, that's four different ways to apply a plugin and I don't really understand the relationship between them at all. From the other answer, I get that apply(...) is the legacy way and will eventually be deprecated, but what about the other three?

Furthermore, I'm confused by why the `kotlin-dsl` doesn't even need a version. What is this voodoo magic?

And finally, for the sake of consistency, I would like to standardize the plugins block (let's ignore the apply(...) since it's legacy functionality) so that everything uses id(...). How do I convert the other two?


Solution

  • There is actually mostly only 2 ways, which you already identified: the buildscript dependency + apply, or the plugins block. What's in your plugins block here is actually just helpers:

    • id("some.plugin.id") version "version" is the basic way of registering a plugin with an ID and a version
    • kotlin() is really just a helper function provided by the Kotlin DSL that calls id() behind the scenes with a org.jetbrains.kotlin. prefix before whatever string you passed. So kotlin("jvm") is just a shorthand for id("org.jetbrains.kotlin.jvm")
    • kotlin-dsl is also a helper function that is a shortcut for the Kotlin DSL Gradle plugin. I believe the string ID is org.gradle.kotlin.kotlin-dsl.

    In the legacy way of applying plugins, you had to declare the dependency on the plugin in the buildscript block so the classes of the plugin are added to the classpath for the compilation/execution of the Gradle script itself. As a second step, calling apply would actually apply the plugin to the current project.

    With the plugins block, both happen at the same time, so it's more convenient to use. You can also add apply false after the plugin declaration so that it's just added to the classpath without also applying it to the project:

    plugins {
        id("com.foo.bar.someplugin") version 1.2.3 apply false
    }
    

    This is useful if you want to declare all plugins and their versions in the root project, and then just apply the relevant ones in subprojects by using the plugins block without versions:

    plugins {
        id("com.foo.bar.someplugin")
    }
    

    Furthermore, I'm confused by why the kotlin-dsl doesn't even need a version. What is this voodoo magic?

    As you can see from the above explanation, any plugin that's already on the classpath doesn't need a version. This applies to plugins that are already declared in a parent project, or in the settings.gradle(.kts)'s plugins, and to built-in Gradle plugins.

    The Kotlin DSL plugin is a built-in Gradle plugin, so it uses a version that's dependent on the version of Gradle you are using. It is similar to the java or application plugins.

    It's also explicitly advised to avoid specifying the version for it in the doc:

    Avoid specifying a version for the kotlin-dsl plugin. Each Gradle release is meant to be used with a specific version of the kotlin-dsl plugin and compatibility between arbitrary Gradle releases and kotlin-dsl plugin versions is not guaranteed. Using an unexpected version of the kotlin-dsl plugin in a build will emit a warning and can cause hard to diagnose problems.

    Now as for your other question:

    I would like to standardize the plugins block (let's ignore the apply(...) since it's legacy functionality) so that everything uses id(...). How do I convert the other two?

    The way they are written here is quite idiomatic, so this should be considered the "standard". This is actually how it's advised to be used in the doc. Using kotlin-dsl is a nice way to distinguish built-in Gradle plugins from third party plugins. Also, it is a type-safe way to declare the plugin, it's understood by the IDE and you can search for references etc. Strings are just inferior in this respect.

    If you really really wanted to apply it with the string-based syntax, you could probably use id("org.gradle.kotlin.kotlin-dsl"), but I've never seen a project do that so far.

    The kotlin() helper could be more debatable, and a matter of personal taste, but IMO the less arbitrary strings, the better.