Painfully UX: Simple use-case overly hard (Gradle 5, Kotlin DSL, multi-modules, java-library with Maven release)


(Ben) #1

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.

Task
Build & release a project with several interdependent submodules in Maven default directory layout and release them as high-quality Maven artifacts/repository in a to-the-point, simple Gradle build (i.e. DRY).

My results (after a day)

I can build & test the modules and create some POM release (3h)
I was able to add a generator as dependency and add an additional src-Directory (3-4h)
The POM release contains -sources and -javadoc (1h)
Support for -SNAPSHOT builds, Version embedded in MANIFEST.MF, …
Add license Information to POM.xml
probably many more “standard” tasks to come

My current struggles
I ported my current “results” to a sample project. See here https://github.com/bentolor/gradle-maven-multimodule-kotlindsl

Currently I’m failing to declare the necessary task to provide standard -sources and -javadoc artifacts in my central build (DRY!)

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:

Rant (Sorry)
In some point the UX for Gradle and the Kotlin DSL in special is really a nightmare. The main issues which really cause me much headaches are:

  • Many samples based on old Kotlin-DSL version out there in the wild (Okay –not particulary s/o “fault”)
  • Reference documentation and Kotlin-DSL examples only describes the “whitepaper scenario” (meaning: single-module cases)
  • Confusing conversions necessary from whenever porting a solution to the submodule case.
    • I.e. dependencies { compile("commons-logging:commons-logging:1.2") } “suddenly” needs to become dependencies { "compile"("commons-logging:commons-logging:1.2") } (note the quotes),
    • task<Jar>("javadocJar") { … } obviously needs to be converted in sth. like a register()?
    • Some attributes suddenly no longer availalable in subproject scope. I.e. from(sourceSets.main.get().allJava) works great in a single-file use-case, but sourceSets becomes inaccessible if wrapped into a subprojects { } block
  • It’s hard to browse the Kotlin DSL. The IDEA autocomplete is veeery laggy and incomplete and does not allow in-depth source navigation. I ended up reading i.e. the Source Code of JavaLibraryPlugin.java to understand what has to be done to add additional source roots.

Please prove me wrong! (aka: Help anyone)

I really would love to see Gradle being a good tool and I’m hoping that I’m simply missing a few basic and simple ways to approach such a common taks.

Can a few knowledgeable guys maybe just spare a short look on my (very!) example project above and try to incrementally improve it to a full-fledged, reference build for simple, multi-modules projects?

Thanks a lot & Sorry for the long rant.


(Ben) #2

Because I did not receive any feedback yet I also syndicated this question on Stackoverflow: Gradle 5 Kotlin DSL: Howto declare common Tasks & Maven Artifacts for submodules in a multi-module Java library.

Publishing is not working after the upgrade to 5.0 seems to have a very related issue in the same area, too.


(Ben) #3

Hi @rodrigo @eskatos Can one of you point me to a helpful example for my use case?


(Louis Jacomet) #4

Hello,

Are you aware of the Kotlin DSL primer?

And in particular the sections Type safe model accessors and Multi-project builds.
These should help your understanding regarding some of the issues you raise in the “Rant” part of your post.


(Ben) #5

Thanks @ljacomet for rehearsing the pointer to the Kotlin DSL primer. Your refocusing helped me a few steps. On rereading I was able to learn…

  • … about gradle kotlinDslAccessorsReport
  • … that the official hint regarding documentation is actually really to understand & read the plugin’s source code
  • … about the the()-shorthand: the<SourceSetContainer>()["main"].srcDir("src/core/java")
  • about plugins { id … apply false}. Not wanting to applying i.e. the java-library within my root project is actually one of the bigger obstacles I have vs. the “white paper examples” which are relying on directly inlining those.

Nevertheless even after rereading Using the container API ff. I still do not understand how I can/need to lazily wire things together within the subproject scopes of a multi-project setup in the root build to get my -source.jar et. al. running.
The demonstrated examples are all within the scope of a single-file build and my experience is that they are not applicable within a subproject { } block. Especially I assume that i.e. lazy references obtained in the root project are not valid/correct to be (re-)used within subprojects.

To sum up: It really turns out that I need to learn much more about the implementation details of Gradle on a Source-Code level that I imagined. While I’m still far away of being able to publish my Java library via Gradle, I achieved the very same results within 2h by simply googling, copying & adjusting some sample pom.xml. I only needed to tweak a little i.e. to use a legacy Ant tasks for source code generation.

I think a reference project as drafted in my mention Github would be really a big win for potential new users coming over from Maven.


(Ben) #6

Meanwhile I got an awesome response on Stackoverflow which brings me a few steps progress and I’m currently incorporating them in my sample project.

I really miss those sort of best practice examples and responsiveness in the official places.