Skip to content

Commit 8c3a337

Browse files
authored
Merge branch 'main' into alwx/experiment/cirrus-labs
2 parents 3034d58 + 400f0ac commit 8c3a337

12 files changed

Lines changed: 454 additions & 105 deletions

File tree

.github/workflows/native-tests.yml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,36 @@ jobs:
4949
working-directory: packages/core/RNSentryCocoaTester
5050
run: pod install
5151

52+
- name: List Available Simulators
53+
run: xcrun simctl list devices available iPhone
54+
5255
- name: Run iOS Tests
5356
working-directory: packages/core/RNSentryCocoaTester
5457
env:
5558
SCHEME: RNSentryCocoaTester
5659
CONFIGURATION: Release
57-
DESTINATION: 'platform=iOS Simulator,OS=latest,name=iPhone 16'
5860
run: |
61+
# Find first available iPhone simulator from latest iOS runtime
62+
DEVICE_ID=$(xcrun simctl list devices available iPhone -j | jq -r '
63+
.devices |
64+
to_entries |
65+
map(select(.key | startswith("com.apple.CoreSimulator.SimRuntime.iOS-"))) |
66+
sort_by(.key) |
67+
reverse |
68+
.[0].value[] |
69+
select(.isAvailable == true) |
70+
.udid
71+
' | head -1)
72+
if [ -z "$DEVICE_ID" ]; then
73+
echo "No iPhone simulators available"
74+
exit 1
75+
fi
76+
echo "Using simulator: $DEVICE_ID"
77+
5978
env NSUnbufferedIO=YES \
6079
xcodebuild -workspace *.xcworkspace \
6180
-scheme $SCHEME -configuration $CONFIGURATION \
62-
-destination "$DESTINATION" \
81+
-destination "id=$DEVICE_ID" \
6382
-quiet \
6483
test
6584

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,32 @@
66
> make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
77
<!-- prettier-ignore-end -->
88
9+
## Unreleased
10+
11+
### Features
12+
13+
- Add experimental `sentry-span-attributes` prop to attach custom attributes to user interaction spans ([#5569](https://github.com/getsentry/sentry-react-native/pull/5569))
14+
```tsx
15+
<Pressable
16+
sentry-label="checkout"
17+
sentry-span-attributes={{
18+
'user.type': 'premium',
19+
'cart.value': 150
20+
}}
21+
onPress={handleCheckout}>
22+
<Text>Checkout</Text>
23+
</Pressable>
24+
```
25+
26+
### Dependencies
27+
28+
- Bump Bundler Plugins from v4.7.0 to v4.8.0 ([#5581](https://github.com/getsentry/sentry-react-native/pull/5581))
29+
- [changelog](https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/main/CHANGELOG.md#480)
30+
- [diff](https://github.com/getsentry/sentry-javascript-bundler-plugins/compare/4.7.0...4.8.0)
31+
- Bump JavaScript SDK from v10.36.0 to v10.37.0 ([#5589](https://github.com/getsentry/sentry-react-native/pull/5589))
32+
- [changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#10370)
33+
- [diff](https://github.com/getsentry/sentry-javascript/compare/10.36.0...10.37.0)
34+
935
## 7.10.0
1036

1137
### Fixes

dev-packages/e2e-tests/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"devDependencies": {
1414
"@babel/preset-env": "^7.25.3",
1515
"@babel/preset-typescript": "^7.18.6",
16-
"@sentry/core": "10.36.0",
16+
"@sentry/core": "10.37.0",
1717
"@sentry/react-native": "7.10.0",
1818
"@types/node": "^20.9.3",
1919
"@types/react": "^18.2.64",

packages/core/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,21 @@
6868
"react-native": ">=0.65.0"
6969
},
7070
"dependencies": {
71-
"@sentry/babel-plugin-component-annotate": "4.7.0",
72-
"@sentry/browser": "10.36.0",
71+
"@sentry/babel-plugin-component-annotate": "4.8.0",
72+
"@sentry/browser": "10.37.0",
7373
"@sentry/cli": "2.58.4",
74-
"@sentry/core": "10.36.0",
75-
"@sentry/react": "10.36.0",
76-
"@sentry/types": "10.36.0"
74+
"@sentry/core": "10.37.0",
75+
"@sentry/react": "10.37.0",
76+
"@sentry/types": "10.37.0"
7777
},
7878
"devDependencies": {
7979
"@babel/core": "^7.26.7",
8080
"@expo/metro-config": "~0.20.0",
8181
"@mswjs/interceptors": "^0.25.15",
8282
"@react-native/babel-preset": "0.80.0",
83-
"@sentry-internal/eslint-config-sdk": "10.36.0",
84-
"@sentry-internal/eslint-plugin-sdk": "10.36.0",
85-
"@sentry-internal/typescript": "10.36.0",
83+
"@sentry-internal/eslint-config-sdk": "10.37.0",
84+
"@sentry-internal/eslint-plugin-sdk": "10.37.0",
85+
"@sentry-internal/typescript": "10.37.0",
8686
"@sentry/wizard": "6.11.0",
8787
"@testing-library/react-native": "^13.2.2",
8888
"@types/jest": "^29.5.13",

packages/core/src/js/touchevents.tsx

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { SeverityLevel } from '@sentry/core';
1+
import type { SeverityLevel, SpanAttributeValue } from '@sentry/core';
22
import { addBreadcrumb, debug, dropUndefinedKeys, getClient, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
33
import * as React from 'react';
44
import type { GestureResponderEvent } from 'react-native';
@@ -39,6 +39,13 @@ export type TouchEventBoundaryProps = {
3939
* Label Name used to identify the touched element.
4040
*/
4141
labelName?: string;
42+
/**
43+
* Custom attributes to add to user interaction spans.
44+
* Accepts an object with string keys and values that are strings, numbers, booleans, or arrays.
45+
*
46+
* @experimental This API is experimental and may change in future releases.
47+
*/
48+
spanAttributes?: Record<string, SpanAttributeValue>;
4249
};
4350

4451
const touchEventStyles = StyleSheet.create({
@@ -52,6 +59,7 @@ const DEFAULT_BREADCRUMB_TYPE = 'user';
5259
const DEFAULT_MAX_COMPONENT_TREE_SIZE = 20;
5360

5461
const SENTRY_LABEL_PROP_KEY = 'sentry-label';
62+
const SENTRY_SPAN_ATTRIBUTES_PROP_KEY = 'sentry-span-attributes';
5563
const SENTRY_COMPONENT_PROP_KEY = 'data-sentry-component';
5664
const SENTRY_ELEMENT_PROP_KEY = 'data-sentry-element';
5765
const SENTRY_FILE_PROP_KEY = 'data-sentry-source-file';
@@ -204,6 +212,28 @@ class TouchEventBoundary extends React.Component<TouchEventBoundaryProps> {
204212
});
205213
if (span) {
206214
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_INTERACTION);
215+
216+
// Apply custom attributes from sentry-span-attributes prop
217+
// Traverse the component tree to find custom attributes
218+
let instForAttributes: ElementInstance | undefined = e._targetInst;
219+
let customAttributes: Record<string, SpanAttributeValue> | undefined;
220+
221+
while (instForAttributes) {
222+
if (instForAttributes.elementType?.displayName === TouchEventBoundary.displayName) {
223+
break;
224+
}
225+
226+
customAttributes = getSpanAttributes(instForAttributes);
227+
if (customAttributes && Object.keys(customAttributes).length > 0) {
228+
break;
229+
}
230+
231+
instForAttributes = instForAttributes.return;
232+
}
233+
234+
if (customAttributes && Object.keys(customAttributes).length > 0) {
235+
span.setAttributes(customAttributes);
236+
}
207237
}
208238
}
209239

@@ -291,6 +321,26 @@ function getLabelValue(props: Record<string, unknown>, labelKey: string | undefi
291321
: undefined;
292322
}
293323

324+
function getSpanAttributes(currentInst: ElementInstance): Record<string, SpanAttributeValue> | undefined {
325+
if (!currentInst.memoizedProps) {
326+
return undefined;
327+
}
328+
329+
const props = currentInst.memoizedProps;
330+
const attributes = props[SENTRY_SPAN_ATTRIBUTES_PROP_KEY];
331+
332+
// Validate that it's an object (not null, not array)
333+
if (
334+
typeof attributes === 'object' &&
335+
attributes !== null &&
336+
!Array.isArray(attributes)
337+
) {
338+
return attributes as Record<string, SpanAttributeValue>;
339+
}
340+
341+
return undefined;
342+
}
343+
294344
/**
295345
* Convenience Higher-Order-Component for TouchEventBoundary
296346
* @param WrappedComponent any React Component

0 commit comments

Comments
 (0)