How to write Gradle plugins - answers to common questions and alternative implementation solutions

Overview

Gradle Plugins: Why? How?

There is some misunderstanding and confusion about the concept of Plugins in Gradle. This is unfortunate, as it is one of the central concepts of Gradle. This README, together with the examples in this repository, aims at clarifying the most central points and questions.

For a quick introduction on the topic, you may also watch this 5min video:

Table of contents

FAQ

Is writing a Gradle Plugin super complicated?

No.

I only use Gradle in my Java/Android application multi-project - do I need to write plugins?

Yes. Plugins are the mechanism to put build/project configuration in a central place.

Do I need to learn Kotlin or Groovy to write Gradle plugins and to configure my build?

No. You can use Java (or Scala) if you prefer.

What is a 'Core Plugin'?

The term core plugin refers to a plugin that is part of the Gradle distribution – for example id("java-library"). It is always available.

What is a 'Community Plugin'?

The term community plugin refers to a plugin published to the Gradle Plugin Portal or another repository - for example id("com.diffplug.spotless").
To make a community plugin available so that you can use it similarly to a core plugin, you need to declare the repository that provides the plugin - for example: repositories.gradlePluginPortal().
And you need to define a dependency to the plugin - for example:
implementation("com.diffplug.spotless:spotless-plugin-gradle:6.1.0").

What is a 'Convention Plugin'?

The term convention plugin refers to a plugin you write yourself in a plugin build (aka build logic or builSrc build). It is a separate Gradle build that you link to your main build by using the includeBuild() statement in the pluginManagement {} block of your settings file - for example includeBuild("gradle-build-logic"). A convention plugin usually composes existing core plugins and community plugins and configures them with your own conventions - for example setting the Java version via java.toolchain.languageVersion.set(JavaLanguageVersion.of(17)).

When do I NOT need to write a plugin?

You do not need convention plugins when your project is small and isolated so that it does not consist of multiple subprojects. That is, you only have one build.gradle(.kts) script. In this case, you can do all the build configuration in this one script and apply community plugins directly with a version (without dependency declaration) in that script - for example id("org.jetbrains.kotlin.jvm") version "1.5.21".

My projects are small, but I have many of them in a multi-repo setup - what now?

You put your convention plugins into a separate Git repository and use that to share build configuration among all your small builds. You can either use the local clone of that Git repository directly via includeBuild(), or publish your convention plugins to a Maven repository and then use them in your builds as if they were community plugins.

Do I need to use a specific way of implementing a Plugin to use a certain Gradle feature?

No. In all cases, all features are accessed through a Java API. You can choose freely between the options presented below.

I... have more questions

Please ask by opening an issue.

Different Options for Writing Plugins

The choice of how to implement a plugin is purely technical and depends on your and your team's preference of language and tools. Some considerations are listed below.

If you intend to write a plugin for local use ony (convention plugin) or for publishing it to share it between multiple builds in different repositories for a wider audience (community plugin) does not influence this choice.

Choices for implementing a plugin

  1. Use Gradle's Kotlin DSL - The plugin ls a .gradle.kts file (preferred for convention plugins in most cases)
  2. Use Gradle's Groovy DSL - The plugin is a .gradle file
  3. Write a Java class (or a Scala/Kotlin/Groovy/.. class) - The plugin is an abstract class that implements the apply(Project project) method of the Plugin<Project> interface.

Technically, (1) and (2) are called pre-compiled script plugins because Gradle will generate a class - similar to option (3) - from the Gradle DSL script.

How do I do it?

This repository contains an example in 7 different flavors using different approaches/languages. You can download one of the examples to explore or as a starting point for your own project (via download-directory.github.io):

Here are the typical things you need to do when writing a plugin. They are shown here as a list of successive commits in this repository. Each commit does the corresponding thing in all 7 approaches. It is exactly the same thing in each approach just with different syntax. This helps to understand the differences between them.

The example project does not contain any source code, but is ready for Java development. If you open the project you downloaded with IntelliJ IDEA, you can create Java source folders and files through the IDE.

To build the project:

  • Run ./gradlew build to build the Java example project
  • To publish plugins to a custom repository, run ./gradlew :gradle-build-logic:java-plugins:publish
  • To publish plugins to the plugin portal, run ./gradlew :gradle-build-logic:java-plugins:publishPlugins

