Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [1.0.0] - 2026-05-30

### Removed

Expand All @@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `ExtensionFunctionGenerator` emits non-suspend `is*Enabled()` / `get*()` extension functions — they delegate to `getValueCached` and can be called from any context without a coroutine. Callers that previously wrapped them in `runBlocking { … }` or a coroutine scope can drop the wrapper.
- `ConfigValues.resetOverride` re-resolves the effective value synchronously through the full provider priority chain; [getValueCached] reflects the updated value immediately after the call returns.
- Generated `GeneratedLocalFlagsX` / `GeneratedRemoteFlagsX` objects are now `internal` to their declaring Gradle module — each feature module's flag declarations are an implementation detail and no longer leak across module boundaries. Cross-module flag introspection (e.g. the debug screen) flows exclusively through `GeneratedFeaturedRegistry.all`, which the aggregator plugin builds from per-module manifests. The sample app demonstrates the per-module wiring pattern: one `ConfigValues` per feature module plus a dedicated debug aggregator, all sharing the same `LocalConfigValueProvider`.
- The plugin's ProGuard-rules generation task is renamed from `generateProguardRules` to `generateFeaturedProguardRules` to avoid name collisions with other plugins. (#190)
- User documentation moved from the in-repo MkDocs site to the [GitHub Wiki](https://github.com/AndroidBroadcast/Featured/wiki); the `docs/` site and `mkdocs.yml` are removed from the repository. (#193)

### Added

Expand All @@ -31,13 +33,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New `dev.androidbroadcast.featured.application` Gradle plugin: aggregates `featured-manifest.json` artifacts from project dependencies declared via `featuredAggregation(project(...))` and generates `object GeneratedFeaturedRegistry { val all: List<ConfigParam<*>> }` in `build/generated/featured/commonMain/`. Apply alongside `dev.androidbroadcast.featured` in the application module; wire the output directory into your source set manually (e.g., `kotlin.sourceSets.commonMain.kotlin.srcDir(...)`). Modules declaring `enum` flags also require a regular `implementation(project(...))` dependency in the consumer so the enum class is on the compile classpath; primitive-only modules need only `featuredAggregation(...)`.
- Three KMP sample feature modules — `:sample:feature-checkout`, `:sample:feature-promotions`, `:sample:feature-ui` — each declaring its own flags via the `featured { ... }` DSL. Serves as the canonical multi-module reference.
- `EnumDropdown` component in `featured-debug-ui` for overriding `enum`-typed flags in `FeatureFlagsDebugScreen`; `ConfigParam<E>` now carries `enumConstants: List<E>?` populated by codegen so the debug UI can render the dropdown without reflection.
- `featured-gradle-plugin` extracted to a `build-logic/` included build; `pluginManagement { includeBuild("build-logic") }` in the root `settings.gradle.kts` exposes it to all main-build subprojects without a version coordinate.
- `featured-gradle-plugin` lives at the repo root as an included build; `pluginManagement { includeBuild("featured-gradle-plugin") }` in the root `settings.gradle.kts` exposes it to all main-build subprojects without a version coordinate.

### Fixed

- `ConfigValues.observe()` now wraps provider `Flow` collection in `catch` — exceptions thrown by a local or remote provider are routed to `onProviderError` instead of propagating and breaking the observation flow. (#196)
- Restored R8 per-function DCE: ProGuard `-assumevalues` rules now target the actual Kotlin-compiled class name (`GeneratedFlagExtensionsXKt`). The rules were silently no-op since `@file:JvmName` was removed in an earlier PR; unused boolean flags are once again eliminated at shrinking time.
- iOS framework can now `export(project(":sample:feature-*"))` without the K/N `ObjCExportCodeGenerator` crashing — requires `api(project(...))` linkage in the aggregator module so K/N has access to type adapters for generic `ConfigParam<E>` specializations.

### Platform stability

- **Android — Stable.** Public API and behavior are covered by SemVer.
- **iOS (SKIE / Swift DCE) — Preview.** Functional, but the Swift-facing API and the SPM packaging may change in minor releases without a major bump.
- **JVM — Preview.** Functional, but the API may change in minor releases without a major bump.

## [1.0.0-Beta1] - 2026-05-17

### Added
Expand Down Expand Up @@ -115,5 +124,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- License mismatch: use MIT in all POM declarations (#174)
- Stale artifact IDs in quick-start docs (#179)

[Unreleased]: https://github.com/androidbroadcast/Featured/compare/v1.0.0-Beta1...HEAD
[Unreleased]: https://github.com/androidbroadcast/Featured/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/androidbroadcast/Featured/compare/v1.0.0-Beta1...v1.0.0
[1.0.0-Beta1]: https://github.com/androidbroadcast/Featured/releases/tag/v1.0.0-Beta1
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ For non-reactive reads (logging, eager-conditional paths) use `configValues.getV
- **Explicit API mode** is on for every KMP module — all public declarations need explicit visibility. Generated flag objects are deliberately `internal`.
- **Version catalog** (`gradle/libs.versions.toml`) is the single source of truth for dependency versions.
- **Spotless / ktlint** runs over `**/*.kt` and `**/*.kts` excluding `build/`. CI fails on `spotlessCheck`.
- **Binary Compatibility Validator** enforces public-API stability — a public-surface change without `apiDump` update fails CI. Featured has **no migration window** for breaking changes; breaking changes go in directly, the version number reflects it.
- **Public-API stability is reviewed manually in PRs** — there is no automated Binary Compatibility Validator gate (BCV was removed in #150). Reviewers check public-surface changes by hand. Featured has **no migration window** for breaking changes; breaking changes go in directly, the version number reflects it.
- **Branching:** `develop` is the integration branch; PRs go to `develop`, not `main`. `main` is updated only on releases. One logical change per PR — do not bundle.
- **Comment language:** English (per `.github/copilot-instructions.md`).
- **iOS:** SKIE is applied in `:core`; the XCFramework is named `FeaturedCore`. SKIE config is `skie.toml` at repo root.
Expand Down
12 changes: 5 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,14 @@ Featured follows [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`
- Changing a function signature in a way that requires call-site updates
- Changing the behavior of an existing API in a way that requires migration

Binary Compatibility Validator (BCV) enforces this automatically — a CI check will fail if
a public API surface changes without an explicit `apiDump` update.
Public API changes are reviewed manually during code review — there is no automated Binary Compatibility Validator gate. Reviewers verify that any public-surface change is intentional and that the version bump reflects it.

## Deprecation Policy
## API Stability and Breaking Changes

1. An API is marked `@Deprecated` with a `ReplaceWith` suggestion and a `DeprecationLevel.WARNING`.
2. The deprecated API is kept for **at least one minor release** before being promoted to `ERROR` level.
3. APIs at `ERROR` level are removed in the **next major release**.
Featured has **no deprecation or migration window**. Breaking changes are made directly; the version number reflects the impact per the Versioning table above.

Example timeline: deprecated in `1.2.0` → error in `1.3.0` → removed in `2.0.0`.
- **Android (Stable):** a breaking public-API change (removed/renamed symbol, changed signature) requires a `MAJOR` version bump.
- **iOS (Preview) and JVM (Preview):** public API may change in `MINOR` releases without a major bump; no migration window is provided.

## Releasing a New Version

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ Featured is a type-safe, reactive feature-flag and configuration management libr
- **Multiple providers** — DataStore, SharedPreferences, NSUserDefaults, JavaPreferences, Firebase Remote Config, ConfigCat, or a custom one.
- **Debug UI** — a ready-made Compose screen for overriding flags at runtime.

## Platform stability

| Platform | Status |
|---|---|
| Android | **Stable** |
| iOS (SKIE / DCE) | **Preview** |
| JVM | **Preview** |

*Preview* means the platform is functional but its public API may change in minor releases without a major version bump. *Stable* platforms follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Quick example

```kotlin
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ android.r8.strictInputValidation=true
android.proguard.failOnMissingFiles=true

# Publishing
VERSION_NAME=1.0.0-Beta1
VERSION_NAME=1.0.0

# Dokka
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
Loading