Ra/build/convention plugins - #7
Merged
Merged
Conversation
added 7 commits
June 12, 2026 10:25
…atalog Expose the version catalog to the build-logic included build so upcoming convention plugins read versions and coordinates from the same single source of truth as every module: - Declare the Android SDK levels (compileSdk, minSdk, targetSdk) and the JVM target in [versions]. Today each Android module repeats these as literals; centralizing them first means the next SDK bump becomes a one-line change. - Add the AGP and Kotlin Gradle plugin artifacts to [libraries] and wire them as compileOnly dependencies of :convention. Convention plugins compile against those APIs while the main build keeps providing them at runtime via the root plugins block, so a single copy stays on the build classpath. - Import the catalog in build-logic/settings.gradle.kts; an included build does not inherit the main build catalog automatically. - Merge the two identical kotlinxCoroutinesCore/kotlinxCoroutinesTest version refs into one kotlinxCoroutines ref in catalog. No module configuration changes yet.
…on plugins Every module now declares its build archetype through one convention plugin instead of repeating toolchain configuration: - com.compose.chi.android.application: AGP application plugin, shared Android conventions, target SDK, and packaging rules (:app). - com.compose.chi.android.library: AGP library plugin plus the same shared Android conventions (:data, :presentation). - com.compose.chi.kotlin.jvm: Kotlin JVM plugin pinned to the project JVM toolchain (:domain). Both Android plugins funnel through a single configureKotlinAndroid helper that reads compileSdk, minSdk, and the Java level from the version catalog, so the application and library archetypes cannot drift apart and the next SDK bump is a one-line catalog change instead of a three-file edit. Module build scripts keep only what genuinely distinguishes them: namespace, application identity and build types, opt-in features such as test fixtures, and their dependencies. Compose wiring intentionally stays inline in this step; it becomes its own composable convention plugin next.
…n plugin Compose is a capability layered on top of a module archetype, not an archetype of its own, so com.compose.chi.android.compose stacks on either Android convention plugin instead of existing once per archetype. It now owns the whole Compose toolchain in one place: - the Compose compiler Gradle plugin, keeping the Kotlin and Compose compiler versions in lockstep, - the compose build feature flag, - the Compose BOM on the implementation classpath, so modules declare Compose artifacts without versions, - preview tooling: ui-tooling-preview to compile @Preview composables, with the full ui-tooling inspector on debug builds only. The plugin fails fast with an actionable message when applied to a non-Android module. Which Compose libraries a module actually uses (material3, navigation, ...) stays declared in the module itself: conventions own toolchain concerns, modules own their feature surface.
Two dependency groups were declared once per module without ever varying, which makes them platform policy rather than module choice. Move them where policy lives: - com.compose.chi.koin: a new convention plugin owning the Koin BOM and koin-android for the three DI-wired modules (:app, :presentation, :data). The BOM on the implementation classpath also versions any extra Koin artifact a module adds itself, so :presentation keeps only its module-specific, version-free koin-androidx-compose line. :domain never applies it - the domain layer stays DI-framework free by architecture policy. - Universal test policy: JUnit 4 and Konsist move into all three base conventions. Every module colocates Konsist architecture tests with the code they verify, so a new module is born with that toolchain on its test classpath and the policy cannot be forgotten. The line drawn on purpose: test libraries that describe what a module actually exercises (MockK, Turbine, coroutines-test) and instrumented test dependencies stay declared per module. A build script should still answer the question of what its module really uses for everything that is a genuine choice.
The verifyModuleArchitecture task previously walked the project model inside a doLast action. Reading Project state at execution time is exactly what the configuration cache forbids, so the check was the one thing standing between this build and enabling the cache. Split the work along the configuration/execution boundary: - ModuleArchitecturePlugin now snapshots the actual module graph through lazy providers. Gradle evaluates them when fingerprinting task inputs, after every module has been configured, so the snapshot still sees the final declared dependencies of each module. - A new VerifyModuleArchitectureTask receives the contract and the snapshot as plain @input value properties and compares them in its action without ever touching Project state. Same contract, same violation messages, two improvements for free: the value inputs participate in up-to-date checking, and a contract module missing from the build now reports as a normal violation instead of an unknown-project failure.
…essors With every task in the build configuration-cache compatible, turn on the Gradle execution features a modular build is shaped for: - org.gradle.configuration-cache=true: skip the configuration phase entirely when build scripts have not changed; warm verification runs drop to about a second. - org.gradle.parallel=true: the enforced module graph keeps projects decoupled, which is exactly what makes parallel execution safe. - org.gradle.caching=true: reuse task outputs across builds and branches from the local build cache. - Daemon heap raised to 4 GB; 2 GB is tight for AGP 9 plus Kotlin 2.3 across four modules. Module dependencies also move from string paths to type-safe project accessors (TYPESAFE_PROJECT_ACCESSORS): implementation(projects.domain) is compile-checked, so a renamed or mistyped module path now fails the build instead of being discovered at resolution time. The architecture verification keeps seeing accessor-declared dependencies, since they are ordinary ProjectDependency instances.
Update the documentation to match the build after the convention-plugin extraction: - docs/modularization.md: the Gradle plumbing walkthrough now shows the real build scripts - archetype convention plugins instead of repeated android blocks - plus a table of the six plugin ids and what each owns, the settings with build-logic and type-safe accessors, and the policy line for which dependencies live in conventions versus modules. The test-fixtures consumer snippet now lists the actual consumers (:data and :presentation). - README.md: build row of the tech stack, project tree with build-logic, technologies checklist, and a roadmap entry for the build conventions and Gradle modernization work. - CHANGELOG.md: new section covering the convention plugins, catalog centralization, configuration-cache compatible verification, and the enabled Gradle execution features, with the verification steps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.