NOTE: As mentioned in a comment to this article, Gradle 7 offers version catalogs as incubating feature which are a much better solution to this problem!
Dependencies in Gradle composite build
In Gradle projects with multiple subprojects quite often the subprojects use common dependencies. We want to make sure that all the dependencies have the same version and save us some typing. Until recently the common way to define the versions of these dependencies was in the buildSrc
subproject.
This is now discouraged because every change to buildSrc
causes the whole project to be rebuilt. This doesn’t allow us to take advantage of build caching and is a big time waste. Please refer to the linked article for very convincing benchmarks comparing build times with and without buildSrc
.
The aforementioned article also mentions how to solve this problem by using Gradle composite builds. For your custom Gradle plugins simply create an included build in your project and put your plugin code there.
For the dependencies list the article recommends to create a dependencies plugin and also put it in the included build. However I struggled a bit with the exact steps how to implement it, that’s why I decided to write down an easy to follow how-to guide.
I have also created an example project where I use Gradle composite build. This is the exact commit where I moved the dependency versions from buildSrc
to an included build in the gradlePlugins
directory.
Create a gradlePlugins subproject
In your project’s root directory create a subproject for all your plugins. I named it gradlePlugins
:
You need to register this subproject in settings.gradle.kts
as an includeBuild
:
includeBuild("gradlePlugins")
Now this directory is registered as a regular Gradle project and we can work in it.
Configure gradlePlugins build file
Create a build.gradle.kts
file inside gradlePlugins
. In this file you need to configure the Kotlin DSL and set repositories (this is important as for some reason Gradle doesn’t reuse here the repositories you defined in your root project build.gradle.kts
):
Now we can migrate our dependency versions to gradlePlugins
project.
Create DependenciesPlugin
Inside the gradlePlugins
project create first the src/main/kotlin
directory. It should be recognized by IntelliJ as a source directory and marked blue (if not make sure you have synced your last Gradle file changes).
Inside this directory create a package for your plugins. I named it like my application main package with the gradle
subpackage appended at the end:
As you see I also created a class file for my DependenciesPlugin
. Let’s see what we need to put there.
DependenciesPlugin source code
As you see this is just an empty Gradle plugin (the apply()
method doesn’t do anything). It ‘s just a container for the companion object
where I can now put all the dependency versions I want to reuse:
Next step will be to tell Gradle how we want to access this plugin in other subprojects.
Register DependenciesPlugin
To register created plugin we have to modify gradlePlugins/build.gradle.kts
. We need to give this plugin an id
so that we can apply it in other subprojects, and we need to tell what class is implementing this plugin’s logic (this is the class we just created).
We can do it inside the gradlePlugin
closure:
Now that plugin is already known in our project, let’s make use of it.
Apply DependenciesPlugin
In my project I have dependency on the Koin library in two subprojects: androidApp
and shared
(it’s a Kotlin Multiplatform project).
Let’s take as an example the androidApp/build.gradle.kts
. We need to do three things to use our DependenciesPlugin.koinVersion
here.
- Apply the
DependenciesPlugin
inside theplugins
block - Import the package of the
DependenciesPlugin
companion object - Use the
DependenciesPlugin.koinVersion
insidedependencies
as the version number for Koin
It all looks like this:
Now we can use the DependenciesPlugin
in the same way in the shared
subproject and all other subprojects.