Skip to content

Commit 2c735cc

Browse files
antonisclaude
andauthored
fix(ios): Add SENTRY_PROJECT_ROOT env var for monorepo support (#5961)
* fix(ios): Add SENTRY_PROJECT_ROOT env var for monorepo support Allow overriding the project root in Xcode build phase scripts via SENTRY_PROJECT_ROOT for monorepo setups where the ios directory is not directly under the React Native project root. Fixes #2880 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: Add changelog entry for SENTRY_PROJECT_ROOT Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6cc2aa7 commit 2c735cc

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
99
## Unreleased
1010

11+
### Fixes
12+
13+
- Add `SENTRY_PROJECT_ROOT` env var to override project root in Xcode build phase scripts for monorepo setups ([#5961](https://github.com/getsentry/sentry-react-native/pull/5961))
14+
1115
### Features
1216

1317
- Enable "Open Sentry" button in Playground for Expo apps ([#5947](https://github.com/getsentry/sentry-react-native/pull/5947))

packages/core/scripts/sentry-xcode-debug-files.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ set -e
2121
LOCAL_NODE_BINARY=${NODE_BINARY:-node}
2222

2323
# The project root by default is one level up from the ios directory
24-
RN_PROJECT_ROOT="${PROJECT_DIR}/.."
24+
# SENTRY_PROJECT_ROOT can be set to override this for monorepo setups
25+
# where the ios directory is not directly under the project root.
26+
# See: https://github.com/getsentry/sentry-react-native/issues/2880
27+
RN_PROJECT_ROOT="${SENTRY_PROJECT_ROOT:-${PROJECT_DIR}/..}"
2528

2629
[ -z "$SENTRY_PROPERTIES" ] && export SENTRY_PROPERTIES=sentry.properties
2730
[ -z "$SENTRY_DOTENV_PATH" ] && [ -f "$RN_PROJECT_ROOT/.env.sentry-build-plugin" ] && export SENTRY_DOTENV_PATH="$RN_PROJECT_ROOT/.env.sentry-build-plugin"

packages/core/scripts/sentry-xcode.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ set -x -e
1010
LOCAL_NODE_BINARY=${NODE_BINARY:-node}
1111

1212
# The project root by default is one level up from the ios directory
13-
RN_PROJECT_ROOT="${PROJECT_DIR}/.."
13+
# SENTRY_PROJECT_ROOT can be set to override this for monorepo setups
14+
# where the ios directory is not directly under the project root.
15+
# See: https://github.com/getsentry/sentry-react-native/issues/2880
16+
RN_PROJECT_ROOT="${SENTRY_PROJECT_ROOT:-${PROJECT_DIR}/..}"
1417

1518
[ -z "$SENTRY_PROPERTIES" ] && export SENTRY_PROPERTIES=sentry.properties
1619
[ -z "$SENTRY_DOTENV_PATH" ] && [ -f "$RN_PROJECT_ROOT/.env.sentry-build-plugin" ] && export SENTRY_DOTENV_PATH="$RN_PROJECT_ROOT/.env.sentry-build-plugin"

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

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

458+
describe('SENTRY_PROJECT_ROOT override', () => {
459+
it('resolves SOURCEMAP_FILE relative to SENTRY_PROJECT_ROOT instead of PROJECT_DIR/..', () => {
460+
const customRoot = path.join(tempDir, 'monorepo-package');
461+
fs.mkdirSync(customRoot, { recursive: true });
462+
463+
const echoScript = path.join(tempDir, 'mock-sentry-cli-echo-sourcemap.js');
464+
fs.writeFileSync(
465+
echoScript,
466+
`
467+
const sourcemapFile = process.env.SOURCEMAP_FILE || 'not-set';
468+
console.log('SOURCEMAP_FILE=' + sourcemapFile);
469+
process.exit(0);
470+
`,
471+
);
472+
473+
const result = runScript({
474+
SENTRY_PROJECT_ROOT: customRoot,
475+
SENTRY_CLI_EXECUTABLE: echoScript,
476+
SOURCEMAP_FILE: 'relative/path.map',
477+
});
478+
479+
const expectedPath = path.join(customRoot, 'relative/path.map');
480+
expect(result.exitCode).toBe(0);
481+
expect(result.stdout).toContain(`SOURCEMAP_FILE=${expectedPath}`);
482+
});
483+
484+
it('resolves SOURCEMAP_FILE relative to PROJECT_DIR/.. when SENTRY_PROJECT_ROOT is not set', () => {
485+
const echoScript = path.join(tempDir, 'mock-sentry-cli-echo-sourcemap.js');
486+
fs.writeFileSync(
487+
echoScript,
488+
`
489+
const sourcemapFile = process.env.SOURCEMAP_FILE || 'not-set';
490+
console.log('SOURCEMAP_FILE=' + sourcemapFile);
491+
process.exit(0);
492+
`,
493+
);
494+
495+
const result = runScript({
496+
SENTRY_CLI_EXECUTABLE: echoScript,
497+
SOURCEMAP_FILE: 'relative/path.map',
498+
});
499+
500+
// Without SENTRY_PROJECT_ROOT, falls back to PROJECT_DIR/..
501+
const projectRoot = path.dirname(tempDir);
502+
const expectedPath = path.join(projectRoot, 'relative/path.map');
503+
expect(result.exitCode).toBe(0);
504+
expect(result.stdout).toContain(`SOURCEMAP_FILE=${expectedPath}`);
505+
});
506+
507+
it('finds sentry.options.json in SENTRY_PROJECT_ROOT', () => {
508+
const customRoot = path.join(tempDir, 'monorepo-package');
509+
fs.mkdirSync(customRoot, { recursive: true });
510+
511+
const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123' });
512+
fs.writeFileSync(path.join(customRoot, 'sentry.options.json'), optionsContent);
513+
514+
const buildDir = path.join(tempDir, 'build');
515+
const resourcesPath = 'Resources';
516+
fs.mkdirSync(path.join(buildDir, resourcesPath), { recursive: true });
517+
518+
const result = runScript({
519+
SENTRY_PROJECT_ROOT: customRoot,
520+
SENTRY_DISABLE_AUTO_UPLOAD: 'true',
521+
SENTRY_COPY_OPTIONS_FILE: 'true',
522+
CONFIGURATION_BUILD_DIR: buildDir,
523+
UNLOCALIZED_RESOURCES_FOLDER_PATH: resourcesPath,
524+
});
525+
526+
expect(result.exitCode).toBe(0);
527+
expect(result.stdout).toContain('Copied');
528+
const destPath = path.join(buildDir, resourcesPath, 'sentry.options.json');
529+
const copied = JSON.parse(fs.readFileSync(destPath, 'utf8'));
530+
expect(copied.dsn).toBe('https://key@sentry.io/123');
531+
});
532+
});
533+
458534
describe('sentry.options.json SENTRY_ENVIRONMENT override', () => {
459535
it('copies file without modification when SENTRY_ENVIRONMENT is not set', () => {
460536
const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123', environment: 'production' });

0 commit comments

Comments
 (0)