Other resources and feedback

This repository is about explaining the different technical approaches of writing plugins. It's not so much about how to actually configure specific things in Gradle. It only shows examples of the most prominent things (Extensions, Task Configuration, Dependency Declaration).

Which Option should I choose?

Here are a few things to consider. There is no one-fits-all right choice.

But there is the good news that all approaches can be combined. If you split your build configuration into many small plugins, which you should do anyway for good structure and readability, you can use a different approach for each plugin. Thus, if at some point you want to migrate from one approach to another, you can do it step-by-step.

Here is a non-exhaustive list of aspects you may consider when making the choice.

Conceptual considerations

  • General readability and compactness: The Kotlin DSL and Groovy DSL solutions are more compact and thus generally simpler to read and to maintain. That's why Gradle provides them in the first place. However, other factors below might overrule this advantage.
  • IDE Support: If you use IntelliJ IDEA, the support for Kotlin DSL is quite good nowadays. You get code completion, code navigation, and proper warnings in your plugin scripts. So if you use IDEA and have no other preference, due to the compactness argument above, Kotlin DSL is often the best choice. If you mainly use Eclipse for example, you probably don't do Kotlin development as Kotlin is not well-supported. Then another language might be the better choice from the tooling perspective.
  • Language preference, experience and languages use in other parts of the Project (now and future): If the build configuration looks alien to most developers in a team, chances are high that it ends up unmaintained at some point leading to more trouble later. If the configuration is performed in a familiar language, getting into it is usually easier for developers not familiar with Gradle. So if your work, for example, on a pure Java (Scala) project, doing everything in Java (Scala) might be a better choice despite some more verbose syntax. This not only concerns the current state of the project but also the future. E.g. if there are plans to gain Kotlin knowledge to do Kotlin development in the future, you might as well start with Kotlin DSL for your build configuration.

Technical/performance considerations and other caveats

  • Kotlin DSL compilation time: Although conceptually Kotlin DSL is the best choice most of the time, there is a technical drawback. The compilation of Kotlin code and scripts is slower compared to pure Java or Groovy. However, you will only notice this with a larger amount of build configuration. Furthermore, the results of the compilation are cached. The issue only manifests when you change build configuration. Builds that you run after the scripts have been compiled already, are not affected by this drawback. Both JetBrains and Gradle are working on improving this and the disadvantage will probably go away long term. If this is an issue for you anyway, but you still want to use a DSL, you could consider the Groovy DSL instead.
  • Kotlin runtime (standard library) version is fixed by Gradle: If you use Kotlin DSL or Kotlin for your plugins, you need to be aware that it will run against the Kotlin version packaged with Gradle. If you use kotlin-dsl in plugin development, you will automatically develop against the Kotlin version packaged with the Gradle distribution you are using. This is only a concern if you publish plugins publicly (e.g. to the Plugin Portal) that are used with multiple Gradle versions. You do not have this concern when developing plugins in plain Java.
  • Groovy runtime (standard library) version is fixed by Gradle: The issue described above also applies for plugins developed in Groovy DSL or Groovy.
  • Other runtimes/dependencies: If your plugin has dependencies, for example the Scala Library, it can only be combined with other plugins that have the same dependencies if all plugins work with compatible versions of the dependencies. Gradle loads all the plugins and their dependencies together because they may interact with each other. Thus, if there are dependency conflicts, Gradle's dependency resolution will resolve them and select only one version of a dependency. This is only a concern if you publish plugins publicly (e.g. to the Plugin Portal) where you do not know with which other plugins they may be combined. This is a general concern to be aware of with all approaches. But it's specific if the language you use forces you to have a certain dependency (Scala and Clojure in the examples). If you develop a community plugin that you share, it is preferred to use a language that Gradle can run without additional dependencies (Java, Kotlin or Groovy).
You might also like...
A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes.
A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes.

Change Tracker Plugin A Gradle plugin to help analyse the dependency between modules and run tasks only on modules impacted by specific set of changes

Android Gradle Plugin -- Auto Check big image and compress image in building.

McImage I will continue to update, please rest assured to use 中文文档 Android优雅的打包时自动化获取全部res资源 McImage is a Non-invasive plugin for compress all res in

