robstoll / atrium

A multiplatform expectation library for Kotlin
https://docs.atriumlib.org
European Union Public License 1.2
572 stars 212 forks source link

Create BOMs for dependency versions #1419

Open vlsi opened 1 year ago

vlsi commented 1 year ago

Platform (all, jvm, js): all Extension (none, kotlin 1.3): none

Non-Code related feature

Currently the build uses rootProject.extra for declaring dependency versions which is cumbersome for usage (e.g. it does not support precompiled script plugins), and it can't be reused.

I suggest creating BOMs with dependency constraints, so the dependencies can be declared without versions.

I think the following BOMs make sense: a) Atrium modules, without third-party dependencies. In other words, something like junit-bom: https://junit.org/junit5/docs/current/user-guide/#dependency-metadata-junit-bom b) BOM with third-party runtime dependencies (if any) c) BOM with test dependencies

robstoll commented 1 year ago

Just as info, Atrium already provides BOMs for consumers of atrium (the bundle modules), I guess that covers a) What's your use case that you need b) and c) ?

vlsi commented 1 year ago

The current bundle modules are not BOMs. See https://blog.gradle.org/alignment-with-gradle-module-metadata for the description of "a".

In other words, "a" should be dependency constraints rather than versions:

In that case, every atrium module could depend on such bom, and Gradle would automatically align versions. For instance, consider user declares dependency on api-fluent-en_GB:0.18 and translations-en_GB:0.19. api-fluent-en_GB:0.18 brings atrium-bom:0.18 while translations-en_GB:0.19 brings atrium-bom:0.19. atrium-bom:0.19 will bring constraints on both modules to 0.19, so final resolution would align both dependencies to 0.19.

In JUnit, junit-bom is <type>pom</type>: https://repo1.maven.org/maven2/org/junit/junit-bom/5.9.3/junit-bom-5.9.3.pom In other words, it specifies only versions rather than explicit dependencies.

vlsi commented 1 year ago

The use cases for b and c are to remove the current pattern of storing versions in extra properties: https://github.com/robstoll/atrium/blob/cca39fc1f1e334dcfca73c84a1af76b49ba2d49b/build.gradle.kts#L20-L29

project.extra was a thing ~7 years ago, however, it did not work great overall, especially for declaring versions. For instance, you have to remember the exact name of the extra every time you use a dependency, and you have to invent a name for a dependency every time you add new one.

The modern approach for naming dependencies is version catalogs, however, there are issues with using precompiled script plugins + version catalogs together.

Another (accompanying) approach to align versions is creating platforms. In that case, you import that platform once, and declare the dependencies without versions, so you don't need refer to extra names.

vlsi commented 1 year ago

One of the major drawbacks of having val jacocoToolVersion by extra("0.8.9") is that you miss Renovate / Dependabot support for the custom syntax. You have to manually discover which versions are available, and it is unclear what to watch for.

For instance, consider val spekVersion by extra("2.0.12"). How do I check if there's an update available? Which maven coordinate do I search for? It would be way easier to have it as a constraint (e.g. see https://github.com/apache/jmeter/blob/b76c5f73025b21ec9a17605910a9b4a3e2c4321f/src/bom-thirdparty/build.gradle.kts#L78 ), so both robots and humans could suggest and evaluate upgrades.

robstoll commented 1 year ago

regarding a) you are totally right. would make sense to have a proper BOM in addition where the bundle modules would use it.

project.extra was a thing ~7 years ago,

Oho.. looks like I am getting old-school :laughing: Thanks for your input, easy way for me to catch up on new gradle stuff

regard b, c) I see, the use cases are more contributor oriented. Good with me.

robstoll commented 1 year ago

we no longer use rootProject.extra but libs.versions.toml but an additional BOM would still be nice