feat(core): Support SENTRY_ENVIRONMENT in bare React Native builds#5823
feat(core): Support SENTRY_ENVIRONMENT in bare React Native builds#5823
Conversation
Read SENTRY_ENVIRONMENT env variable during the sentry.options.json copy step in both Gradle and Xcode build scripts, overriding the environment value in the destination copy without modifying the source. Closes #5779 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
🤖 This preview updates automatically when you update the PR. |
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d scripts Wrap JSON parsing in try-catch (Gradle) and if-guard (Xcode) so invalid sentry.options.json falls back to a plain copy instead of failing the build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@sentry review |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Shell-interpolated paths in inline JS break on special characters
- I fixed the inline Node invocation to read source and destination paths from process.argv and pass them as separate shell arguments, so apostrophes in paths no longer break JavaScript parsing.
Or push these changes by commenting:
@cursor push 89d91c5ec9
Preview (89d91c5ec9)
diff --git a/packages/core/scripts/sentry-xcode.sh b/packages/core/scripts/sentry-xcode.sh
--- a/packages/core/scripts/sentry-xcode.sh
+++ b/packages/core/scripts/sentry-xcode.sh
@@ -103,10 +103,12 @@
if [ -n "$SENTRY_ENVIRONMENT" ]; then
if "$LOCAL_NODE_BINARY" -e "
var fs = require('fs');
- var opts = JSON.parse(fs.readFileSync('$SENTRY_OPTIONS_FILE_PATH', 'utf8'));
+ var sourcePath = process.argv[1];
+ var destinationPath = process.argv[2];
+ var opts = JSON.parse(fs.readFileSync(sourcePath, 'utf8'));
opts.environment = process.env.SENTRY_ENVIRONMENT;
- fs.writeFileSync('$SENTRY_OPTIONS_FILE_DESTINATION_PATH', JSON.stringify(opts));
- " 2>/dev/null; then
+ fs.writeFileSync(destinationPath, JSON.stringify(opts));
+ " -- "$SENTRY_OPTIONS_FILE_PATH" "$SENTRY_OPTIONS_FILE_DESTINATION_PATH" 2>/dev/null; then
echo "[Sentry] Overriding 'environment' from SENTRY_ENVIRONMENT environment variable"
else
echo "[Sentry] Failed to override environment, copying file as-is." 1>&2This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
…tion Avoids breaking inline JS when paths contain special characters like single quotes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
packages/core/sentry.gradle
Outdated
| copy { | ||
| from sentryOptionsFile | ||
| into androidAssetsDir | ||
| rename { String fileName -> configFile } | ||
| } | ||
| } | ||
| } else { | ||
| copy { | ||
| from sentryOptionsFile | ||
| into androidAssetsDir | ||
| rename { String fileName -> configFile } | ||
| } |
There was a problem hiding this comment.
Q: This condition and the catch one performs the same action, is it possible to unify them?
Always copy the file first, then override environment in-place if SENTRY_ENVIRONMENT is set. This removes duplicate copy blocks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 4a17c8f+dirty | 406.62 ms | 400.58 ms | -6.04 ms |
| df1f7df+dirty | 442.64 ms | 427.16 ms | -15.48 ms |
| a483f9f+dirty | 396.82 ms | 453.28 ms | 56.46 ms |
| 60cd796+dirty | 445.84 ms | 492.45 ms | 46.61 ms |
| 5c16cdc+dirty | 423.48 ms | 452.35 ms | 28.88 ms |
| 80e4616+dirty | 411.58 ms | 462.12 ms | 50.54 ms |
| 55b77fc+dirty | 411.87 ms | 417.16 ms | 5.29 ms |
| bca62c0+dirty | 414.36 ms | 451.06 ms | 36.70 ms |
| 0b64753+dirty | 448.67 ms | 474.61 ms | 25.94 ms |
| 4e6d7d7+dirty | 480.73 ms | 515.73 ms | 35.00 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 4a17c8f+dirty | 43.75 MiB | 47.99 MiB | 4.24 MiB |
| df1f7df+dirty | 43.75 MiB | 48.08 MiB | 4.33 MiB |
| a483f9f+dirty | 43.75 MiB | 48.41 MiB | 4.66 MiB |
| 60cd796+dirty | 43.75 MiB | 48.07 MiB | 4.32 MiB |
| 5c16cdc+dirty | 17.75 MiB | 19.68 MiB | 1.94 MiB |
| 80e4616+dirty | 43.75 MiB | 48.55 MiB | 4.80 MiB |
| 55b77fc+dirty | 43.75 MiB | 47.99 MiB | 4.24 MiB |
| bca62c0+dirty | 43.75 MiB | 48.41 MiB | 4.66 MiB |
| 0b64753+dirty | 17.75 MiB | 19.70 MiB | 1.95 MiB |
| 4e6d7d7+dirty | 43.75 MiB | 48.40 MiB | 4.64 MiB |
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ea3e26e+dirty | 1229.13 ms | 1228.46 ms | -0.67 ms |
| 80e4616+dirty | 1221.32 ms | 1225.64 ms | 4.32 ms |
| 818a608+dirty | 1205.76 ms | 1208.00 ms | 2.24 ms |
| 77061ed+dirty | 1233.16 ms | 1234.88 ms | 1.71 ms |
| bef3709+dirty | 1222.07 ms | 1220.24 ms | -1.83 ms |
| a206511+dirty | 1185.00 ms | 1186.35 ms | 1.35 ms |
| 74979ac+dirty | 1210.49 ms | 1213.31 ms | 2.82 ms |
| a2bb688+dirty | 1223.53 ms | 1232.90 ms | 9.37 ms |
| 8a868fe+dirty | 1221.50 ms | 1230.78 ms | 9.28 ms |
| d590428+dirty | 1211.77 ms | 1220.51 ms | 8.75 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ea3e26e+dirty | 3.41 MiB | 4.58 MiB | 1.17 MiB |
| 80e4616+dirty | 3.38 MiB | 4.60 MiB | 1.22 MiB |
| 818a608+dirty | 2.63 MiB | 3.91 MiB | 1.28 MiB |
| 77061ed+dirty | 2.63 MiB | 3.98 MiB | 1.34 MiB |
| bef3709+dirty | 3.38 MiB | 4.78 MiB | 1.40 MiB |
| a206511+dirty | 3.41 MiB | 4.67 MiB | 1.25 MiB |
| 74979ac+dirty | 3.38 MiB | 4.60 MiB | 1.22 MiB |
| a2bb688+dirty | 2.63 MiB | 3.99 MiB | 1.36 MiB |
| 8a868fe+dirty | 3.38 MiB | 4.60 MiB | 1.22 MiB |
| d590428+dirty | 3.38 MiB | 4.78 MiB | 1.39 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ea3e26e+dirty | 1216.61 ms | 1214.15 ms | -2.47 ms |
| 80e4616+dirty | 1206.90 ms | 1205.94 ms | -0.96 ms |
| 818a608+dirty | 1218.84 ms | 1223.18 ms | 4.34 ms |
| 77061ed+dirty | 1210.77 ms | 1218.45 ms | 7.68 ms |
| bef3709+dirty | 1217.79 ms | 1225.33 ms | 7.54 ms |
| a206511+dirty | 1225.02 ms | 1223.74 ms | -1.28 ms |
| 74979ac+dirty | 1212.33 ms | 1212.54 ms | 0.21 ms |
| a2bb688+dirty | 1244.82 ms | 1238.60 ms | -6.22 ms |
| 8a868fe+dirty | 1206.85 ms | 1215.04 ms | 8.19 ms |
| d590428+dirty | 1221.23 ms | 1225.27 ms | 4.03 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ea3e26e+dirty | 3.41 MiB | 4.58 MiB | 1.17 MiB |
| 80e4616+dirty | 3.38 MiB | 4.60 MiB | 1.22 MiB |
| 818a608+dirty | 3.19 MiB | 4.48 MiB | 1.29 MiB |
| 77061ed+dirty | 3.19 MiB | 4.54 MiB | 1.36 MiB |
| bef3709+dirty | 3.38 MiB | 4.78 MiB | 1.40 MiB |
| a206511+dirty | 3.41 MiB | 4.67 MiB | 1.25 MiB |
| 74979ac+dirty | 3.38 MiB | 4.60 MiB | 1.22 MiB |
| a2bb688+dirty | 3.19 MiB | 4.56 MiB | 1.37 MiB |
| 8a868fe+dirty | 3.38 MiB | 4.60 MiB | 1.22 MiB |
| d590428+dirty | 3.38 MiB | 4.78 MiB | 1.39 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 70250df+dirty | 418.08 ms | 480.84 ms | 62.76 ms |
| 8d89cc9+dirty | 357.69 ms | 415.79 ms | 58.10 ms |
| 1853710+dirty | 360.67 ms | 396.28 ms | 35.61 ms |
| 55b77fc+dirty | 410.46 ms | 414.11 ms | 3.65 ms |
| 69602ce+dirty | 375.37 ms | 405.28 ms | 29.91 ms |
| c1573b3+dirty | 355.65 ms | 448.82 ms | 93.17 ms |
| 90afdd3+dirty | 367.79 ms | 404.84 ms | 37.05 ms |
| 955f2eb+dirty | 388.13 ms | 433.56 ms | 45.44 ms |
| 80e4616+dirty | 427.31 ms | 461.15 ms | 33.84 ms |
| 276d348+dirty | 356.30 ms | 405.27 ms | 48.97 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 70250df+dirty | 43.94 MiB | 48.91 MiB | 4.97 MiB |
| 8d89cc9+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
| 1853710+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
| 55b77fc+dirty | 43.94 MiB | 48.82 MiB | 4.88 MiB |
| 69602ce+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
| c1573b3+dirty | 7.15 MiB | 8.42 MiB | 1.27 MiB |
| 90afdd3+dirty | 7.15 MiB | 8.43 MiB | 1.28 MiB |
| 955f2eb+dirty | 7.15 MiB | 8.42 MiB | 1.27 MiB |
| 80e4616+dirty | 43.94 MiB | 49.38 MiB | 5.44 MiB |
| 276d348+dirty | 7.15 MiB | 8.42 MiB | 1.26 MiB |
lucas-zimerman
left a comment
There was a problem hiding this comment.
LGT Ready-to-merge and then merge it!
…uilds (#16948) <!-- Use this checklist to make sure your PR is ready for merge. You may delete any sections you don't need. --> ## DESCRIBE YOUR PR *Tell us what you're changing and why. If your PR **resolves an issue**, please link it so it closes automatically.* Support SENTRY_ENVIRONMENT in bare React Native builds ## IS YOUR CHANGE URGENT? Help us prioritize incoming PRs by letting us know when the change needs to go live. - [ ] Urgent deadline (GA date, etc.): <!-- ENTER DATE HERE --> - [ ] Other deadline: <!-- ENTER DATE HERE --> - [x] None: Not urgent, can wait up to 1 week+⚠️ Merge after getsentry/sentry-react-native#5823 is shipped ## SLA - Teamwork makes the dream work, so please add a reviewer to your PRs. - Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it. Thanks in advance for your help! ## PRE-MERGE CHECKLIST *Make sure you've checked the following before merging your changes:* - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) ## LEGAL BOILERPLATE <!-- Sentry employees and contractors can delete or ignore this section. --> Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. ## EXTRA RESOURCES - [Sentry Docs contributor guide](https://docs.sentry.io/contributing/) --------- Co-authored-by: Alex Krawiec <alex.krawiec@sentry.io>


📢 Type of change
📜 Description
Extends
SENTRY_ENVIRONMENTsupport to bare (non-Expo) React Native projects. When theSENTRY_ENVIRONMENTenvironment variable is set at build time, it overrides theenvironmentvalue in thesentry.options.jsoncopy that gets bundled into the native app — without modifying the source file.Android (
sentry.gradle): Parses JSON with Groovy'sJsonSlurper, setsenvironment, writes to assets.iOS (
sentry-xcode.sh): Uses$LOCAL_NODE_BINARY(already available) to parse/modify/write.Both fall back to a plain file copy when the env var is not set.
💡 Motivation and Context
Closes #5779 (for bare RN — Expo support shipped in #5796 / 8.4.0)
A user reported that the Expo-only solution doesn't cover bare React Native projects. This extends the same
SENTRY_ENVIRONMENTsupport to the native build scripts.💚 How did you test it?
sentry-xcode-scripts.test.ts):SENTRY_ENVIRONMENTis not setSENTRY_ENVIRONMENTis setsentry.options.json📝 Checklist
sendDefaultPIIis enabled🔮 Next steps