Skip to content

internal: Migrate build to sbt 2.0.1#4185

Merged
xerial merged 7 commits into
mainfrom
internal/20260701_141030-sbt-2.0.1-migration
Jul 2, 2026
Merged

internal: Migrate build to sbt 2.0.1#4185
xerial merged 7 commits into
mainfrom
internal/20260701_141030-sbt-2.0.1-migration

Conversation

@xerial

@xerial xerial commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

Migrates the entire repository build from sbt 1.12.2 → sbt 2.0.1. sbt 2.x runs its build DSL on Scala 3 and changes several defaults (all tasks cached, dependency eviction promoted to errors, platform-aware %%, exportJars default), so this touches build tooling across all six sub-builds: root, sbt-airframe, airspec, and the three example projects.

Plugin replacements

Old New
sbt-scalajs-crossproject + sbt-scala-native-crossproject org.wvlet.uni:sbt-uni-crossproject 2026.1.14
sbt-revolver (reStart) org.wvlet.uni:sbt-uni 2026.1.14uniRestart background fork-run
scalajs-env-jsdom-nodejs / PWEnv (no Scala 3 build) sbt-uni-playwrightPlaywrightJSEnv
sbt-antlr4 (no sbt 2.x build) ANTLR4 tool invoked directly from a sourceGenerators task in airframe-sql
sbt-pack 0.23→1.0.0, sbt-mima 1.1.4→1.1.6, sbt-jmh 0.4.7→0.4.8, sbt-scalajs→1.22.0, sbt-scala-native→0.5.12, sbt-ide-settings→1.1.4 sbt2 builds

Source-level fixes for the Scala 3 build DSL

  • Vararg splices xs: _*xs*; parenthesized single-arg lambdas { x: T => }{ (x: T) => }
  • PathFinder.get.get(); %%%%%
  • Def.uncached(...) wrapping for File/JSEnv/CompileAnalysis-typed tasks (now cached by default)
  • evictionErrorLevel := Warn (sbt 2.x promotes eviction conflicts to errors) and exportJars := false (sbt 2.x defaults it to true, which broke file-based resource loading e.g. YamlReader)
  • ConflictWarning.disable in metabuilds (sbt-airframe → coursier pulls _2.13 scala-xml vs _3)

sbt-airframe — migrated in-repo, sbt-2-only, released as 2026.2.0

sbt-airframe has no published sbt 2.x artifact, so it is migrated in-repo (Scala 3.8.3; FileConverter + Def.uncached fixes in AirframeHttpPlugin.scala; coursier for3Use2_13 + module exclusions). It now supports only sbt 2.x (drops sbt 1.x / Scala 2.12), so the whole airframe suite is bumped a minor to 2026.2.0 to signal that. The root build, integrationTest, and the RPC examples consume it via SBT_AIRFRAME_VERSION (default 2026.2.0). Its release workflow now publishes the _3 (not _2.12) airframe libraries it depends on.

integrationTest deliberately keeps AirframeHttpPlugin (not sbt-uni) because its purpose is to test that plugin's own client codegen.

CI bootstrap (temporary)

The root metabuild needs sbt-airframe 2026.2.0 to load, but that can only be released from main after this merges — a release deadlock. A temporary bootstrap-sbt-airframe composite action publishLocals it in the jobs that load the root build. Remove it once sbt-airframe 2026.2.0 is on Maven Central.

Ship order

  1. Merge this PR.
  2. ruby ./scripts/release.rb on main, entering 2026.2.0 at the prompt → tag v2026.2.0 → publishes org.wvlet.airframe:sbt-airframe_sbt2_3:2026.2.0 (and the rest of the suite) to Maven Central.
  3. Remove the temporary CI bootstrap action/steps (the default SBT_AIRFRAME_VERSION=2026.2.0 then resolves from Central).

Validation

All 13 CI checks green: Code format; Scala 2.12/2.13/3/3.7.x/JDK25; Scala 3 Integration Test; Scala.js 2.12/2.13/3; Scala Native; AirSpec; sbt-airframe (scripted).

🤖 Generated with Claude Code

sbt 2.x runs its build DSL on Scala 3 and changes several defaults
(cached tasks, eviction-as-error, platform-aware %%), so the whole
build tooling needed updating rather than a version bump alone.

Plugin replacements, chosen to have real sbt 2.x artifacts:
- sbt-scalajs-crossproject + sbt-scala-native-crossproject
  -> org.wvlet.uni:sbt-uni-crossproject
