|
| 1 | +import org.gradle.api.initialization.ProjectDescriptor |
| 2 | + |
1 | 3 | pluginManagement { |
2 | 4 | includeBuild("build-logic") |
3 | 5 | repositories { |
@@ -190,3 +192,99 @@ include( |
190 | 192 | ":vendor:tipkit:tipkit-m2", |
191 | 193 | ":vendor:opencv:sdk", |
192 | 194 | ) |
| 195 | + |
| 196 | +// ---- Cross-module aggregation wiring (single source of truth) ---- |
| 197 | +// The root build script can no longer discover modules by iterating `subprojects` |
| 198 | +// (Isolated Projects forbids it), so the module sets used for coverage and the |
| 199 | +// aggregate unit-test task are derived here from the actual included projects and |
| 200 | +// handed to the root project via extra properties. New modules are picked up |
| 201 | +// automatically; only modules that break the usual conventions need to be listed |
| 202 | +// in the small denylists below (their plugin type isn't knowable until project |
| 203 | +// configuration, which IP forbids the root from inspecting). |
| 204 | +// Only real modules, not the intermediate container projects that Gradle |
| 205 | +// auto-creates for nested paths (e.g. `:apps:flipcash:shared`) — those have no |
| 206 | +// build script and must not receive a `kover(project(...))` / test dependency. |
| 207 | +val includedProjectPaths = buildList { |
| 208 | + fun collect(descriptor: ProjectDescriptor) { |
| 209 | + val hasBuildScript = descriptor.projectDir.resolve("build.gradle.kts").exists() || |
| 210 | + descriptor.projectDir.resolve("build.gradle").exists() |
| 211 | + if (descriptor.path != ":" && hasBuildScript) { |
| 212 | + add(descriptor.path) |
| 213 | + } |
| 214 | + descriptor.children.forEach(::collect) |
| 215 | + } |
| 216 | + collect(rootProject) |
| 217 | +} |
| 218 | + |
| 219 | +// Coverage: every module under these paths applies a `flipcash.android.*` |
| 220 | +// convention plugin (which pulls in Kover); :apps:flipcash:app applies Kover |
| 221 | +// directly. The denylist holds the modules under those paths that have no Kover. |
| 222 | +val koverPaths = listOf(":apps:flipcash", ":libs", ":ui", ":definitions", ":services:flipcash", ":services:opencode") |
| 223 | +val nonKoverModules = setOf( |
| 224 | + ":apps:flipcash:benchmark", // com.android.test — no Kover |
| 225 | + ":apps:flipcash:shared:ksp", // pure-JVM helper — no Kover |
| 226 | + ":definitions:opencode:protos", // java-library proto jar — no Kover |
| 227 | + ":definitions:flipcash:protos", // java-library proto jar — no Kover |
| 228 | +) |
| 229 | +val koverModules = includedProjectPaths.filter { path -> |
| 230 | + koverPaths.any { path == it || path.startsWith("$it:") } && path !in nonKoverModules |
| 231 | +} |
| 232 | + |
| 233 | +// Aggregate unit tests: :apps:flipcash plus the two service modules. Android |
| 234 | +// modules expose `testDebugUnitTest`, pure-JVM modules expose `test`, and the |
| 235 | +// androidTest `:benchmark` module has no unit-test task. |
| 236 | +val unitTestPaths = listOf(":apps:flipcash", ":services:flipcash", ":services:opencode") |
| 237 | +val jvmUnitTestModules = setOf(":apps:flipcash:shared:ksp") |
| 238 | +val noUnitTestModules = setOf(":apps:flipcash:benchmark") |
| 239 | +val unitTestCandidates = includedProjectPaths.filter { path -> |
| 240 | + unitTestPaths.any { path == it || path.startsWith("$it:") } && path !in noUnitTestModules |
| 241 | +} |
| 242 | +val androidUnitTestModules = unitTestCandidates.filter { it !in jvmUnitTestModules } |
| 243 | + |
| 244 | +// Forced dependency versions for the per-project configuration below. The |
| 245 | +// version catalog isn't registered on projects yet at `beforeProject` time, so |
| 246 | +// the coordinates are resolved here from the catalog's TOML (keeping them in sync |
| 247 | +// with `gradle/libs.versions.toml`) and captured as plain strings. |
| 248 | +val versionsToml = rootDir.resolve("gradle/libs.versions.toml").readText() |
| 249 | +fun catalogVersion(key: String): String = |
| 250 | + Regex("""(?m)^\s*${Regex.escape(key)}\s*=\s*"([^"]+)"""") |
| 251 | + .find(versionsToml)?.groupValues?.get(1) |
| 252 | + ?: error("Version '$key' not found in gradle/libs.versions.toml") |
| 253 | +val kotlinVersion = catalogVersion("kotlin") |
| 254 | +val serializationVersion = catalogVersion("kotlinx-serialization") |
| 255 | + |
| 256 | +// Per-project configuration that previously lived in the root build script's |
| 257 | +// `allprojects { }` block, plus handing the aggregation lists above to the root |
| 258 | +// project. Isolated Projects forbids a project (the root) configuring other |
| 259 | +// projects, so this runs via the isolated `gradle.lifecycle.beforeProject` hook, |
| 260 | +// which applies per-project setup to every project (including the root) without |
| 261 | +// crossing project boundaries. |
| 262 | +// |
| 263 | +// The action is isolated (serialized), so it must not capture a reference to this |
| 264 | +// settings script. Everything it needs is therefore copied into local `val`s in |
| 265 | +// the block below — captured by value rather than via the script object. |
| 266 | +run { |
| 267 | + val koverModulesForRoot = koverModules.toList() |
| 268 | + val androidUnitTestForRoot = androidUnitTestModules.toList() |
| 269 | + val jvmUnitTestForRoot = jvmUnitTestModules.toList() |
| 270 | + val forcedDependencies = listOf( |
| 271 | + "org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion", |
| 272 | + "org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion", |
| 273 | + "org.jetbrains.kotlin:kotlin-metadata-jvm:$kotlinVersion", |
| 274 | + ) |
| 275 | + gradle.lifecycle.beforeProject { |
| 276 | + if (path == ":") { |
| 277 | + extra["flipcash.koverModules"] = koverModulesForRoot |
| 278 | + extra["flipcash.androidUnitTestModules"] = androidUnitTestForRoot |
| 279 | + extra["flipcash.jvmUnitTestModules"] = jvmUnitTestForRoot |
| 280 | + } |
| 281 | + |
| 282 | + configurations.configureEach { |
| 283 | + exclude(mapOf("group" to "org.jetbrains.kotlin", "module" to "kotlin-stdlib-jdk7")) |
| 284 | + resolutionStrategy.force(*forcedDependencies.toTypedArray()) |
| 285 | + } |
| 286 | + tasks.matching { task -> task.name.contains("kapt") }.configureEach { |
| 287 | + enabled = false |
| 288 | + } |
| 289 | + } |
| 290 | +} |
0 commit comments