diff options
-rwxr-xr-x | build.sc | 6 | ||||
-rw-r--r-- | contrib/docker/src/DockerModule.scala | 73 | ||||
-rw-r--r-- | docs/pages/9 - Contrib Modules.md | 44 |
3 files changed, 122 insertions, 1 deletions
@@ -333,6 +333,11 @@ object contrib extends MillModule { def ivyDeps = Agg(ivy"org.flywaydb:flyway-core:5.2.4") } + + object docker extends MillModule { + def moduleDeps = Seq(scalalib) + } + object bloop extends MillModule { def moduleDeps = Seq(scalalib) def ivyDeps = Agg( @@ -340,7 +345,6 @@ object contrib extends MillModule { ivy"com.lihaoyi::ujson-circe:0.7.4" ) } - } diff --git a/contrib/docker/src/DockerModule.scala b/contrib/docker/src/DockerModule.scala new file mode 100644 index 00000000..bbf4d926 --- /dev/null +++ b/contrib/docker/src/DockerModule.scala @@ -0,0 +1,73 @@ +import mill.T +import mill.scalalib.JavaModule +import os.Shellable.IterableShellable + +import scala.collection.immutable._ + +trait DockerModule { outer: JavaModule => + + trait DockerConfig extends mill.Module { + /** + * Tags that should be applied to the built image + * In the standard registry/repository:tag format + */ + def tags: T[Seq[String]] = T(List(outer.artifactName())) + def labels: T[Map[String, String]] = Map.empty[String, String] + def baseImage: T[String] = "gcr.io/distroless/java:latest" + def pullBaseImage: T[Boolean] = T(baseImage().endsWith(":latest")) + private def baseImageCacheBuster: T[(Boolean, Double)] = T.input { + val pull = pullBaseImage() + if(pull) (pull, Math.random()) else (pull, 0d) + } + + def dockerfile: T[String] = T { + val jarName = assembly().path.last + val labelRhs = labels() + .map { case (k, v) => + val lineBrokenValue = v + .replace("\r\n", "\\\r\n") + .replace("\n", "\\\n") + .replace("\r", "\\\r") + s""""$k"="$lineBrokenValue"""" + } + .mkString(" ") + + val labelLine = if(labels().isEmpty) "" else s"LABEL $labelRhs" + + s""" + |FROM ${baseImage()} + |$labelLine + |COPY $jarName /$jarName + |ENTRYPOINT ["java", "-jar", "/$jarName"] + """.stripMargin + } + + final def build = T { + val dest = T.ctx().dest + + val asmPath = outer.assembly().path + os.copy(asmPath, dest / asmPath.last) + + os.write(dest / "Dockerfile", dockerfile()) + + val log = T.ctx().log + + val tagArgs = tags().flatMap(t => List("-t", t)) + + val (pull, _) = baseImageCacheBuster() + val pullLatestBase = IterableShellable(if(pull) Some("--pull") else None) + + val result = os + .proc("docker", "build", tagArgs, pullLatestBase, dest) + .call(stdout = os.Inherit, stderr = os.Inherit) + + log.info(s"Docker build completed ${if(result.exitCode == 0) "successfully" else "unsuccessfully"} with ${result.exitCode}") + tags() + } + + final def push() = T.command { + val tags = build() + tags.foreach(t => os.proc("docker", "push", t).call(stdout = os.Inherit, stderr = os.Inherit)) + } + } +}
\ No newline at end of file diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md index c3d4751a..36eb40ef 100644 --- a/docs/pages/9 - Contrib Modules.md +++ b/docs/pages/9 - Contrib Modules.md @@ -99,6 +99,50 @@ object project extends BuildInfo { * `def buildInfoPackageName: Option[String]`, default: `None` The package name of the object. +### Docker + +Automatically build docker images from your mill project. + +Requires the docker CLI to be installed. + +In the simplest configuration just extend `DockerModule` and declare a `DockerConfig` object. + +```scala +import mill._, scalalib._ + +import ivy`com.lihaoyi::mill-contrib-docker:VERSION` +import contrib.docker.DockerModule + +object foo extends JavaModule with DockerModule { + object docker extends DockerConfig +} +``` + +Then + +``` +$ mill foo.docker.build +$ docker run foo +``` + +#### Configuration + +Configure the image by overriding tasks in the `DockerConfig` object + +```scala +object docker extends DockerConfig { + // Override tags to set the output image name + def tags = List("aws_account_id.dkr.ecr.region.amazonaws.com/hello-repository") + + def baseImage = "openjdk:11" + + // Configure whether the docker build should check the remote registry for a new version of the base image before building. + // By default this is true if the base image is using a latest tag + def pullBaseImage = true +} +``` + +Run mill in interactive mode to see the docker client output, like `mill -i foo.docker.build`. ## Flyway |