{"id":13610165,"url":"https://github.com/j-roskopf/ComposeGuard","last_synced_at":"2025-04-12T22:33:07.142Z","repository":{"id":239909219,"uuid":"800960208","full_name":"j-roskopf/ComposeGuard","owner":"j-roskopf","description":"A Gradle plugin for detecting regressions in Jetpack Compose","archived":false,"fork":false,"pushed_at":"2024-05-28T17:01:21.000Z","size":1005,"stargazers_count":57,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-05-29T05:15:03.672Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/j-roskopf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-15T10:29:08.000Z","updated_at":"2024-05-30T05:41:13.889Z","dependencies_parsed_at":"2024-05-30T05:41:11.140Z","dependency_job_id":"faf5035e-ecf6-460e-9364-07fb84259311","html_url":"https://github.com/j-roskopf/ComposeGuard","commit_stats":null,"previous_names":["j-roskopf/composeguard"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-roskopf%2FComposeGuard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-roskopf%2FComposeGuard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-roskopf%2FComposeGuard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j-roskopf%2FComposeGuard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/j-roskopf","download_url":"https://codeload.github.com/j-roskopf/ComposeGuard/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248641545,"owners_count":21138226,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T19:01:41.999Z","updated_at":"2025-04-12T22:33:07.136Z","avatar_url":"https://github.com/j-roskopf.png","language":"Kotlin","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/compose_guard_icon.png\" width=\"512\"\u003e\n  \u003ch1\u003eCompose Guard\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://central.sonatype.com/namespace/com.joetr.compose.guard\"\u003e\u003cimg alt=\"Maveb Central\" src=\"https://img.shields.io/maven-central/v/com.joetr.compose.guard/com.joetr.compose.guard.gradle.plugin\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://opensource.org/license/mit/\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/badge/License-MIT-blue.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/j-roskopf/ComposeGuard/actions/workflows/release.yml\"\u003e\u003cimg alt=\"Release Workflow\" src=\"https://github.com/j-roskopf/ComposeGuard/actions/workflows/release.yml/badge.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://androidweekly.net/issues/issue-624\"\u003e\u003cimg alt=\"Android Weekly\" src=\"https://img.shields.io/badge/News-Android_Weekly_%23624-palevioletred?logo=android\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://blog.canopas.com/android-stack-weekly-issue-126-e892cc8bf543\"\u003e\u003cimg alt=\"Android Stack Weekly\" src=\"https://img.shields.io/badge/News-Android_Stack_Weekly_%23126-palevioletred?logo=android\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://mailchi.mp/kotlinweekly/kotlin-weekly-408\"\u003e\u003cimg alt=\"Kotlin Weekly\" src=\"https://img.shields.io/badge/News-Kotlin_Weekly_%23408-palevioletred?logo=kotlin\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://jetc.dev/issues/215#github-j-roskopf--composeguard\"\u003e\u003cimg alt=\"Jetpack Compose Newsletter\" src=\"https://img.shields.io/badge/News-Jetpack_Compose_Newsletter_%23215-palevioletred?logo=jetpackcompose\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://jetc.dev/issues/216#compose-guard-detecting-regressions-in-jetpack-compose\"\u003e\u003cimg alt=\"Jetpack Compose Newsletter\" src=\"https://img.shields.io/badge/News-Jetpack_Compose_Newsletter_%23216-palevioletred?logo=jetpackcompose\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://hitsofcode.com/github/j-roskopf/ComposeGuard/view?branch=main\"\u003e\u003cimg src=\"https://hitsofcode.com/github/j-roskopf/ComposeGuard?branch=main\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\u003cbr\u003e\n\n\nA gradle plugin for detecting regressions in Jetpack Compose / Compose Multiplatform:\n* New restartable but not skippable @Composables are added\n* New unstable classes are added (only triggers if they are used as a @Composable parameter)\n* New @dynamic properties are added\n* New unstable parameters are added to a @Composable\n\nIn an Android project, Compose Guard adds 3 tasks:\n* `\u003cvariant\u003eComposeCompilerGenerate` (example `./gradlew releaseComposeCompilerGenerate`)\n  - Generate golden compose metrics to compare against\n* `\u003cvariant\u003eComposeCompilerCheck` (example `./gradlew releaseComposeCompilerCheck`)\n  - Generates new metrics and compares against golden values\n* `./gradlew composeCompilerClean`\n  - Deletes all compiler metrics\n\nIn a Multiplatform project, Compose Guard adds the same 2 `Check` and `Generate` tasks (as well as a root `composeCompilerClean` task) for each supported target following the pattern `\u003ctarget\u003e\u003cvariant if applicable\u003eComposeCompilerGenerate`\n* `\u003ctarget\u003e\u003cvariant\u003eComposeCompilerGenerate` \n  - Examples: `./gradlew androidReleaseComposeCompilerGenerate`, `./gradlew jvmComposeCompilerGenerate`, ` ./gradlew iosArm64ComposeCompilerGenerate`, `./gradlew jsComposeCompilerGenerate`, `./gradlew wasmJsComposeCompilerGenerate`\n  - Generate golden compose metrics to compare against\n* `\u003ctarget\u003e\u003cvariant\u003eComposeCompilerCheck` \n  - Examples: `./gradlew androidReleaseComposeCompilerCheck`, `./gradlew jvmComposeCompilerCheck`, `./gradlew iosArm64ComposeCompilerCheck`, `./gradlew jsComposeCompilerCheck`, `./gradlew wasmJsComposeCompilerCheck`\n  - Generates new metrics and compares against golden values\n* `./gradlew composeCompilerClean`\n  - Deletes all compiler metrics\n\n## Platforms\n![](https://img.shields.io/badge/Android-black.svg?style=for-the-badge\u0026logo=android) | ![](https://img.shields.io/badge/iOS-black.svg?style=for-the-badge\u0026logo=apple) | ![](https://img.shields.io/badge/Desktop-black.svg?style=for-the-badge\u0026logo=apple) | ![](https://img.shields.io/badge/Web-black.svg?style=for-the-badge\u0026logo=google-chrome)\n:----: | :----: |:----------------------------------------------------------------------------------:| :----:\n✅ | ✅ |                                         ✅                                          | ✅\n\n\n## Adding To Your Project\n\nAvailable via Maven Central - ![Maven Central Version](https://img.shields.io/maven-central/v/com.joetr.compose.guard/com.joetr.compose.guard.gradle.plugin)\n\nIn your root build file:\n\n```kotlin\nplugins {\n    id(\"com.joetr.compose.guard\") version \"\u003clatest version\u003e\" apply false\n}\n```\n\nIn any module you want to apply checks:\n\n```kotlin\nplugins {\n    id(\"com.joetr.compose.guard\")\n}\n```\n\n## Configuring Compose Guard\n\nEach check that is performed has the ability to be turned off in case it is not useful to you.\n\n```kts\ncomposeGuardCheck {\n    errorOnNewDynamicProperties = false // defaults to true\n    errorOnNewRestartableButNotSkippableComposables = false // defaults to true\n    errorOnNewUnstableClasses = false // defaults to true\n    errorOnNewUnstableParams = false // defaults to true\n    /**\n     * In strong skipping mode (https://developer.android.com/develop/ui/compose/performance/stability/strongskipping)\n     * you may not care about new unstable params if the composable is already skippable\n     */\n    ignoreUnstableParamsOnSkippableComposables = true // defaults to false\n\n    /**\n     * If baseline metrics are missing, the check task will no longer fail and will instead just report\n     * all checks. \n     */\n    reportAllOnMissingBaseline = true // defaults to false\n\n    /**\n     * Stability cannot be automatically inferred across module boundaries. With this option enabled,\n     * any properties marked as 'runtime' stability will be inferred to be unstable. If you can guarantee properties\n     * as stable across module boundaries, mark them as so. \n     */\n    assumeRuntimeStabilityAsUnstable = true // defaults to false\n}\n```\n\nThe output directory of the golden metrics has the ability to be configured as well.\n\n```kotlin\ncomposeGuardGenerate {\n    outputDirectory = layout.projectDirectory.dir(\"custom_dir\").asFile\n}\n```\n\nAdditionally, if you would prefer complete control over how the metrics are generated, you can disable this plugin from configuring the Kotlin compile task.\nThis is intended advanced users that prefer compiler performance over easy baseline generation.\nWith this set, the plugin no longer configures anything in the Kotlin compile task. \nSo an end user would be responsible for generating the golden metrics and the check metrics before running the check task.\n\n```kotlin\ncomposeGuard { \n    configureKotlinTasks = false // defaults to true\n}\n```\n\n## Signing locally\n\nThis is required to test.\n\n* Install gnupg - https://formulae.brew.sh/formula/gnupg\n* Generate a key - https://central.sonatype.org/publish/requirements/gpg/#generating-a-key-pair\n  * `gpg --full-generate-key` \n* List keys and grab newly generated key (40 digits)\n  * `gpg --list-keys`\n* `gpg --export-secret-keys THE_KEY_THAT_YOU_JUST_GENERATED \u003e composeguard.gpg`\n* Modify your gradle home `gradle.properties` with the following:\n```\nsigning.keyId=LAST_8_DIGITS_OF_KEY\nsigning.password=PASSWORD_USED_TO_GENERATE_KEY\nsigning.secretKeyRingFile=/Users/YOURUSERNAME/.gnupg/composeguard.gpg (or wherever you stored the keyring you generated earlier)\n```\n\n## Binary Compatibility Validator\n\nThis project uses [this](https://github.com/Kotlin/binary-compatibility-validator) tool to ensure the public binary API wasn't changed in a way that makes it binary incompatible.\n\nThe tool allows dumping binary API of a JVM part of a Kotlin library that is public in the sense of Kotlin visibilities.\n\nTo generate a new binary dump, run `./gradlew apiDump` in the root of the project.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj-roskopf%2FComposeGuard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fj-roskopf%2FComposeGuard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj-roskopf%2FComposeGuard/lists"}