I really would like to appreciate Gradle 5 especially in combination with the new Kotlin DSL, but I’m having a very hard time to get (in my eyes) a very, very simple and common build running with Gradle.
Release a Java library with several interdependent submodules in Maven default directory layout as high-quality Maven artifacts/repository in a to-the-point, simple Gradle build (i.e. DRY).
Therefore: Have a root project as umbrella which defines & contains all the common configuration (practically all except the real dependencies).
I ported my current "results" to a sample project on Github and asked this question in the Gradle forum already.
Currently I'm failing to declare the necessary task to provide standard -sources
and -javadoc
artifacts in my central build.
For example these three "solutions" which you'll find on looking for a Kotlin DSL based solutions all do no (longer) work in a multi-module scenario:
/build.gradle.kts
)Complete example see on Github: https://github.com/bentolor/gradle-maven-multimodule-kotlindsl
subprojects {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
group = "de.bentolor.sampleproject"
version = "0.1.0"
repositories {
jcenter()
}
dependencies {
// Dependencies used in EVERY module
"compile"("commons-logging:commons-logging:1.2")
"testImplementation"("junit:junit:4.12")
}
tasks {
// not working
/*register("sourcesJar", Jar::class.java) {
from(sourceSets.main.get().allJava)
classifier = "sources"
}*/
// not working, eiher
/* task<Jar>("sourcesJar") {
from(sourceSets.main.get().allJava)
classifier = "sources"
} */
}
configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
configure<PublishingExtension> {
publications {
create<MavenPublication>(project.name) {
from(components["java"])
// won't work, beause inaccessible declaration in `tasks{}`-Block
//add("archives", javadocJar)
//add("archives", sourcesJar)
}
}
repositories {
mavenLocal()
}
}
}
/module2/build.gradle.kts
group = "de.bentolor.sampleproject.module2"
dependencies {
compile(project(":module1"))
}
Try this:
subprojects {
apply<JavaLibraryPlugin>()
apply<MavenPublishPlugin>()
group = "de.bentolor.sampleproject"
version = "0.1.0"
repositories {
jcenter()
}
dependencies {
val implementation by configurations
val testImplementation by configurations
implementation("commons-logging:commons-logging:1.2")
testImplementation("junit:junit:4.12")
}
// This will work, but as long as these tasks are need only for publishing you can declare them inplace later where you need
// tasks {
// val sourcesJar by creating(Jar::class) {
// val sourceSets: SourceSetContainer by project
// from(sourceSets["main"].allJava)
// classifier = "sources"
// }
// val javadoc by getting(Javadoc::class)
// val javadocJar by creating(Jar::class) {
// from(javadoc)
// classifier = "javadoc"
// }
// }
configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
configure<PublishingExtension> {
publications {
create<MavenPublication>(project.name) {
from(components["java"])
// If you configured them before
// val sourcesJar by tasks.getting(Jar::class)
// val javadocJar by tasks.getting(Jar::class)
val sourcesJar by tasks.creating(Jar::class) {
val sourceSets: SourceSetContainer by project
from(sourceSets["main"].allJava)
classifier = "sources"
}
val javadocJar by tasks.creating(Jar::class) {
from(tasks.get("javadoc"))
classifier = "javadoc"
}
artifact(sourcesJar)
artifact(javadocJar)
}
}
}
}
A few notes:
String
-based apply
, when you can do a type-safe apply<T>()
?dependencies
, when you can use delegates, which is less hacky and better refactorable.implementation
instead of compile
Why sourceSets
is not working in a multi-module project?
When you're using Kotlin DSL it generates accessors for projects based on the applied plugins. It's a two-step process: first Gradle processes plugins (that's why it's recommended to put them in plugins
block) and generates accessors and then you can use them in your code (accessors are generated as Kotlin extensions for Project
, NamedDomainObjectContainer
and so on). But if you're configuring subprojects there are two issues:
sourceSets
is one of the accessors generated by Kotlin DSL for children. And it's just not available in parent. You can try it yourself: apply only java
plugin in subprojects
. sourceSets
will be available in children build scripts, but not in parent.
This is also why you can use java
in children, but have to use configure<JavaPluginExtension>
when configuring it in parent.
But you can use delegates to get references for domain objects, like tasks, source sets, configuration and so on.