Problem: taskValue outside a task or setting macro reports an error naming value.
Solution: use a dedicated taskValue marker, preserve macro processing, and add diagnostic and behavioral regression tests.
**Problem**
The clean task no longer works as intended on sbt 2.x due to the disk cache.
**Solution**
This implements an in-memory state of invalidation for subproject and
configuration axes. So clean task would mark subprojects to be
invalidated regardless of the disk cache state.
The invalidation state would be lifted once any cached task executes,
so it's not technically same as sbt 1.x, but the UX should be similar.
Task-local filters used in sources.all(filter).value currently produce generic Scala macro scope errors. Report one actionable diagnostic at the offending reference, explaining how to move the definition outside the task or use Def.taskDyn.
Fixes#899
Add the task join as an extension method on Seq[Def.Initialize[Task[A]]] in
Def. Member resolution tries extension methods before implicit
conversions, so it is selected ahead of the generic conversion regardless of
whether sbt.Scoped is in scope.
With usePipelining enabled, earlyOutputPing was completed only as a side
effect of zinc reporting progress mid-compile (CompileProgress.afterEarlyOutput
via writeEarlyOut / notifyNoEarlyOut in zinc-core). On an action-cache hit zinc
never runs, and on a failed compile it never reports, so the promise stayed
unfulfilled and every task waiting on it - compileEarly and makePickleProducts
across downstream pipelined projects - parked forever. A warm compile;compile
on a multi-module build hung indefinitely (#9486).
The compile task now completes the ping on every resolution path. Zinc's own
completion still wins when zinc ran (tryComplete is atomic, so it can never
pre-empt it); a cache hit completes it from the pickle jar's presence on disk
(absent jar means downstream falls back to a full compile, which is the correct
degradation); a failed compile completes it false so waiters take the full
compile path and propagate the failure instead of hanging.
Generated-by: kimi-code/k3 (Oh My Pi)
Def.setting and Def.task macro expansion looks for internal wrapper
call generated for .value.
It visits all function calls in the macro. If the block contains
functions call whose type parameter is HKT, macro expansion crashed.
Macro expansion tries to match IO against '[a], and failed with MatchError.
This commit adds wildcard pattern, and leave unmatched type arguments unchanged.
**problem**
.previous was implemented as an inline expansion to wrapInitTask(Previous.runtime(in)(<instance of JsonFormat[A1]))
For example, the .previous on taskKey[String] gets inlined like
this, and then sbt's macro moves `Previous.runtime(...)(using StringJsonFormat)` into task input.
lazy val fingerprints = taskKey[String]("...")
val previousFingerprints = fingerprints.previous
// inlined
val previousFingerprints: Option[String] = {
InputWrapper.wrapInitTask(
Previous.runtime(...)(using StringJsonFormat)
)
}
- https://github.com/sbt/sbt/blob/6c8ee6ea37f93204c248f87fda788a661571a7ef/main-settings/src/main/scala/sbt/Def.scala#L410-L412
- https://github.com/sbt/sbt/blob/6c8ee6ea37f93204c248f87fda788a661571a7ef/core-macros/src/main/scala/sbt/internal/util/appmacro/Cont.scala#L468
However, if the return type of task is a bit more complicated like
Seq[String], it doesn't work:
Scala 3 Compiler's inliner creates a synthetic proxy symbol if the
inlining tree is an application, whose arguments are unstable path.
For example,
lazy val fingerprints = taskKey[Seq[String]]("...")
val previousFingerprints = fingerprints.previous
// inline to
val previousFingerprints: Option[Seq[String]] = {
val x$2$proxy1 = immSeqFormat(StringJsonFormat)
InputWrapper.wrapInitTask(
Previous.runtime(...)(using x$2$proxy1)
)
}
https://github.com/scala/scala3/blob/cc7d6db700f695234c615b9e6fca4e6895b573d4/compiler/src/dotty/tools/dotc/inlines/Inliner.scala#L324-L329
However, sbt2's Cont macro captures only `Previous.runtime(...)(using x$2$proxy1)`, while it doesn't capture the proxy definition. Consequently, while sbt macro moves the `Previous.runtime(...)` application as a task input, the proxy definition is left in the task body.
mapN(
(
link / fingerprints,
Previous.runtime(...)(using x$2$proxy1) // here x$2$proxy1 can't be found
)
) {
...
val x$2$proxy1 = ...
}
Then we get:
-- Error: /.../build.sbt:14:59
14 | val previousFingerprints = (link / fingerprints).previous
| ^
|While expanding a macro, a reference to value x$2$proxy1 was used outside the scope where it was defined
**How this PR fixed**
This commit fixes the problem by defining a dedicated Scala3 macro for .previous that summon JsonFormat[A1] inside the macro before constructing the wrapped previous.runtime(...)(using ...) by inliner. The macro insert the found given value tree directly into the previous.runtime(...)(using $found).
This way, Cont macro always moves the Previous.runtime tree along with it's given argument, without leaking compiler-generated inline proxies across scopes.
* [2.x] feat: Add cacheVersion setting for global cache invalidation
**Problem**
There was no escape hatch to invalidate all task caches when needed.
**Solution**
Add `Global / cacheVersion` setting that incorporates into the cache key
hash. Changing it invalidates all caches. Defaults to reading system
property `sbt.cacheversion`, or else 0L. When 0L, the hash is identical
to the previous behavior (backward compatible).
Fixes#8992
* [2.x] refactor: Simplify BuildWideCacheConfiguration and add cacheVersion test
- Replace auxiliary constructors with default parameter values
- Add unit test verifying cacheVersion invalidates the cache
* [2.x] fix: Restore auxiliary constructors for binary compatibility
* [2.x] test: Improve cacheVersion scripted test and add release note
- Scripted test now verifies cache invalidation via a counter
that increments only when the task body actually executes
- Add release note documenting the cacheVersion setting
Fixes#1144
The compileTimeOnly message on wrapInitInputTask said "`value` can
only be called on an input task..." when the user called `.evaluated`,
not `.value`. Changed to say `evaluated` and suggest `.toTask(" <args>").value`
as an alternative.
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Treat explicit plugin toggles as last-call-wins for the same plugin.
This avoids contradictory include/exclude states when disablePlugins(X) is followed by
enablePlugins(X) (and vice versa), aligning behavior with normal override expectations.
Apply the same semantics to ProjectMatrix and add regression coverage:
- unit tests in main/src/test/scala/ProjectSpec.scala
- scripted test in sbt-app/src/sbt-test/project/i1926-disable-enable-plugin
**Problem**
The configuration name translation in logging was incorrect. When a
configuration like MultiJvm (id="MultiJvm", name="multi-jvm") was
displayed, it showed "Multi-jvm" instead of "MultiJvm" because the
display logic was guessing the identifier by capitalizing the ivy
config name.
**Solution**
This fix:
- Adds configNameToIdent reverse mapping in ConfigIndex to look up
the correct Configuration.id from the ivy config name
- Adds toConfigIdent method in KeyIndex trait for display lookup
- Updates Scope.display to accept a config name lookup function
- Updates showLoadingKey and showContextKey to use the index lookup
Fixes#5211
Generated-by: Claude
Add a rootProject convenience macro that expands to a Project with base "."
and the enclosing val name as id. Allows writing `val root = rootProject`
instead of `val root = (project in file("."))` for a stable root project id.
When using `ProjectMatrix` with `CrossVersion.full` and Scala 2 versions like `2.13.18`, the project ID incorrectly became `$1$2_13_18` instead of `foo2_13_18`.
**Root cause:** The Scala 3 compiler creates synthetic intermediate vals (e.g., `$1`) during macro expansion. The `enclosingTerm` function in the macros was stopping at these synthetic symbols instead of continuing up the symbol tree to find the actual val name.
**Fix:** Added `Flags.Synthetic` check to skip compiler-generated symbols in:
- `main-settings/src/main/scala/sbt/std/KeyMacro.scala`
- `lm-core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala`
---------
Co-authored-by: byteforge38 <[email protected]>
**Problem**
There's a disconnect between what is perceived to be the current
Scala version, and what sbt uses internally, and thus what it
chooses to be the default scalaVersion.
**Solution**
This displays a warning if scalaVersion setting is missing.
**Problem**
sha256 is currently a bottleneck for no-op compilation.
**Solution**
This adds a local, in-memory cache of sha256 hashes of binary files
using their timestamp and file size.
The size of the digest cache can be configured using localDigestCacheByteSize,
which is set to 1MB by default.
**Problem**
For sbt 1.x, the user is forced to pick between having a stable ID for the root project,
or having the automatic aggregation of all subprojects.
The problem becomes more pronounced for large build that frequent add/remove subprojects.
**Solution**
This implements `.autoAggregate` method on `Project`, which is implemented as
`this.aggregate(LocalAggregate)`.
At the loading time, we can automatically expand `LocalAggregate` to a list of subproject references,
after we discover all subprojects.
The `autoAggregate` will use the base directory of the subproject to pick the parent-child
relationship. For example, a root project would aggregate all subprojects,
but `bar` might aggregate only `bar/bar1` and `bar/bar2`.
**Problem**
test task is typed to unit.
To distinguish test from any other tasks, we want to actually type this to something.
**Solution**
Forward TestResult to the test task.
This flips the default `:=` operation to the cached task.
To opt out of the cache, use `Def.uncached(...)` or
mark the key with `@cacheLevel(include = Array.empty)`