{"id":13473525,"url":"https://github.com/Kotlin/binary-compatibility-validator","last_synced_at":"2025-03-26T19:34:15.204Z","repository":{"id":37535393,"uuid":"238709060","full_name":"Kotlin/binary-compatibility-validator","owner":"Kotlin","description":"Public API management tool","archived":false,"fork":false,"pushed_at":"2025-02-26T17:49:55.000Z","size":1520,"stargazers_count":861,"open_issues_count":69,"forks_count":67,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-02-26T18:43:55.518Z","etag":null,"topics":["api-management","binary-compatibility","change-management","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kotlin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.TXT","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":"2020-02-06T14:36:53.000Z","updated_at":"2025-02-25T14:11:45.000Z","dependencies_parsed_at":"2023-02-09T04:01:17.544Z","dependency_job_id":"6e144044-c55d-4606-b780-ef91d61cfd94","html_url":"https://github.com/Kotlin/binary-compatibility-validator","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fbinary-compatibility-validator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fbinary-compatibility-validator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fbinary-compatibility-validator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kotlin%2Fbinary-compatibility-validator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kotlin","download_url":"https://codeload.github.com/Kotlin/binary-compatibility-validator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245722840,"owners_count":20661833,"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":["api-management","binary-compatibility","change-management","kotlin"],"created_at":"2024-07-31T16:01:04.435Z","updated_at":"2025-03-26T19:34:15.187Z","avatar_url":"https://github.com/Kotlin.png","language":"Kotlin","readme":"[![Kotlin Alpha](https://kotl.in/badges/alpha.svg)](https://kotlinlang.org/docs/components-stability.html)\n[![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)\n[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/binary-compatibility-validator)](https://central.sonatype.com/search?q=org.jetbrains.kotlinx.binary-compatibility-validator)\n[![License](https://img.shields.io/github/license/Kotlin/binary-compatibility-validator)](LICENSE.TXT)\n[![KDoc link](https://img.shields.io/badge/API_reference-KDoc-blue)](https://kotlin.github.io/binary-compatibility-validator/)\n\n# Binary compatibility validator\n\nThe tool allows dumping binary API of a JVM part of a Kotlin library that is public in the sense of Kotlin visibilities and ensures that the public binary API wasn't changed in a way that makes this change binary incompatible.\n\n## Contents\n\n* [Requirements](#requirements)\n* [Setup](#setup)\n  * [Tasks](#tasks)\n  * [Optional parameters](#optional-parameters)\n  * [Workflow](#workflow)\n  * [Experimental KLib ABI validation support](#experimental-klib-abi-validation-support)\n* [What constitutes the public API](#what-constitutes-the-public-api)\n  * [Classes](#classes)\n  * [Members](#members)\n* [What makes an incompatible change to the public binary API](#what-makes-an-incompatible-change-to-the-public-binary-api)\n  * [Class changes](#class-changes)\n  * [Class member changes](#class-member-changes)\n* [Building locally](#building-the-project-locally)\n\n## Requirements\n\nBinary compatibility validator plugin requires Gradle `6.1.1` or newer.\n\nKotlin version `1.6.20` or newer.\n\n## Setup\n\nBinary compatibility validator is a Gradle plugin that can be added to your build in the following way:\n\n- in `build.gradle.kts`\n```kotlin\nplugins {\n    id(\"org.jetbrains.kotlinx.binary-compatibility-validator\") version \"0.17.0\"\n}\n```\n\n- in `build.gradle`\n\n```groovy\nplugins {\n    id 'org.jetbrains.kotlinx.binary-compatibility-validator' version '0.17.0'\n}\n```\n\nIt is enough to apply the plugin only to the root project build file; all sub-projects will be configured automatically.\n\n### Tasks\n\nThe plugin provides two tasks:\n\n  * `apiDump` — builds the project and dumps its public API in project `api` subfolder. \n  API is dumped in a human-readable format. If API dump already exists, it will be overwritten.\n  * `apiCheck` — builds the project and checks that project's public API is the same as golden value\n  in project `api` subfolder. This task is automatically inserted into `check` pipeline, so both `build` and `check`\n  tasks will start checking public API upon their execution.\n\n\u003e For projects with multiple JVM targets, multiple subfolders will be created, e.g. `api/jvm` and `api/android`\n\n### Optional parameters\n\nBinary compatibility validator can be additionally configured with the following DSL:\n\nGroovy\n```groovy\napiValidation {\n    /**\n     * Packages that are excluded from public API dumps even if they\n     * contain public API. \n     */\n    ignoredPackages += [\"kotlinx.coroutines.internal\"]\n\n    /**\n     * Sub-projects that are excluded from API validation \n     */\n    ignoredProjects += [\"benchmarks\", \"examples\"]\n\n    /**\n     * Classes (fully qualified) that are excluded from public API dumps even if they\n     * contain public API.\n     */\n    ignoredClasses += [\"com.company.BuildConfig\"]\n\n    /**\n     * Set of annotations that exclude API from being public.\n     * Typically, it is all kinds of `@InternalApi` annotations that mark \n     * effectively private API that cannot be actually private for technical reasons.\n     */\n    nonPublicMarkers += [\"my.package.MyInternalApiAnnotation\"]\n\n    /**\n     * Flag to programmatically disable compatibility validator\n     */\n    validationDisabled = true\n\n    /**\n     * A path to a subdirectory inside the project root directory where dumps should be stored.\n     */\n    apiDumpDirectory = \"api\"\n}\n```\n\nKotlin\n```kotlin\napiValidation {\n    /**\n     * Packages that are excluded from public API dumps even if they\n     * contain public API.\n     */\n    ignoredPackages.add(\"kotlinx.coroutines.internal\")\n\n    /**\n     * Sub-projects that are excluded from API validation\n     */\n    ignoredProjects.addAll(listOf(\"benchmarks\", \"examples\"))\n\n    /**\n     * Classes (fully qualified) that are excluded from public API dumps even if they\n     * contain public API.\n     */\n    ignoredClasses.add(\"com.company.BuildConfig\")\n    \n    /**\n     * Set of annotations that exclude API from being public.\n     * Typically, it is all kinds of `@InternalApi` annotations that mark\n     * effectively private API that cannot be actually private for technical reasons.\n     */\n    nonPublicMarkers.add(\"my.package.MyInternalApiAnnotation\")\n\n    /**\n     * Flag to programmatically disable compatibility validator\n     */\n    validationDisabled = false\n\n    /**\n     * A path to a subdirectory inside the project root directory where dumps should be stored.\n     */\n    apiDumpDirectory = \"aux/validation\"\n}\n```\n\n### Producing dump of a jar\n\nBy default, binary compatibility validator analyzes project output class files from `build/classes` directory when building an API dump.\nIf you pack these classes into an output jar not in a regular way, for example, by excluding certain classes, applying `shadow` plugin, and so on,\nthe API dump built from the original class files may no longer reflect the resulting jar contents accurately.\nIn that case, it makes sense to use the resulting jar as an input of the `apiBuild` task:\n\nKotlin\n```kotlin\ntasks {\n    apiBuild {\n        // \"jar\" here is the name of the default Jar task producing the resulting jar file\n        // in a multiplatform project it can be named \"jvmJar\"\n        // if you applied the shadow plugin, it creates the \"shadowJar\" task that produces the transformed jar\n        inputJar.value(jar.flatMap { it.archiveFile })\n    }\n}\n```\n\n\n### Workflow\n\nWhen starting to validate your library public API, we recommend the following workflow:\n\n- Preparation phase (one-time action):\n  * As the first step, apply the plugin, configure it and execute `apiDump`.\n  * Validate your public API manually.\n  * Commit `.api` files to your VCS.\n  * At this moment, default `check` task will validate public API along with test run and will fail \n    the build if API differs.\n \n- Regular workflow\n  * When doing code changes that do not imply any changes in public API, no additional \n    actions should be performed. `check` task on your CI will validate everything.\n  * When doing code changes that imply changes in public API, whether it is a new API or\n    adjustments in existing one, `check` task will start to fail. `apiDump` should be executed manually,\n    the resulting diff in `.api` file should be verified: only signatures you expected to change should be changed.\n  * Commit the resulting `.api` diff along with code changes. \n\n### Experimental KLib ABI validation support\n\nThe KLib validation support is experimental and is a subject to change (applies to both an API and the ABI dump format).\nA project has to use Kotlin 1.9.20 or newer to use this feature.\n\nTo validate public ABI of a Kotlin library (KLib) corresponding option should be enabled explicitly:\n```kotlin\napiValidation {\n    @OptIn(kotlinx.validation.ExperimentalBCVApi::class)\n    klib {\n        enabled = true\n    }\n}\n```\n\nWhen enabled, KLib support adds additional dependencies to existing `apiDump` and `apiCheck` tasks.\nGenerate KLib ABI dumps are places alongside JVM dumps (in `api` subfolder, by default) \nin files named `\u003cproject name\u003e.klib.api`.\nThe dump file combines all dumps generated for individual targets with declarations specific to some targets being\nannotated with corresponding target names.\nDuring the validation phase, that file is compared to the dump extracted from the latest version of the library, \nand any differences between these two files are reported as errors.\n\nGenerated ABI dumps include a library name,\nso it's [recommended](https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:naming_recommendations) \nto set Gradle's `rootProject.name` for your library. \nWithout declaring the root project's name, Gradle defaults to using the project's directory name, which can lead to \nunstable validation behavior due to potential mismatches in naming.\n\nCurrently, all options described in [Optional parameters](#optional-parameters) section are supported for klibs too.\nThe only caveat here is that all class names should be specified in the JVM-format,\nlike `package.name.ClassName$SubclassName`.\n\nPlease refer to a [design document](docs/design/KLibSupport.md) for details on the format and rationale behind the \ncurrent implementation.\n\n#### KLib ABI dump generation and validation on Linux and Windows hosts\n\nCurrently, compilation to Apple-specific targets (like `iosArm64` or `watchosX86`) supported only on Apple hosts.\nTo ease the development on Windows and Linux hosts, binary compatibility validator does not validate ABI for targets\nnot supported on the current host, even if `.klib.api` file contains declarations for these targets.\n\nThis behavior could be altered to force an error when klibs for some targets could not be compiled:\n```kotlin\napiValidation {\n    @OptIn(kotlinx.validation.ExperimentalBCVApi::class)\n    klib {\n        enabled = true\n        // treat a target being unsupported on a host as an error\n        strictValidation = true\n    }\n}\n```\n\nWhen it comes to dump generation (`apiDump` task) on non-Apple hosts, binary compatibility validator attempts\nto infer an ABI from dumps generated for supported targets and an old dump from project's `api` folder (if any).\nInferred dump may not match an actual dump,\nand it is recommended to update a dump on hosts supporting all required targets, if possible. \n\n# What constitutes the public API\n\n### Classes\n\nA class is considered to be effectively public if all the following conditions are met:\n\n - it has public or protected JVM access (`ACC_PUBLIC` or `ACC_PROTECTED`)\n - it has one of the following visibilities in Kotlin:\n    - no visibility (means no Kotlin declaration corresponds to this compiled class)\n    - *public*\n    - *protected*\n    - *internal*, only in case if the class is annotated with `PublishedApi`\n - it isn't a local class\n - it isn't a synthetic class with mappings for `when` tableswitches (`$WhenMappings`)\n - it contains at least one effectively public member, in case if the class corresponds\n   to a kotlin *file* with top-level members or a *multifile facade*\n - in case if the class is a member in another class, it is contained in the *effectively public* class\n - in case if the class is a protected member in another class, it is contained in the *non-final* class\n\n### Members\n\nA member of the class (i.e. a field or a method) is considered to be effectively public\nif all the following conditions are met:\n\n - it has public or protected JVM access (`ACC_PUBLIC` or `ACC_PROTECTED`)\n - it has one of the following visibilities in Kotlin:\n    - no visibility (means no Kotlin declaration corresponds to this class member)\n    - *public*\n    - *protected*\n    - *internal*, only in case if the class is annotated with `PublishedApi`\n\n    \u003e Note that Kotlin visibility of a field exposed by `lateinit` property is the visibility of its setter.\n - in case if the member is protected, it is contained in *non-final* class\n - it isn't a synthetic access method for a private field\n\n## What makes an incompatible change to the public binary API\n\n### Class changes\n\nFor a class a binary incompatible change is:\n\n - changing the full class name (including package and containing classes)\n - changing the superclass, so that the class no longer has the previous superclass in\n   the inheritance chain\n - changing the set of implemented interfaces so that the class\n   no longer implements interfaces it had implemented before\n - changing one of the following access flags:\n    - `ACC_PUBLIC`, `ACC_PROTECTED`, `ACC_PRIVATE` — lessening the class visibility\n    - `ACC_FINAL` — making non-final class final\n    - `ACC_ABSTRACT` — making non-abstract class abstract\n    - `ACC_INTERFACE` — changing class to interface and vice versa\n    - `ACC_ANNOTATION` — changing annotation to interface and vice versa\n\n### Class member changes\n\nFor a class member a binary incompatible change is:\n\n - changing its name\n - changing its descriptor (erased return type and parameter types for methods);\n   this includes changing field to method and vice versa\n - changing one of the following access flags:\n    - `ACC_PUBLIC`, `ACC_PROTECTED`, `ACC_PRIVATE` — lessening the member visibility\n    - `ACC_FINAL` — making non-final field or method final\n    - `ACC_ABSTRACT` — making non-abstract method abstract\n    - `ACC_STATIC` — changing instance member to static and vice versa\n\n\n## Building the project locally\n\nIn order to build and run tests in the project in IDE, two prerequisites are required:\n\n* Java 11 or above in order to use the latest ASM\n* All build actions in the IDE should be delegated to Gradle\n\n## Contributing\n\nRead the [Contributing Guidelines](CONTRIBUTING.md).\n","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKotlin%2Fbinary-compatibility-validator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKotlin%2Fbinary-compatibility-validator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKotlin%2Fbinary-compatibility-validator/lists"}