Skip to content

[4/4] feat(plugin): Auto-install Sentry Cocoa when the spm4Kmp plugin is applied#559

Open
buenaflor wants to merge 9 commits into
feat/spm4kmp-phase2-samplesfrom
feat/spm4kmp-phase3-plugin-autoinstall
Open

[4/4] feat(plugin): Auto-install Sentry Cocoa when the spm4Kmp plugin is applied#559
buenaflor wants to merge 9 commits into
feat/spm4kmp-phase2-samplesfrom
feat/spm4kmp-phase3-plugin-autoinstall

Conversation

@buenaflor

@buenaflor buenaflor commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Phase 4 of the stacked spm4Kmp migration (stacked on #560). Adds an spm4Kmp auto-install path to the Sentry Kotlin Multiplatform Gradle plugin: when a consumer applies the spm4Kmp plugin (io.github.frankois944.spmForKmp) alongside the Sentry plugin, the matching Sentry Cocoa version is added to their Apple targets automatically.

Why: SPM consumers previously had to add the Sentry Swift package to Xcode themselves and the plugin resolved the framework via a fragile DerivedData search (CocoaFrameworkLinker). Mirroring the existing CocoaPods auto-install, detecting spm4Kmp lets the plugin declare the correctly-versioned Sentry package so spm4Kmp fetches and links it, removing the manual step and the brittle path resolution.

What changed:

  • New Spm4KmpAutoInstallExtension (enabled + sentryCocoaVersion, defaulting to BuildConfig.SentryCocoaVersion), exposed as sentryKmp { autoInstall.spm { ... } } and registered as the spm extension.
  • installSentryForSpm4Kmp adds remotePackageVersion(getsentry/sentry-cocoa, products = { add("Sentry") }) to each Apple target via swiftPackageConfig(cinteropName = "sentryCocoa"). Link-only (exportToKotlin = false) because the published SDK klib already carries the Sentry cinterop bindings; consumers only need the framework at link time. Idempotent and opt-out guarded.
  • Registered during the configuration phase via nested plugins.withId on both the spm4Kmp and Kotlin Multiplatform plugins, so it is robust to plugin application order (spm4Kmp consumes swiftPackageConfig before afterEvaluate, so an afterEvaluate registration is too late — confirmed by the sample initially generating no sentryCocoa tasks).
  • The manual CocoaFrameworkLinker is skipped when CocoaPods is applied or when the Sentry Swift package is actually registered with spm4Kmp (auto-installed or user-defined sentryCocoa config). Merely applying spm4Kmp for other Swift packages with the Sentry spm auto-install opted out keeps the fallback linker active for plain SPM-in-Xcode consumers.
  • Because the Swift package is registered at target creation time, the sentryKmp spm opt-out/version override must precede the kotlin {} block; documented in the README and the extension KDoc.
  • compileOnly dependency on the spm4Kmp DSL (resolved from gradlePluginPortal()); the compile/test classpaths request Java 17-compatible variants (spm4Kmp ships Java 17) while the plugin keeps emitting Java 11 bytecode, so non-spm4Kmp consumers stay on JDK 11. The linker check deliberately uses only Gradle core types so spm4Kmp classes are never touched unless the consumer applies the plugin.
  • Converted the kmp-app-spm sample to apply spm4Kmp and rely on the auto-install. The iosApp's Xcode-side sentry-cocoa package reference was removed: spm4Kmp links the static Sentry product into the dynamic shared.framework, so the app no longer needs its own Sentry package dependency.
  • Tests for the new extension/behavior/opt-out, plugin-order robustness, and the linker fallback (101 tests), plus README and migration-doc updates.

Of note for review: the configuration-phase registration via nested plugins.withId (timing-sensitive) and the link-only add("Sentry") choice — both validated by the sample xcodebuild (BUILD SUCCEEDED) and the sample generating its own sentryCocoa cinterop.

Verification: plugin compileKotlin + test (101 tests), :sentry-samples:kmp-app-spm:shared:linkDebugFrameworkIosSimulatorArm64, SPM sample xcodebuild (BUILD SUCCEEDED), spotlessApply/detekt/apiCheck green.

Made with Cursor

@buenaflor buenaflor force-pushed the feat/spm4kmp-phase2-samples branch from 2b44fe4 to 0fca03c Compare June 9, 2026 19:55
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase3-plugin-autoinstall branch from 281033d to 2212073 Compare June 9, 2026 19:58
@buenaflor buenaflor changed the title [PR 4] feat(plugin): auto-install Sentry Cocoa via spm4Kmp [4/4] feat(plugin): Auto-install Sentry Cocoa when the spm4Kmp plugin is applied Jun 9, 2026
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase2-samples branch from 0fca03c to df55744 Compare June 10, 2026 10:59
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase3-plugin-autoinstall branch from 2212073 to e81481d Compare June 10, 2026 10:59
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase2-samples branch from df55744 to 9ead63f Compare June 10, 2026 11:14
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase3-plugin-autoinstall branch 2 times, most recently from cbfc489 to d156da3 Compare June 10, 2026 11:18
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase2-samples branch from 9ead63f to 50ba5fb Compare June 10, 2026 11:18
Base automatically changed from feat/spm4kmp-phase2-samples to feat/spm4kmp-phase1-migration June 10, 2026 11:18
@buenaflor buenaflor force-pushed the feat/spm4kmp-phase3-plugin-autoinstall branch from d156da3 to fcb454f Compare June 10, 2026 11:19
@buenaflor buenaflor changed the base branch from feat/spm4kmp-phase1-migration to feat/spm4kmp-phase2-samples June 10, 2026 11:21
buenaflor and others added 3 commits June 10, 2026 13:27
When a consumer applies the spm4Kmp plugin (io.github.frankois944.spmForKmp)
alongside the Sentry KMP Gradle plugin, the matching Sentry Cocoa version is now
added to their Apple targets automatically, so they no longer declare the Sentry
Swift package manually or rely on the fragile DerivedData framework linker.

- Add Spm4KmpAutoInstallExtension (enabled + sentryCocoaVersion, default
  BuildConfig.SentryCocoaVersion), exposed as sentryKmp { autoInstall.spm { } }
- installSentryForSpm4Kmp adds remotePackageVersion(getsentry/sentry-cocoa,
  products = { add("Sentry") }) to each Apple target via swiftPackageConfig
  (link-only: the published SDK klib already carries the Sentry cinterop bindings)
- Register during the configuration phase via plugins.withId, since spm4Kmp
  consumes swiftPackageConfig before afterEvaluate; idempotent + opt-out guarded
- Skip the manual CocoaFrameworkLinker when CocoaPods or spm4Kmp is applied;
  the linker stays as the fallback for plain SPM-in-Xcode consumers
- compileOnly against the spm4Kmp DSL (gradlePluginPortal); request Java 17 deps
  on the compile/test classpaths while keeping Java 11 plugin bytecode
- Convert the kmp-app-spm sample to apply spm4Kmp and use the auto-install
- Tests + README/migration docs

Verified: plugin compileKotlin + test, sample iOS link generates its own
sentryCocoa cinterop, SPM sample xcodebuild BUILD SUCCEEDED, spotless/detekt green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Align the plugin's compileOnly spm4Kmp DSL dependency with the SDK's
Config.spmForKmpVersion (1.9.3), which adds watchosArm32 (armv7k) support.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lugin-autoinstall

# Conflicts:
#	sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/AutoInstallExtension.kt
#	sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/SentryPlugin.kt
buenaflor and others added 2 commits June 10, 2026 15:49
…ample

With the spm4Kmp auto-install in place, the static Sentry product is
linked into the dynamic shared.framework (all Sentry ObjC classes are
defined symbols there), so embedding Sentry-Dynamic in the iosApp would
load a second copy of every Sentry class at runtime. Remove the
XCRemoteSwiftPackageReference, its Package.resolved pins, and the
pbxproj editing in update-cocoa.sh; the Sentry Cocoa version is now
single-sourced from Config.kt and the plugin's gradle.properties.

Verified via xcodebuild (BUILD SUCCEEDED) and a simulator launch of the
sample app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@buenaflor buenaflor marked this pull request as ready for review June 10, 2026 21:31
@buenaflor buenaflor requested a review from romtsn as a code owner June 10, 2026 21:31
Copilot AI review requested due to automatic review settings June 10, 2026 21:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds spm4Kmp-aware auto-installation to the Sentry Kotlin Multiplatform Gradle plugin so that, when io.github.frankois944.spmForKmp is applied, the plugin automatically registers the matching getsentry/sentry-cocoa Swift package for Apple targets (removing the need for manual Xcode SwiftPM setup / brittle DerivedData searching).

Changes:

  • Introduces Spm4KmpAutoInstallExtension and wires it into sentryKmp.autoInstall (plus a top-level spm extension).
  • Adds installSentryForSpm4Kmp and integrates it via plugins.withId(...) so configuration happens during Gradle configuration phase.
  • Updates the SPM sample + docs/changelog + update script to rely on the new auto-install path.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
sentry-samples/kmp-app-spm/shared/build.gradle.kts Applies spm4Kmp plugin in the sample to exercise auto-install.
sentry-samples/kmp-app-spm/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved Removes Xcode SwiftPM lockfile (no longer needed if Xcode project no longer declares Sentry package).
sentry-samples/kmp-app-spm/iosApp.xcodeproj/project.pbxproj Removes the Xcode SwiftPM sentry-cocoa reference + Sentry-Dynamic framework dependency.
sentry-samples/kmp-app-spm/iosApp.xcodeproj/.swiftpm/xcode/package.xcworkspace/xcshareddata/swiftpm/Package.resolved Removes generated SwiftPM lockfile under .swiftpm.
sentry-kotlin-multiplatform-gradle-plugin/src/test/java/io/sentry/kotlin/multiplatform/gradle/SentryPluginTest.kt Adds unit tests for the new spm extension + spm4Kmp install behavior.
sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/Spm4KmpAutoInstallExtension.kt New extension for spm4Kmp auto-install configuration.
sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/SentryPlugin.kt Implements spm4Kmp auto-install + adjusts DerivedData linker skipping behavior.
sentry-kotlin-multiplatform-gradle-plugin/src/main/java/io/sentry/kotlin/multiplatform/gradle/AutoInstallExtension.kt Adds spm to the auto-install configuration surface.
sentry-kotlin-multiplatform-gradle-plugin/settings.gradle.kts Adds gradlePluginPortal() to resolve spm4Kmp marker/DSL for compileOnly.
sentry-kotlin-multiplatform-gradle-plugin/gradle/libs.versions.toml Adds spm4Kmp dependency coordinates/version.
sentry-kotlin-multiplatform-gradle-plugin/build.gradle.kts Adds compileOnly/test dependency on spm4Kmp and requests Java 17 variants on build classpaths.
scripts/update-cocoa.sh Stops updating Xcode project SwiftPM pins; version now flows via Gradle plugin config.
README.md Documents spm4Kmp auto-install usage.
CHANGELOG.md Adds unreleased changelog entry for spm4Kmp auto-install feature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 116 to 119
name = iosApp;
packageProductDependencies = (
24E1CB3E2C17E00200F78D70 /* Sentry-Dynamic */,
);
productName = NSExceptionKtSample;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff is correct; the description was stale. spm4Kmp links the static Sentry product into the dynamic shared.framework, so the iosApp no longer needs its own sentry-cocoa package reference (validated by the sample xcodebuild). PR description updated.

Comment thread README.md
…-out

Address review feedback on the spm4Kmp auto-install:

- Gate the spm4Kmp install on both the spm4Kmp and Kotlin Multiplatform
  plugins via nested plugins.withId, so applying KMP after spm4Kmp no
  longer silently skips the Sentry Swift package registration.
- Skip the manual DerivedData fallback linker only when the Sentry
  Swift package is actually registered with spm4Kmp (auto-installed or
  user-defined sentryCocoa config), instead of whenever the spm4Kmp
  plugin is applied. Consumers that use spm4Kmp for other packages but
  opt out of the Sentry spm auto-install keep the fallback linker.
- Document that the sentryKmp spm opt-out and version override must be
  configured before the kotlin block declares Apple targets, since the
  Swift package is registered at target creation time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lugin-autoinstall

# Conflicts:
#	CHANGELOG.md

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 127c49c. Configure here.

…ageConfig container

The spm4Kmp auto-install skipped targets based on a sentryCocoa cinterop
on the main compilation, but spm4Kmp creates that cinterop only in its
own afterEvaluate and capitalizes the name (SentryCocoa), so the check
could never match a user-defined Sentry Swift package config. Check the
spm4Kmp swiftPackageConfig container instead (global sentryCocoa entry
or per-target sentryCocoa_<Target> key), which exists from the moment
the config is declared.

Also warn when the spm auto-install opt-out is configured after the
kotlin { } block: the Swift package is registered at target creation,
so a late opt-out (including the global autoInstall.enabled flag) is
read too late to take effect. Document this on AutoInstallExtension and
in the README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants