Skip to content

Migrate to sbt 2#998

Merged
xerial merged 4 commits into
mainfrom
migrate-to-sbt2
Jun 30, 2026
Merged

Migrate to sbt 2#998
xerial merged 4 commits into
mainfrom
migrate-to-sbt2

Conversation

@xerial

@xerial xerial commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

  • Bump sbt 1.12.13 -> 2.0.1, unblocked now that sbt-jcheckstyle 0.3.0 publishes an sbt2 cross-build (supersedes Update sbt to 2.0.1 #997, which only bumped build.properties and isn't sufficient on its own)
  • Bump sbt-jcheckstyle 0.2.1 -> 0.3.0 and sbt-osgi 0.10.0 -> 0.11.0-RC1 (the only version with a published sbt2 cross-build so far); sbt-pgp, sbt-scalafmt, and sbt-dynver already have sbt2 cross-builds at their current versions
  • Fix build.sbt for sbt 2's new task engine: wrap the jcheckStyle-dependsOn compile overrides in Def.uncached(...) (CompileAnalysis has no JsonFormat to cache against), and clear new Scala 3.8 strictness warnings (implicitConversions import, method-call dependsOn syntax)
  • sbt 2 itself requires JDK 17+ to run, but CI still needs to verify the library at runtime on JDK 8/11/17/21/24, and release.yml/snapshot.yml previously launched ./sbt on JDK 8/11 directly. Decoupled "JDK running sbt" from "JDK under test" via Test / fork + Test / javaHome (driven by a TEST_JAVA_HOME env var), and updated CI.yml/release.yml/snapshot.yml to install a fixed modern JDK (21) to launch sbt while forking tests onto the matrix JDK. Published bytecode is unaffected since it's already pinned to 1.8 via javacOptions.

Test plan

  • ./sbt clean compile / Test/compile — succeeds, checkstyle passes
  • ./sbt clean test — full suite passes (193 tests, 0 failures/errors) on a freshly cleared sbt2 cache
  • ./sbt jcheckStyle / ./sbt scalafmtCheckAll — pass
  • ./sbt package / ./sbt publishLocal — succeed (exercises sbt-osgi, sbt-pgp, sbt-dynver)
  • CI run on this PR (JDK 8/11/17/21/24 matrix + code_format) — verifying the JDK-decoupling approach end-to-end, since it can't be fully tested locally (only one local JDK available)

🤖 Generated with Claude Code

xerial added 4 commits June 30, 2026 12:27
Now that sbt-jcheckstyle 0.3.0 publishes an sbt2 cross-build, the sbt2
migration (superseding scala-steward PR #997) is unblocked. Bumps:

- sbt: 1.12.13 -> 2.0.1
- sbt-jcheckstyle: 0.2.1 -> 0.3.0 (the actual blocker)
- sbt-osgi: 0.10.0 -> 0.11.0-RC1 (only version with an sbt2 cross-build)
- sbt-pgp, sbt-scalafmt, sbt-dynver already cross-built for sbt2 at their
  current versions

build.sbt changes required by sbt 2's new task engine:
- Wrap the jcheckStyle-dependsOn compile overrides in Def.uncached(...);
  CompileAnalysis has no JsonFormat to cache against
- Add implicitConversions import and method-call dependsOn syntax to clear
  new Scala 3.8 strictness warnings

sbt 2 itself requires JDK 17+ to run, while CI still needs to verify the
library at runtime on JDK 8/11/17/21/24. Decouple the two via
Test/fork + Test/javaHome (driven by a TEST_JAVA_HOME env var), and update
CI.yml/release.yml/snapshot.yml to install a fixed modern JDK to launch sbt
itself while forking tests onto the matrix JDK. Published bytecode is
unaffected since it's already pinned to 1.8 via javacOptions.
CI's JDK8 lane failed: javac resolves API calls against whichever JDK
actually runs it, not the -source/-target level, so compiling on JDK21
(now required to launch sbt 2) bound to JDK9+-only covariant overloads
like ByteBuffer.flip(): ByteBuffer that don't exist on a real JDK8 at
runtime (NoSuchMethodError). This is exactly what the pre-migration setup
avoided by compiling and running each CI lane on the same single JDK.

Restore that by scoping the existing TEST_JAVA_HOME-driven javaHome
setting to the whole build instead of just Test, so sbt forks an external
javac from that JDK for compilation too. Considered --release 8 instead,
but that also hides the sun.misc.Unsafe/sun.nio.ch.DirectBuffer internals
this code intentionally relies on, requiring extra flags for a more
fragile setup than just compiling with the real target JDK.

Wire release.yml/snapshot.yml the same way so published bytecode is
compiled with a real JDK8/JDK11 again, matching their original intent.
The previous fix forked javac onto the target JDK, but missed that the
test suite is Scala, and the Scala compiler always runs in-process inside
the sbt JVM (it doesn't fork the way javac does). With sbt 2 forcing that
JVM to be JDK17+, test code calling e.g. ByteBuffer.flip() directly (as
MessageUnpackerTest.scala does) was still resolving to JDK9's covariant
ByteBuffer.flip():ByteBuffer override, which doesn't exist on real JDK8 ->
NoSuchMethodError at runtime, regardless of the javac fork fix.

scalac's -release flag avoids this the same way --release does for javac,
without needing an ignore-symbol-file escape hatch, since the test sources
never touch JDK-internal APIs the way the main sources' sun.misc.Unsafe
usage does. Verified via javap that the compiled call site now resolves to
Buffer.flip():Buffer instead of the covariant override.
saveToTmpFile called File.createTempFile("testbuf", ".dat", new
File("target")) before tmp.getParentFile.mkdirs() — createTempFile
requires the parent directory to already exist, so under occasional
filesystem timing in CI sandboxes this threw "No such file or directory"
before the directory got created. Surfaced while validating the sbt 2
migration's CI matrix; unrelated to sbt 2 itself, but was intermittently
failing the JDK8 test lane via fail-fast cancellation of the rest of the
matrix.
@xerial xerial merged commit feb87ef into main Jun 30, 2026
11 checks passed
@xerial xerial deleted the migrate-to-sbt2 branch June 30, 2026 20:05
@xerial xerial mentioned this pull request Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant