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
> rm build.mill # remove any existing build file
> 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
> 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
...
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
> rm build.mill # remove any existing build file
> 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
> rm build.mill # remove any existing build file
> 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 Mill build file to fastexcel-writer/package.mill
writing Mill build file to fastexcel-reader/package.mill
writing Mill build file to e2e/package.mill
writing Mill build file to build.mill
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
error: ...fastexcel-reader/src/main/java/module-info.java:4:27: module not found: com.fasterxml.aalto
error: ...fastexcel-writer/src/main/java/module-info.java:2:14: module not found: opczip
Gradle
> 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: plug-in not found: ErrorProne
SBT
> rm build.mill # remove any existing build file
> git init .
> git remote add -f origin https://github.com/tototoshi/scala-csv.git
> git checkout 2.0.0
> ./mill init
converting sbt build
...
init completed, run "mill resolve _" to list available tasks
> ./mill compile # You will have to further configure the `CrossScalaModule` for different Scala versions
compiling 7 Scala sources and 3 Java sources to ...
error: class CSVReader protected (private val lineReader: LineReader)(implicit format: CSVFormat) extends Closeable with CSVReaderCompat {
error: ^
error: one error found
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:
> rm build.mill # remove any existing build file
> git init .
> git remote add -f origin https://github.com/iluwatar/java-design-patterns
> git checkout ede37bd05568b1b8b814d8e9a1d2bbd71d9d615d
> ./mill init --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 ...
...
Capabilities
The conversion
-
handles deeply nested modules
-
captures publish settings
-
configures dependencies for configurations:
-
no configuration
-
Compile
-
Test
-
Runtime
-
Provided
-
Optional
-
-
configures testing frameworks:
-
Java:
-
JUnit 4
-
JUnit 5
-
TestNG
-
-
Scala:
-
ScalaTest
-
Specs2
-
µTest
-
MUnit
-
Weaver
-
ZIOTest
-
ScalaCheck
-
-
-
configures multiple, compile and test, resource directories
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
-
--jvm-id
(-j
): disttribution 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 totest
)./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
-
--cache-repository
: use cache for Maven repository system./mill init --cache-repository
-
--process-plugins
: process Maven plugin executions and configurations./mill init --process-plugins
You can run mill init multiple times. It is recommended to run it first without any options.
|
Verified projects
The conversion has been tested with the following projects:
./mill init --base-module JansiModule --deps-object Deps --cache-repository --process-plugins
-
geo (multi-module build)
./mill init --base-module GeoModule --deps-object Deps --merge --cache-repository --process-plugins
Post init
, the following tasks were executed successfully:
-
compile
-
test
-
publishLocal
Limitations
The conversion does not support
-
build extensions
-
build profiles
-
non-Java sources
Maven plugin support is limited to
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, inmvnDeps
orrunMvnDeps
.
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.