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
2 changes: 1 addition & 1 deletion .claude/skills/create-java-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Derive the branch name from the changes being made. Use `feat/`, `fix/`, `ref/`,
## Step 2: Format Code and Regenerate API Files

```bash
./gradlew spotlessApply apiDump
./gradlew spotlessApply updateKotlinAbi
```

This is **required** before every PR in this repo. It formats all Java/Kotlin code via Spotless and regenerates the `.api` binary compatibility files.
Expand Down
2 changes: 1 addition & 1 deletion .cursor/BUGBOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ rule file in [`.cursor/rules/`](rules) for the area the diff touches (`api`, `op
## What NOT to flag

- Formatting and import order — Spotless owns it.
- Contents of generated `.api` files, beyond confirming `apiDump` was run.
- Contents of generated `.api` files, beyond confirming `updateKotlinAbi` was run.
- Conventional commit / PR title format, and missing changelog entries — CI and Danger check both.
- Speculative refactors or improvements unrelated to the diff.
4 changes: 2 additions & 2 deletions .cursor/rules/api.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ description: Public API surface, binary compatibility, and common classes to mod

## API Compatibility

Public API is tracked via `.api` files generated by the [Binary Compatibility Validator](https://github.com/Kotlin/binary-compatibility-validator) Gradle plugin. Each module has its own file at `<module>/api/<module>.api`.
Public API is tracked via `.api` files generated by the [ABI validation](https://kotlinlang.org/docs/gradle-binary-compatibility-validation.html) built into the Kotlin Gradle plugin. Each module has its own file at `<module>/api/<module>.api`.

- **Never edit `.api` files manually.** Run `./gradlew apiDump` to regenerate them.
- **Never edit `.api` files manually.** Run `./gradlew updateKotlinAbi` to regenerate them.
- `./gradlew check` validates current code against `.api` files and fails on unintended changes.
- `@ApiStatus.Internal` marks classes/methods as internal — they still appear in `.api` files but are not part of the public contract.
- `@ApiStatus.Experimental` marks API that may change in future versions.
Expand Down
2 changes: 1 addition & 1 deletion .cursor/rules/options.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ When a feature has its own capture path (e.g. `captureLog`), the relevant classe
4. `ManifestMetadataReader.java` — Android manifest support (if Android-relevant)
5. `SentryAutoConfigurationTest.kt` — Spring Boot property binding tests (all three Spring Boot modules)
6. Tests for all of the above (`SentryOptionsTest`, `ExternalOptionsTest`, `ManifestMetadataReaderTest`)
7. Run `./gradlew apiDump` — the nested class and its methods appear in `sentry.api`
7. Run `./gradlew updateKotlinAbi` — the nested class and its methods appear in `sentry.api`
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ rule file in `.cursor/rules/`:

| Rule | Read it when working on |
|---|---|
| `api` | Public API surface, binary compatibility, `.api` files, `apiDump`, `IScope`/`IScopes`/`Sentry` static API, protocol classes |
| `api` | Public API surface, binary compatibility, `.api` files, `updateKotlinAbi`, `IScope`/`IScopes`/`Sentry` static API, protocol classes |
| `options` | `SentryOptions`, namespaced options, `ExternalOptions`, `sentry.properties`, `ManifestMetadataReader`, Spring Boot properties |
| `scopes` | Scope management, forking, lifecycle, `ScopeType`, thread-local storage, scope bleeding, Hub → Scopes migration |
| `deduplication` | Duplicate event detection, `DuplicateEventDetectionEventProcessor`, `enableDeduplication` |
Expand Down Expand Up @@ -42,7 +42,7 @@ The project uses **Gradle** with Kotlin DSL. Key build files:

```bash
# Format code and regenerate .api files (REQUIRED before committing)
./gradlew spotlessApply apiDump
./gradlew spotlessApply updateKotlinAbi

# Run all tests and linter
./gradlew check
Expand Down Expand Up @@ -74,7 +74,7 @@ resolves the per-module test task, including integration test suites, for you.
3. **Use todo tracking**: Work through todo items, marking them as complete as you go
4. **High-level communication**: Give high-level explanations of changes made, not step-by-step descriptions
5. **Simplicity first**: Make every task and code change as simple as possible. Avoid massive or complex changes. Impact as little code as possible.
6. **Format and regenerate**: Once done, format code and regenerate .api files: `./gradlew spotlessApply apiDump`
6. **Format and regenerate**: Once done, format code and regenerate .api files: `./gradlew spotlessApply updateKotlinAbi`
7. **Propose commit**: As final step, git stage relevant files and propose (but not execute) a single git commit command. This applies to implementation work; when the task is to open a PR, the `create-java-pr` skill takes over from here and does commit, push, and open it.

## Repository Skills
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ or

# Binary compatibility validation

To prevent breaking ABI changes and exposing things we should not, we make use of https://github.com/Kotlin/binary-compatibility-validator. If your change intended to introduce a new public method/property or modify the existing one you can overwrite the API declarations to make CI happy as follows (overwrites them from scratch):
To prevent breaking ABI changes and exposing things we should not, we make use of https://kotlinlang.org/docs/gradle-binary-compatibility-validation.html. If your change intended to introduce a new public method/property or modify the existing one you can overwrite the API declarations to make CI happy as follows (overwrites them from scratch):

```shell
make api
Expand All @@ -86,7 +86,7 @@ make api
or

```shell
./gradlew apiDump
./gradlew updateKotlinAbi
```

However, if your change did not intend to modify the public API, consider changing the method/property visibility or removing the change altogether.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ checkFormat:

# Binary compatibility validator
api:
./gradlew apiDump
./gradlew updateKotlinAbi

# Assemble release and Android test apk of the uitest-android module
assembleUiTestRelease:
Expand Down
4 changes: 4 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ gradlePlugin {
id = "io.sentry.jdk-target"
implementationClass = "io.sentry.gradle.JdkTargetConvention"
}
register("sentryApiValidation") {
id = "io.sentry.api-validation"
implementationClass = "io.sentry.gradle.SentryApiValidationPlugin"
}
register("sentryAnimalSniffer") {
id = "io.sentry.animalsniffer"
implementationClass = "io.sentry.gradle.SentryAnimalSnifferPlugin"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.sentry.gradle

import org.gradle.api.provider.SetProperty

/** Configuration for the `io.sentry.api-validation` convention plugin. */
abstract class ApiValidationExtension {
/**
* Packages that are public to the JVM but not part of the SDK's API, and so are left out of the
* dump. Subpackages are left out too.
*/
abstract val ignoredPackages: SetProperty<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.sentry.gradle

import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.kotlin.dsl.create
import org.jetbrains.kotlin.gradle.dsl.abi.AbiValidationExtension
import org.jetbrains.kotlin.gradle.dsl.abi.AbiValidationMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation

private val KOTLIN_PLUGIN_IDS =
listOf(
"org.jetbrains.kotlin.jvm",
"org.jetbrains.kotlin.android",
"org.jetbrains.kotlin.multiplatform",
)

/**
* Checks the public ABI of a module against the dump checked into its `api` directory, using the
* Kotlin Gradle plugin's own ABI validation. Adds `checkKotlinAbi`, which `check` depends on, and
* `updateKotlinAbi`, which rewrites the dump.
*/
@OptIn(ExperimentalAbiValidation::class)
class SentryApiValidationPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create<ApiValidationExtension>("sentryApiValidation")

// The abiValidation extension only exists once a Kotlin plugin has been applied, and a module
// may list this plugin before that one.
KOTLIN_PLUGIN_IDS.forEach {
project.pluginManager.withPlugin(it) { enable(project, extension) }
}
}

private fun enable(project: Project, extension: ApiValidationExtension) {
val kotlin = project.extensions.getByName("kotlin") as ExtensionAware
when (val abi = kotlin.extensions.getByName("abiValidation")) {
is AbiValidationMultiplatformExtension -> abi.also { it.enabled.set(true) }
is AbiValidationExtension -> abi.also { it.enabled.set(true) }
else -> throw GradleException("Unexpected abiValidation extension: ${abi.javaClass.name}")
}.filters {
// Lazy, because the module configures the extension after this plugin has been applied.
exclude { byNames.addAll(extension.ignoredPackages.map { it.map { pkg -> "$pkg.**" } }) }
}
}
}
46 changes: 0 additions & 46 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ plugins {
alias(libs.plugins.spotless) apply false
alias(libs.plugins.detekt)
`maven-publish`
alias(libs.plugins.binary.compatibility.validator)
Comment thread
cursor[bot] marked this conversation as resolved.
alias(libs.plugins.vanniktech.maven.publish) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
Expand Down Expand Up @@ -43,51 +42,6 @@ buildscript {
}
}

apiValidation {
Comment thread
markushi marked this conversation as resolved.
ignoredPackages.addAll(
setOf(
"io.sentry.android.core.internal"
)
)
ignoredProjects.addAll(
listOf(
"sentry-samples-android",
"sentry-samples-console",
"sentry-samples-console-opentelemetry-noagent",
"sentry-samples-jul",
"sentry-samples-log4j2",
"sentry-samples-logback",
"sentry-samples-openfeign",
"sentry-samples-servlet",
"sentry-samples-spring",
"sentry-samples-spring-jakarta",
"sentry-samples-spring-7",
"sentry-samples-spring-boot",
"sentry-samples-spring-boot-opentelemetry",
"sentry-samples-spring-boot-opentelemetry-noagent",
"sentry-samples-spring-boot-jakarta",
"sentry-samples-spring-boot-jakarta-log4j2",
"sentry-samples-spring-boot-jakarta-opentelemetry",
"sentry-samples-spring-boot-jakarta-opentelemetry-noagent",
"sentry-samples-spring-boot-webflux",
"sentry-samples-spring-boot-webflux-jakarta",
"sentry-samples-spring-boot-4",
"sentry-samples-spring-boot-4-log4j2",
"sentry-samples-spring-boot-4-opentelemetry",
"sentry-samples-spring-boot-4-opentelemetry-noagent",
"sentry-samples-spring-boot-4-otlp",
"sentry-samples-spring-boot-4-webflux",
"sentry-samples-ktor-client",
"sentry-uitest-android",
"sentry-uitest-android-critical",
"test-app-size",
"sentry-samples-netflix-dgs",
"sentry-samples-console-otlp",
"sentry-test-support"
)
)
}

allprojects {
group = Config.Sentry.group
version = providers.gradleProperty(Config.Sentry.versionNameProp).get()
Expand Down
1 change: 0 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
buildconfig = { id = "com.github.gmazzo.buildconfig", version = "5.6.5" }
dokka = { id = "org.jetbrains.dokka", version = "2.0.0" }
dokka-javadoc = { id = "org.jetbrains.dokka-javadoc", version = "2.0.0" }
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version = "0.13.0" }
errorprone = { id = "net.ltgt.errorprone", version = "5.1.1" }
gradle-versions = { id = "com.github.ben-manes.versions", version = "0.42.0" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
Expand Down
3 changes: 3 additions & 0 deletions sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.errorprone)
alias(libs.plugins.gradle.versions)
id("io.sentry.api-validation")
}

android {
Expand Down Expand Up @@ -135,3 +136,5 @@ dependencies {
testRuntimeOnly(libs.androidx.fragment.ktx)
testRuntimeOnly(libs.timber)
}

sentryApiValidation { ignoredPackages.add("io.sentry.android.core.internal") }
1 change: 1 addition & 0 deletions sentry-android-distribution/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
id("com.android.library")
alias(libs.plugins.kotlin.android)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-fragment/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-navigation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-navigation3/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-ndk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
id("com.android.library")
alias(libs.plugins.kotlin.android)
alias(libs.plugins.gradle.versions)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-replay/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-sqlite/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-android-timber/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.gradle.versions)
alias(libs.plugins.detekt)
id("io.sentry.api-validation")
}

android {
Expand Down
1 change: 1 addition & 0 deletions sentry-apache-http-client-5/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.errorprone)
alias(libs.plugins.gradle.versions)
id("io.sentry.api-validation")
}

kotlin {
Expand Down
1 change: 1 addition & 0 deletions sentry-apollo-3/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer.android")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-apollo-4/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer.android")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-apollo-5/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer.android")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-apollo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer.android")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-async-profiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ plugins {
alias(libs.plugins.dokka)
alias(libs.plugins.dokka.javadoc)
`maven-publish` // necessary for publishMavenLocal task to publish correct artifacts
id("io.sentry.api-validation")
}

kotlin {
Expand Down
1 change: 1 addition & 0 deletions sentry-graphql-22/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-graphql-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-graphql/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
1 change: 1 addition & 0 deletions sentry-jcache/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.buildconfig)
id("io.sentry.animalsniffer")
id("io.sentry.api-validation")
}

tasks.named<KotlinCompile>("compileKotlin") {
Expand Down
Loading
Loading