Multi-module sample showcasing Featured aggregator plugin#200
Conversation
Moves featured-gradle-plugin/ to build-logic/featured-gradle-plugin/ and
wires it via pluginManagement.includeBuild("build-logic") so subprojects
in the main build can apply id("dev.androidbroadcast.featured") without
a version coordinate. Unblocks the multi-module sample restructure that
needs the plugin available to feature modules in the same build.
build-logic has its own settings file with the version catalog reused
from the parent (from(files("../gradle/libs.versions.toml"))) and a
gradle.beforeProject hook that propagates parent gradle.properties
(notably VERSION_NAME) so the plugin still publishes with the project
version instead of "unspecified".
Root publishToMavenCentral / publishToMavenLocal proxy tasks delegate
to the included build so the publish workflow keeps a single entrypoint.
The plugin constraint is dropped from featured-bom: a java-platform BOM
only constrains dependency resolution and is irrelevant to plugins
applied through pluginManagement.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduces :sample:feature-checkout, :sample:feature-promotions, and
:sample:feature-ui as canonical demo of the Featured aggregator workflow:
each module applies the plugin, declares its own flags via the
featured { localFlags / remoteFlags } DSL, and exposes a public
observe-bridge file (Flow<T>-shaped) on ConfigValues. The bridges are
the pedagogical surface — GeneratedLocalFlags/GeneratedRemoteFlags
contain ConfigParam<T> instances that consumers compose into Flow via
observe(...).map { it.value }.
Fixes a latent codegen bug surfaced by the first cross-platform use of
GeneratedFlagExtensions: extensions were emitted non-suspend but
ConfigValues.getValue is suspend, so any Kotlin/Native or AndroidMain
compile failed. ExtensionFunctionGenerator now emits suspend extensions,
ConfigParamGenerator widens GeneratedLocalFlags / GeneratedRemoteFlags
to public so they can be referenced from observer bridges in other
modules, and the generated extensions file name now includes a module-
derived suffix (e.g. GeneratedFlagExtensionsSampleFeatureCheckout.kt) so
each module's JVM class name is unique without relying on @file:JvmName
(which doesn't resolve in commonMain on KMP iOS targets).
GenerateConfigParamTask now wipes its output directory on each run so
file-name changes don't leave stale generated sources behind.
Out of scope (tracked as follow-up): ProguardRulesGenerator and
featured-shrinker-tests still target the legacy non-suspend extension
signature; R8 per-function DCE via -assumevalues silently stops
matching the new suspend JVM signature until that subsystem is reworked.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Applies dev.androidbroadcast.featured.application to :sample:shared and replaces the hand-written SampleFeatureFlags with the plugin- generated GeneratedFeaturedRegistry.all sourced via featuredAggregation from :sample:feature-checkout, :sample:feature-promotions, and :sample:feature-ui. The three feature modules are also added as api dependencies because CheckoutVariant and the observe-bridge extensions defined in them appear in the public surface that downstream sample app modules (:sample:android-app, :sample:desktop) consume directly. The iOS framework blocks export the three modules so Swift sees CheckoutVariant without needing a separate Pod. generateFeaturedRegistry produces an object with five ConfigParam entries (sorted by modulePath then key) which the debug screen and ViewModel now consume in Phase 5. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 5 of PR D rewires the sample ViewModel and screens to consume
flags through the new observe-bridge pattern instead of the deleted
hand-written SampleFeatureFlags. SampleViewModel now exposes five
StateFlow<T> built from the per-module Flow bridges with stateIn
defaults that mirror each feature module's DSL default, plus four
suspend-launching setters routed through ConfigValues.override.
FeaturedSample picks up CheckoutVariant from its new home in
:sample:feature-checkout; MainActivity points FeatureFlagsDebugScreen
at GeneratedFeaturedRegistry.all.
A second collision surfaced during the first Android assembleDebug:
ConfigParamGenerator emitted a fixed-name GeneratedLocalFlags /
GeneratedRemoteFlags object in the same package across every module,
so feature-checkout and feature-ui produced duplicate dex classes
under the same FQN. ConfigParamGenerator now names both the file and
the public object with a module-derived suffix (e.g.
GeneratedLocalFlagsSampleFeatureCheckout), matching the
GeneratedFlagExtensions fix from Phase 3. The three observe-bridge
files reference the suffixed objects accordingly.
The matching iOS link crash in ObjCExportCodeGenerator was the
side-effect of the previous implementation-vs-api wiring: K/N could
not resolve the concrete type adapter for ConfigParam<CheckoutVariant>
because the feature klibs weren't on the link path. Phase 4's
api(project(":sample:feature-*")) switch and Phase 3b's matching
visibility/api widening jointly fix it — a clean
linkDebugFrameworkIosSimulatorArm64 now succeeds without changes here.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ConfigParam<E> now carries enumConstants: List<E>? so the debug UI can discover the legal values without runtime reflection. Plugin codegen fills the field for both per-module objects and the aggregated GeneratedFeaturedRegistry by emitting kotlin.enumValues<EnumFqn>() .toList() for any flag with enumTypeFqn in the manifest. FeatureFlagsDebugScreen dispatches to a new EnumDropdown (ExposedDropdownMenuBox + DropdownMenuItem) whenever param.enumConstants != null, mirroring the boolean/string/int input treatment: current value visible in the text field, options in the dropdown, source badge updates to LOCAL on selection. Boolean and scalar input paths are unchanged. Verified on Pixel 10 emulator: the sample's checkout_variant enum can be flipped to NEW_SINGLE_PAGE / NEW_MULTI_STEP via the debug screen, the main screen reacts immediately, and DataStore persistence survives both rotation and cold restart. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Updates the [Unreleased] CHANGELOG with the PR D shape: three sample feature modules, build-logic-extracted plugin, enum override input in the debug screen, and the module-suffixed generator filenames. Adds a sample/CLAUDE.md as the short navigational note for future sessions working on the sample (module map, observe-bridge convention, how to add a flag). The GitHub wiki pages Sample-App.md and Multi-Module- Setup.md are updated in the separate .wiki repo alongside this PR. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The three sample feature modules wrapped iosX64() / iosArm64() /
iosSimulatorArm64() in a listOf(...) whose result was discarded.
The constructors register the targets via side-effect; the wrapper
was leftover from copying :sample:shared (which uses .forEach to
configure framework binaries). In the leaf modules the wrapper
reads as if a .forEach { ... } was deleted. Replace with bare
statements to match the idiom used elsewhere.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
build-logic/settings.gradle.kts read the root gradle.properties via
raw java.util.Properties().load(FileInputStream), which the
configuration cache does not fingerprint. After a VERSION_NAME bump
the included build could publish the cached previous version.
Switch to providers.fileContents(...).asText so Gradle invalidates
the cache when the parent file changes. pluginManagement {} also
moves to the first block as the docs require.
Cover the new ConfigParam.enumConstants field in equals, hashCode,
and toString with focused unit tests so the :core ≥90% line-coverage
gate stays green and the equality semantics — registry dedup depends
on them — are pinned.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
There was a problem hiding this comment.
1 issue found across 107 files
Partial review: This PR has more than 50 files, so cubic reviewed the highest-priority files first. During the trial, paid plans get a higher file limit.
You can try an ultrareview to bypass the file limit, comment @cubic-dev-ai ultrareview. Learn more.
Fix all with cubic | Re-trigger cubic
There was a problem hiding this comment.
Pull request overview
This PR turns the repository’s sample into a multi-module, end-to-end demonstration of the Featured aggregation workflow (including enum flags + debug UI overrides), and moves the Gradle plugin into an included build-logic/ build to better mirror real consumer usage.
Changes:
- Restructure the sample into three feature modules plus a pure aggregator
:sample:sharedconsumingGeneratedFeaturedRegistry.all. - Extract
featured-gradle-pluginintobuild-logic/and add new/updated codegen + manifest/aggregation tasks and tests. - Extend debug UI to support enum-typed params via
ConfigParam.enumConstants.
Reviewed changes
Copilot reviewed 35 out of 107 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle.kts | Includes build-logic and registers new sample feature modules. |
| sample/shared/src/commonMain/kotlin/dev/androidbroadcast/featured/SampleViewModel.kt | Switches sample VM to per-module observer/setter bridges and adds checkout/promotions flags. |
| sample/shared/src/commonMain/kotlin/dev/androidbroadcast/featured/SampleFeatureFlags.kt | Removes legacy hand-maintained sample flag registry. |
| sample/shared/src/commonMain/kotlin/dev/androidbroadcast/featured/FeaturedSample.kt | Updates imports to use feature-checkout CheckoutVariant. |
| sample/shared/build.gradle.kts | Applies aggregator plugin, wires generated registry output, and aggregates feature modules. |
| sample/feature-ui/src/commonMain/kotlin/dev/androidbroadcast/featured/sample/ui/UiFlagObservers.kt | Adds ConfigValues observe/set extensions for UI flags. |
| sample/feature-ui/src/androidMain/AndroidManifest.xml | Adds minimal Android manifest for the new module. |
| sample/feature-ui/build.gradle.kts | New KMP feature module declaring UI local flags via DSL and wiring generated sources. |
| sample/feature-promotions/src/commonMain/kotlin/dev/androidbroadcast/featured/sample/promotions/PromotionsFlagObservers.kt | Adds ConfigValues observe/set extensions for promotions flag. |
| sample/feature-promotions/src/androidMain/AndroidManifest.xml | Adds minimal Android manifest for the new module. |
| sample/feature-promotions/build.gradle.kts | New KMP feature module declaring promotions remote flag via DSL and wiring generated sources. |
| sample/feature-checkout/src/commonMain/kotlin/dev/androidbroadcast/featured/sample/checkout/CheckoutVariant.kt | Moves CheckoutVariant enum into checkout feature module. |
| sample/feature-checkout/src/commonMain/kotlin/dev/androidbroadcast/featured/sample/checkout/CheckoutFlagObservers.kt | Adds ConfigValues observe/set extensions for checkout flags. |
| sample/feature-checkout/src/androidMain/AndroidManifest.xml | Adds minimal Android manifest for the new module. |
| sample/feature-checkout/build.gradle.kts | New KMP feature module declaring checkout flags (incl enum) via DSL and wiring generated sources. |
| sample/CLAUDE.md | Documents the new multi-module sample layout and observer-bridge convention. |
| sample/android-app/src/main/kotlin/dev/androidbroadcast/featured/sample/MainActivity.kt | Switches debug registry source to GeneratedFeaturedRegistry.all. |
| featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ExtensionFunctionGenerator.kt | Removes legacy generator from old module location. |
| featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ConfigParamGenerator.kt | Removes legacy generator from old module location. |
| featured-debug-ui/src/commonMain/kotlin/dev/androidbroadcast/featured/debugui/FeatureFlagsDebugScreen.kt | Adds enum dropdown UI path and override wiring. |
| featured-bom/build.gradle.kts | Removes gradle-plugin from BOM dependency list. |
| core/src/commonTest/kotlin/dev/androidbroadcast/featured/ConfigParamTest.kt | Adds tests covering enumConstants behavior in ConfigParam. |
| core/src/commonMain/kotlin/dev/androidbroadcast/featured/ConfigParam.kt | Adds enumConstants to ConfigParam and updates equals/toString. |
| CHANGELOG.md | Documents sample restructure, generator renames/suspend changes, enum dropdown, and build-logic extraction. |
| build.gradle.kts | Adds root proxy publish tasks delegating to included build. |
| build-logic/settings.gradle.kts | Sets up included build repos, version propagation from parent gradle.properties, includes plugin module. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/XcconfigGeneratorTest.kt | Adds unit tests for Xcconfig generator output. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/ProguardRulesGeneratorTest.kt | Adds unit tests for ProGuard rules generator output. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/TestFixtureSupport.kt | Adds shared fixture-copy + ANDROID_HOME helper utilities. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/GenerateFeaturedManifestTaskRegistrationTest.kt | Verifies manifest task registration and wiring. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedManifestSerializationTest.kt | Tests manifest JSON contract and forward-compat behavior. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedManifestIntegrationTest.kt | Adds TestKit integration tests for manifest generation. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedManifestEmptyDslTest.kt | Tests manifest generation when no DSL block exists. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedManifestConfigurationTest.kt | Validates featuredManifest consumable configuration attributes/artifacts. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedKmpPublicationTest.kt | Ensures featuredManifest does not leak into published KMP metadata. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/LocalFlagEntryTest.kt | Adds unit tests for LocalFlagEntry.isLocal behavior. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/IosConstValGeneratorTest.kt | Adds unit tests for iOS const-val generation. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/GenerateXcconfigTaskRegistrationTest.kt | Verifies generateXcconfig task registration and wiring. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/GenerateProguardRulesTaskRegistrationTest.kt | Verifies ProGuard task registration and wiring. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/GenerateIosConstValTaskRegistrationTest.kt | Verifies iOS const-val task registration and wiring. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FlagEntryUtilsTest.kt | Adds tests for modulePathToFileSuffix behavior. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FlagContainerTest.kt | Adds tests for DSL flag container and enum declarations. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginTest.kt | Smoke tests for plugin application and ID. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/ExtensionFunctionGeneratorTest.kt | Updates tests for file naming + suspend extensions + no @JvmName. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/GenerateFeaturedRegistryTaskRegistrationTest.kt | Verifies aggregator registry task registration and defaults. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/GeneratedFeaturedRegistryGeneratorTest.kt | Adds enumConstants emission assertions for enum flags. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/FeaturedAggregationParseErrorTest.kt | Ensures malformed manifests produce path-bearing errors. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/FeaturedAggregationIntegrationTest.kt | Adds TestKit integration tests for multi-module aggregation. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/FeaturedAggregationDuplicateKeyTest.kt | Adds tests ensuring duplicate keys are rejected with good messages. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/FeaturedAggregationDescriptorIntegrityTest.kt | Adds validation tests guarding against Kotlin source injection via manifests. |
| build-logic/featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/aggregation/FeaturedAggregationConfigurationTest.kt | Verifies featuredAggregation configurations and attribute setup. |
| build-logic/featured-gradle-plugin/src/test/fixtures/manifest-publish-project/settings.gradle.kts | New fixture project for manifest generation integration tests. |
| build-logic/featured-gradle-plugin/src/test/fixtures/manifest-publish-project/gradle.properties | Fixture properties enabling configuration cache. |
| build-logic/featured-gradle-plugin/src/test/fixtures/manifest-publish-project/build.gradle.kts | Fixture root build file. |
| build-logic/featured-gradle-plugin/src/test/fixtures/manifest-publish-project/app/src/main/AndroidManifest.xml | Fixture manifest for Android library module. |
| build-logic/featured-gradle-plugin/src/test/fixtures/manifest-publish-project/app/build.gradle.kts | Fixture build with flags including enum and remote boolean. |
| build-logic/featured-gradle-plugin/src/test/fixtures/kmp-publish-project/settings.gradle.kts | Fixture settings for KMP publishing smoke test. |
| build-logic/featured-gradle-plugin/src/test/fixtures/kmp-publish-project/module/src/commonMain/kotlin/.gitkeep | Keeps empty fixture source directory. |
| build-logic/featured-gradle-plugin/src/test/fixtures/kmp-publish-project/module/build.gradle.kts | Fixture KMP module applying plugin and maven-publish. |
| build-logic/featured-gradle-plugin/src/test/fixtures/kmp-publish-project/gradle.properties | Fixture configuration cache enablement. |
| build-logic/featured-gradle-plugin/src/test/fixtures/kmp-publish-project/build.gradle.kts | Fixture root build file. |
| build-logic/featured-gradle-plugin/src/test/fixtures/jvm-empty-featured-project/settings.gradle.kts | Fixture settings for “no DSL block” TestKit test. |
| build-logic/featured-gradle-plugin/src/test/fixtures/jvm-empty-featured-project/build.gradle.kts | Fixture JVM module applying plugin with no featured{} block. |
| build-logic/featured-gradle-plugin/src/test/fixtures/android-project/src/main/kotlin/dev/androidbroadcast/featured/testapp/CheckoutVariant.kt | Fixture enum type for Android integration scenarios. |
| build-logic/featured-gradle-plugin/src/test/fixtures/android-project/src/main/AndroidManifest.xml | Fixture Android manifest. |
| build-logic/featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts | Fixture settings for Android integration tests. |
| build-logic/featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts | Fixture Android app applying plugin and declaring flags. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/settings.gradle.kts | Fixture settings for multi-module aggregation integration tests. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/gradle.properties | Fixture configuration cache enablement. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/feature-profile/src/main/AndroidManifest.xml | Fixture manifest for feature-profile module. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/feature-profile/build.gradle.kts | Fixture feature module with string + remote boolean flags. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/feature-checkout/src/main/AndroidManifest.xml | Fixture manifest for feature-checkout module. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/feature-checkout/build.gradle.kts | Fixture feature module with boolean + enum flags. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/build.gradle.kts | Fixture root build file. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/app/src/main/AndroidManifest.xml | Fixture manifest for aggregating app module. |
| build-logic/featured-gradle-plugin/src/test/fixtures/aggregator-multi-module-project/app/build.gradle.kts | Fixture aggregating app using featuredAggregation dependencies. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/XcconfigGenerator.kt | Adds Xcode xcconfig generation logic for Swift compilation conditions. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ScanResultParser.kt | Adds backwards-compatible parsing for flags.txt formats into LocalFlagEntry. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ResolveFlagsTask.kt | Adds task to serialize DSL flags into flags.txt. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ProguardRulesGenerator.kt | Adds ProGuard rule generation for local flags. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/manifest/GenerateFeaturedManifestTask.kt | Adds per-module manifest JSON generation task. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedManifestContract.kt | Defines schema-major attribute and configuration/task constants. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/manifest/FeaturedManifest.kt | Introduces manifest JSON model and encoder/decoder settings. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/LocalFlagEntry.kt | Adjusts LocalFlagEntry companion constants for new generators. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/IosConstValGenerator.kt | Adds iOS expect/actual const-val generation for local flags. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/GenerateXcconfigTask.kt | Adds task to write FeatureFlags.generated.xcconfig. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/GenerateProguardRulesTask.kt | Adds task to write generated ProGuard rules. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/GenerateIosConstValTask.kt | Adds task to write iOS expect/actual constants for flags. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/GenerateConfigParamTask.kt | Updates config param generation task to module-suffixed filenames. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagSpec.kt | Adds DSL backing model and descriptor serialization. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagEntryUtils.kt | Adds modulePathToFileSuffix helper used for unique generated filenames. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FlagContainer.kt | Adds Gradle DSL receiver for flag declarations (incl enum support). |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt | New main plugin implementation wiring tasks + manifest configuration. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedExtension.kt | New DSL extension exposing localFlags/remoteFlags blocks. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedApplicationPlugin.kt | Adds aggregator plugin creating featuredAggregation configs + registry task. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ExtensionFunctionGenerator.kt | New generator emitting module-suffixed suspend extensions without @JvmName. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/ConfigParamGenerator.kt | New generator emitting module-suffixed public Generated{Local,Remote}Flags objects. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/AndroidProguardWiring.kt | Wires generated ProGuard rules into AGP variants and minify tasks. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/aggregation/GenerateFeaturedRegistryTask.kt | Adds registry aggregation task with validation against duplicates/injection. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/aggregation/GeneratedFeaturedRegistryGenerator.kt | Updates registry codegen to emit enumConstants for enum params. |
| build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/aggregation/AggregationContract.kt | Adds constants for aggregation configurations/task/package/object. |
| build-logic/featured-gradle-plugin/README.md | Documents plugin usage and enum caveats. |
| build-logic/featured-gradle-plugin/CLAUDE.md | Adds maintainer notes for plugin DSL/tasks/tests. |
| build-logic/featured-gradle-plugin/build.gradle.kts | Defines plugin publication, plugin IDs, and TestKit classpath wiring. |
Comments suppressed due to low confidence (1)
build-logic/featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/GenerateConfigParamTask.kt:57
- GenerateConfigParamTask deletes the entire outputDir (
dir.deleteRecursively()), but this directory is also used by other generation tasks (e.g. GenerateIosConstValTask writesgenerated/featured/commonMain/FeatureFlagExpect.kt). Running these tasks in the same build can delete each other’s outputs and cause nondeterministic compilation failures. Prefer isolating outputs per task (separate subdirectories) or deleting only the specific files this task owns (the module-suffixed GeneratedLocalFlags*/GeneratedRemoteFlags*/GeneratedFlagExtensions* files).
| private fun LocalFlagEntry.toConfigParamExpression(): String { | ||
| val typeArg = type | ||
| val namedArgs = | ||
| buildList { | ||
| add("key = \"$key\"") | ||
| add("defaultValue = ${formatDefault()}") | ||
| if (description != null) add("description = \"$description\"") | ||
| if (category != null) add("category = \"$category\"") |
cubic flagged that the codegen emits the deprecated kotlin.enumValues<T>() helper. Replace with kotlin.enums.enumEntries<T>() (stable since Kotlin 1.9): it returns EnumEntries<T> — a lazy, cached List<T> — so the trailing .toList() is no longer needed. Generated ConfigParam<E> objects in per-module GeneratedLocalFlags* and in the aggregated GeneratedFeaturedRegistry both benefit; ConfigParam.enumConstants still types as List<T>? unchanged. Tests pin the new emit string. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Addressed in b26ba01 — switched both |
What changed
Restructures the sample app from a single hand-maintained
SampleFeatureFlags.ktinto a 3-module aggregator demonstration offeatured-gradle-plugin's end-to-end workflow.Sample structure:
:sample:feature-checkout— ownsCheckoutVariantenum + 2 local flags (new_checkoutBoolean,checkout_variantenum).:sample:feature-promotions— 1 remote flag (promo_banner_enabledBoolean).:sample:feature-ui— 2 local UI flags (main_button_redBoolean,new_feature_section_enabledBoolean).:sample:shared— pure aggregator applyingdev.androidbroadcast.featured.application, declaringfeaturedAggregation(project(":sample:feature-*")), consumingGeneratedFeaturedRegistry.all. Houses Compose UI andSampleViewModel. No flag declarations of its own.:sample:android-app/:sample:desktop/iosApp/— unchanged shells; Android wiresDataStoreConfigValueProvider+FeatureFlagsDebugScreen.Plugin moves:
featured-gradle-pluginextracted to abuild-logic/included build wired viapluginManagement.includeBuild("build-logic"). Subprojects applyid("dev.androidbroadcast.featured")without a version coordinate.build-logic/settings.gradle.ktspropagates the parentgradle.properties(notablyVERSION_NAME) so Vanniktech publishes with the project version.publishToMavenCentral/publishToMavenLocalproxy tasks delegate to the included build — single entrypoint preserved.Codegen hardening (fixes surfaced by the first real cross-platform consumption):
ExtensionFunctionGeneratornow emitssuspendextensions —ConfigValues.getValuehas always been suspend; the generated callers needed to match.ConfigParamGeneratorwidensGeneratedLocalFlags/GeneratedRemoteFlagstopublicand appends a module-derived suffix to both the file name and the object name (e.g.GeneratedLocalFlagsSampleFeatureCheckout). Eliminates JVM class collisions when multiple aggregated modules sit on the same classpath without relying on@file:JvmName(which doesn't resolve in KMP commonMain on iOS native).GenerateConfigParamTaskcleans its output directory each run so file-name changes don't leave stale generated sources behind.ConfigParam<T>gainsenumConstants: List<T>?; the per-module and aggregator codegen paths both emitkotlin.enumValues<EnumFqn>().toList()for enum-typed params.Debug UI:
FeatureFlagsDebugScreenadds anEnumDropdown(Material3ExposedDropdownMenuBox) dispatched wheneverparam.enumConstants != null. Boolean / scalar input paths unchanged.Why
PR D closes the 4-PR registry-redesign chain (A = manifest producer, B = aggregator codegen, C = UI-agnostic debug screen, D = production-grade demo). The sample now showcases the canonical multi-module workflow the plugin was designed for, including enum flags overridable from the debug screen at runtime — previously demoed only by hand-rolled boilerplate that hid the public-API story.
Artifacts
Per-phase implementation reports + final finalize report live in
swarm-report/(gitignored):pr-d-multi-module-sample-state.md— overall plan + phase tracker.pr-d-multi-module-sample-stage-1.md…stage-7.md— per-phase rationale, verification outcomes, deviations.pr-d-multi-module-sample-debug-extensions.md+pr-d-multi-module-sample-debug-ios.md— root-cause investigations for the codegen / iOS link blockers.pr-d-multi-module-sample-e2e-scenario.md— Phase 6 manual QA scenario (24/24 PASS).pr-d-multi-module-sample-finalize.md— Phase A code review (opus) PASS; 1 NIT fixed in08a787d.How to test
Pre-merge CI runs the full Gradle matrix (build / lint / test / publishToMavenLocal). Already-validated locally on:
./gradlew :sample:android-app:assembleDebug— green./gradlew :sample:desktop:assemble— green./gradlew :sample:shared:linkDebugFrameworkIosSimulatorArm64— green./gradlew -p build-logic :featured-gradle-plugin:check— green./gradlew spotlessCheck— green./gradlew publishToMavenLocal— producesfeatured-gradle-plugin-1.0.0-Beta1artifacts in~/.m2Manual QA (already executed, scenario file in
swarm-report/):CheckoutVariantaccessible from Swift surface.Result: 24/24 PASS.
Release Notes
Changed
:sample:feature-checkout,:sample:feature-promotions,:sample:feature-ui);:sample:sharedbecomes a pure aggregator.featured-gradle-pluginextracted tobuild-logic/; the published Maven coordinates and plugin id are unchanged.GeneratedLocalFlags<ModuleSuffix>/GeneratedRemoteFlags<ModuleSuffix>— to avoid duplicate-class JVM collisions across modules. Consumers should prefer module-local extension bridges (*FlagObservers.ktpattern) over direct references to the generated objects.is<Name>Enabled()extensions are nowsuspend. Callers that invoked them from non-suspend contexts will not compile until they switch to eitherrunBlocking(discouraged) or the observe-bridge / suspend-context pattern.Added
EnumDropdowninput inFeatureFlagsDebugScreen;ConfigParam<E>carriesenumConstants: List<E>?populated by codegen for enum-typed flags.Fixed
export(project(...))no longer triggers an internalObjCExportCodeGeneratorcrash — paired with theapi(project(...))linkage so K/N resolves type adapters for genericConfigParam<E>specializations.Status
Follow-ups (not blocking this PR)
featured-shrinker-testsandProguardRulesGeneratorstill target the legacy non-suspend extension signature; R8 per-function DCE via-assumevaluesis silently degraded until reworked. Tracked separately.🤖 Generated with Claude Code