Reputation: 41
I'm working on a springboot microservices application using Gradle and I want to have a separate parent module for all the common parts that is going to be used by all of my microservices (abstract entities, common properties, dependencies versions ...). This parent module is going to have it's own repository. I have done something similar when I worked on a maven app, by having a <packaging>pom</packaging>
for the parent project.
So my questions are, Am I doing the right thing by separating the common aspects of my application in a separate repository ? and what is the best way to do so in gradle ?
Edit :
In order for me to be more precise about my problematic, I want to do what is described in this approach using Gradle instead of maven.
https://stackoverflow.com/a/27865893/8326336
Thank you for your help.
Upvotes: 1
Views: 1006
Reputation: 101
Personally I would try to reuse only complex parts, or complex tasks/plugins if really needed. There is a maintenance cost with "parent logic" especially for things that change often and a lot flexibility can be lost. Also updating multiple dependent projects is not fun. So be careful.
With Gradle it's possible to reuse some common build logic. One way of doing this is to create a convention Gradle project. I will use Kotlin dsl in examples, but same thing can be done with groovy.
First create a normal Gradle project and put in build.gradle.kts config like:
plugins {
// Kotlin dsl plugin since we will use Kotlin dsl
// (you can also use Groovy version if you like Groovy)
`kotlin-dsl`
// Plugin needed to publish it
id("maven-publish")
}
repositories {
// This repository is needed for getting kotlin-gradle-plugin,
// you can also add any other repo here if you add any other dep.
gradlePluginPortal()
}
dependencies {
// This is needed so we can access gradle constructs
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30")
}
publishing {
// Config to publish it
publications {
create<MavenPublication>("maven") {
group = "com.mycompany"
artifactId = "gradle-conventions"
version = "1.0.0"
from(components["java"])
}
}
repositories {
// my repositories where I want publish this
}
}
Where to put common logic? You put it in src/main/kotlin
(or groovy if you use groovy). So lets create such structure:
└── src
└── main
└── kotlin
├── dependencies
│ └── CommonDependencies.kt
├── my-company.java-conventions.gradle.kts
Where CommonDependenies.kt
has our dependencies:
package dependencies
open class CommonDependencies {
val guava = "com.google.guava:guava:30.1.1-jre"
}
and my-company.java-conventions.gradle.kts
has our common Java settings:
import dependencies.CommonDependencies
plugins {
id("java-library")
}
// register extension so we can nicely access variables from CommonDependencies
extensions.create<CommonDependencies>("commonLibs")
java {
// All our projects will use toolchains with Java11
toolchain.languageVersion.set(JavaLanguageVersion.of("11"))
}
tasks.test {
// All our projects use Junit
useJUnitPlatform()
}
Now since this is a regular project you can publish it to maven repo. For testing purposes, let's publish it to local maven repo with:
./gradlew publishToMavenLocal
Ok, our conventions are all set. Now how we can use them?
In consumer project we have to add our project to build logic classpath. This can be done by adding our project to buildSrc/build.gradle(.kts)
or to buildScript. Lets for example put it into buildSrc.
buildSrc/build.gradle.kts
example:
repositories {
// I have put maven local here just because I published
// convention project to maven local
mavenLocal()
gradlePluginPortal()
}
dependencies {
implementation("com.mycompany:gradle-conventions:1.0.0")
}
And after this is set, IDE reloaded, you can use your conventions in your modules. Example:
plugins {
id("my-company.java-conventions")
}
dependencies {
implementation(commonLibs.guava)
}
includeBuild()
. For example if you have projects in same folders like that:├── gradle-conventions
├── gradle-project-consuming-conventions
You would do in settings.gradle(.kts) of gradle-project-consuming-convention: includeBuild("../gradle-conventions")
In my-company.java-conventions.gradle.kts
you can skip my-company
. Name it however you think is best, just be careful that it does not conflict with official plugins.
I used Gradle 7.2
Upvotes: 3