Gradle plugin that generates a Swift Package Manager manifest and an XCFramework to distribute a Kotlin Multiplatform library for Apple platforms.

Multiplatform Swift Package This is a Gradle plugin for Kotlin Multiplatform projects that generates an XCFramework for your native Apple targets and

Gradle Plugin for publishing artifacts to Sonatype and Nexus

Introduction Due to Sonatype's strict validation rules, the publishing requirement must be satisfied by every artifact which wants to be published to

Gradle plugin that parses version updates and assigns them to groups of people.

Notifier Gradle Plugin This gradle plugin serves the need of automating how dependencies are handles in a project. More specifically, it functions usi

A Gradle plugin enforcing pre-commit and commit-msg Git hooks configuration

A Gradle plugin enforcing pre-commit and commit-msg Git hooks configuration. Conventional-commits-ready.

Klinker is a gradle plugin making it possible to link kotlin native executables with custom linkers and options.

Klinker is a gradle plugin making it possible to link kotlin native executables with custom linkers and options. It does this by creating a static library for kotlin compilation, then generates a c+kotlin wrapper that calls into kotlin to start the app, finally using the specified compiler to compile and link the c code and kotlin library into a binary.

Gradle plugin to check, if rest-controllers are used by clients and clients have suitable rest-interfaces

Verify-Feign Gradle Plugin This plugin will help you to verify all rest-clients and -controllers in a multimodule spring project. It will check, if al

The core Gradle plugin and associated logic used for Slack's Android app

slack-gradle-plugin This repository contains the core Gradle plugin and associated logic used for Slack's Android app. This repo is effectively read-o

Owner
Jendrik Johannes
Jendrik Johannes
Kmp4free - A Gradle Plugin that allows seamless switching between Kotlin JVM and the Kotlin Multiplatform Plugins

?? kmp4free Allows you to toggle between Kotlin JVM Plugin -> Kotlin Multiplatform with a Gradle Property kmp4free=true. This Gradle Plugin was built

Sam Edwards 61 Oct 14, 2022
Kotlin Gradle plugins for conveniently setting up Kotlin projects (JVM/MPP), publishing, Dokka, etc

Arrow Gradle config Add basic config to a Kotlin Multiplatform project In an Arrow KMP project, just add to the plugin block: plugins { kotlin("mu

ΛRROW 8 Aug 3, 2022
Gradle plugins for easy start into kotlin

Starter gradle plugins for kotlin The aim The aim of this project is to create a

MIPT-NPM 5 Mar 5, 2022
Showcases different ways of writing backwards-compatible Gradle plugins.

manifestprinter This project showcases different ways of writing backwards-compatible Gradle plugins. It accompanies a talk held at droidcon Berlin 20

Simon Schiller 5 Jul 12, 2022
Gradle Plugin to automatically upgrade your gradle project dependencies and send a GitHub pull request with the changes

Gradle Plugin to automatically upgrade your gradle project dependencies and send a GitHub pull request with the changes

Dipien 142 Dec 29, 2022
Gradle plugin to ease Kotlin IR plugin development and usage in multimodule gradle projects

Gradle plugin to ease Kotlin IR plugin development and usage in multimodule gradle projects. Former: kotlin-ir-plugin-adapter-gradle

null 2 Mar 8, 2022
Useful and Fun plugins to use for Aliucord!

♥ Aliucord Plugins ♥ What do I need to use plugins ? To obtain Aliucord plugins (Plugins for Discord) make sure you have Aliucord installed! If you do

Link 10 Sep 2, 2022
Free plugins for kraken using the community api.

Community Plugins Free plugins for kraken using the community api. Wiki Make sure you read the Wiki for guides and information on how to use the commu

RSKrakenCommunity 2 Jun 25, 2022
Gradle Plugin to enable auto-completion and symbol resolution for all Kotlin/Native platforms.

CompleteKotlin Gradle Plugin to enable auto-completion and symbol resolution for all Kotlin/Native platforms. What this plugin provides This zero-conf

Louis CAD 235 Jan 3, 2023
Gradle Plugin that allows you to decompile bytecode compiled with Jetpack Compose Compiler Plugin into Java and check it

decomposer Gradle Plugin that allows you to decompile bytecode compiled with Jetpack Compose Compiler Plugin into Java and check it How to use Run bui

Takahiro Menju 56 Nov 18, 2022