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"))
}
Gradle's Kotlin DSL provides an alternative syntax to the traditional Groovy DSL with an enhanced editing experience in supported IDEs, with superior content assist, refactoring, documentation, and more.
Gradle allows you to define one or more default tasks that are executed if no other tasks are specified. defaultTasks 'clean', 'run' tasks. register('clean') { doLast { println 'Default Cleaning! ' } } tasks.
gradle file which helps Gradle build tool to specify this build is a debug build with certain keyAlias etc. So these building blocks, API, etc are formats to use Gradle in android, hence called Gradle DSL (domain-specific language).
To see which tasks are available for our build we can run Gradle with the command-line option -t or --tasks. Gradle outputs the available tasks from our build script. By default only the tasks which are dependencies on other tasks are shown. To see all tasks we must add the command-line option --all.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With