Skip to content

Bump Mill to 0.12.10 #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ jobs:
with:
jvm: temurin:17
- run: |
./mill -i "java-class-name.writeNativeImageScript" generate.sh "" && \
./mill -i "java-class-name.writeNativeImageScript" --scriptDest generate.sh --imageDest "" && \
./generate.sh && \
./mill -i "java-class-name.copyToArtifacts" artifacts/
./mill -i "java-class-name.copyToArtifacts" --directory artifacts/
if: runner.os != 'Windows'
- run: |
@call ./mill.bat -i "java-class-name.writeNativeImageScript" generate.bat ""
@call ./mill.bat -i "java-class-name.writeNativeImageScript" --scriptDest generate.bat --imageDest ""
@call generate.bat
@call ./mill.bat -i "java-class-name.copyToArtifacts" artifacts/
@call ./mill.bat -i "java-class-name.copyToArtifacts" --directory artifacts/
shell: cmd
if: runner.os == 'Windows'
- name: Test
Expand All @@ -41,7 +41,7 @@ jobs:
path: artifacts/
if-no-files-found: error
retention-days: 1
- run: ./mill -i ci.upload artifacts/
- run: ./mill -i ci.upload --directory artifacts/
if: github.event_name == 'push'
env:
UPLOAD_GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -58,9 +58,9 @@ jobs:
with:
jvm: temurin:17
- run: |
./mill -i "java-class-name.static.writeNativeImageScript" generate.sh "" && \
./mill -i "java-class-name.static.writeNativeImageScript" --scriptDest generate.sh --imageDest "" && \
./generate.sh && \
./mill -i "java-class-name.static.copyToArtifacts" artifacts/
./mill -i "java-class-name.static.copyToArtifacts" --directory artifacts/
- uses: actions/upload-artifact@v4
with:
name: launcher-linux-static
Expand All @@ -69,7 +69,7 @@ jobs:
retention-days: 1
- name: Test
run: ./mill -i java-class-name-tests.static.test
- run: ./mill -i ci.upload artifacts/
- run: ./mill -i ci.upload --directory artifacts/
if: github.event_name == 'push'
env:
UPLOAD_GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -86,9 +86,9 @@ jobs:
with:
jvm: temurin:17
- run: |
./mill -i "java-class-name.mostly-static.writeNativeImageScript" generate.sh "" && \
./mill -i "java-class-name.mostly-static.writeNativeImageScript" --scriptDest generate.sh --imageDest "" && \
./generate.sh && \
./mill -i "java-class-name.mostly-static.copyToArtifacts" artifacts/
./mill -i "java-class-name.mostly-static.copyToArtifacts" --directory artifacts/
- uses: actions/upload-artifact@v4
with:
name: launcher-linux-mostly-static
Expand All @@ -97,7 +97,7 @@ jobs:
retention-days: 1
- name: Test
run: ./mill -i java-class-name-tests.mostly-static.test
- run: ./mill -i ci.upload artifacts/
- run: ./mill -i ci.upload --directory artifacts/
if: github.event_name == 'push'
env:
UPLOAD_GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .mill-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.11.13
0.12.10
164 changes: 96 additions & 68 deletions build.sc → build.mill.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import $ivy.`de.tototec::de.tobiasroeser.mill.vcs.version::0.4.1`
import $ivy.`io.github.alexarchambault.mill::mill-native-image::0.1.31-1`
import $ivy.`io.github.alexarchambault.mill::mill-native-image-upload:0.1.31-1`

import de.tobiasroeser.mill.vcs.version._
import io.github.alexarchambault.millnativeimage.NativeImage
import io.github.alexarchambault.millnativeimage.upload.Upload
import mill._
import mill.scalalib._
import coursier.core.Version
import scala.concurrent.duration.DurationInt
import coursier.core.{Dependency, DependencyManagement}
import coursier.version.VersionConstraint
import mill.api.Loose

import scala.annotation.unused
import scala.concurrent.duration.DurationInt
import java.io.File

