Skip to content

Commit 03daa62

Browse files
antonisclaude
andcommitted
fix(ios): resolve relative SOURCEMAP_FILE against project root in Xcode build script
When users set SOURCEMAP_FILE to a relative path (e.g. `SOURCEMAP_FILE=maps/main.jsbundle.map`), the value is now resolved against the project root (one level up from `ios/`) rather than against the `ios/` directory where the Xcode build script runs. Without this fix, sentry-cli could not find the source map because the bundle is created relative to the project root. Fixes #3889 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5a14e8e commit 03daa62

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

packages/core/scripts/sentry-xcode.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ RN_PROJECT_ROOT="${PROJECT_DIR}/.."
1515
[ -z "$SENTRY_PROPERTIES" ] && export SENTRY_PROPERTIES=sentry.properties
1616
[ -z "$SENTRY_DOTENV_PATH" ] && [ -f "$RN_PROJECT_ROOT/.env.sentry-build-plugin" ] && export SENTRY_DOTENV_PATH="$RN_PROJECT_ROOT/.env.sentry-build-plugin"
1717
[ -z "$SOURCEMAP_FILE" ] && export SOURCEMAP_FILE="$DERIVED_FILE_DIR/main.jsbundle.map"
18+
# Resolve relative SOURCEMAP_FILE to absolute. The script runs from `ios/` (Xcode's PWD),
19+
# but users typically specify paths relative to the project root. Without this, sentry-cli
20+
# would resolve relative paths against `ios/` and fail to find the file.
21+
# See: https://github.com/getsentry/sentry-react-native/issues/3889
22+
if [[ "$SOURCEMAP_FILE" != /* ]]; then
23+
export SOURCEMAP_FILE="$(cd "$RN_PROJECT_ROOT" && pwd)/$SOURCEMAP_FILE"
24+
fi
1825

1926
if [ -z "$SENTRY_CLI_EXECUTABLE" ]; then
2027
# Try standard resolution safely

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,4 +454,81 @@ describe('sentry-xcode.sh', () => {
454454
expect(result.stdout).toContain('SENTRY_DISABLE_AUTO_UPLOAD=true');
455455
expect(result.stdout).toContain('skipping sourcemaps upload');
456456
});
457+
458+
describe('SOURCEMAP_FILE path resolution', () => {
459+
// Returns a mock sentry-cli that prints the SOURCEMAP_FILE env var it received.
460+
const makeSourcmapEchoScript = (dir: string): string => {
461+
const scriptPath = path.join(dir, 'mock-sentry-cli-echo-sourcemap.js');
462+
fs.writeFileSync(
463+
scriptPath,
464+
`
465+
const sourcemapFile = process.env.SOURCEMAP_FILE || 'not-set';
466+
console.log('SOURCEMAP_FILE=' + sourcemapFile);
467+
process.exit(0);
468+
`,
469+
);
470+
return scriptPath;
471+
};
472+
473+
it('leaves an absolute SOURCEMAP_FILE unchanged', () => {
474+
const absolutePath = path.join(tempDir, 'absolute', 'main.jsbundle.map');
475+
const echoScript = makeSourcmapEchoScript(tempDir);
476+
477+
const result = runScript({
478+
SENTRY_CLI_EXECUTABLE: echoScript,
479+
SOURCEMAP_FILE: absolutePath,
480+
});
481+
482+
expect(result.exitCode).toBe(0);
483+
expect(result.stdout).toContain(`SOURCEMAP_FILE=${absolutePath}`);
484+
});
485+
486+
it('resolves a relative SOURCEMAP_FILE against the project root, not ios/', () => {
487+
// PROJECT_DIR is tempDir (simulates the ios/ folder).
488+
// RN_PROJECT_ROOT = PROJECT_DIR/.. = parent of tempDir.
489+
// A user setting SOURCEMAP_FILE=relative/path.map expects it relative to the project root.
490+
const echoScript = makeSourcmapEchoScript(tempDir);
491+
492+
const result = runScript({
493+
SENTRY_CLI_EXECUTABLE: echoScript,
494+
SOURCEMAP_FILE: 'relative/path.map',
495+
});
496+
497+
const projectRoot = path.dirname(tempDir); // PROJECT_DIR/.. = RN_PROJECT_ROOT
498+
const expectedPath = path.join(projectRoot, 'relative/path.map');
499+
500+
expect(result.exitCode).toBe(0);
501+
expect(result.stdout).toContain(`SOURCEMAP_FILE=${expectedPath}`);
502+
});
503+
504+
it('resolves a ./prefixed SOURCEMAP_FILE against the project root', () => {
505+
const echoScript = makeSourcmapEchoScript(tempDir);
506+
507+
const result = runScript({
508+
SENTRY_CLI_EXECUTABLE: echoScript,
509+
SOURCEMAP_FILE: './maps/main.jsbundle.map',
510+
});
511+
512+
// The script concatenates: "$(cd RN_PROJECT_ROOT && pwd)/./maps/main.jsbundle.map"
513+
// The ./ is preserved but the path is absolute and valid for sentry-cli.
514+
const projectRoot = path.dirname(tempDir);
515+
const expectedPath = `${projectRoot}/./maps/main.jsbundle.map`;
516+
517+
expect(result.exitCode).toBe(0);
518+
expect(result.stdout).toContain(`SOURCEMAP_FILE=${expectedPath}`);
519+
});
520+
521+
it('uses the absolute default SOURCEMAP_FILE when not set by the user', () => {
522+
const echoScript = makeSourcmapEchoScript(tempDir);
523+
524+
const result = runScript({
525+
SENTRY_CLI_EXECUTABLE: echoScript,
526+
// SOURCEMAP_FILE intentionally not set — script should default to $DERIVED_FILE_DIR/main.jsbundle.map
527+
DERIVED_FILE_DIR: tempDir,
528+
});
529+
530+
expect(result.exitCode).toBe(0);
531+
expect(result.stdout).toContain(`SOURCEMAP_FILE=${tempDir}/main.jsbundle.map`);
532+
});
533+
});
457534
});

0 commit comments

Comments
 (0)