[2.x] fix: Undefined per-project settings order (#8862)

Closes #7173
This commit is contained in:
Daniil Sivak 2026-03-03 22:09:14 +03:00 committed by GitHub
parent b1db6ba44d
commit 81edea48bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 11 deletions

View File

@ -417,17 +417,31 @@ private[sbt] object Load {
inScope(GlobalScope)(loaded.autos.globalSettings) ++
loaded.units.toSeq.flatMap { (uri, build) =>
val pluginBuildSettings = loaded.autos.buildSettings(uri)
val projectSettings = build.defined flatMap { (id, project) =>
val ref = ProjectRef(uri, id)
val defineConfig: Seq[Setting[?]] =
for (c <- project.configurations)
yield ((ref / ConfigKey(c.name) / configuration) :== c)
val builtin: Seq[Setting[?]] =
(thisProject :== project) +: (thisProjectRef :== ref) +: defineConfig
val settings = builtin ++ injectSettings.project ++ project.settings
// map This to thisScope, Select(p) to mapRef(uri, rootProject, p)
transformSettings(projectScope(ref), uri, rootProject, settings)
}
// Collect transformed settings per project and split them into "own-scope" and "cross-project":
// "own-scope" - key's project axis is `ref` itself (or global)
// "cross-project" - key explicitly targets a different project (`otherProj / key += ...`)
//
// It's necessary so that global defaults always precedes any other project's append
// See https://github.com/sbt/sbt/issues/7173
val (ownSettingsSeqs, crossSettingsSeqs) =
build.defined.toSeq.map { (id, project) =>
val ref = ProjectRef(uri, id)
val defineConfig: Seq[Setting[?]] =
for (c <- project.configurations)
yield ((ref / ConfigKey(c.name) / configuration) :== c)
val builtin: Seq[Setting[?]] =
(thisProject :== project) +: (thisProjectRef :== ref) +: defineConfig
val settings = builtin ++ injectSettings.project ++ project.settings
// map This to thisScope, Select(p) to mapRef(uri, rootProject, p)
val transformed = transformSettings(projectScope(ref), uri, rootProject, settings)
transformed.partition { s =>
s.key.scope.project match {
case Select(r) => r == ref
case _ => true // global scope
}
}
}.unzip
val projectSettings = (ownSettingsSeqs ++ crossSettingsSeqs).flatten
val buildScope = Scope(Select(BuildRef(uri)), Zero, Zero, Zero)
val buildBase = baseDirectory :== build.localBase
val settings3 = pluginBuildSettings ++ (buildBase +: build.buildSettings)

View File

@ -0,0 +1,27 @@
val check = taskKey[Unit]("Verify cross-project source generator is applied")
lazy val foo = project
.in(file("foo"))
.settings(
check := Def.uncached {
val gens = (Compile / sourceGenerators).value
assert(
gens.nonEmpty,
s"#7173: `foo / Compile / sourceGenerators` should contain the generator registered by fooAux"
)
}
)
lazy val fooAux = project
.in(file("foo-aux"))
.settings(
foo / Compile / sourceGenerators += Def.task(Seq.empty[File])
)
lazy val bar = project
// Fails:
lazy val baz = project
// Succeeds without i7173 edits:
// lazy val ewikqelkqweqopweo = project

View File

@ -0,0 +1,3 @@
# Adding an unrelated project (baz) should not prevent foo / Compile / sourceGenerators
# from including the generator registered by fooAux.
> foo/check