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 only 2 mechanisms, which you already identified:

    1. (legacy) the buildscript dependency + apply
    2. (current) the plugins block

    Your plugins block seems to have multiple approaches, but those are really just helpers for the second mechanism:

    Important background

    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.

    The plugins block was introduced to streamline this and make it more convenient. When you add a plugin there, it is both added to the classpath AND applied to the project.

    You can still choose to only add a plugin to the classpath without applying it to the current project by adding apply false after the plugin declaration:

    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")
    }
    

    Plugins without version

    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 (kotlin-dsl) 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.

    "Standardize" the plugins block

    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, and I even had to search for this ID which is never advertised anywhere.

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