Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
541652c
Intial Groovy setup
lostiniceland Aug 20, 2025
51d6266
adding more test cases and fixing classloader issue during groovy com…
lostiniceland Sep 11, 2025
4bcb5b1
improve test-only-groovy to not rely on an existing outer module
lostiniceland Sep 12, 2025
45dfd9b
3-stage compile to support Groovy <-> Java cycles
lostiniceland Sep 15, 2025
cacf2c7
manage BOMs in Tests
lostiniceland Sep 16, 2025
eb13bc6
test with cross-compile Groovy 4 & 5
lostiniceland Sep 23, 2025
13c7ec9
samples
lostiniceland Sep 23, 2025
ea34a49
docs
lostiniceland Sep 24, 2025
9a26ea3
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 24, 2025
b8d28f7
Groovy Compiler options for bytecode version, preview features and as…
lostiniceland Sep 24, 2025
507b11b
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 24, 2025
e218ec2
Added example tests to CI setup
lefou Sep 26, 2025
485a8c3
Rudimentarily fix webpage generation
lefou Sep 26, 2025
f0cc0b8
Cleanup and Testcase for targetBytecode and previewEnabled
lostiniceland Sep 26, 2025
48b6020
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 26, 2025
21cf8f7
minor test improvement
lostiniceland Sep 26, 2025
0df8825
Mark API as experimental
lefou Sep 27, 2025
2c80e4b
Fix mima setup
lefou Sep 27, 2025
d232684
minor review remarks
lostiniceland Sep 29, 2025
7fac9ce
use Mill caching for stub folder
lostiniceland Sep 29, 2025
b5177ad
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 29, 2025
eed6b58
Revert back to experimental module
lostiniceland Oct 13, 2025
00b6893
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ jobs:
millargs: "'example.androidlib.__.local.daemon'"
setup-android: true

- java-version: 17
millargs: "'example.groovylib.__.local.daemon'"
setup-android: true

- java-version: 17
millargs: "'example.thirdparty[androidtodo].packaged.daemon'"
setup-android: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package mill.api.daemon.internal

trait GroovyModuleApi extends JavaModuleApi
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ object BspModuleApi {
val Java = "java"
val Scala = "scala"
val Kotlin = "kotlin"
val Groovy = "groovy"
}

/** Used to define the [[BspBuildTarget.tags]] field. */
Expand Down
124 changes: 124 additions & 0 deletions example/groovylib/basic/1-simple/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//// SNIPPET:BUILD

package build
import mill.*, groovylib.*

object foo extends GroovyModule {
def groovyVersion = "5.0.1"

def mvnDeps = Seq(
mvn"org.apache.groovy:groovy-cli-commons", // BOM already loaded by module
mvn"org.apache.groovy:groovy-xml" // BOM already loaded by module
)

def mainClass = Some("foo.Foo")

object test extends GroovyTests with TestModule.Junit5 {
def jupiterVersion = "5.13.4"

def mvnDeps = Seq(
mvn"org.apache.groovy:groovy-test" // BOM already loaded by module
)
}
}

// This is a basic Mill build for a single `GroovyModule`, with one
// third-party dependency and a test suite using the JUnit framework.
//// SNIPPET:TREE
// ----
// build.mill
// foo/
// src/
// foo/Foo.groovy
// resources/
// ...
// test/
// src/
// foo/FooTest.groovy
// out/foo/
// compile.json
// compile.dest/
// ...
// test/
// compile.json
// compile.dest/
// ...
// ----
//
// NOTE: The default Mill source folder layout `foo/src/` differs from that of Maven/Gradle's
// `foo/src/main/groovy`. If you wish to use the Maven source folder layout, e.g. for migrating
// an existing codebase, you should use
// xref:#_maven_compatible_modules[Maven-Compatible Modules]
//
//// SNIPPET:DEPENDENCIES
//
// This example project uses two third-party dependencies
// - Groovy-Cli-Commons for CLI argument parsing
// - Groovy-Xml for HTML templating and escaping
// and uses them to wrap a given input string in HTML templates with proper escaping.
//
// Typical usage of a `GroovyModule` is shown below

/** Usage

> ./mill resolve foo._ # List what tasks are available to run
foo.assembly
...
foo.compile
...
foo.run
...
*/
/** Usage
> ./mill inspect foo.compile # Show documentation and inputs of a task
foo.compile(GroovyModule...)
Compiles all the sources to JVM class files.
Compiles the current module to generate compiled classfiles/bytecode.
Inputs:
foo.allJavaSourceFiles
foo.allGroovySourceFiles
foo.compileClasspath
foo.upstreamCompileOutput
foo.javacOptions
foo.zincReportCachedProblems
...
*/
/** Usage
> ./mill foo.compile # compile sources into classfiles
...
Compiling 1 Groovy sources to...
*/
/** Usage
> ./mill foo.run # run the main method, if any
error: Error: missing option --text
...
*/
/** Usage
> ./mill foo.run --text hello
<h1>hello</h1>
*/
/** Usage
> ./mill foo.test
...
Test foo.FooTest testSimple finished, ...
Test foo.FooTest testEscaping finished, ...
Test foo.FooTest finished, ...
Test run finished: 0 failed, 0 ignored, 2 total, ...
*/
/** Usage
> ./mill foo.assembly # bundle classfiles and libraries into a jar for deployment

> ./mill show foo.assembly # show the output of the assembly task
".../out/foo/assembly.dest/out.jar"

> java -jar ./out/foo/assembly.dest/out.jar --text hello
<h1>hello</h1>

> ./out/foo/assembly.dest/out.jar --text hello # mac/linux
<h1>hello</h1>

> cp ./out/foo/assembly.dest/out.jar out.bat # windows

> ./out.bat --text hello # windows
<h1>hello</h1>
*/
32 changes: 32 additions & 0 deletions example/groovylib/basic/1-simple/foo/src/foo/Foo.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package foo

