Skip to content

Commit

Permalink
Merge 6d81a10 into f92edd9
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich authored Jan 22, 2025
2 parents f92edd9 + 6d81a10 commit 4682761
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Rename `navigation.processing` span to more expressive `Navigation dispatch to screen A mounted/navigation cancelled` ([#4423](https://github.com/getsentry/sentry-react-native/pull/4423))
- Add RN SDK package to `sdk.packages` for Cocoa ([#4381](https://github.com/getsentry/sentry-react-native/pull/4381))
- Add experimental version of `startWithConfigureOptions` for Apple platforms ([#4444](https://github.com/getsentry/sentry-react-native/pull/4444))
- Add initialization using `sentry.options.json` for Apple platforms ([#4447](https://github.com/getsentry/sentry-react-native/pull/4447))

### Internal

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
3380C6C42CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3380C6C32CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift */; };
33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */; };
339C6C3C2D3EB25100CA72ED /* RNSentryStartTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339C6C3B2D3EB23B00CA72ED /* RNSentryStartTests.swift */; };
339C6C422D3FD3AE00CA72ED /* RNSentryStartFromFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339C6C412D3FD39500CA72ED /* RNSentryStartFromFileTests.swift */; };
339C6C482D3FD9A700CA72ED /* invalid.options.json in Resources */ = {isa = PBXBuildFile; fileRef = 339C6C462D3FD91900CA72ED /* invalid.options.json */; };
339C6C492D3FD9A700CA72ED /* invalid.options.txt in Resources */ = {isa = PBXBuildFile; fileRef = 339C6C452D3FD90200CA72ED /* invalid.options.txt */; };
339C6C4B2D3FD9B200CA72ED /* valid.options.json in Resources */ = {isa = PBXBuildFile; fileRef = 339C6C4A2D3FD9AB00CA72ED /* valid.options.json */; };
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; };
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */; };
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33F58ACF2977037D008F60EA /* RNSentryTests.mm */; };
Expand Down Expand Up @@ -41,6 +45,11 @@
33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryOnDrawReporterTests.m; sourceTree = "<group>"; };
339C6C3B2D3EB23B00CA72ED /* RNSentryStartTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryStartTests.swift; sourceTree = "<group>"; };
339C6C3D2D3FA04D00CA72ED /* RNSentryVersion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryVersion.h; path = ../ios/RNSentryVersion.h; sourceTree = SOURCE_ROOT; };
339C6C412D3FD39500CA72ED /* RNSentryStartFromFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryStartFromFileTests.swift; sourceTree = "<group>"; };
339C6C442D3FD62D00CA72ED /* RNSentrySDK+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNSentrySDK+Test.h"; sourceTree = "<group>"; };
339C6C452D3FD90200CA72ED /* invalid.options.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = invalid.options.txt; sourceTree = "<group>"; };
339C6C462D3FD91900CA72ED /* invalid.options.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = invalid.options.json; sourceTree = "<group>"; };
339C6C4A2D3FD9AB00CA72ED /* valid.options.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = valid.options.json; sourceTree = "<group>"; };
33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryFramesTrackerListenerTests.m; sourceTree = "<group>"; };
33AFDFEE2B8D14C200AAB120 /* RNSentryFramesTrackerListenerTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSentryFramesTrackerListenerTests.h; sourceTree = "<group>"; };
33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryDependencyContainerTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -75,6 +84,7 @@
3360896929524163007C7730 = {
isa = PBXGroup;
children = (
339C6C432D3FD41C00CA72ED /* TestAssets */,
33AFE0122B8F319000AAB120 /* RNSentry */,
3360899029524164007C7730 /* RNSentryCocoaTesterTests */,
3360897329524163007C7730 /* Products */,
Expand All @@ -94,6 +104,7 @@
3360899029524164007C7730 /* RNSentryCocoaTesterTests */ = {
isa = PBXGroup;
children = (
339C6C412D3FD39500CA72ED /* RNSentryStartFromFileTests.swift */,
339C6C3B2D3EB23B00CA72ED /* RNSentryStartTests.swift */,
332D334A2CDCC8EB00547D76 /* RNSentryCocoaTesterTests-Bridging-Header.h */,
332D33492CDCC8E100547D76 /* RNSentryTests.h */,
Expand All @@ -120,9 +131,20 @@
path = Replay;
sourceTree = "<group>";
};
339C6C432D3FD41C00CA72ED /* TestAssets */ = {
isa = PBXGroup;
children = (
339C6C4A2D3FD9AB00CA72ED /* valid.options.json */,
339C6C462D3FD91900CA72ED /* invalid.options.json */,
339C6C452D3FD90200CA72ED /* invalid.options.txt */,
);
path = TestAssets;
sourceTree = "<group>";
};
33AFE0122B8F319000AAB120 /* RNSentry */ = {
isa = PBXGroup;
children = (
339C6C442D3FD62D00CA72ED /* RNSentrySDK+Test.h */,
339C6C3D2D3FA04D00CA72ED /* RNSentryVersion.h */,
333B58AF2D36A7FD000F8D04 /* RNSentrySDK.h */,
333B58A92D35BB2D000F8D04 /* RNSentryStart+Test.h */,
Expand Down Expand Up @@ -157,6 +179,7 @@
3360898929524164007C7730 /* Sources */,
BB7D14838753E6599863899B /* Frameworks */,
CC7959F3721CB3AD7CB6A047 /* [CP] Copy Pods Resources */,
339C6C472D3FD99900CA72ED /* Resources */,
);
buildRules = (
);
Expand Down Expand Up @@ -201,6 +224,19 @@
};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
339C6C472D3FD99900CA72ED /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
339C6C482D3FD9A700CA72ED /* invalid.options.json in Resources */,
339C6C4B2D3FD9B200CA72ED /* valid.options.json in Resources */,
339C6C492D3FD9A700CA72ED /* invalid.options.txt in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
30F19D4E16BEEFEC68733838 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -252,6 +288,7 @@
332D33472CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift in Sources */,
339C6C3C2D3EB25100CA72ED /* RNSentryStartTests.swift in Sources */,
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */,
339C6C422D3FD3AE00CA72ED /* RNSentryStartFromFileTests.swift in Sources */,
336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */,
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */,
33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
#import "RNSentryReplayBreadcrumbConverter.h"
#import "RNSentryReplayMask.h"
#import "RNSentryReplayUnmask.h"
#import "RNSentrySDK.h"
#import "RNSentrySDK+Test.h"
#import "RNSentryStart.h"
#import "RNSentryVersion.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import XCTest

final class RNSentryStartFromFileTests: XCTestCase {

func testNoThrowOnMissingOptionsFile() {
var wasConfigurationCalled = false

RNSentrySDK.start(getNonExistingOptionsPath(), configureOptions: { _ in
wasConfigurationCalled = true
})

XCTAssertTrue(wasConfigurationCalled)

let actualOptions = PrivateSentrySDKOnly.options
XCTAssertNil(actualOptions.dsn)
XCTAssertNil(actualOptions.parsedDsn)
}

func testNoThrowOnInvalidFileType() {
var wasConfigurationCalled = false

RNSentrySDK.start(getInvalidOptionsTypePath(), configureOptions: { _ in
wasConfigurationCalled = true
})

XCTAssertTrue(wasConfigurationCalled)

let actualOptions = PrivateSentrySDKOnly.options
XCTAssertNil(actualOptions.dsn)
XCTAssertNil(actualOptions.parsedDsn)
}

func testNoThrowOnInvalidOptions() {
var wasConfigurationCalled = false

RNSentrySDK.start(getInvalidOptionsPath(), configureOptions: { _ in
wasConfigurationCalled = true
})

XCTAssertTrue(wasConfigurationCalled)

let actualOptions = PrivateSentrySDKOnly.options
XCTAssertNil(actualOptions.dsn)
XCTAssertNotNil(actualOptions.parsedDsn)
XCTAssertEqual(actualOptions.environment, "environment-from-invalid-file")
}

func testLoadValidOptions() {
var wasConfigurationCalled = false

RNSentrySDK.start(getValidOptionsPath(), configureOptions: { _ in
wasConfigurationCalled = true
})

XCTAssertTrue(wasConfigurationCalled)

let actualOptions = PrivateSentrySDKOnly.options
XCTAssertNil(actualOptions.dsn)
XCTAssertNotNil(actualOptions.parsedDsn)
XCTAssertEqual(actualOptions.environment, "environment-from-valid-file")
}

func testOptionsFromFileInConfigureOptions() {
var wasConfigurationCalled = false

RNSentrySDK.start(getValidOptionsPath()) { options in
wasConfigurationCalled = true
XCTAssertEqual(options.environment, "environment-from-valid-file")
}

XCTAssertTrue(wasConfigurationCalled)
}

func testOptionsOverwrittenInConfigureOptions() {
RNSentrySDK.start(getValidOptionsPath()) { options in
options.environment = "new-environment"
}

let actualOptions = PrivateSentrySDKOnly.options
XCTAssertEqual(actualOptions.environment, "new-environment")
}

func getNonExistingOptionsPath() -> String {
return "/non-existing.options.json"
}

func getInvalidOptionsTypePath() -> String {
guard let path = getTestBundle().path(forResource: "invalid.options", ofType: "txt") else {
fatalError("Could not get invalid type options path")
}
return path
}

func getInvalidOptionsPath() -> String {
guard let path = getTestBundle().path(forResource: "invalid.options", ofType: "json") else {
fatalError("Could not get invalid options path")
}
return path
}

func getValidOptionsPath() -> String {
guard let path = getTestBundle().path(forResource: "valid.options", ofType: "json") else {
fatalError("Could not get invalid options path")
}
return path
}

func getTestBundle() -> Bundle {
let maybeBundle = Bundle.allBundles.first(where: { $0.bundlePath.hasSuffix(".xctest") })
guard let bundle = maybeBundle else {
fatalError("Could not find test bundle")
}
return bundle
}
}
9 changes: 9 additions & 0 deletions packages/core/RNSentryCocoaTester/RNSentrySDK+Test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#import "RNSentrySDK.h"

@interface
RNSentrySDK (Test)

+ (void)start:(NSString *)path
configureOptions:(void (^)(SentryOptions *_Nonnull options))configureOptions;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dsn": "https://[email protected]/123456",
"environment": "environment-from-invalid-file",
"invalid-option": 123
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invalid-options
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"dsn": "https://[email protected]/123456",
"environment": "environment-from-valid-file"
}
17 changes: 15 additions & 2 deletions packages/core/ios/RNSentrySDK.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,21 @@ SENTRY_NO_INIT

/**
* @experimental
* Inits and configures Sentry for React Native applications. Make sure to
* set a valid DSN.
* Inits and configures Sentry for React Native applications using `sentry.options.json`
* configuration file.
*
* @discussion Call this method on the main thread. When calling it from a background thread, the
* SDK starts on the main thread async.
*/
+ (void)start;

/**
* @experimental
* Inits and configures Sentry for React Native applicationsusing `sentry.options.json`
* configuration file and `configureOptions` callback.
*
* The `configureOptions` callback can overwrite the config file options
* and add non-serializable items to the options object.
*
* @discussion Call this method on the main thread. When calling it from a background thread, the
* SDK starts on the main thread async.
Expand Down
56 changes: 55 additions & 1 deletion packages/core/ios/RNSentrySDK.m
Original file line number Diff line number Diff line change
@@ -1,11 +1,65 @@
#import "RNSentrySDK.h"
#import "RNSentryStart.h"

static NSString *SENTRY_OPTIONS_RESOURCE_NAME = @"sentry.options";
static NSString *SENTRY_OPTIONS_RESOURCE_TYPE = @"json";

@implementation RNSentrySDK

+ (void)start
{
[self startWithConfigureOptions:nil];
}

+ (void)startWithConfigureOptions:(void (^)(SentryOptions *options))configureOptions
{
SentryOptions *options = [[SentryOptions alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:SENTRY_OPTIONS_RESOURCE_NAME
ofType:SENTRY_OPTIONS_RESOURCE_TYPE];

[self start:path configureOptions:configureOptions];
}

+ (void)start:(NSString *)path configureOptions:(void (^)(SentryOptions *options))configureOptions
{
NSError *readError = nil;
NSError *parseError = nil;
NSError *optionsError = nil;

NSData *_Nullable content = nil;
if (path != nil) {
content = [NSData dataWithContentsOfFile:path options:0 error:&readError];
}

NSDictionary *dict = nil;
if (content != nil) {
dict = [NSJSONSerialization JSONObjectWithData:content options:0 error:&parseError];
}

if (readError != nil) {
NSLog(@"[RNSentry] Failed to load options from %@, with error: %@", path,
readError.localizedDescription);
}

if (parseError != nil) {
NSLog(@"[RNSentry] Failed to parse JSON from %@, with error: %@", path,
parseError.localizedDescription);
}

SentryOptions *options = nil;
if (dict != nil) {
options = [RNSentryStart createOptionsWithDictionary:dict error:&optionsError];
}

if (optionsError != nil) {
NSLog(@"[RNSentry] Failed to parse options from %@, with error: %@", path,
optionsError.localizedDescription);
}

if (options == nil) {
// Fallback in case that options file could not be parsed.
options = [[SentryOptions alloc] init];
}

[RNSentryStart updateWithReactDefaults:options];
if (configureOptions != nil) {
configureOptions(options);
Expand Down
5 changes: 4 additions & 1 deletion packages/core/ios/RNSentryStart.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ + (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)
}

// Exclude Dev Server and Sentry Dsn request from Breadcrumbs
// TODO: Migrate for manual init
NSString *dsn = [self getURLFromDSN:[mutableOptions valueForKey:@"dsn"]];
// TODO: For Auto Init from JS dev server is resolved automatically, for init from options file
// dev server has to be specified manually
NSString *devServerUrl = [mutableOptions valueForKey:@"devServerUrl"];
sentryOptions.beforeBreadcrumb
= ^SentryBreadcrumb *_Nullable(SentryBreadcrumb *_Nonnull breadcrumb)
Expand Down Expand Up @@ -86,6 +87,8 @@ + (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)
sentryOptions.spotlightUrl = spotlightValue;
} else if ([spotlightValue isKindOfClass:[NSNumber class]]) {
sentryOptions.enableSpotlight = [spotlightValue boolValue];
// TODO: For Auto init from JS set automatically for init from options file have to be
// set manually
id defaultSpotlightUrl = [mutableOptions valueForKey:@"defaultSidecarUrl"];
if (defaultSpotlightUrl != nil) {
sentryOptions.spotlightUrl = defaultSpotlightUrl;
Expand Down
21 changes: 21 additions & 0 deletions packages/core/scripts/sentry-xcode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,24 @@ fi
if [ -f "$SENTRY_COLLECT_MODULES" ]; then
/bin/sh "$SENTRY_COLLECT_MODULES"
fi

SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX="Skipping options file copy. To disable this behavior, set SENTRY_COPY_OPTIONS_FILE=false in your environment variables."
SENTRY_OPTIONS_FILE_NAME="sentry.options.json"
SENTRY_OPTIONS_FILE_DESTINATION_PATH="$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/$SENTRY_OPTIONS_FILE_NAME"
[ -z "$SENTRY_OPTIONS_FILE_PATH" ] && SENTRY_OPTIONS_FILE_PATH="$RN_PROJECT_ROOT/$SENTRY_OPTIONS_FILE_NAME"
[ -z "$SENTRY_COPY_OPTIONS_FILE" ] && SENTRY_COPY_OPTIONS_FILE=true

if [ "$SENTRY_COPY_OPTIONS_FILE" = true ]; then
if [[ -z "$CONFIGURATION_BUILD_DIR" ]]; then
echo "[Sentry] CONFIGURATION_BUILD_DIR is not set. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
elif [[ -z "$UNLOCALIZED_RESOURCES_FOLDER_PATH" ]]; then
echo "[Sentry] UNLOCALIZED_RESOURCES_FOLDER_PATH is not set. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
fi

if [ -f "$SENTRY_OPTIONS_FILE_PATH" ]; then
cp "$SENTRY_OPTIONS_FILE_PATH" "$SENTRY_OPTIONS_FILE_DESTINATION_PATH"
echo "[Sentry] Copied $SENTRY_OPTIONS_FILE_PATH to $SENTRY_OPTIONS_FILE_DESTINATION_PATH"
else
echo "[Sentry] $SENTRY_OPTIONS_FILE_PATH not found. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
fi
fi
Loading

0 comments on commit 4682761

Please sign in to comment.