Fixes#2998
When test is run at the prompt in a multi-project build,
sbt aggregates <proj>/test across subprojects. Each subproject's
TestResultLogger emits its own pass/fail summary inline, but the
aggregation layer never restated which projects failed. The final
"sbt.TestsFailedException" line surfaced no project names or failing
test classes, so on CI users had to scrollback-grep through thousands
of log lines to find what broke.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
**Problem**
We need some tooling to debug caching issues.
**Solution**
This adds an exeprimental execution log support,
which shows input and output of cached tasks.
**Problem**
Current MixedAnalyzingCompiler analysis cache caches using the last write,
assuming all writing happens via it. However, this doesn't work with
sbt 2.x caching system where the gz file under it can switch.
**Solution**
This switches to using caffeine caching, which includes file size
and file timestamp for local analysis caching.
**Problem**
Some tests are failing.
**Solution**
* Port EvictionErrorSpec to lm-coursier
* Port EvictionWarningSpec to lm-coursier
* Port InclExclSpec to lm-coursier
* Port ZincComponentCompilerSpec to lm-coursier
* Apparently we still need lmIvy
Bumps io to released 1.12.0 which contains the atomic-write changes
to IO.copyFile, IO.transfer(InputStream, File), and IO.jar/zip.
ActionCacheStore.putBlob now uses IO.transfer instead of duplicating
staging logic.
**Problem**
Projects defined in subdirectory build.sbt files are
not correctly resolved to the base directory relative to the file.
**Solution**
Call resolveBase.
Bug 1: bgRun forks with inheritIO() instead of LoggedOutput
bgRunTask / bgRunMainTask resolve their fork options via (run / forkOptions), which inherits run / connectInput := true. That has two downstream consequences:
1. ForkRun.configLogged (in run/src/main/scala/sbt/Run.scala) skips installing OutputStrategy.LoggedOutput(log) whenever config.connectInput == true.
2. Fork.apply (in run/src/main/scala/sbt/Fork.scala) sees connectInput && outputStrategy == StdoutOutput and takes the interactiveFork path, which calls jpb.inheritIO().
Bug 2: Background-job log relay drops messages after the spawning task ends
Even after Bug 1 is fixed, LoggedOutput routes the forked process's stdout into the background ManagedLogger, whose appenders include a shared RelayAppender. The relay calls CommandExchange.logMessage(event), which uses isChannelOwner(c) to pick the target channel.
**Problem**
In sbt 2.x, forking still creates layered classloader in the worker process,
which doesn't work for some tests.
**Solution**
This provides an escape hatch to emulate the sbt 1.x semantics of
using the system classpath for testing.
**Problem**
`dependencyTree` with `--browse` can throw when desktop browse is unavailable (for example on Wayland/headless environments), causing command failure.
**Solution**
Handle unsupported desktop/browse actions and runtime browse failures gracefully by logging a warning instead of throwing, and add regression tests for unsupported/throwing desktop scenarios.
Generated-by: Cursor Codex 5.3