gradle icon indicating copy to clipboard operation
gradle copied to clipboard

jvm-test-suite - support depencency bundles

Open jakobrahm opened this issue 1 year ago • 7 comments

Expected Behavior

I assumed that this setup would work:

libs.versions.toml

[libraries]
spring-test = { module = "org.springframework.boot:spring-boot-starter-test" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine" }

[bundles]
spring-test = ["spring-test", "junit-jupiter-api", "junit-jupiter-engine"]

build.gradle.kts

testing {
    suites {
        register<JvmTestSuite>("integrationTest") {
            useJUnitJupiter()

            dependencies {
                implementation(libs.bundles.spring.test)
            }
        }
    }
}

Current Behavior (optional)

It seems like you'll have to include all depenencies individually like:

libs.versions.toml

[libraries]
spring-test = { module = "org.springframework.boot:spring-boot-starter-test" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine" }

build.gradle.kts

testing {
    suites {
        register<JvmTestSuite>("integrationTest") {
            useJUnitJupiter()

            dependencies {
                implementation(libs.spring.test)
                implementation(libs.junit.jupiter.api)
                implementation(libs.junit.jupiter.engine)
            }
        }
    }
}

Context

In a multi-project build there are multiple benefits with declaring dependency versions centrally and to be able to bundle them is a great way of streamlining the project configurations. I've managed to do a workaround by extending the testImplementation configuration, but as far as I know, it's an anti pattern to use config.extendsFrom? Am I missing something obvious?

jakobrahm avatar Aug 23 '24 12:08 jakobrahm

Solution

libs.versions.toml

[libraries]
spring-test = { module = "org.springframework.boot:spring-boot-starter-test" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine" }

[bundles]
spring-test-bundle = ["spring-test", "junit-jupiter-api", "junit-jupiter-engine"]

build.gradle.kts

testing {
    suites {
        register<JvmTestSuite>("integrationTest") {
            useJUnitJupiter()

            dependencies {
                implementation(libs.bundles.spring.test.bundle.get())
            }
        }
    }
}

What's Happening?

  • Bundle Defined: You create a spring-test-bundle in libs.versions.toml.
  • Bundle Applied: In your build.gradle.kts, you apply that bundle to your integrationTest suite.

This approach keeps your dependencies centralized and clean. If you prefer, you can extend testImplementation, but using bundles like this is generally more maintainable.

Kaos2121 avatar Aug 24 '24 03:08 Kaos2121

@Kaos2121 Thanks! I am getting the following error though:

Screenshot 2024-08-24 at 10 36 43

jakobrahm avatar Aug 24 '24 08:08 jakobrahm

@Kaos2121 Thanks! I am getting the following error though:

Screenshot 2024-08-24 at 10 36 43

1.	Bundle Name: Ensure libs.bundles.spring.test.bundle.get() matches exactly with what’s in libs.versions.toml.
2.	Remove .get(): Try using implementation(libs.bundles.spring.test.bundle) without .get().
3.	Verify References: Double-check that all dependencies are correctly referenced and resolve properly.

Check these

Kaos2121 avatar Aug 24 '24 20:08 Kaos2121

1.	Bundle Name: Ensure libs.bundles.spring.test.bundle.get() matches exactly with what’s in libs.versions.toml.
2.	Remove .get(): Try using implementation(libs.bundles.spring.test.bundle) without .get().
3.	Verify References: Double-check that all dependencies are correctly referenced and resolve properly.

Check these

The reference seems correct (I'm able to follow the reference in the IDE). Without .get(), the error logs hint that a list of references is unsupported:

Cannot convert the provided notation to an object of type Dependency: org.gradle.accessors.dm.LibrariesForLibs$SpringTestBundleAccessors@74078d7a.
The following types/formats are supported:
  - String or CharSequence values, for example 'org.gradle:gradle-core:1.0'.
  - Maps, for example [group: 'org.gradle', name: 'gradle-core', version: '1.0'].
  - FileCollections, for example files('some.jar', 'someOther.jar').
  - Projects, for example project(':some:project:path').
  - ClassPathNotation, for example gradleApi().

jakobrahm avatar Aug 25 '24 19:08 jakobrahm

The issue is in the backlog of the relevant team and is prioritized by them.


This is a known limitation

You cannot add version catalog bundles directly. Instead, use the bundle method on each configuration. Kotlin and Groovy: implementation(libs.bundles.testing) becomes implementation.bundle(libs.bundles.testing)

However, at least our docs should be updated to reference these differences here.

And the error should be more clear. It might be hard to fix since it's a compilation error, but from a user perspective, it's something we should address.

ov7a avatar Aug 26 '24 09:08 ov7a

The issue is in the backlog of the relevant team and is prioritized by them.

This is a known limitation

You cannot add version catalog bundles directly. Instead, use the bundle method on each configuration. Kotlin and Groovy: implementation(libs.bundles.testing) becomes implementation.bundle(libs.bundles.testing)

However, at least our docs should be updated to reference these differences here.

And the error should be more clear. It might be hard to fix since it's a compilation error, but from a user perspective, it's something we should address.

Thanks! implementation.bundle is a "good enough" solution for me but it would indeed be great with updated docs.

jakobrahm avatar Aug 28 '24 07:08 jakobrahm

Thinking some more about this, I wonder if we should not update the root dependencies block so that it behaves the same:

  • Add a bundle method on Configuration to pass in a version catalog bundle
  • Deprecate passing a bundle directly
  • Remove on next major

ljacomet avatar Aug 28 '24 12:08 ljacomet

Maybe the whole "traditional" dependencies block should be redone to use the new API you also use in jvm test suites block and so on to gain full equality also for future changes, not only adjusting the bundle usage.

Vampire avatar Jan 13 '25 12:01 Vampire