New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gradle-scala plugin overrides isolated gradle provisioner scala version in spotless #21502
Comments
@tgodzik Since you have worked on the gradle-scala plugin in the past and also with scalafmt I believe you may have some idea/context on this. |
I am not familiar with Spotless, though the issue here seems that it's using a specific Scalafmt version released for 2.12 instead of using the one for the current Scala version. I also relies quite heavily on reflection, which might also cause other problems. Scalafmt should work well both with Scala 2.13 and 2.12 (probably any Scala version) with the API that we already use in Metals: I wonder if it would be possible to replace the current implementation with API, which is run in it's own classloader as far as I can remember. The other option would be to dynamically download scalafmt version base don which is used in the project currently. I think it's not possible currently to have two different Scala versions on the classpath when using Gradle. Gradle Scala plugin needs a specific version and I don't think it's isolated behind a separate classloader. As long as both spotless and Scala plugin use the same classpath it will not work (unless I am mistaken and it actually does separate classloaders 🤔 ) |
@tgodzik Thanks for the reply
So this seems to be the case, if you look at https://github.com/diffplug/spotless/blob/0fd20bb80c6c426d20e0a3157c3c2b89317032da/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java the Scala version happens to be hardcoded depending on what version of Scalafmt you are using, so if you happen to use Scalafmt 3.x it will just always pick Scala 2.13.x
Design wise this seems like the best solution as it will always work and it makes sense for a CLI tool to run on its own completely isolated.
As you say, if Gradle cannot support proper classload isolation for Scala then yes it appears that our next best solution is to dynamically figure out if there is a gradle-scala plugin loaded and if so then we get the major scala version from the gradle-scala plugin and use that instead. |
A full reproducer would help if anything needs to change in Gradle itself. |
I had another look at this during the weekend and I think that it makes more sense to wait until Gradle provides classloader isolation in their plugins by default, i.e. https://docs.gradle.org/current/userguide/designing_gradle_plugins.html
Another solution for the gradle-scala plugin itself would be to manually implement classloader isolation but I assume that would be a large amount of work. @ljacomet Do you know if there is any movement in gradle to implement classloader isolation on the plugin level or is this still something that is far off? |
Managed to solve this issue via spotless (see diffplug/spotless#1283) |
Expected Behavior
When using gradle + gradle-scala and specifying the scala version with
-PscalaVersion=2.12
along with spotless-scala (https://github.com/diffplug/spotless) with scalafmt 3.5.8, there shouldn't be any problems and it should check/format the code fine.Current Behavior
Currently if you use spotless scala along with scalafmt 3.5.8 + scala 2.12 to see if the code is formatted, i.e.
You get the following stack trace
Context
Relevant issue in spotless: diffplug/spotless#1273
Relevant PR in kafka: apache/kafka#12475
The reason why spotless-scala with scalafmt is failing is because the usage of
-PscalaVersion=2.12
causes gradle-scala plugin to override the scala version. While this is expected/fine if you happen to be building your project for a different version of Scala, in the case of spotless-scala (that uses scalafmt underneath) the version of scala should not be overridden because regardless of what Scala version you are building the project, scalafmt 3.5.8 only works with Scala 2.13.x. Specifically if you look at the stacktrace its complaining about classes that only exist in Scala 2.13.x stdlib but not in Scala 2.12.x stdlib. This is why if you run./gradlew -PscalaVersion=2.13 :spotlessScalaCheck
there is no issue (since scalafmt 3.5.8 is compildSpotless is already trying to solve this problem by isolating it (see diffplug/spotless#1273 (comment)) but for some reason the
-PscalaVersion=2.12
bypasses this isolation. My immediate suspicion is that guild-scala is providing the scala runtime/stdlib globally within gradle which is being picked up by spotless-scala? If this is the case I imagine the way to solve this issue is to use an isolated classloader (no idea if Gradle is already doing this?)Steps to Reproduce
Checkout the following branch/PR apache/kafka#12475 and run
./gradlew -PscalaVersion=2.12 :spotlessScalaCheck
.Your Environment
My environment is MacOS Montery 12.5 M1 however this problem occurs on any platform (this is evidenced by the fact it fails in Kafka's CI/CD, see https://ci-builds.apache.org/job/Kafka/job/kafka-pr/job/PR-12475/)
Build scan URL: https://scans.gradle.com/s/bycldhmiy5imy
The text was updated successfully, but these errors were encountered: