Repository: getsentry/sentry-capacitor
Pull request #421 (2023-07-26 11:52:13)

fix yarn.lock
Somehow the Yarn.lock got dirt... 

#skip-changelog.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7bbcf82..2a9d07c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,9 @@
 
 ### Dependencies
 
+- Bump Sentry Android SDK to `6.19.0` ([#406](https://github.com/getsentry/sentry-capacitor/pull/406))
+  - [changelog](https://github.com/getsentry/sentry-java/releases/tag/6.19.0)
+  - [diff](https://github.com/getsentry/sentry-java/compare/6.17.0...6.19.0)
 - Bump sentry-cocoa SDK to `8.8.0` ([#397](https://github.com/getsentry/sentry-capacitor/pull/397))
   - [changelog](https://github.com/getsentry/sentry-cocoa/releases/tag/8.8.0)
   - [diff](https://github.com/getsentry/sentry-cocoa/compare/7.27.1...8.8.0)
diff --git a/android/build.gradle b/android/build.gradle
index 9c08a19..efa8857 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -80,7 +80,7 @@ repositories {
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
     implementation project(':capacitor-android')
-    implementation 'io.sentry:sentry-android:6.17.0'
+    implementation 'io.sentry:sentry-android:6.19.0'
     testImplementation "junit:junit:$junitVersion"
     androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
     androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
diff --git a/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java b/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java
index dfb833b..f5b9f5b 100644
--- a/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java
+++ b/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java
@@ -2,7 +2,6 @@ package io.sentry.capacitor;
 
 import android.content.Context;
 import android.content.pm.PackageInfo;
-import android.util.Log;
 import com.getcapacitor.JSArray;
 import com.getcapacitor.JSObject;
 import com.getcapacitor.NativePlugin;
@@ -16,6 +15,7 @@ import io.sentry.Sentry;
 import io.sentry.SentryEvent;
 import io.sentry.SentryLevel;
 import io.sentry.UncaughtExceptionHandlerIntegration;
+import io.sentry.android.core.BuildConfig;
 import io.sentry.android.core.AnrIntegration;
 import io.sentry.android.core.NdkIntegration;
 import io.sentry.android.core.SentryAndroid;
@@ -25,7 +25,6 @@ import io.sentry.protocol.User;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -37,6 +36,9 @@ import java.util.logging.Logger;
 @NativePlugin
 public class SentryCapacitor extends Plugin {
 
+    private static final String NATIVE_SDK_NAME = "sentry.native.android.capacitor";
+    private static final String ANDROID_SDK_NAME = "sentry.java.android.capacitor";
+
     static final Logger logger = Logger.getLogger("capacitor-sentry");
     private Context context;
     private static PackageInfo packageInfo;
@@ -63,11 +65,22 @@ public class SentryCapacitor extends Plugin {
         SentryAndroid.init(
             this.getContext(),
             options -> {
+                SdkVersion sdkVersion = options.getSdkVersion();
+                if (sdkVersion == null) {
+                    sdkVersion = new SdkVersion(ANDROID_SDK_NAME, BuildConfig.VERSION_NAME);
+                } else {
+                    sdkVersion.setName(ANDROID_SDK_NAME);
+                }
+
                 if (capOptions.has("debug") && capOptions.getBool("debug")) {
                     options.setDebug(true);
                     logger.setLevel(Level.INFO);
                 }
 
+                options.setSentryClientName(sdkVersion.getName() + "/" + sdkVersion.getVersion());
+                options.setNativeSdkName(NATIVE_SDK_NAME);
+                options.setSdkVersion(sdkVersion);
+
                 String dsn = capOptions.getString("dsn") != null ? capOptions.getString("dsn") : "";
                 logger.info(String.format("Starting with DSN: '%s'", dsn));
                 options.setDsn(dsn);
@@ -343,11 +356,11 @@ public class SentryCapacitor extends Plugin {
         if (sdk != null) {
             switch (sdk.getName()) {
                 // If the event is from capacitor js, it gets set there and we do not handle it here.
-                case "sentry.native":
-                    setEventEnvironmentTag(event, "android", "native");
+                case NATIVE_SDK_NAME:
+                    setEventEnvironmentTag(event, "native");
                     break;
-                case "sentry.java.android":
-                    setEventEnvironmentTag(event, "android", "java");
+                case ANDROID_SDK_NAME:
+                    setEventEnvironmentTag(event, "java");
                     break;
                 default:
                     break;
@@ -355,8 +368,8 @@ public class SentryCapacitor extends Plugin {
         }
     }
 
-    private void setEventEnvironmentTag(SentryEvent event, String origin, String environment) {
-        event.setTag("event.origin", origin);
+    private void setEventEnvironmentTag(SentryEvent event, String environment) {
+        event.setTag("event.origin", "android");
         event.setTag("event.environment", environment);
     }
 
diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift
index 351cf69..c160e0f 100644
--- a/ios/Plugin/Plugin.swift
+++ b/ios/Plugin/Plugin.swift
@@ -9,6 +9,8 @@ import Sentry
 @objc(SentryCapacitor)
 public class SentryCapacitor: CAPPlugin {
 
+    private let nativeSdkName = "sentry.cocoa.capacitor";
+
     private var sentryOptions: Options?
 
     // The Cocoa SDK is init. after the notification didBecomeActiveNotification is registered.
@@ -45,6 +47,9 @@ public class SentryCapacitor: CAPPlugin {
         do {
             let options = try Options.init(dict: optionsDict)
 
+            let sdkVersion = PrivateSentrySDKOnly.getSdkVersionString()
+            PrivateSentrySDKOnly.setSdkName(nativeSdkName, andVersionString: sdkVersion)
+
              // Note: For now, in sentry-cocoa, beforeSend is not called before captureEnvelope
             options.beforeSend = { [weak self] event in
                 self?.setEventOriginTag(event: event)
@@ -290,15 +295,26 @@ public class SentryCapacitor: CAPPlugin {
     }
 
     private func setEventOriginTag(event: Event) {
-        guard let sdk = event.sdk, isValidSdk(sdk: sdk), let name = sdk["name"] as? String, name == "sentry.cocoa"  else {
+        guard let sdk = event.sdk, isValidSdk(sdk: sdk), let name = sdk["name"] as? String, name == nativeSdkName  else {
             return
         }
-        setEventEnvironmentTag(event: event, origin: "ios", environment: "native")
+        setEventEnvironmentTag(event: event, environment: "native")
     }
 
-    private func setEventEnvironmentTag(event: Event, origin: String, environment: String) {
-        event.tags?["event.origin"] = origin
-        event.tags?["event.environment"] = environment
+    private func setEventEnvironmentTag(event: Event, environment: String) {
+        var newTags = [String: String]()
+
+        if let tags = event.tags, !tags.isEmpty {
+            newTags.merge(tags) { (_, new) in new }
+        }
+
+        newTags["event.origin"] = "ios"
+
+        if !environment.isEmpty {
+            newTags["event.environment"] = environment
+        }
+
+        event.tags = newTags
     }
 
     private func isValidSdk(sdk: [String: Any]) -> Bool {
diff --git a/src/integrations/sdkinfo.ts b/src/integrations/sdkinfo.ts
index 1e1517e..88df351 100644
--- a/src/integrations/sdkinfo.ts
+++ b/src/integrations/sdkinfo.ts
@@ -16,7 +16,7 @@ export class SdkInfo implements Integration {
    */
   public name: string = SdkInfo.id;
 
-  private _nativeSdkInfo: Package | null = null;
+  private _nativeSdkPackage: Package | null = null;
 
   /**
    * @inheritDoc
@@ -25,9 +25,9 @@ export class SdkInfo implements Integration {
     addGlobalEventProcessor(async event => {
       // The native SDK info package here is only used on iOS as `beforeSend` is not called on `captureEnvelope`.
       // this._nativeSdkInfo should be defined a following time so this call won't always be awaited.
-      if (NATIVE.platform === 'ios' && this._nativeSdkInfo === null) {
+      if (NATIVE.platform === 'ios' && this._nativeSdkPackage === null) {
         try {
-          this._nativeSdkInfo = await NATIVE.fetchNativeSdkInfo();
+          this._nativeSdkPackage = await NATIVE.fetchNativeSdkInfo();
         } catch (_) {
           // If this fails, go ahead as usual as we would rather have the event be sent with a package missing.
           logger.warn(
@@ -37,19 +37,18 @@ export class SdkInfo implements Integration {
       }
 
       event.platform = event.platform || 'javascript';
-      event.sdk = {
-        ...event.sdk,
-        name: SDK_NAME,
-        packages: [
-          ...((event.sdk && event.sdk.packages) || []),
-          ...((this._nativeSdkInfo && [this._nativeSdkInfo]) || []),
-          {
-            name: 'npm:@sentry/capacitor',
-            version: SDK_VERSION,
-          },
-        ],
-        version: SDK_VERSION,
-      };
+      event.sdk = event.sdk || {};
+      event.sdk.name = event.sdk.name || SDK_NAME;
+      event.sdk.version = event.sdk.version || SDK_VERSION;
+      event.sdk.packages = [
+        // default packages are added by baseclient and should not be added here
+        ...(event.sdk.packages || []),
+        ...((this._nativeSdkPackage && [this._nativeSdkPackage]) || []),
+        {
+          name: 'npm:@sentry/capacitor',
+          version: SDK_VERSION,
+        },
+      ];
 
       return event;
     });
diff --git a/src/version.ts b/src/version.ts
index c1d64aa..97eebde 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1,2 +1,3 @@
+export const SDK_PACKAGE_NAME = 'npm:@sentry/capacitor';
 export const SDK_NAME = 'sentry.javascript.capacitor';
 export const SDK_VERSION = '0.12.1';
diff --git a/yarn.lock b/yarn.lock
index f7be05b..2fbf49e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3060,11 +3060,6 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0:
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
 
-is-unicode-supported@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714"
-  integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==
-
 is-windows@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"


Test patch:
diff --git a/test/integrations/sdkinfo.test.ts b/test/integrations/sdkinfo.test.ts
new file mode 100644
index 0000000..7224f4f
--- /dev/null
+++ b/test/integrations/sdkinfo.test.ts
@@ -0,0 +1,88 @@
+import type { Event, EventHint, Package } from '@sentry/types';
+
+import { SDK_NAME, SDK_VERSION } from '../../src/';
+import { SdkInfo } from '../../src/integrations';
+import { NATIVE } from '../../src/wrapper';
+
+let mockedFetchNativeSdkInfo: jest.Mock<PromiseLike<Package | null>, []>;
+
+const mockPackage = {
+  name: 'sentry-cocoa',
+  version: '0.0.1',
+};
+
+jest.mock('../../src/wrapper', () => {
+  const actual = jest.requireActual('../../src/wrapper');
+
+  return {
+    NATIVE: {
+      ...actual.NATIVE,
+      platform: 'ios',
+      fetchNativeSdkInfo: () => mockedFetchNativeSdkInfo(),
+    },
+  };
+});
+
+afterEach(() => {
+  NATIVE.platform = 'ios';
+});
+
+describe('Sdk Info', () => {
+  it('Adds native package and javascript platform to event on iOS', async () => {
+    mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(mockPackage);
+    const mockEvent: Event = {};
+    const processedEvent = await executeIntegrationFor(mockEvent);
+
+    expect(processedEvent?.sdk?.packages).toEqual(expect.arrayContaining([mockPackage]));
+    expect(processedEvent?.platform === 'javascript');
+    expect(mockedFetchNativeSdkInfo).toBeCalledTimes(1);
+  });
+
+  it('Adds javascript platform but not native package on Android', async () => {
+    NATIVE.platform = 'android';
+    mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(mockPackage);
+    const mockEvent: Event = {};
+    const processedEvent = await executeIntegrationFor(mockEvent);
+
+    expect(processedEvent?.sdk?.packages).toEqual(expect.not.arrayContaining([mockPackage]));
+    expect(processedEvent?.platform === 'javascript');
+    expect(mockedFetchNativeSdkInfo).not.toBeCalled();
+  });
+
+  it('Does not overwrite existing sdk name and version', async () => {
+    mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(null);
+    const mockEvent: Event = {
+      sdk: {
+        name: 'test-sdk',
+        version: '1.0.0',
+      },
+    };
+    const processedEvent = await executeIntegrationFor(mockEvent);
+
+    expect(processedEvent?.sdk?.name).toEqual('test-sdk');
+    expect(processedEvent?.sdk?.version).toEqual('1.0.0');
+  });
+
+  it('Does use default sdk name and version', async () => {
+    mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(null);
+    const mockEvent: Event = {};
+    const processedEvent = await executeIntegrationFor(mockEvent);
+
+    expect(processedEvent?.sdk?.name).toEqual(SDK_NAME);
+    expect(processedEvent?.sdk?.version).toEqual(SDK_VERSION);
+  });
+});
+
+function executeIntegrationFor(mockedEvent: Event, mockedHint: EventHint = {}): Promise<Event | null> {
+  const integration = new SdkInfo();
+  return new Promise((resolve, reject) => {
+    integration.setupOnce(async eventProcessor => {
+      try {
+        const processedEvent = await eventProcessor(mockedEvent, mockedHint);
+        resolve(processedEvent);
+      } catch (e) {
+        reject(e);
+      }
+    });
+  });
+}