Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
> make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
<!-- prettier-ignore-end -->

## Unreleased

### Fixes

- Load `.xcode.env` and `.xcode.env.local` in the Expo plugin's "Upload Debug Symbols to Sentry" build phase before it looks for Node, so builds started from Xcode opened in the Dock or Finder find the upload script ([#6860](https://github.com/getsentry/sentry-react-native/pull/6860))

## 8.30.0

### Features
Expand Down
11 changes: 10 additions & 1 deletion packages/core/plugin/src/withSentryIOS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ const SENTRY_REACT_NATIVE_XCODE_PATH =
const SENTRY_REACT_NATIVE_XCODE_DEBUG_FILES_PATH =
"`${NODE_BINARY:-node} --print \"require('path').dirname(require.resolve('@sentry/react-native/package.json')) + '/scripts/sentry-xcode-debug-files.sh'\"`";
const SENTRY_DISABLE_AUTO_UPLOAD_EXPORT = 'export SENTRY_DISABLE_AUTO_UPLOAD=true';
// Same as the "Bundle React Native code and images" phase of the Expo template.
const LOAD_XCODE_ENV = `if [[ -f "$PODS_ROOT/../.xcode.env" ]]; then
source "$PODS_ROOT/../.xcode.env"
fi
if [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then
source "$PODS_ROOT/../.xcode.env.local"
fi`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[[ ]] and source are bash features. The Xcode phase works because /bin/sh on macOS is bash. But our Jest jobs run on ubuntu-latest, where /bin/sh is dash. Could you please update it to POSIX form that works on both shells?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe something like that:

const LOAD_XCODE_ENV = `if [ -f "$PODS_ROOT/../.xcode.env" ]; then
  . "$PODS_ROOT/../.xcode.env"
fi
if [ -f "$PODS_ROOT/../.xcode.env.local" ]; then
  . "$PODS_ROOT/../.xcode.env.local"
fi`;


export const withSentryIOS: ConfigPlugin<{
sentryProperties: string;
Expand Down Expand Up @@ -114,7 +121,9 @@ export function getDebugFilesUploadScript(disableAutoUpload: boolean = false): s
// The resolved script path is wrapped in double quotes so a project path containing spaces is
// passed to `/bin/sh` as a single argument instead of being word-split. See issue #6583.
const disableAutoUploadExport = disableAutoUpload ? `${SENTRY_DISABLE_AUTO_UPLOAD_EXPORT}\n` : '';
return `${disableAutoUploadExport}/bin/sh "${SENTRY_REACT_NATIVE_XCODE_DEBUG_FILES_PATH}"`;
// NODE_BINARY is needed to find the script, before the script itself can load `.xcode.env`.
// Xcode launched from the Dock or Finder does not have `node` on its PATH. See issue #6859.
return `${disableAutoUploadExport}${LOAD_XCODE_ENV}\n/bin/sh "${SENTRY_REACT_NATIVE_XCODE_DEBUG_FILES_PATH}"`;
}

export function requoteExistingSentryBundleScript(script: BuildPhase): void {
Expand Down
56 changes: 54 additions & 2 deletions packages/core/test/expo-plugin/modifyXcodeProject.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { execFileSync } from 'child_process';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';

import { warnOnce } from '../../plugin/src/logger';
import {
addDisableAutoUploadToExistingScript,
Expand Down Expand Up @@ -470,7 +475,8 @@ describe('overwriteDebugFilesUploadScript: existing phase re-quoted on upgrade (
overwriteDebugFilesUploadScript(script, true);
const parsed = JSON.parse(script.shellScript);
expect(parsed).toBe(getDebugFilesUploadScript(true));
expect(parsed).toMatch(/^export SENTRY_DISABLE_AUTO_UPLOAD=true\n\/bin\/sh "`/);
expect(parsed).toMatch(/^export SENTRY_DISABLE_AUTO_UPLOAD=true\n/);
expect(parsed).toContain('\n/bin/sh "`');
});

it('drops a previously injected export when disableAutoUpload is toggled back to false', () => {
Expand All @@ -488,6 +494,51 @@ describe('overwriteDebugFilesUploadScript: existing phase re-quoted on upgrade (
});
});

describe('Upload Debug Symbols phase finds Node from .xcode.env (issue #6859)', () => {
let projectRoot: string;

// Stands in for Node: prints the path of a stub debug files script, like `node --print` does.
const writeFakeNode = (name: string): string => {
const stubScript = path.join(projectRoot, 'sentry-xcode-debug-files.sh');
fs.writeFileSync(stubScript, `echo "ran with ${name}"\n`);
const fakeNode = path.join(projectRoot, name);
fs.writeFileSync(fakeNode, `#!/bin/sh\necho "${stubScript}"\n`, { mode: 0o755 });
return fakeNode;
};

// Xcode launched from the Dock or Finder only has launchd's PATH, which has no `node`.
const runPhase = (script: string): string =>
execFileSync('/bin/sh', ['-c', script], {
cwd: path.join(projectRoot, 'ios'),
env: { PATH: '/usr/bin:/bin:/usr/sbin:/sbin', PODS_ROOT: path.join(projectRoot, 'ios', 'Pods') },
encoding: 'utf8',
});

beforeEach(() => {
projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sentry-xcode-env-'));
fs.mkdirSync(path.join(projectRoot, 'ios', 'Pods'), { recursive: true });
});

afterEach(() => {
fs.rmSync(projectRoot, { recursive: true, force: true });
});

it('uses NODE_BINARY from .xcode.env when node is not on the PATH', () => {
const fakeNode = writeFakeNode('node-from-xcode-env');
fs.writeFileSync(path.join(projectRoot, 'ios', '.xcode.env'), `export NODE_BINARY="${fakeNode}"\n`);

expect(runPhase(getDebugFilesUploadScript())).toBe('ran with node-from-xcode-env\n');
});

it('prefers NODE_BINARY from .xcode.env.local over .xcode.env', () => {
fs.writeFileSync(path.join(projectRoot, 'ios', '.xcode.env'), 'export NODE_BINARY=$(command -v node)\n');
const fakeNode = writeFakeNode('node-from-xcode-env-local');
fs.writeFileSync(path.join(projectRoot, 'ios', '.xcode.env.local'), `export NODE_BINARY="${fakeNode}"\n`);

expect(runPhase(getDebugFilesUploadScript(true))).toBe('ran with node-from-xcode-env-local\n');
});
});

describe('Project paths with spaces are quoted (issue #6583)', () => {
let consoleWarnMock: jest.SpyInstance<void, [message?: any, ...optionalParams: any[]], any>;

Expand Down Expand Up @@ -564,7 +615,8 @@ export NODE_BINARY=node

it('quotes the debug files upload script path with disableAutoUpload', () => {
const result = getDebugFilesUploadScript(true);
expect(result).toMatch(/^export SENTRY_DISABLE_AUTO_UPLOAD=true\n\/bin\/sh "`/);
expect(result).toMatch(/^export SENTRY_DISABLE_AUTO_UPLOAD=true\n/);
expect(result).toContain('\n/bin/sh "`');
expect(result).toContain('sentry-xcode-debug-files.sh');
expect(result).not.toMatch(/\/bin\/sh `/);
});
Expand Down
Loading