From 68bde9262933db0e12b7e2e45144ec2ff12bfeda Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sat, 23 May 2026 18:37:10 +0800 Subject: [PATCH 1/5] chore: upgrade Scala Native to 0.5.12 Motivation: Adopt the latest Scala Native 0.5.x release so future native profiling and benchmarking use the current toolchain baseline. Modification: Bump the sjsonnet native cross module from Scala Native 0.5.11 to 0.5.12, use java.util.HexFormat for native hash rendering now that Scala Native provides it, and allow fork PR CI to use Maven Central when no Databricks JFrog token is available. Result: JVM tests, native tests, native linking, formatting, and the full test suite pass locally. The kube-prometheus native output remains byte-identical against a 0.5.11 baseline. References: https://github.com/scala-native/scala-native/releases/tag/v0.5.12 --- .github/scripts/fix-build-config.sh | 74 ++++++++++++++++----- build.mill | 2 +- sjsonnet/src-native/sjsonnet/Platform.scala | 21 ++---- 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/.github/scripts/fix-build-config.sh b/.github/scripts/fix-build-config.sh index fdbd27bc..05bb588b 100755 --- a/.github/scripts/fix-build-config.sh +++ b/.github/scripts/fix-build-config.sh @@ -5,23 +5,77 @@ JFROG_HOSTNAME="databricks.jfrog.io" JFROG_REALM="Artifactory Realm" JFROG_USERNAME="gha-service-account" JFROG_URL="https://${JFROG_HOSTNAME}/artifactory/db-maven/" +MAVEN_CENTRAL_URL="https://maven-central.storage-download.googleapis.com/maven2/" + +replace_repo1_in_mill() { + python3 - "$1" << 'PY' +from pathlib import Path +import sys + +path = Path("mill") +path.write_text(path.read_text().replace("https://repo1.maven.org/maven2", sys.argv[1])) +PY +} + +force_no_server_in_mill() { + python3 - << 'PY' +from pathlib import Path + +path = Path("mill") +text = path.read_text() +old = '"${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"' +new = '"${MILL}" --no-server $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"' +path.write_text(text.replace(old, new)) +PY +} -# Configure sbt repositories mkdir -p ~/.sbt -cat > ~/.sbt/repositories << EOF +if [[ "${JFROG_ACCESS_TOKEN}" == "dummy" ]]; then + # Fork PRs cannot mint the Databricks JFrog OIDC token. Use public Maven Central directly so new + # public dependency versions that have not yet been mirrored to JFrog can still be validated. + cat > ~/.sbt/repositories << EOF +[repositories] + local + google-maven-central: ${MAVEN_CENTRAL_URL} +EOF + echo "COURSIER_REPOSITORIES=${MAVEN_CENTRAL_URL}" >> "$GITHUB_ENV" + mill_version="$(sed -n -E 's#^//\|[[:space:]]*mill-version:[[:space:]]*([^[:space:]]+).*#\1#p' build.mill | head -n 1)" + if [[ -z "${mill_version}" ]]; then mill_version="1.1.0"; fi + echo "MILL_VERSION=${mill_version%-jvm}-jvm" >> "$GITHUB_ENV" + replace_repo1_in_mill "${MAVEN_CENTRAL_URL%/}" + force_no_server_in_mill + { + echo "-Djava.net.preferIPv4Stack=true" + echo "-Djdk.tls.client.protocols=TLSv1.2" + } >> .mill-jvm-opts +else + # Configure sbt repositories + cat > ~/.sbt/repositories << EOF [repositories] local databricks-jfrog: ${JFROG_URL} EOF -# Configure sbt credentials -cat > ~/.sbt/.credentials << EOF + # Configure sbt credentials + cat > ~/.sbt/.credentials << EOF realm=${JFROG_REALM} host=${JFROG_HOSTNAME} user=${JFROG_USERNAME} password=${JFROG_ACCESS_TOKEN} EOF + mkdir -p ~/.config/coursier + { + echo "jfrog.host=${JFROG_HOSTNAME}" + echo "jfrog.realm=${JFROG_REALM}" + echo "jfrog.username=${JFROG_USERNAME}" + echo "jfrog.password=${JFROG_ACCESS_TOKEN}" + } > ~/.config/coursier/credentials.properties + + echo "COURSIER_REPOSITORIES=${JFROG_URL}" >> "$GITHUB_ENV" + replace_repo1_in_mill "https://${JFROG_USERNAME}:${JFROG_ACCESS_TOKEN}@${JFROG_URL:8}" +fi + # Configure global.sbt to load credentials mkdir -p ~/.sbt/1.0 cat > ~/.sbt/1.0/global.sbt << 'EOF' @@ -31,15 +85,3 @@ credentials ++= { else Nil } EOF - - -mkdir -p ~/.config/coursier -{ - echo "jfrog.host=${JFROG_HOSTNAME}" - echo "jfrog.realm=${JFROG_REALM}" - echo "jfrog.username=${JFROG_USERNAME}" - echo "jfrog.password=${JFROG_ACCESS_TOKEN}" -} > ~/.config/coursier/credentials.properties - -echo "COURSIER_REPOSITORIES=${JFROG_URL}" >> "$GITHUB_ENV" -sed -i "s|https://repo1.maven.org/maven2|https://${JFROG_USERNAME}:${JFROG_ACCESS_TOKEN}@${JFROG_URL:8}|g" ./mill diff --git a/build.mill b/build.mill index 58350b72..4dd0300a 100644 --- a/build.mill +++ b/build.mill @@ -261,7 +261,7 @@ object sjsonnet extends VersionFileModule { with SjsonnetPublishModule with SjsonnetJvmNative { def moduleDir = super.moduleDir / os.up - def scalaNativeVersion = "0.5.11" + def scalaNativeVersion = "0.5.12" val sourceDirs = Seq( "src", "src-native", diff --git a/sjsonnet/src-native/sjsonnet/Platform.scala b/sjsonnet/src-native/sjsonnet/Platform.scala index ab8f580e..7bbdc50c 100644 --- a/sjsonnet/src-native/sjsonnet/Platform.scala +++ b/sjsonnet/src-native/sjsonnet/Platform.scala @@ -4,6 +4,7 @@ import java.io.{ByteArrayOutputStream, File} import java.nio.charset.StandardCharsets.UTF_8 import java.util import java.util.Base64 +import java.util.HexFormat import java.util.zip.GZIPOutputStream import scala.scalanative.regex.Pattern import scala.annotation.nowarn @@ -11,7 +12,7 @@ import scala.collection.mutable import org.virtuslab.yaml.* object Platform { - private val hexChars = "0123456789abcdef".toCharArray + private val hexFormat = HexFormat.of() private def repeatCapacity(s: String, count: Int): Int = if (count > 0 && s.length <= Int.MaxValue / count) s.length * count else 0 @@ -172,22 +173,10 @@ object Platform { result.mkString("\n") } - private def bytesToHex(bytes: Array[Byte]): String = { - val out = new Array[Char](bytes.length * 2) - var i = 0 - var j = 0 - while (i < bytes.length) { - val b = bytes(i) & 0xff - out(j) = hexChars(b >>> 4) - out(j + 1) = hexChars(b & 0x0f) - i += 1 - j += 2 - } - new String(out) - } - private def computeHash(algorithm: String, s: String): String = - bytesToHex(java.security.MessageDigest.getInstance(algorithm).digest(s.getBytes(UTF_8))) + hexFormat.formatHex( + java.security.MessageDigest.getInstance(algorithm).digest(s.getBytes(UTF_8)) + ) def md5(s: String): String = computeHash("MD5", s) From 74af192120f1e1b0507ddc2bfe8cb1de31921584 Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sun, 24 May 2026 01:51:30 +0800 Subject: [PATCH 2/5] ci: avoid forcing mill jvm launcher in fork builds Motivation: Fork PR CI cannot use Databricks JFrog OIDC credentials, so #867 needs a public Maven fallback for new Scala Native 0.5.12 artifacts. The previous fallback also forced the Mill JVM launcher, which bypassed restored Mill native-launcher caches and failed early while downloading the launcher from the Google Maven mirror. Modification: Use the canonical Maven Central endpoint for dummy-token fork builds and stop exporting MILL_VERSION with a -jvm suffix. Keep the no-server Mill wrapper patch and JVM TLS options so fork builds can reuse restored launcher caches while resolving new public dependencies from Maven Central. Result: The CI fallback targets the actual fork-build failure path without changing authenticated Databricks/JFrog builds or project source code. --- .github/scripts/fix-build-config.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/scripts/fix-build-config.sh b/.github/scripts/fix-build-config.sh index 05bb588b..f4ad623e 100755 --- a/.github/scripts/fix-build-config.sh +++ b/.github/scripts/fix-build-config.sh @@ -5,7 +5,7 @@ JFROG_HOSTNAME="databricks.jfrog.io" JFROG_REALM="Artifactory Realm" JFROG_USERNAME="gha-service-account" JFROG_URL="https://${JFROG_HOSTNAME}/artifactory/db-maven/" -MAVEN_CENTRAL_URL="https://maven-central.storage-download.googleapis.com/maven2/" +MAVEN_CENTRAL_URL="https://repo.maven.apache.org/maven2/" replace_repo1_in_mill() { python3 - "$1" << 'PY' @@ -36,12 +36,9 @@ if [[ "${JFROG_ACCESS_TOKEN}" == "dummy" ]]; then cat > ~/.sbt/repositories << EOF [repositories] local - google-maven-central: ${MAVEN_CENTRAL_URL} + maven-central: ${MAVEN_CENTRAL_URL} EOF echo "COURSIER_REPOSITORIES=${MAVEN_CENTRAL_URL}" >> "$GITHUB_ENV" - mill_version="$(sed -n -E 's#^//\|[[:space:]]*mill-version:[[:space:]]*([^[:space:]]+).*#\1#p' build.mill | head -n 1)" - if [[ -z "${mill_version}" ]]; then mill_version="1.1.0"; fi - echo "MILL_VERSION=${mill_version%-jvm}-jvm" >> "$GITHUB_ENV" replace_repo1_in_mill "${MAVEN_CENTRAL_URL%/}" force_no_server_in_mill { From d6a43c024fe17182ed2b7bf7b5c42070f7ee4067 Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sun, 24 May 2026 01:56:04 +0800 Subject: [PATCH 3/5] ci: harden mill bootstrap for fork builds Motivation: Fork PR CI still failed before project compilation because the native Mill launcher path resolved mill-runner-daemon through Maven Central, and the hosted runner hit a Java TLS handshake failure. Modification: Keep the dummy-token Maven Central fallback, but explicitly use the JVM Mill launcher and patch the Mill bootstrap curl with retries. This avoids the runner-daemon resolution path and makes transient Maven Central connection failures less likely to fail the job immediately. Result: Fork PR builds can bootstrap Mill from the public mill-dist artifact path while authenticated Databricks/JFrog builds remain unchanged. --- .github/scripts/fix-build-config.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/scripts/fix-build-config.sh b/.github/scripts/fix-build-config.sh index f4ad623e..8c6f7122 100755 --- a/.github/scripts/fix-build-config.sh +++ b/.github/scripts/fix-build-config.sh @@ -29,6 +29,18 @@ path.write_text(text.replace(old, new)) PY } +add_curl_retries_in_mill() { + python3 - << 'PY' +from pathlib import Path + +path = Path("mill") +text = path.read_text() +old = 'curl -f -L -o "${MILL_TEMP_DOWNLOAD_FILE}" "${MILL_DOWNLOAD_URL}"' +new = 'curl --retry 5 --retry-delay 2 --retry-all-errors -f -L -o "${MILL_TEMP_DOWNLOAD_FILE}" "${MILL_DOWNLOAD_URL}"' +path.write_text(text.replace(old, new)) +PY +} + mkdir -p ~/.sbt if [[ "${JFROG_ACCESS_TOKEN}" == "dummy" ]]; then # Fork PRs cannot mint the Databricks JFrog OIDC token. Use public Maven Central directly so new @@ -39,8 +51,12 @@ if [[ "${JFROG_ACCESS_TOKEN}" == "dummy" ]]; then maven-central: ${MAVEN_CENTRAL_URL} EOF echo "COURSIER_REPOSITORIES=${MAVEN_CENTRAL_URL}" >> "$GITHUB_ENV" + mill_version="$(sed -n -E 's#^//\|[[:space:]]*mill-version:[[:space:]]*([^[:space:]]+).*#\1#p' build.mill | head -n 1)" + if [[ -z "${mill_version}" ]]; then mill_version="1.1.0"; fi + echo "MILL_VERSION=${mill_version%-jvm}-jvm" >> "$GITHUB_ENV" replace_repo1_in_mill "${MAVEN_CENTRAL_URL%/}" force_no_server_in_mill + add_curl_retries_in_mill { echo "-Djava.net.preferIPv4Stack=true" echo "-Djdk.tls.client.protocols=TLSv1.2" From cfa3ec6331cfadd3895142ab860da14519f6c3df Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sun, 24 May 2026 01:59:39 +0800 Subject: [PATCH 4/5] ci: use storage bucket maven fallback Motivation: GitHub-hosted fork PR runners consistently fail TLS handshakes against repo.maven.apache.org and the storage-download Maven mirror before #867 reaches project compilation. Modification: Point the dummy-token Maven fallback at the standard Google Maven Central storage bucket while retaining the JVM Mill launcher, no-server wrapper patch, and retry-hardened bootstrap curl. Result: The fork-only CI path avoids the failing Maven Central endpoints without changing authenticated Databricks/JFrog builds or sjsonnet source code. --- .github/scripts/fix-build-config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/fix-build-config.sh b/.github/scripts/fix-build-config.sh index 8c6f7122..4d481dd1 100755 --- a/.github/scripts/fix-build-config.sh +++ b/.github/scripts/fix-build-config.sh @@ -5,7 +5,7 @@ JFROG_HOSTNAME="databricks.jfrog.io" JFROG_REALM="Artifactory Realm" JFROG_USERNAME="gha-service-account" JFROG_URL="https://${JFROG_HOSTNAME}/artifactory/db-maven/" -MAVEN_CENTRAL_URL="https://repo.maven.apache.org/maven2/" +MAVEN_CENTRAL_URL="https://maven-central.storage.googleapis.com/maven2/" replace_repo1_in_mill() { python3 - "$1" << 'PY' From 50707d66538a72877f68f8067f32f83f635dc463 Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sun, 24 May 2026 02:09:07 +0800 Subject: [PATCH 5/5] ci: retrigger scala native upgrade checks Motivation: The previous #867 validation run reached green results for Graal, JS, WASM, and Native, but the JVM job failed during actions/checkout before project code or build scripts ran. This account cannot rerun failed jobs on databricks/sjsonnet directly. Modification: Add an empty commit to trigger a fresh pull_request validation run without changing repository contents. Result: CI can re-run from a clean checkout attempt while preserving the actual Scala Native 0.5.12 migration changes.