Migrating From Gradle to Mill

The Mill init command can be used to convert a Gradle build to Mill. This has limitations and is not intended to reliably migrate 100% of Gradle builds out there in the wild, but is instead meant to provide the basic scaffolding of a Mill build for you to further refine and update manually.

Each Gradle project in a build tree is converted to a Mill module. A nested test module is defined, if src/test exists, and is configured with a supported test framework, if found.

Again, note that mill init imports a Gradle build on a best-effort basis. This means that while simple projects can be expected to complete without issue:

> rm build.mill # remove any existing build file

> git init .
> git remote add -f origin https://github.com/komamitsu/fluency.git
> git checkout 2.7.3 # multi-module Java project that requires Java 16+

> ./mill init --base-module FluencyModule --jvm-id 16
converting Gradle build
writing Mill build file to fluency-aws-s3/package.mill
writing Mill build file to fluency-core/package.mill
writing Mill build file to fluency-fluentd-ext/package.mill
writing Mill build file to fluency-fluentd/package.mill
writing Mill build file to fluency-treasuredata/package.mill
writing Mill build file to build.mill
init completed, run "mill resolve _" to list available tasks

> ./mill __.compile
compiling 9 Java sources to ...out/fluency-aws-s3/compile.dest/classes ...
compiling 6 Java sources to ...out/fluency-aws-s3/test/compile.dest/classes ...
compiling 27 Java sources to ...out/fluency-core/compile.dest/classes ...
compiling 8 Java sources to ...out/fluency-core/test/compile.dest/classes ...

> ./mill fluency-core.test # running all tests takes too long
Test org.komamitsu.fluency.FluencyTest finished, ...
Test org.komamitsu.fluency.validation.ValidatableTest finished, ...
Test org.komamitsu.fluency.buffer.BufferTest finished, ...
Test org.komamitsu.fluency.buffer.BufferPoolTest finished, ...
Test org.komamitsu.fluency.flusher.FlusherTest finished, ...
Test org.komamitsu.fluency.recordformat.MessagePackRecordFormatterTest finished, ...

Projects with a complex build often require some manual tweaking in order to work:

> rm build.mill # remove any existing build file

> git init .
> git remote add -f origin https://github.com/mockito/mockito.git
> git checkout v5.15.2 # multi-module Java project that requires Java 17+

> ./mill init --base-module MockitoModule --jvm-id 17   # init ignores custom dependency configurations
converting Gradle build
ignoring errorprone dependency (com.google.errorprone,error_prone_core,2.23.0)
init completed, run "mill resolve _" to list available tasks

> ./mill __.compile   # compilation error can be by fixed by using the Mill plugin for ErrorProne
error: ...Unexpected javac output: error: plug-in not found: ErrorProne

Capabilities

The conversion

  • handles deeply nested modules

  • captures publish settings

  • configures dependencies for configurations

    • implementation / api

    • compileOnly / compileOnlyApi

    • runtimeOnly

    • testImplementation

    • testCompileOnly

  • configures testing frameworks

    • JUnit 4

    • JUnit 5

    • TestNG

Command line arguments

The conversion and its output (the generated Mill build files) can be customized using

  • --base-module (-b): name of generated base module trait defining shared settings

    ./mill init --base-module MyModule
  • --base-project (-g): name of Gradle project to extract settings for --base-module

    ./mill init --base-module MyModule --base-project lib
    If not specified, a project will be selected arbitrarily.
  • --jvm-id (-j): distribution and version of custom JVM to configure in --base-module

    ./mill init --base-module MyModule --jvm-id 17
    ./mill init --base-module MyModule --jvm-id temurin:17
    ./mill init --base-module MyModule --jvm-id temurin:17.0.1
  • --test-module (-t): name of generated nested test module (defaults to test)

    ./mill init --test-module test
  • --deps-object (-d): name of generated companion object defining dependency constants

    ./mill init --deps-object Deps
  • --merge (-m): merge build files generated for a multi-module build

    ./mill init --merge
  • --publish-properties (-p): capture Maven publish properties

    ./mill init --publish-properties
You can run mill init multiple times. It is recommended to run it first without any options.

Limitations

The conversion does not support

  • custom dependency configurations

  • custom tasks

  • non-Java sources

Gradle plugin support is limited to

These limitations can be overcome by:

FAQ

How to fix java.lang.UnsupportedClassVersionError error thrown by mill init?

Select a Java Runtime compatible with the version of Gradle used and pass it using the --jvm-id argument.

How to fix test compilation errors?

  • The test framework configured may be for an unsupported version; try upgrading the corresponding dependencies.

  • Mill does not add compileIvyDeps dependencies to the transitive dependencies of the nested test module; specify the dependencies again, in ivyDeps or runIvyDeps.