Support sbt 2.0.0 (drop sbt 1.x cross-build)#620
Conversation
This completes the sbt 2 migration. Now that sbt 2.0.0 is officially
released, the plugin targets sbt 2.0.0 / Scala 3.8.4 exclusively.
Cross-building back to sbt 1.x is no longer supported, since the
required source-level changes (Scala 3 syntax, sbt 2 cached-task
output types, Def.uncached escape hatch) would be too invasive to
keep both targets in one source tree.
Plugin changes:
- Bump to sbt 2.0.0 and Scala 3.8.4 (matches sbt 2.0.0's bundled compiler)
- Wrap pack/packArchive*/packCopyDependencies and related tasks in
Def.uncached(...) — opts out of sbt 2's typed cache, which doesn't
accept File/Path outputs or custom return types without JsonFormat
- Drop Def.derive wrappers on file-producing tasks: sbt 2's automatic
dynamicFileOutputs broadcasts those derivations into delegated
scopes where the underlying task is not defined and the build fails
to load. The wrapped tasks are project-level, not config-scoped, so
Def.derive was unnecessary
- Hardcode Runtime config for packLibJars/packModuleEntries instead of
reading configuration.value at project scope (no longer defined
without Def.derive)
- Switch packTargetDir default from target.value to
baseDirectory.value / "target" — sbt 2's target.value resolves to a
nested target/out/jvm/u/{project}/ path, which is not the stable
location users expect for pack output
- Plumb sbt's fileConverter through PluginCompat so HashedVirtualFileRef
paths are resolved with the build's MappedFileConverter (which
expands ${OUT}/${BASE} placeholders) instead of the placeholder-leaving
PlainVirtualFileConverter
Source layout & tooling:
- Consolidate scala-2/ and scala-3/ PluginCompat into a single
src/main/scala/ tree
- Update .scalafmt.conf dialect to scala3
- Drop sbt 1.x CI job; simplify command to `./sbt test scripted`
Scripted test fixes:
- Replace `force ()` infix invocation with `.force()` (Scala 3
rejects the Scala 2 nullary-method infix form)
- nested-project: set distinct project names + crossPaths := false
to avoid sbt 2's "Overlapping output directories" check
- copy-dependencies: anchor packCopyDependenciesTarget to
baseDirectory.value / "target" for the same reason packTargetDir
was anchored
- Remove sbt 1.x pins on jvm-version-opts and exclude-test-config
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request migrates the sbt-pack plugin to Scala 3 and sbt 2.0.0. Key changes include replacing Def.derive with Def.uncached, integrating sbt 2.x's FileConverter for virtual file compatibility, and updating target directory definitions to avoid nested output directories. Feedback suggests updating packCopyDependenciesTarget to use packTargetDir.value / "lib" instead of target.value / "lib" to maintain consistency with the updated packTargetDir and ensure dependencies are copied to the correct location.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| }, | ||
| packCopyDependenciesUseSymbolicLinks := true, | ||
| packIncludedProjectScopes := Seq("compile->"), | ||
| packCopyDependenciesTarget := target.value / "lib", |
There was a problem hiding this comment.
Since packTargetDir was updated to default to baseDirectory.value / "target" to avoid sbt 2.0's nested output directory, packCopyDependenciesTarget should also be updated to use packTargetDir.value / "lib" instead of target.value / "lib". This ensures that copied dependencies are placed in the stable, user-expected target/lib directory by default, maintaining consistency with packTargetDir and sbt 1.x behavior.
packCopyDependenciesTarget := packTargetDir.value / "lib",- .scala-steward.conf: drop the 'scala-library 2.12.*' pin; sbt 2 plugins use Scala 3. The pin still lives on the sbt-1 branch where it is still correct. - .github/dependabot.yml: add a second updates entry targeting the sbt-1 branch so GitHub Actions versions stay current on that branch too. Note: scala-steward only tracks the default branch by default. To get Scala/sbt update PRs opened against the sbt-1 branch, the repo needs a non-default-branch entry in the scala-steward fleet config (e.g. scala-steward-org/repos-github-oss). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Resumes the sbt 2 migration now that sbt 2.0.0 is officially released, and completes it by targeting sbt 2.0.0 / Scala 3.8.4 exclusively. Cross-building back to sbt 1.x is dropped — the source-level differences (Scala 3 syntax, sbt 2 cached-task output types,
Def.uncachedescape hatch,fileConverterplumbing) make a single cross-built source tree impractical.Plugin changes
Def.uncached(...)— opts out of sbt 2's typed cache, which doesn't acceptFile/Pathoutputs or custom return types withoutJsonFormat.Def.derivewrappers on file-producing tasks. sbt 2's automaticdynamicFileOutputsbroadcasts the derivations into delegated scopes where the underlying task isn't defined, causing build-load failures.Runtimeconfig forpackLibJars/packModuleEntries(was readingconfiguration.value, which is now unresolved at project scope after droppingDef.derive).packTargetDirdefaults tobaseDirectory.value / "target"instead oftarget.value— sbt 2'starget.valueresolves to a nestedtarget/out/jvm/u/{project}/path, not the stable location users expect.fileConverterthroughPluginCompatsoHashedVirtualFileRefpaths resolve via the build'sMappedFileConverter(expands${OUT}/${BASE}placeholders) instead of the placeholder-leavingPlainVirtualFileConverter.Layout & tooling
scala-2/andscala-3/PluginCompat into a singlesrc/main/scala/tree..scalafmt.confdialect toscala3../sbt test scripted.Scripted test fixes
force ()infix invocation with.force()(Scala 3 rejects the Scala 2 nullary-method infix form).nested-project: distinct project names +crossPaths := falseto avoid sbt 2's "Overlapping output directories" check.copy-dependencies: anchorpackCopyDependenciesTargettobaseDirectory.value / "target"for the same reason aspackTargetDir.jvm-version-optsandexclude-test-config— they now run under sbt 2.Test plan
./sbt scalafmtCheckAll— clean./sbt test— 5 unit tests pass./sbt scripted— all 17 scripted tests pass under sbt 2.0.0🤖 Generated with Claude Code