Scala Build Examples

Example Builds for Real Projects

Mill comes bundled with example builds for real-world open-source projects, demonstrating how Mill can be used to build code outside of tiny example codebases:

Acyclic

build.mill (download, browse)
package build
import mill._, scalalib._, publish._

acyclic test suite assumes files are on disk at specific paths relative to os.pwd. To avoid changing the test code, we instead copy the necessary files into the os.pwd when preparing the resources for test suite execution

os.copy.over(
  interp.watch(mill.api.WorkspaceRoot.workspaceRoot / "acyclic"),
  os.pwd / "acyclic",
  createFolders = true
)

object Deps {
  def acyclic = ivy"com.lihaoyi:::acyclic:0.3.6"
  def scalaCompiler(scalaVersion: String) = ivy"org.scala-lang:scala-compiler:$scalaVersion"
  val utest = ivy"com.lihaoyi::utest:0.8.4"
}

val crosses =
  Seq("2.11.12") ++
    Range.inclusive(8, 17).map("2.12." + _) ++
    Range.inclusive(0, 10).map("2.13." + _)

object acyclic extends Cross[AcyclicModule](crosses)
trait AcyclicModule extends CrossScalaModule with PublishModule {
  def crossFullScalaVersion = true
  def artifactName = "acyclic"
  def publishVersion = "1.3.3.7"

  def pomSettings = PomSettings(
    description = artifactName(),
    organization = "com.lihaoyi",
    url = "https://github.com/com-lihaoyi/acyclic",
    licenses = Seq(License.MIT),
    versionControl = VersionControl.github(owner = "com-lihaoyi", repo = "acyclic"),
    developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi"))
  )

  def compileIvyDeps = Agg(Deps.scalaCompiler(crossScalaVersion))

  object test extends ScalaTests with TestModule.Utest {
    def sources = Task.Sources(millSourcePath / "src", millSourcePath / "resources")
    def ivyDeps = Agg(Deps.utest, Deps.scalaCompiler(crossScalaVersion))
  }
}

Acyclic is an example of a very small project that is a Scala compiler plugin. It is cross-built against all point versions of Scala from 2.11.12 to 2.13.10, and has a dependency on the org.scala-lang:scala-compiler

> ./mill resolve acyclic[_].compile
acyclic[2.11.12].compile
acyclic[2.12.10].compile
acyclic[2.12.11].compile
acyclic[2.12.12].compile
acyclic[2.12.13].compile
acyclic[2.12.14].compile
acyclic[2.12.15].compile
acyclic[2.12.16].compile
acyclic[2.12.8].compile
acyclic[2.12.9].compile
acyclic[2.13.0].compile
acyclic[2.13.1].compile
acyclic[2.13.2].compile
acyclic[2.13.3].compile
acyclic[2.13.4].compile
acyclic[2.13.5].compile
acyclic[2.13.6].compile
acyclic[2.13.7].compile
acyclic[2.13.8].compile
acyclic[2.13.9].compile

> ./mill acyclic[2.12.17].compile
compiling 6 Scala sources...
...

> ./mill acyclic[2.13.10].test.testLocal # acyclic tests need testLocal due to classloader assumptions
-------------------------------- Running Tests --------------------------------
...

Fansi

build.mill (download, browse)
package build
import mill._, scalalib._, scalajslib._, scalanativelib._, publish._

val dottyCommunityBuildVersion = sys.props.get("dottyVersion").toList

val scalaVersions = Seq("2.12.17", "2.13.8", "2.11.12", "3.1.3") ++ dottyCommunityBuildVersion

trait FansiModule extends PublishModule with CrossScalaModule with PlatformScalaModule {
  def publishVersion = "1.3.3.7"

  def pomSettings = PomSettings(
    description = artifactName(),
    organization = "com.lihaoyi",
    url = "https://github.com/com-lihaoyi/Fansi",
    licenses = Seq(License.MIT),
    versionControl = VersionControl.github(owner = "com-lihaoyi", repo = "fansi"),
    developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi"))
  )

  def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode::0.3.0")

  trait FansiTests extends ScalaTests with TestModule.Utest {
    def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.8.4")
  }
}

object fansi extends Module {
  object jvm extends Cross[JvmFansiModule](scalaVersions)
  trait JvmFansiModule extends FansiModule with ScalaModule {
    object test extends FansiTests with ScalaTests
  }

  object js extends Cross[JsFansiModule](scalaVersions)
  trait JsFansiModule extends FansiModule with ScalaJSModule {
    def scalaJSVersion = "1.16.0"
    object test extends FansiTests with ScalaJSTests
  }

  object native extends Cross[NativeFansiModule](scalaVersions)
  trait NativeFansiModule extends FansiModule with ScalaNativeModule {
    def scalaNativeVersion = "0.4.5"
    object test extends FansiTests with ScalaNativeTests
  }
}

Fansi is an example of a small library that is cross built against every minor version of Scala (including Scala 3.x) and every platform: JVM, JS, and Native. Both the library and the test suite are duplicated across all entries in the {version}x{platform} matrix, and you can select which one you want to compile, test, or publish

> ./mill resolve __.compile
fansi.js[2.11.12].test.compile
fansi.js[2.12.17].compile
fansi.js[2.12.17].test.compile
fansi.js[2.13.8].compile
fansi.js[2.13.8].test.compile
fansi.js[3.1.3].compile
fansi.js[3.1.3].test.compile
fansi.jvm[2.11.12].compile
fansi.jvm[2.11.12].test.compile
fansi.jvm[2.12.17].compile
fansi.jvm[2.12.17].test.compile
fansi.jvm[2.13.8].compile
fansi.jvm[2.13.8].test.compile
fansi.jvm[3.1.3].compile
fansi.jvm[3.1.3].test.compile
fansi.native[2.11.12].compile
fansi.native[2.11.12].test.compile
fansi.native[2.12.17].compile
fansi.native[2.12.17].test.compile
fansi.native[2.13.8].compile
fansi.native[2.13.8].test.compile
fansi.native[3.1.3].compile
fansi.native[3.1.3].test.compile

> ./mill fansi.jvm[2.12.17].compile
compiling 1 Scala source...
...

> ./mill fansi.js[2.13.8].test
Starting process: node
-------------------------------- Running Tests --------------------------------
...

> ./mill fansi.native[3.1.3].publishLocal
Publishing Artifact(com.lihaoyi,fansi_native0.4_3,1.3.3.7) to ivy repo...
...

Real World Mill Builds

Ammonite

Ammonite is an ergonomic Scala REPL.

Scala-CLI

Scala-CLI is the primary CLI tool that runs when you enter scala in the terminal. It is able to compile, test, run, and package your Scala code in a variety of different ways

Coursier

Coursier is a fast JVM dependency resolver, used in many build tools down resolve and download third party dependencies