Skip to content

Commit b111aaf

Browse files
antonisclaude
andcommitted
feat(core): Support SENTRY_ENVIRONMENT in bare React Native builds
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>
1 parent 999a87c commit b111aaf

3 files changed

Lines changed: 97 additions & 5 deletions

File tree

packages/core/scripts/sentry-xcode.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,17 @@ if [ "$SENTRY_COPY_OPTIONS_FILE" = true ]; then
100100
elif [ ! -f "$SENTRY_OPTIONS_FILE_PATH" ]; then
101101
echo "[Sentry] $SENTRY_OPTIONS_FILE_PATH not found. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
102102
else
103-
cp "$SENTRY_OPTIONS_FILE_PATH" "$SENTRY_OPTIONS_FILE_DESTINATION_PATH"
103+
if [ -n "$SENTRY_ENVIRONMENT" ]; then
104+
"$LOCAL_NODE_BINARY" -e "
105+
var fs = require('fs');
106+
var opts = JSON.parse(fs.readFileSync('$SENTRY_OPTIONS_FILE_PATH', 'utf8'));
107+
opts.environment = process.env.SENTRY_ENVIRONMENT;
108+
fs.writeFileSync('$SENTRY_OPTIONS_FILE_DESTINATION_PATH', JSON.stringify(opts));
109+
"
110+
echo "[Sentry] Overriding 'environment' from SENTRY_ENVIRONMENT environment variable"
111+
else
112+
cp "$SENTRY_OPTIONS_FILE_PATH" "$SENTRY_OPTIONS_FILE_DESTINATION_PATH"
113+
fi
104114
echo "[Sentry] Copied $SENTRY_OPTIONS_FILE_PATH to $SENTRY_OPTIONS_FILE_DESTINATION_PATH"
105115
fi
106116
fi

packages/core/sentry.gradle

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,18 @@ tasks.register("copySentryJsonConfiguration") {
3939
androidAssetsDir.mkdirs()
4040
}
4141

42-
copy {
43-
from sentryOptionsFile
44-
into androidAssetsDir
45-
rename { String fileName -> configFile }
42+
def sentryEnv = System.getenv('SENTRY_ENVIRONMENT')
43+
if (sentryEnv) {
44+
def content = new groovy.json.JsonSlurper().parseText(sentryOptionsFile.text)
45+
content.environment = sentryEnv
46+
new File(androidAssetsDir, configFile).text = groovy.json.JsonOutput.toJson(content)
47+
logger.lifecycle("Overriding 'environment' from SENTRY_ENVIRONMENT environment variable")
48+
} else {
49+
copy {
50+
from sentryOptionsFile
51+
into androidAssetsDir
52+
rename { String fileName -> configFile }
53+
}
4654
}
4755
logger.lifecycle("Copied ${configFile} to Android assets")
4856
} else {

packages/core/test/scripts/sentry-xcode-scripts.test.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,80 @@ describe('sentry-xcode.sh', () => {
455455
expect(result.stdout).toContain('skipping sourcemaps upload');
456456
});
457457

458+
describe('sentry.options.json SENTRY_ENVIRONMENT override', () => {
459+
it('copies file without modification when SENTRY_ENVIRONMENT is not set', () => {
460+
const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123', environment: 'production' });
461+
const optionsFile = path.join(tempDir, 'sentry.options.json');
462+
fs.writeFileSync(optionsFile, optionsContent);
463+
464+
const buildDir = path.join(tempDir, 'build');
465+
const resourcesPath = 'Resources';
466+
fs.mkdirSync(path.join(buildDir, resourcesPath), { recursive: true });
467+
468+
const result = runScript({
469+
SENTRY_DISABLE_AUTO_UPLOAD: 'true',
470+
SENTRY_COPY_OPTIONS_FILE: 'true',
471+
SENTRY_OPTIONS_FILE_PATH: optionsFile,
472+
CONFIGURATION_BUILD_DIR: buildDir,
473+
UNLOCALIZED_RESOURCES_FOLDER_PATH: resourcesPath,
474+
});
475+
476+
expect(result.exitCode).toBe(0);
477+
const destPath = path.join(buildDir, resourcesPath, 'sentry.options.json');
478+
const copied = JSON.parse(fs.readFileSync(destPath, 'utf8'));
479+
expect(copied.dsn).toBe('https://key@sentry.io/123');
480+
expect(copied.environment).toBe('production');
481+
});
482+
483+
it('overrides environment from SENTRY_ENVIRONMENT env var', () => {
484+
const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123', environment: 'production' });
485+
const optionsFile = path.join(tempDir, 'sentry.options.json');
486+
fs.writeFileSync(optionsFile, optionsContent);
487+
488+
const buildDir = path.join(tempDir, 'build');
489+
const resourcesPath = 'Resources';
490+
fs.mkdirSync(path.join(buildDir, resourcesPath), { recursive: true });
491+
492+
const result = runScript({
493+
SENTRY_DISABLE_AUTO_UPLOAD: 'true',
494+
SENTRY_COPY_OPTIONS_FILE: 'true',
495+
SENTRY_OPTIONS_FILE_PATH: optionsFile,
496+
CONFIGURATION_BUILD_DIR: buildDir,
497+
UNLOCALIZED_RESOURCES_FOLDER_PATH: resourcesPath,
498+
SENTRY_ENVIRONMENT: 'staging',
499+
});
500+
501+
expect(result.exitCode).toBe(0);
502+
expect(result.stdout).toContain('Overriding');
503+
const destPath = path.join(buildDir, resourcesPath, 'sentry.options.json');
504+
const copied = JSON.parse(fs.readFileSync(destPath, 'utf8'));
505+
expect(copied.environment).toBe('staging');
506+
expect(copied.dsn).toBe('https://key@sentry.io/123');
507+
});
508+
509+
it('does not modify the source sentry.options.json', () => {
510+
const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123', environment: 'production' });
511+
const optionsFile = path.join(tempDir, 'sentry.options.json');
512+
fs.writeFileSync(optionsFile, optionsContent);
513+
514+
const buildDir = path.join(tempDir, 'build');
515+
const resourcesPath = 'Resources';
516+
fs.mkdirSync(path.join(buildDir, resourcesPath), { recursive: true });
517+
518+
runScript({
519+
SENTRY_DISABLE_AUTO_UPLOAD: 'true',
520+
SENTRY_COPY_OPTIONS_FILE: 'true',
521+
SENTRY_OPTIONS_FILE_PATH: optionsFile,
522+
CONFIGURATION_BUILD_DIR: buildDir,
523+
UNLOCALIZED_RESOURCES_FOLDER_PATH: resourcesPath,
524+
SENTRY_ENVIRONMENT: 'staging',
525+
});
526+
527+
const source = JSON.parse(fs.readFileSync(optionsFile, 'utf8'));
528+
expect(source.environment).toBe('production');
529+
});
530+
});
531+
458532
describe('SOURCEMAP_FILE path resolution', () => {
459533
// Returns a mock sentry-cli that prints the SOURCEMAP_FILE env var it received.
460534
const makeSourcemapEchoScript = (dir: string): string => {

0 commit comments

Comments
 (0)