gradle icon indicating copy to clipboard operation
gradle copied to clipboard

Use a project dependency for test->main dependency in Java plugin

Open oehme opened this issue 6 years ago • 9 comments

Instead of doing sourceSets.test.compileClasspath += sourceSets.main.output, the Java plugin should use dependencies { testImplementation thisProject } and Gradle will automatically wire in the main variant of the project.

oehme avatar Aug 23 '18 12:08 oehme

While this change should work, it has some unwanted consequences due to the fact that our variant model for JVM components isn't fully fleshed out:

  • With the java plugin applied, this results in testCompile depending on jar (instead of just classes)
  • With the java-library plugin applied, testCompile correctly depends on classes (and doesn't require the main jar to be built). However the testRuntimeClasspath ends up requiring the jar for the project.

I'm sure we can solve these problems by more correctly modelling the variants when either the java or java-library plugin is installed. Currently, we don't model any classes variants for the java plugin, and only the api-classes variant with the java-library plugin.

I'm not sure if this is worth rushing into 5.0.

bigdaz avatar Sep 29 '18 20:09 bigdaz

After a little bit more experimentation, here's what I think is required:

  1. A new outgoing variant Usage.RUNTIME_CLASSES_AND_RESOURCES on runtimeElements that has both the classes and resources directories as artifacts.
  2. Appropriate compatibility and disambiguation rules to choose this variant for a self-referencing project dependency when resolving the testRuntimeClasspath configuration.
  3. As stated in the main comment, change the testImplementation configuration to have a project dependency on self.

However, this has another implication: cross-project dependencies would be resolved the same way, so the test runtime classpath would now contain classes and resources directories for all dependent project, rather than jar files. This might be better, but would be a breaking change.

I think we'll want to do this in a less disruptive way, perhaps by adding rules that choose the new variant only for self-project dependencies, and not for cross-project dependencies.

bigdaz avatar Sep 29 '18 23:09 bigdaz

@oehme Given my previous comments, do you still want to target this for 5.0?

bigdaz avatar Oct 01 '18 16:10 bigdaz

I think using the JAR is actually better, as it is much faster to load on Windows than classes folders. For the same reason I'm also in favor of creating API JARs instead of classes folders for compilation, but that's another issue.

I don't think we need different behavior for local and downstream consumption. The price is small on Linux and on Windows it's actually faster to compile against a JAR.

I'm fine with doing this in another release, I just added it to 5.0 as it may break some hidden assumptions that some plugins might have.

oehme avatar Oct 01 '18 16:10 oehme

But changing tests to have a local jar input instead of classes and resources would be a breaking change, and should probably be changed over a deprecation cycle: WDYT?

bigdaz avatar Oct 01 '18 19:10 bigdaz

You mean by adding an opt-in and then nagging users to use it? That seems reasonable.

oehme avatar Oct 02 '18 09:10 oehme

Note that this is the root cause for #10872

ljacomet avatar Oct 11 '19 12:10 ljacomet

We should make this configurable. And then we can change the default in a major (e.g. 8.0).

This should be considered when we pick https://github.com/gradle/gradle/issues/12912 back up.

jjohannes avatar Jan 18 '21 15:01 jjohannes

We already modify our test compile classpath to swap the main classes out for the jar, purely for the performance benefits. Not having to do that in our own scripts would be nice. :)

Also if you wanted a real performance boost, you could even skip generating the classes to the filesystem in the first place, and write them directly into the jar along with the resources. ;)

hakanai avatar Mar 02 '22 04:03 hakanai

@jvandort let's split this so we can put compileElements into 8.0

big-guy avatar Oct 21 '22 21:10 big-guy