392

I don't understand gradle plugins block

apply plugin: 'someplugin1'
apply plugin: 'maven'

and other one:

plugins {
   id 'org.hidetake.ssh' version '1.1.2'
}

In first block We have some plugin name. in second one package and version. I don't understand where I should use first block and when second one.

Yevgen Kulik
  • 5,713
  • 2
  • 22
  • 44
  • 117
    With Gradle, get ready for seeing 2+ ways to do the same thing! – Paulo Merson Apr 05 '18 at 18:18
  • 52
    Gradle is the Perl of build systems. – sakra Oct 23 '19 at 12:32
  • Just as a note, in second case with `plugins {}` you don't use package, but rather fully qualified plugin id. Check for details in Gradle documentation https://docs.gradle.org/current/userguide/custom_plugins.html#sec:creating_a_plugin_id – RenatoIvancic Jun 02 '21 at 20:06

7 Answers7

320

The plugins block is the newer method of applying plugins, and they must be available in the Gradle plugin repository. The apply approach is the older, yet more flexible method of adding a plugin to your build.

The new plugins method does not work in multi-project configurations (subprojects, allprojects), but will work on the build configuration for each child project.

I would think that as functionality progresses, the plugins configuration method will overtake the older approach, but at this point both can be and are used concurrently.

cjstehno
  • 13,468
  • 4
  • 44
  • 56
  • 15
    Keep in mind, that applying a plugin using the plugins DSL (`plugins {...}`) does not work for your private plugins or company plugins which are not published to the official Gradle plugin repo. That's why I hope the old approach will at least survive until the new one does support searching in private repositories. – Datz Aug 16 '19 at 21:07
  • 5
    `plugins` works in multi-project, according to Gradle tutorial (Gradle version 5.6.2) https://guides.gradle.org/creating-multi-project-builds/#add_documentation It uses `plugins` block with `apply false` to add the plugin to the overall project, but doesn't add it to the root project. The subproject uses `plugins` blocks again to add the plugin. – yetsun Sep 29 '19 at 01:38
  • 53
    This is absolutely terrible, two directives with completely different syntax and inputs, on top of which being incompatible. Gradle is by far the largest pain in the neck when using Java and Kotlin. – Christian May 23 '20 at 15:24
  • 2
    @Christian, Maven is by far the largest pain in the neck when using Java... and I have no idea about it's Kotlin support. – Berin Loritsch Oct 14 '20 at 14:56
  • 7
    @Datz since Gradle 6 you can use your own custom plugins (and even disable the official Gradle plugin repo) by defining repositories in a pluginManagement block in settings.gradle. – Peter Headland Nov 03 '20 at 22:44
  • @Datz where your private or company Java library published? I used to build a private Nexus center and publish a private plugin to it. I don't think it's a problem to use `plugins` block – jerry Dec 11 '22 at 19:47
  • @jerry maybe the `plugins` block now supports private repositories? I can't tell because I don't use Gradle at the moment. – Datz Dec 12 '22 at 07:32
  • From I write my first plugin, it was supported. Defined at `settings.gradle` or `init.gradle` in [pluginManagement](https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_management) block – jerry Dec 12 '22 at 18:20
  • It's like the Gradle team just makes it work without following any convention. – emeraldhieu Jun 05 '23 at 19:18
115

As already mentioned by @cjstehno the apply plugin is a legacy method that you should avoid.

With the introduction of the plugins DSL, users should have little reason to use the legacy method of applying plugins. It is documented here in case a build author cannot use the plugins DSL due to restrictions in how it currently works.

With the new plugins block method, you can add a plugin and control when to apply it using an optional parameter apply:

plugins {
    id «plugin id» version «plugin version» [apply «false»]
}

You would still use the legacy method in situations where you want to apply an already added but not applied plugin in your plugins block. E.g, in the master project a plugin xyz is added but not applied and it should be applied only in a subproject subPro:

plugins {
  id "xyz" version "1.0.0" apply false
}

subprojects { subproject ->
    if (subproject.name == "subPro") {
        apply plugin: 'xyz'
    }
}

