diff --git a/CHANGELOG.md b/CHANGELOG.md index 6418b28f9a..afe8eb0c41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ ## Unreleased +### Fixes + +- 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)) + ### Features - Enable "Open Sentry" button in Playground for Expo apps ([#5947](https://github.com/getsentry/sentry-react-native/pull/5947)) diff --git a/packages/core/scripts/sentry-xcode-debug-files.sh b/packages/core/scripts/sentry-xcode-debug-files.sh index e261b12c04..8bbd18a6f7 100755 --- a/packages/core/scripts/sentry-xcode-debug-files.sh +++ b/packages/core/scripts/sentry-xcode-debug-files.sh @@ -21,7 +21,10 @@ set -e LOCAL_NODE_BINARY=${NODE_BINARY:-node} # The project root by default is one level up from the ios directory -RN_PROJECT_ROOT="${PROJECT_DIR}/.." +# SENTRY_PROJECT_ROOT can be set to override this for monorepo setups +# where the ios directory is not directly under the project root. +# See: https://github.com/getsentry/sentry-react-native/issues/2880 +RN_PROJECT_ROOT="${SENTRY_PROJECT_ROOT:-${PROJECT_DIR}/..}" [ -z "$SENTRY_PROPERTIES" ] && export SENTRY_PROPERTIES=sentry.properties [ -z "$SENTRY_DOTENV_PATH" ] && [ -f "$RN_PROJECT_ROOT/.env.sentry-build-plugin" ] && export SENTRY_DOTENV_PATH="$RN_PROJECT_ROOT/.env.sentry-build-plugin" diff --git a/packages/core/scripts/sentry-xcode.sh b/packages/core/scripts/sentry-xcode.sh index 069f08be01..e8b52e846a 100755 --- a/packages/core/scripts/sentry-xcode.sh +++ b/packages/core/scripts/sentry-xcode.sh @@ -10,7 +10,10 @@ set -x -e LOCAL_NODE_BINARY=${NODE_BINARY:-node} # The project root by default is one level up from the ios directory -RN_PROJECT_ROOT="${PROJECT_DIR}/.." +# SENTRY_PROJECT_ROOT can be set to override this for monorepo setups +# where the ios directory is not directly under the project root. +# See: https://github.com/getsentry/sentry-react-native/issues/2880 +RN_PROJECT_ROOT="${SENTRY_PROJECT_ROOT:-${PROJECT_DIR}/..}" [ -z "$SENTRY_PROPERTIES" ] && export SENTRY_PROPERTIES=sentry.properties [ -z "$SENTRY_DOTENV_PATH" ] && [ -f "$RN_PROJECT_ROOT/.env.sentry-build-plugin" ] && export SENTRY_DOTENV_PATH="$RN_PROJECT_ROOT/.env.sentry-build-plugin" diff --git a/packages/core/test/scripts/sentry-xcode-scripts.test.ts b/packages/core/test/scripts/sentry-xcode-scripts.test.ts index ec0056fe7b..1f822db47e 100644 --- a/packages/core/test/scripts/sentry-xcode-scripts.test.ts +++ b/packages/core/test/scripts/sentry-xcode-scripts.test.ts @@ -455,6 +455,82 @@ describe('sentry-xcode.sh', () => { expect(result.stdout).toContain('skipping sourcemaps upload'); }); + describe('SENTRY_PROJECT_ROOT override', () => { + it('resolves SOURCEMAP_FILE relative to SENTRY_PROJECT_ROOT instead of PROJECT_DIR/..', () => { + const customRoot = path.join(tempDir, 'monorepo-package'); + fs.mkdirSync(customRoot, { recursive: true }); + + const echoScript = path.join(tempDir, 'mock-sentry-cli-echo-sourcemap.js'); + fs.writeFileSync( + echoScript, + ` + const sourcemapFile = process.env.SOURCEMAP_FILE || 'not-set'; + console.log('SOURCEMAP_FILE=' + sourcemapFile); + process.exit(0); + `, + ); + + const result = runScript({ + SENTRY_PROJECT_ROOT: customRoot, + SENTRY_CLI_EXECUTABLE: echoScript, + SOURCEMAP_FILE: 'relative/path.map', + }); + + const expectedPath = path.join(customRoot, 'relative/path.map'); + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain(`SOURCEMAP_FILE=${expectedPath}`); + }); + + it('resolves SOURCEMAP_FILE relative to PROJECT_DIR/.. when SENTRY_PROJECT_ROOT is not set', () => { + const echoScript = path.join(tempDir, 'mock-sentry-cli-echo-sourcemap.js'); + fs.writeFileSync( + echoScript, + ` + const sourcemapFile = process.env.SOURCEMAP_FILE || 'not-set'; + console.log('SOURCEMAP_FILE=' + sourcemapFile); + process.exit(0); + `, + ); + + const result = runScript({ + SENTRY_CLI_EXECUTABLE: echoScript, + SOURCEMAP_FILE: 'relative/path.map', + }); + + // Without SENTRY_PROJECT_ROOT, falls back to PROJECT_DIR/.. + const projectRoot = path.dirname(tempDir); + const expectedPath = path.join(projectRoot, 'relative/path.map'); + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain(`SOURCEMAP_FILE=${expectedPath}`); + }); + + it('finds sentry.options.json in SENTRY_PROJECT_ROOT', () => { + const customRoot = path.join(tempDir, 'monorepo-package'); + fs.mkdirSync(customRoot, { recursive: true }); + + const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123' }); + fs.writeFileSync(path.join(customRoot, 'sentry.options.json'), optionsContent); + + const buildDir = path.join(tempDir, 'build'); + const resourcesPath = 'Resources'; + fs.mkdirSync(path.join(buildDir, resourcesPath), { recursive: true }); + + const result = runScript({ + SENTRY_PROJECT_ROOT: customRoot, + SENTRY_DISABLE_AUTO_UPLOAD: 'true', + SENTRY_COPY_OPTIONS_FILE: 'true', + CONFIGURATION_BUILD_DIR: buildDir, + UNLOCALIZED_RESOURCES_FOLDER_PATH: resourcesPath, + }); + + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain('Copied'); + const destPath = path.join(buildDir, resourcesPath, 'sentry.options.json'); + const copied = JSON.parse(fs.readFileSync(destPath, 'utf8')); + expect(copied.dsn).toBe('https://key@sentry.io/123'); + }); + }); + describe('sentry.options.json SENTRY_ENVIRONMENT override', () => { it('copies file without modification when SENTRY_ENVIRONMENT is not set', () => { const optionsContent = JSON.stringify({ dsn: 'https://key@sentry.io/123', environment: 'production' });