import groovy.xml.MarkupBuilder
import groovy.cli.commons.CliBuilder

class Foo {
static String generateHtml(String text) {
def writer = new StringWriter()
new MarkupBuilder(writer).h1 {
mkp.yield text
}
writer.toString()
}

static void main(String[] args) {
def cli = new CliBuilder(usage:'help')
cli.t(longOpt:'text', args: 1, 'Passes text to the HTML generation')
def options = cli.parse(args)

if (!options) {
return
}

if (options.h) {
cli.usage()
return
}

String textToProcess = options.t ?: "hello from main"
println generateHtml(textToProcess)
}
}
15 changes: 15 additions & 0 deletions example/groovylib/basic/1-simple/foo/test/src/foo/FooTest.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package foo

import org.junit.jupiter.api.Test

class FooTest {
@Test
void "generate html created properly"() {
assert Foo.generateHtml("hello") == "<h1>hello</h1>"
}

@Test
void "generated html is properly escaped"() {
assert Foo.generateHtml("<hello>") == "<h1>&lt;hello&gt;</h1>"
}
}
57 changes: 57 additions & 0 deletions example/groovylib/basic/2-compat-modules/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//// SNIPPET:ALL
// Mill's default folder layout of `foo/src/` and `foo/test/src` differs from that
// of Maven or Gradle's `foo/src/main/groovy/` and `foo/src/test/groovy/`. If you are
// migrating an existing codebase, you can use Mill's `GroovyMavenModule` and
// `GroovyMavenTests` as shown below to preserve filesystem compatibility with an existing
// Maven or Gradle build:

package build
import mill.*, groovylib.*

object foo extends GroovyMavenModule {

def groovyVersion = "5.0.1"

object test extends GroovyMavenTests with TestModule.Junit5 {}
object integration extends GroovyMavenTests with TestModule.Junit5 {}
}

// `GroovyMavenModule` is a variant of `GroovyModule`
// that uses the more verbose folder layout of Maven, `sbt`, and other tools:
//
// - `foo/src/main/java`
// - `foo/src/main/groovy`
// - `foo/src/test/java`
// - `foo/src/test/groovy`
// - `foo/src/integration/java`
// - `foo/src/integration/groovy`
//
// Rather than Mill's
//
// - `foo/src`
// - `foo/test/src`
//
// This is especially useful if you are migrating from Maven to Mill (or vice
// versa), during which a particular module may be built using both Maven and
// Mill at the same time

/** Usage

> ./mill foo.compile
Compiling 1 Groovy source...

> ./mill foo.test.compile
Compiling 1 Groovy source...

> ./mill foo.test.testForked
...foo.FooTests hello ...

> ./mill foo.test
...foo.FooTests hello ...

> ./mill foo.integration
...foo.FooIntegrationTests hello ...

*/

// For more details on migrating from other build tools, see xref:migrating/migrating.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package foo

import org.junit.jupiter.api.Test

class FooIntegrationTests {
@Test
void "hello should print correct greeting"() {
// Groovy creates an implicit class for the script named after the file
def foo = new Foo()
assert foo.hello() == "Hello World, Earth"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package foo

def run(){
println(hello())
}

def hello() {
"Hello World, ${Foo2.VALUE}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package foo;

public class Foo2 {
public static final String VALUE = "Earth";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package foo

import org.junit.jupiter.api.Test

class FooTest {

@Test
void "hello should print correct greeting"() {
// Groovy creates an implicit class for the script named after the file
def foo = new Foo()
assert foo.hello() == "Hello World, Earth"
}
}
9 changes: 9 additions & 0 deletions example/groovylib/testing/1-test-suite/bar/src/bar/Bar.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package bar

def hello() {
"Hello World"
}

def run(){
println new Bar().hello()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package bar

import org.junit.jupiter.api.Test
import groovy.mock.interceptor.MockFor

class BarTests{
@Test
void "hello"() {
def result = new Bar().hello()
assert result == "Hello World"
}

@Test
void "world"() {
def result = new Bar().hello()
assert result.endsWith("World")
}

@Test
void "using groovy mocks"() {
def mockBar = new MockFor(Bar)
mockBar.demand.hello { "Hello GroovyMock World" }

mockBar.use{
def result = new Bar().hello()
assert result == "Hello GroovyMock World"
}
}
}
31 changes: 31 additions & 0 deletions example/groovylib/testing/1-test-suite/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//// SNIPPET:BUILD1
package build
import mill.*, groovylib.*

object foo extends GroovyModule {

def groovyVersion = "5.0.1"

object test extends GroovyTests with TestModule.Junit5 {
def jupiterVersion = "5.13.4"

def mvnDeps = Seq(
mvn"org.apache.groovy:groovy-test" // BOM already loaded by module
)
}
}

object bar extends GroovyModule {

def mainClass = Some("bar.Bar")

def groovyVersion = "5.0.1"

object test extends GroovyTests, TestModule.Junit5 {
def jupiterVersion = "5.13.4"

def mvnDeps = Seq(
mvn"org.apache.groovy:groovy-test" // BOM already loaded by module
)
}
}
11 changes: 11 additions & 0 deletions example/groovylib/testing/1-test-suite/foo/src/foo/Foo.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package foo

class Foo {
def hello() {
"Hello World"
}

static void main(String[] args){
println Foo().hello()
}
}
Loading
Loading