-
-
Notifications
You must be signed in to change notification settings - Fork 415
Initial Groovy setup #5747
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
base: main
Are you sure you want to change the base?
Initial Groovy setup #5747
Conversation
fe154eb
to
a7455f8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for opening this PR and welcome to Mill.
I had a quick scan and left some comments where I spotted something. Overall, this looks reasonable, but there might be some more places copied from the Kotlin implementation which aren't adequate for Groovy.
libs/groovylib/api/src/mill/groovylib/worker/api/GroovyWorker.scala
Outdated
Show resolved
Hide resolved
override def prepareOffline(all: Flag): Command[Seq[PathRef]] = Task.Command { | ||
( | ||
super.prepareOffline(all)() ++ | ||
groovyCompilerClasspath() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this include potential compiler plugin dependencies?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there is no real Groovy compiler in the sense of Javac, Scala or Kotlin (there is Groovyc, which is just a CLI wrapper) I guess there is no need for this. The core Groovy dependency is able to compile and you can just extends the normal classpath. Guess this is due to Groovy being a dynamic language where everything is resolved at runtime anyways. The only difference could be when you use @CompileStatic
(doc). I will add this to the tasks to be evaluated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand, that you copied another language module to start this implementation, but it would be helpful, if you could revise it and delete all tasks that aren't needed, like groovycOptions
.
21334e0
to
69cb09a
Compare
@lefou I've resolved most of the issues and fixed the Spock bug. I've also extended the use-cases and backed them by tests to support static compilation as well as a 3-stage compilation for setups where Java depends on Groovy and vice-versa. In the next weeks I will probably find some more time to see about what configuration options are needed and how to support them. |
@lostiniceland Can you resolve the merge conflicts? |
69cb09a
to
f7cd2cf
Compare
@lefou I would like to pull |
You can try, but I think it will break bin-compat. |
I gave it a try and no additional test broke. From SemVer perspective it also shouldn't break anything as long as the trait provides a default implementation. So I will keep this for now. |
bfbe1fe
to
c82f9a2
Compare
@lefou Have a look at the latest commit I managed to manage (pun intended) the JUnit5/Spock dependencies. Since the BOMs are only available at certain versions this will be checked.
What do you think? Do you want to keep this, or should I remove it? |
…pile which also fixed spock not being executed
Starting with JUnit 5.12 and Spock 2.3 a BOM is available on Maven Central. If the version matches the BOMs will be automatically added. For JUnit, this has the effect that the platform-launcher is also managed in the BOM so it is actually not necessary to specify a platform-launcher-version. Hence the launcher is also added when the version is not set and the minimum version is met.
32f8111
to
bda67ee
Compare
Looks like I was wrong about binary compatibility though I am not quite sure what to make of this: Lets say Groovylib is released with Mill 1.0.10 then I cannot use this with Mill 1.0.9. Fine. And plugins targeting 1.0.10 will also still be compatible since the new method has a default implementation. |
9bb4038
to
39cdc7e
Compare
…t transoformations
@lefou I think this PR is ready to get out of the draft status. I've added examples and docs (though There is this outstanding issue with the binary-compatibility caused by adding |
I haven't reviewed this in detail, but let's put this in |
Do I have to change the package from |
Since we also have experimental We already have the example tooling in place for |
Sounds good to me! |
/** | ||
* In a mixed setup this will compile the Groovy sources to Java stubs. | ||
*/ | ||
def compileGroovyStubs( | ||
sourceFiles: Seq[os.Path], | ||
classpath: Seq[os.Path], | ||
outputDir: os.Path | ||
)(implicit | ||
ctx: TaskCtx | ||
) | ||
: Result[CompilationResult] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the output of this? .class
files or .java
files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.java
though they are cleaned up after the last groovy compilation stage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using CompilationResult
in the return isn't appropriate here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this stub-handling somewhere documented? Or can you outline the process and what you mean with "cleaned up after the last compilation stage"?
It looks to me, this groovy stubs should reside in it's own cacheable task, since it should not need to be regenerated when just Java files changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will document it.
In order for Java to compile with dependencies to Groovy, It only needs the method signatures (headers). This is what the Groovy Stubs are. When you have dependencies Groovy -> Java AND Java -> Groovy you need a 3 stage compile
- Groovy compiles to Java stubs (*.java files in the output)
- Java compiles with the Stubs available
2.1 Cleanup stubs after Java compile (I was wrong before, it happens here) - Compile Groovy (now all Java dependencies are also available on the compilepath).
It should actually be very similar in the other toolchains (scala, kotlin) but maybe the external compiler handles this already internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a difference to Scala or Kotlin handling. Both are able to read Java files, so they will always compile their files first and the Java-compiler comes last. Whereas Groovy will first generate stubs, so Java can consume them and succeed with compilation, and then compile Groovy (while consuming the compiled Java classes vie the classpath).
Nevertheless, the only thing needed is a changed classpaths and output paths. There is no need to delete stub files. Especially, since they are needed in the next compile run and don't need any regeneration at all, when nothing has changed to the Groovy files. And even if the Groovy files have changed but the resulting stubs have not, there is no need no recompile Java files at all. Both cases would be automatically handled by Mill, if we properly model it via cached tasks.
private def isGroovyBomAvailable: T[Boolean] = Task { | ||
if (groovyVersion().isBlank) { | ||
false | ||
} else { | ||
Version.isAtLeast(groovyVersion(), "4.0.26")(using Version.IgnoreQualifierOrdering) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name is misleading. It should be useGroovyBom
or groovyUseBom
, since it's not checking for availability but deciding (based on the version).
* def targetBytecode = Some("17") | ||
* }}} | ||
*/ | ||
def targetBytecode: T[Option[String]] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be groovyCompileTargetBytecode
/** | ||
* Convenience trait for projects using Java for production and Groovy for tests in a Maven setup | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add more motivation, why this might be preferable over just adding GroovyModule
(e.g. to avoid implicit groovy deps in the module).
I have been working on Groovy support since I would like to use Mill for projects where tests are written in Spock/Groovy.
It is basically a modified version of the Kotlin support.
Whats currently working:
If anyone would like to provide feedback I would appreciate it.