Notice that you don't need the version anymore. The version is required in the plugins block unless you are using one of the Core Gradle plugins, such as java, scala, ...

I spent some time understanding the difference while trying to create a Spring Boot application, and that's why I am answering this again after a while. The following example for using Spring Boot plugin helped me a lot:

What should currently be used:

plugins {
  id "org.springframework.boot" version "2.0.1.RELEASE"
}

What had been used before Gradle 2.1:

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE"
  }
}

apply plugin: "org.springframework.boot"
Mousa
  • 2,926
  • 1
  • 27
  • 35
  • 5
    This somehow gives the wrong impression. One cannot simply convert `apply plugin xxx` to `plugins { id xxx }` (I tried it and it didn't work) – Christian May 23 '20 at 15:33
  • 1
    I think the answer and the quoted documentation states this clearly. This depends on your case. You can provide more information about your case or post this in a different question. – Mousa Jun 30 '20 at 07:29
  • In my case I was able to convert from the old approach to the new one successfully, for plugin 'org.openapi.generator' just removed the buildscript block and the old apply plugin line and used the id and version inside of plugins block, it worked well – raspacorp Mar 10 '22 at 22:20
  • 2
    If you want to convert `apply plugin` to `plugins { id xxx }`, you might find your plugin at https://plugins.gradle.org/ which will give you the correct `id`, that is often slightly different than the qualified name used with `apply plugin`. – Monkey Supersonic May 18 '22 at 08:10
15

These are two different ways to use Gradle plugin。

The apply plugin way: First resolve plugin you needed from root build.gradle like:

buildscript {
        repositories {
            // other repositories...
            mavenCentral()
        }
        dependencies {
            // other plugins...
            classpath 'com.google.dagger:hilt-android-gradle-plugin:2.44'
    }

Then in the build.gradle of your Android Gradle modules apply the plugin:

apply plugin: 'com.android.application'
apply plugin: 'com.google.dagger.hilt.android'

The plugins way:combine resovle and apply where in your root build.gradle like:

plugins {
    // other plugins...
    id 'com.google.dagger.hilt.android' version '2.44' apply false
}

Then in the build.gradle of your Android Gradle modules apply the plugin:

plugins {
    // other plugins...
    id 'com.android.application'
    id 'com.google.dagger.hilt.android'
}

android {
    // ...
}
RexHuang
  • 151
  • 1
  • 4
  • 1
    I am migrating my gradle files from the old "apply plugin" to the new "plugins {}" approach and I have problems finding proper ids for given dependencies. Is there an universal approach for this? I am currently stack on implementing dependency from: https://github.com/google/play-services-plugins/blob/master/oss-licenses-plugin/README.md Any suggestions on how to find its id for plugins block? – Koger Oct 27 '22 at 11:18
8

Now ( In Gradle 6) you can give repositories name for plugins without using build script. In settings.gradle, we can add plugin pluginManagement

pluginManagement {
    repositories {
        maven {
            url '../maven-repo'
        }
        gradlePluginPortal()
        ivy {
            url '../ivy-repo'
        }
    }
}

Reference: https://docs.gradle.org/current/userguide/plugins.html#sec:custom_plugin_repositories

reinaldoluckman
  • 6,317
  • 8
  • 42
  • 50
Punj
  • 151
  • 2
  • 5
6

I'm going to add a little twist to what's been said. Gradle introduced the concept of a plugins block as a technique to speed up and optimize the build process. Here's what Gradle's documentation says:

This way of adding plugins to a project is much more than a more convenient syntax. The plugins DSL is processed in a way which allows Gradle to determine the plugins in use very early and very quickly. This allows Gradle to do smart things such as:
Optimize the loading and reuse of plugin classes.
Provide editors detailed information about the potential properties and values in the buildscript for editing assistance.
This requires that plugins be specified in a way that Gradle can easily and quickly extract, before executing the rest of the build script. It also requires that the definition of plugins to use be somewhat static.

It's not just a newer way of dealing with plugins, it's a way of improving the build process and/or user's editing experience.

In order for it to work, it needs to be specified at the top of the build, but it also needs to be specified after the buildscript block if one is included. Why is that? Because the code in the build scripts is evaluated in the order its written. The buildscript block must be evaluated before the plugins block is evaluated. Remember, the buildscript block is about setting up of the plugin environment. Hence the rule that the plugins block must be specified after the buildscript block.

The new plugins block not only specifies the plugins that the project is using, but it also specifies whether the plugin is applied. By default, all plugins in the plugins block are automatically applied, unless it is specifically declared not to be applied (i.e., adding "apply false" after the plugin declaration in the plugins block).

So why would you declare a plugin and not apply it. There are two main reasons that I can think of:

1.) so you can declare the version of the plugin you want used. After you've declared a plugin, the plugin is now on the "classpath". Once a plugin is on the classpath you no longer need to specify the version of the plugin when you apply it later. In multiproject builds, that makes supporting buildscripts a little easier. (i.e., you only have one place where the plugin version is specified.)

2.) Sometimes, you may have a plugin, that requires certain things defined before they are applied. In that case, you can declare a plugin in the plugins block, and defer the plugin from being applied until after you define the things that the plugin requires as input. For example, I have a custom plugin that looks for a configuration named "mavenResource". In the dependencies block I'll added a dependency like: "mavenResource(maven_coordinate)". That plugin will find all the dependencies contained in the mavenResource configuration and copy the associated maven artifact to the projects "src/main/resources" directory. As you can see, I don't want to apply that plugin until after the mavenResource configuration is added to that project, and the mavenResource dependencies are defined. Hence, I define my custom plugin the plugins block, and I apply it after the project dependencies have been defined. So, the concept that applying a plugin is old style and wrong is a misconception.

Some of you might wonder what it means to apply a plugin. It's pretty straightforward. It means that you call the plugin's apply function passing it the Gradle Project object for the project where the plugin is being applied. What the plugin does from there on is totally at the discretion of the plugin. Most commonly, the apply function usually creates some Gradle tasks and adds them to the Gradle build task dependency graph. When Gradle starts its execution phase, those tasks will get executed at the appropriate time in the build process. The plugin apply function can also do things like deferring some of it work until afterEvaluate. That's a way to allow other things in the build script to be setup even though they are defined later on in the buildscript. So, you might ask why I didn't do that trick in my custom plugin. What I've observed is that the next subproject starts processing after the root project finishes being evaluated. In my case, I needed the resource added before the next subproject began. So, there was a race condition, that I avoided by not doing the afterEvaluate technique and specifically applying the plugin once the things I needed setup was completed.

Tom Rutchik
  • 1,183
  • 1
  • 12
  • 15
3

I would like to point out though, that is it not required for a plugin to be published remotely to be able to use it! It can also be a UNPUBLISHED locally available plugin (be it convention plugins or otherwise) just as well.

In case one wishes to refer to such an unpublished locally-available plugin, you'll have to include it's so-called "build" within the desired component/build (identified via the settings.gradle(.kts)-file) like so:

pluginManagement {
    includeBuild '<path-to-the-plugin-dir-containing-the-settings-file>'
}

Afther that is done, one may use the local plugin within the plugins {}-DSL-block via its pluginId.

2

If the plugin needs a version then it's safer to put the version number in the pluginManagement block in your settings.gradle file, rather than in plugins block.

By safer I mean that you won't encounter an error like plugin request for plugin already on the classpath must not include a version. That can happen if you includeFlat a project into another project that uses the same plugin and your plugin versions are in the plugins block.

So rather than:

plugins {
    id 'pl.allegro.tech.build.axion-release' version '1.10.3'
}

Do:

plugins {
  id 'pl.allegro.tech.build.axion-release'
}

and then in your settings.gradle file:

pluginManagement {
    plugins {
        id 'pl.allegro.tech.build.axion-release' version '1.10.3'
    }
}
Joman68
  • 2,248
  • 3
  • 34
  • 36