Automated Migration Tools

The Mill init command can be used to convert a Maven, Gradle, or SBT build to Mill. This has limitations and is not intended to reliably migrate 100% of existing 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 Maven module with a pom.xml, Gradle module with a .gradle file, or SBT module is converted to a Mill build.mill/package.mill file containing a top-level MavenModule or SbtModule. 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 importing Maven builds is best-effort. This means that while small projects can be expected to complete without issue:

Maven

> git init .
> git remote add -f origin https://github.com/davidmoten/geo.git
> git checkout 0.8.1 # example multi-module Java project using JUnit4

> ./mill init
converting Maven build
...
init completed, run "mill resolve _" to list available tasks

> ./mill __.compile
compiling 9 Java sources to ...geo...
compiling 2 Java sources to ...geo-mem...
compiling 10 Java sources to ...geo...test...
compiling 1 Java source to ...geo-mem...test...

> ./mill __.test # all tests pass immediately
Test run com.github.davidmoten.geo.GeoHashTest finished: 0 failed, 0 ignored, 66 total, ...
Test run com.github.davidmoten.geo.DirectionTest finished: 0 failed, 0 ignored, 1 total, ...
...

Gradle

> 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
converting Gradle build
...
init completed, run "mill resolve _" to list available tasks

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

> ./mill fluency-core.test # mac/linux
Test org.komamitsu.fluency.flusher.FlusherTest finished, ...
Test org.komamitsu.fluency.recordformat.MessagePackRecordFormatterTest finished, ...
...

SBT

> git init .
> git remote add -f origin https://github.com/scala/scala3-example-project.git
> git checkout 853808c50601e88edaa7272bcfb887b96be0e22a

> ./mill init
converting sbt build
...
init completed, run "mill resolve _" to list available tasks

> ./mill compile
compiling 13 Scala sources to ...

> ./mill test
MySuite:
  + example test that succeeds ...

Larger projects often require some manual tweaking in order to work:

Maven

> git init .
> git remote add -f origin https://github.com/dhatim/fastexcel.git
> git checkout 0.18.4
> # pom.xml has custom profiles for JPMS that mill init does not support
> # https://github.com/dhatim/fastexcel/blob/de56e786a1fe29351e2f8dc1d81b7cdd9196de4a/pom.xml#L251

> ./mill init
converting Maven build
writing build.mill.yaml
writing e2e/package.mill.yaml
writing fastexcel-reader/package.mill.yaml
writing fastexcel-writer/package.mill.yaml
...
init completed, run "mill resolve _" to list available tasks

> ./mill -k __.compile # Compilation needs manual tweaking to pass
error: fastexcel-reader/src/main/java/module-info.java:3:32
module not found: org.apache.commons.compress
fastexcel-reader/src/main/java/module-info.java:4:27
module not found: com.fasterxml.aalto
fastexcel-writer/src/main/java/module-info.java:2:14
module not found: opczip

Gradle

> git init .
> git remote add -f origin https://github.com/mockito/mockito.git
> git checkout v5.19.0 # multi-module Java project

> ./mill init  # imported modules are not fully functional
converting Gradle build
init completed, run "mill resolve _" to list available tasks

> ./mill mockito-core.compile   # Compilation needs manual tweaking to pass
error: mockito-core/src/main/java/module-info.java:8:17
module not found: net.bytebuddy

SBT

> git init .
> git remote add -f origin https://github.com/fthomas/refined.git
> git checkout v0.11.3

> ./mill init
converting sbt build
...
init completed, run "mill resolve _" to list available tasks

> ./mill modules.core.jvm.2_12_20.compile # source roots for custom version ranges need tweaking
compiling 22 Scala sources to ...
error: ...object boolean is not a member of package eu.timepit.refined

Nevertheless, even for larger builds mill init automates most of the tedious busy-work of writing build.mill/package.mill files, and makes it much quicker to get a working Mill build for any existing project. For example, the iluwatar/java-design-patterns repo has 363 subprojects (including test projects) and ./mill init is able to get it imported, compiling, and passing all tests in Mill:

> git init .
> git remote add -f origin https://github.com/iluwatar/java-design-patterns
> git checkout ede37bd05568b1b8b814d8e9a1d2bbd71d9d615d

> ./mill init --mill-jvm-id 21 # Repo needs Java >=21 to build and test

> rm twin/src/test/java/com/iluwatar/twin/BallThreadTest.java # skip flaky test
> rm actor-model/src/test/java/com/iluwatar/actor/ActorModelTest.java # skip flaky test

> ./mill __.compile # Compile all 300+ subprojects!
compiling 6 Java sources to ...service-to-worker...
compiling 4 Java sources to ...update-method...

> ./mill acyclic-visitor.test # run a subproject's tests
...
Test com.iluwatar.acyclicvisitor.ZoomTest#testAcceptForUnix() started
Test com.iluwatar.acyclicvisitor.ZoomTest#testAcceptForUnix() finished, took ...
Test com.iluwatar.acyclicvisitor.ZoomTest finished, took ...
...

Usage

Install mill in your project directory and run:

./mill init

This will generate Mill build files build.mill and package.mill for the root module and all nested modules, respectively. Additionally, meta-build files containing shared configurations are added in the mill-build directory.

To set a custom value for mill-jvm-version in the generated build.mill file, run:

./mill init --mill-jvm-id 25

The init command can be run multiple times with any combination of options. To list all available options, run:

./mill init --help

Limitations

The conversion does not support

  • build extensions

  • build profiles

  • non-Java sources

These limitations can be overcome by:

FAQ

How to fix compilation errors in generated build files?

This could happen if a module and task name collision occurs. Either rename the module or enclose the name in backticks.

How to fix JPMS module not found compilation errors?

Add options for Java modules to javacOptions.

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 compileMvnDeps dependencies to the transitive dependencies of the nested test module; specify the dependencies again, in mvnDeps or runMvnDeps.

java.io.IOError: java.lang.RuntimeException: /packages cannot be represented as URI

This error: java.lang.UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release, java.io.IOError: java.lang.RuntimeException: /packages cannot be represented as URI, and java.lang.RuntimeException: java.lang.reflect.InvocationTargetException thrown by the sbt command invoked by mill init

Update the project’s sbt version to the latest or our tested version v1.10.10, and check whether you have the appropriate Java version, and try again.