object Versions {
Expand All @@ -20,99 +22,114 @@ object Versions {
def osLib = "0.11.4"
def uTest = "0.8.5"
def jline = "3.25.0"
def ubuntu = "24.04"
}

trait JavaMainClassNativeImage extends NativeImage {

def nativeImageOptions = T{
def nativeImageOptions: Target[Seq[String]] = Task {
super.nativeImageOptions() ++ Seq(
"--no-fallback"
)
}
def nativeImagePersist = System.getenv("CI") != null
def nativeImagePersist: Boolean = System.getenv("CI") != null
def nativeImageGraalVmJvmId = s"graalvm-java17:${Versions.graalVmVersion}"
def nativeImageName = "java-class-name"
def nativeImageMainClass = "scala.cli.javaclassname.JavaClassName"

def nameSuffix = ""
def copyToArtifacts(directory: String = "artifacts/") = T.command {
val _ = Upload.copyLauncher(
nativeImage().path,
directory,
"java-class-name",

@unused
def copyToArtifacts(directory: String = "artifacts/"): Command[Unit] = Task.Command {
val _ = Upload.copyLauncher0(
nativeLauncher = nativeImage().path,
directory = directory,
name = "java-class-name",
compress = true,
workspace = Task.workspace,
suffix = nameSuffix
)
}
}

trait JavaClassNameModule extends ScalaModule {
override def scalaVersion = Versions.scala
override def transitiveIvyDeps = T {
super.transitiveIvyDeps()
.map(_.exclude("org.jline" -> "jline-reader"))
.map(_.exclude("org.jline" -> "jline-terminal"))
.map(_.exclude("org.jline" -> "jline-terminal-jna"))
.map(_.exclude("org.jline" -> "jline-terminal-jni"))
.map(_.exclude("org.jline" -> "jline-native"))
}
def jlineDeps = Agg(
ivy"org.jline:jline-reader:${Versions.jline}",
ivy"org.jline:jline-terminal:${Versions.jline}",
ivy"org.jline:jline-terminal-jna:${Versions.jline}",
ivy"org.jline:jline-terminal-jni:${Versions.jline}",
ivy"org.jline:jline-native:${Versions.jline}"
override def scalaVersion: Target[String] = Versions.scala

private def jlineOrg = "org.jline"
def jlineDeps: Loose.Agg[Dep] = Agg(
ivy"$jlineOrg:jline-reader:${Versions.jline}",
ivy"$jlineOrg:jline-terminal:${Versions.jline}",
ivy"$jlineOrg:jline-terminal-jna:${Versions.jline}",
ivy"$jlineOrg:jline-terminal-jni:${Versions.jline}",
ivy"$jlineOrg:jline-native:${Versions.jline}"
)
override def ivyDeps = super.ivyDeps() ++ jlineDeps

override def coursierDependency: Dependency =
super.coursierDependency
.addOverrides(
jlineDeps.toSeq.map(jd => DependencyManagement.Key.from(jd.toDependency(jd.version, jd.version, "")) ->
DependencyManagement.Values.empty.withVersionConstraint(VersionConstraint.Lazy(Versions.jline)))
)

override def allIvyDeps: Target[Agg[Dep]] = Task {
super.allIvyDeps()
.map(_.exclude(jlineOrg -> "jline-*")) ++ jlineDeps
}

override def ivyDeps: Target[Agg[Dep]] = super.ivyDeps().map(_.exclude("org.jline" -> "jline-*")) ++ jlineDeps
}

object `scala3-graal-processor` extends JavaClassNameModule {
override def mainClass = Some("scala.cli.graal.CoursierCacheProcessor")
override def ivyDeps = jlineDeps ++ Agg(
override def mainClass: Target[Option[String]] = Some("scala.cli.graal.CoursierCacheProcessor")
override def ivyDeps: Target[Agg[Dep]] = jlineDeps ++ Agg(
ivy"org.virtuslab.scala-cli::scala3-graal:${Versions.scalaCli}"
)
}

object `java-class-name` extends JavaClassNameModule with JavaMainClassNativeImage with JavaClassNamePublishModule {
def nativeImageClassPath = T {
def nativeImageClassPath: Target[Seq[PathRef]] = Task {
// adapted from https://github.com/VirtusLab/scala-cli/blob/b19086697401827a6f8185040ceb248d8865bf21/build.sc#L732-L744

val classpath = runClasspath().map(_.path).mkString(File.pathSeparator)
val cache = T.dest / "native-cp"
val cache = Task.dest / "native-cp"
// `scala3-graal-processor`.run() do not give me output and I cannot pass dynamically computed values like classpath
System.err.println("Calling scala3 graal processor on")
for (f <- classpath.split(File.pathSeparator))
System.err.println(s" $f")
val res = mill.modules.Jvm.callSubprocess(
val res = mill.util.Jvm.callProcess(
mainClass = `scala3-graal-processor`.finalMainClass(),
classPath = `scala3-graal-processor`.runClasspath().map(_.path),
mainArgs = Seq(cache.toNIO.toString, classpath),
workingDir = os.pwd
mainArgs = Seq(cache.toNIO.toString, classpath)
)
val cp = res.out.text.trim
val cp = res.out.trim()
if (cp.isBlank) System.err.println("class path can't be empty!")
assert(cp.nonEmpty)
System.err.println("Processed class path:")
for (f <- cp.split(File.pathSeparator))
System.err.println(s" $f")
cp.split(File.pathSeparator).toSeq.map(p => mill.PathRef(os.Path(p)))
}
override def ivyDeps = super.ivyDeps() ++ jlineDeps ++ Agg(

override def ivyDeps: Target[Agg[Dep]] = super.ivyDeps() ++ jlineDeps ++ Agg(
ivy"org.scala-lang::scala3-compiler:${Versions.scala}"
)
override def compileIvyDeps = super.compileIvyDeps() ++ Agg(

override def compileIvyDeps: Target[Agg[Dep]] = super.compileIvyDeps() ++ Agg(
ivy"org.graalvm.nativeimage:svm:${Versions.graalVmVersion}"
)

object static extends JavaMainClassNativeImage {
def nameSuffix = "-static"
def nativeImageClassPath = T{

def nativeImageClassPath: Target[Seq[PathRef]] = Task {
`java-class-name`.nativeImageClassPath()
}
def buildHelperImage = T {

def buildHelperImage: Target[Unit] = Task {
os.proc("docker", "build", "-t", "scala-cli-base-musl:latest", ".")
.call(cwd = os.pwd / "musl-image", stdout = os.Inherit)
.call(cwd = Task.workspace / "musl-image", stdout = os.Inherit)
()
}
def nativeImageDockerParams = T{

def nativeImageDockerParams: Target[Option[NativeImage.DockerParams]] = Task {
buildHelperImage()
Some(
NativeImage.linuxStaticParams(
Expand All @@ -121,52 +138,59 @@ object `java-class-name` extends JavaClassNameModule with JavaMainClassNativeIma
)
)
}
def writeNativeImageScript(scriptDest: String, imageDest: String = "") = T.command {

def writeNativeImageScript(scriptDest: String, imageDest: String = ""): Command[Unit] = Task.Command {
buildHelperImage()
super.writeNativeImageScript(scriptDest, imageDest)()
}
}

object `mostly-static` extends JavaMainClassNativeImage {
def nameSuffix = "-mostly-static"
def nativeImageClassPath = T{
def nativeImageClassPath: Target[Seq[PathRef]] = Task {
`java-class-name`.nativeImageClassPath()
}
def nativeImageDockerParams = Some(

def nativeImageDockerParams: Target[Option[NativeImage.DockerParams]] = Some(
NativeImage.linuxMostlyStaticParams(
"ubuntu:18.04", // TODO Pin that?
s"ubuntu:${Versions.ubuntu}",
s"https://github.com/coursier/coursier/releases/download/v${Versions.coursier}/cs-x86_64-pc-linux.gz"
)
)
}
}

object `java-class-name-tests` extends JavaClassNameModule with SbtModule {
trait Tests extends ScalaModule with super.SbtModuleTests with TestModule.Utest {
def launcher: T[PathRef]
def ivyDeps = super.ivyDeps() ++ jlineDeps ++ Seq(
trait Tests extends ScalaModule with super.SbtTests with TestModule.Utest {
def launcher: Target[PathRef]
def ivyDeps: Target[Agg[Dep]] = super.ivyDeps() ++ jlineDeps ++ Seq(
ivy"com.lihaoyi::os-lib:${Versions.osLib}",
ivy"com.lihaoyi::utest:${Versions.uTest}"
)

def testFramework = "utest.runner.Framework"
def forkEnv = super.forkEnv() ++ Seq(

def forkEnv: Target[Map[String, String]] = super.forkEnv() ++ Seq(
"JAVA_CLASS_NAME_CLI" -> launcher().path.toString
)
}

object test extends Tests {
def launcher = `java-class-name`.nativeImage()
def launcher: Target[PathRef] = `java-class-name`.nativeImage()
}

object static extends Tests {
def sources = T.sources(`java-class-name-tests`.test.sources())
def launcher = `java-class-name`.static.nativeImage()
def sources: Target[Seq[PathRef]] = Task.Sources(`java-class-name-tests`.test.sources())
def launcher: Target[PathRef] = `java-class-name`.static.nativeImage()
}

object `mostly-static` extends Tests {
def sources = T.sources(`java-class-name-tests`.test.sources())
def launcher = `java-class-name`.`mostly-static`.nativeImage()
def sources: Target[Seq[PathRef]] = Task.Sources(`java-class-name-tests`.test.sources())
def launcher: Target[PathRef] = `java-class-name`.`mostly-static`.nativeImage()
}
}

def publishVersion0 = T {
def publishVersion0: Target[String] = Task {
val state = VcsVersion.vcsState()
if (state.commitsSinceLastTag > 0) {
val versionOrEmpty = state.lastTag
Expand All @@ -190,9 +214,12 @@ def publishVersion0 = T {

def ghOrg = "VirtusLab"
def ghName = "java-class-name"

trait JavaClassNamePublishModule extends PublishModule {

import mill.scalalib.publish._
def pomSettings = PomSettings(

def pomSettings: Target[PomSettings] = PomSettings(
description = artifactName(),
organization = "org.virtuslab.scala-cli.java-class-name",
url = s"https://github.com/$ghOrg/$ghName",
Expand All @@ -213,22 +240,24 @@ trait JavaClassNamePublishModule extends PublishModule {
)
)
)
def publishVersion =
publishVersion0()

def publishVersion: Target[String] = publishVersion0()
}

@unused
object ci extends Module {
def publishSonatype(tasks: mill.main.Tasks[PublishModule.PublishData]) = T.command {
@unused
def publishSonatype(tasks: mill.main.Tasks[PublishModule.PublishData]): Command[Unit] = Task.Command {
publishSonatype0(
data = define.Target.sequence(tasks.value)(),
log = T.ctx().log
log = Task.ctx().log
)
}

private def publishSonatype0(
data: Seq[PublishModule.PublishData],
log: mill.api.Logger
): Unit = {
data: Seq[PublishModule.PublishData],
log: mill.api.Logger
): Unit = {

val credentials = sys.env("SONATYPE_USERNAME") + ":" + sys.env("SONATYPE_PASSWORD")
val pgpPassword = sys.env("PGP_PASSWORD")
Expand All @@ -252,7 +281,6 @@ object ci extends Module {
snapshotUri = "https://oss.sonatype.org/content/repositories/snapshots",
credentials = credentials,
signed = true,
// format: off
gpgArgs = Seq(
"--detach-sign",
"--batch=true",
Expand All @@ -262,7 +290,6 @@ object ci extends Module {
"--armor",
"--use-agent"
),
// format: on
readTimeout = timeout.toMillis.toInt,
connectTimeout = timeout.toMillis.toInt,
log = log,
Expand All @@ -273,10 +300,11 @@ object ci extends Module {
publisher.publishAll(isRelease, artifacts: _*)
}

def upload(directory: String = "artifacts/") = T.command {
@unused
def upload(directory: String = "artifacts/"): Command[Unit] = Task.Command {
val version = publishVersion0()

val path = os.Path(directory, os.pwd)
val path = os.Path(directory, Task.workspace)
val launchers = os.list(path).filter(os.isFile(_)).map { path =>
path -> path.last
}
Expand Down
Loading