- sbt-revolver (reStart) -> org.wvlet.uni:sbt-uni (uniRestart)
- scalajs-env-jsdom-nodejs / PWEnv (no Scala 3 build)
  -> sbt-uni-playwright (PlaywrightJSEnv)
- sbt-antlr4 (no sbt 2.x build) -> invoke the ANTLR4 tool directly
  from a sourceGenerators task in airframe-sql

sbt-airframe has no published sbt 2.x artifact, so it is migrated
in-repo (Scala 3.8.3, FileConverter/Def.uncached fixes) and consumed
by the root build via SBT_AIRFRAME_VERSION. integrationTest keeps
AirframeHttpPlugin because its purpose is to test that plugin's own
client codegen.

Source-level fixes for the Scala 3 build DSL: vararg splices (xs* ),
parenthesized single-arg lambdas, PathFinder.get(), Def.uncached
wrapping for File/JSEnv/CompileAnalysis-typed tasks, %%% -> %%, and
evictionErrorLevel := Warn to restore sbt 1.x eviction behavior.

Validated: projectDotty/compile, "++2.13; projectJVM/compile",
projectJS/compile, projectNative/compile, sbt-airframe publishLocal,
and airspecJVM/compile.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the internal Internal changes (usually non-user facing) label Jul 1, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

xerial and others added 5 commits July 1, 2026 15:43
sbt-airframe is now a Scala 3 plugin, so its release must publish the
_3 (not _2.12) airframe libraries it depends on; fix the release
workflow accordingly.

Replace the machine-specific local dynver snapshot default for
SBT_AIRFRAME_VERSION with the next release version (2026.1.8),
matching the repo convention (a real, env-overridable release). Until
that tag is published, local builds set SBT_AIRFRAME_VERSION to the
snapshot from scripts/dynver.sh after sbt-airframe/publishLocal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three CI failures surfaced on the migration PR:

- AirSpec (Scala.js): scalajs-test-interface is a plain Scala-versioned
  artifact published only for 2.12/2.13, but sbt 2.x's platform-aware
  %% (and .cross in a Scala.js project) appended a nonexistent _sjs1_
  suffix. Pin the Scala binary suffix explicitly (Scala 3 -> 2.13).

- sbt-airframe scalafmt crashed ("last of empty IndexedSeq") because
  sbt-airframe/.scalafmt.conf still pinned runner.dialect = scala212
  while the migrated plugin now uses Scala 3 syntax; switch to scala3
  and align the scalafmt version with the root config.

- The root build's metabuild needs the not-yet-released sbt-airframe
  plugin to load, so every job that loads it failed to resolve
  org.wvlet.airframe:sbt-airframe_sbt2_3:2026.1.8. This is a release
  deadlock (the plugin can only be released from main after this merges).
  Add a temporary composite action that publishes sbt-airframe locally
  at that version and wire it into the affected jobs. Remove it once
  sbt-airframe 2026.1.8 is on Maven Central.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- YamlReaderTest (and other resource-loading tests) failed because sbt
  2.x defaults exportJars to true, packaging test resources into jars
  that file-based resource loaders (YamlReader) can't read. Restore the
  sbt 1.x class-directory classpath with exportJars := false.

- RxRenderingTest asserted an exact attribute serialization order that
  jsdom happened to produce; under the PlaywrightJSEnv (real chromium)
  the order differs. Assert each attribute independently. The jsdom env
  can't be kept: it has no Scala 3 build and its latest release (1.1.1)
  is binary-incompatible with current Scala.js jsenv APIs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TracerTest wrote to target/trace.json, which failed under sbt 2.x
(FileNotFoundException) because the base target/ directory is no longer
guaranteed to exist (sbt 2.x uses target/out/...). Create the parent
directory in newTracer so the API is robust regardless of cwd layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The openapi scripted test expected target/openapi.yaml, but the plugin
default airframeHttpOpenAPITargetDir := target.value now resolves to
sbt 2.x's versioned target/out/... directory. Restore the sbt 1.x
location (baseDirectory/target) so the generated spec lands where users
(and the scripted test) expect, and align the test's check task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mergify

mergify Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

sbt-airframe now supports only sbt 2.x (Scala 3), dropping sbt 1.x /
Scala 2.12. Bump the referenced release to a new minor, 2026.2.0, to
signal that consumer-visible change. Updates the SBT_AIRFRAME_VERSION
defaults and the CI bootstrap version accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@xerial
xerial merged commit 5e0e546 into main Jul 2, 2026
23 checks passed
@xerial
xerial deleted the internal/20260701_141030-sbt-2.0.1-migration branch July 2, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Internal changes (usually non-user facing)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant