@sentry/wizard 3.24.1 → 3.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/package.json +1 -1
  3. package/dist/src/react-native/expo-env-file.d.ts +2 -0
  4. package/dist/src/react-native/expo-env-file.js +127 -0
  5. package/dist/src/react-native/expo-env-file.js.map +1 -0
  6. package/dist/src/react-native/expo-metro.d.ts +7 -0
  7. package/dist/src/react-native/expo-metro.js +236 -0
  8. package/dist/src/react-native/expo-metro.js.map +1 -0
  9. package/dist/src/react-native/expo.d.ts +16 -0
  10. package/dist/src/react-native/expo.js +195 -0
  11. package/dist/src/react-native/expo.js.map +1 -0
  12. package/dist/src/react-native/git.d.ts +1 -0
  13. package/dist/src/react-native/git.js +85 -0
  14. package/dist/src/react-native/git.js.map +1 -0
  15. package/dist/src/react-native/javascript.d.ts +3 -0
  16. package/dist/src/react-native/javascript.js +119 -1
  17. package/dist/src/react-native/javascript.js.map +1 -1
  18. package/dist/src/react-native/metro.d.ts +3 -0
  19. package/dist/src/react-native/metro.js +17 -15
  20. package/dist/src/react-native/metro.js.map +1 -1
  21. package/dist/src/react-native/react-native-wizard.d.ts +12 -0
  22. package/dist/src/react-native/react-native-wizard.js +91 -78
  23. package/dist/src/react-native/react-native-wizard.js.map +1 -1
  24. package/dist/src/react-native/xcode.js +14 -3
  25. package/dist/src/react-native/xcode.js.map +1 -1
  26. package/dist/src/remix/codemods/handle-error.js +35 -33
  27. package/dist/src/remix/codemods/handle-error.js.map +1 -1
  28. package/dist/src/remix/templates.d.ts +1 -1
  29. package/dist/src/remix/templates.js +1 -1
  30. package/dist/src/remix/templates.js.map +1 -1
  31. package/dist/src/utils/clack-utils.d.ts +2 -1
  32. package/dist/src/utils/clack-utils.js +2 -2
  33. package/dist/src/utils/clack-utils.js.map +1 -1
  34. package/dist/test/react-native/expo-metro.test.d.ts +1 -0
  35. package/dist/test/react-native/expo-metro.test.js +26 -0
  36. package/dist/test/react-native/expo-metro.test.js.map +1 -0
  37. package/dist/test/react-native/expo.test.d.ts +1 -0
  38. package/dist/test/react-native/expo.test.js +57 -0
  39. package/dist/test/react-native/expo.test.js.map +1 -0
  40. package/dist/test/react-native/xcode.test.js +5 -0
  41. package/dist/test/react-native/xcode.test.js.map +1 -1
  42. package/package.json +1 -1
  43. package/src/react-native/expo-env-file.ts +55 -0
  44. package/src/react-native/expo-metro.ts +212 -0
  45. package/src/react-native/expo.ts +175 -0
  46. package/src/react-native/git.ts +25 -0
  47. package/src/react-native/javascript.ts +68 -1
  48. package/src/react-native/metro.ts +3 -3
  49. package/src/react-native/react-native-wizard.ts +72 -76
  50. package/src/react-native/xcode.ts +21 -5
  51. package/src/remix/codemods/handle-error.ts +57 -37
  52. package/src/remix/templates.ts +3 -3
  53. package/src/utils/clack-utils.ts +4 -4
  54. package/test/react-native/expo-metro.test.ts +81 -0
  55. package/test/react-native/expo.test.ts +86 -0
  56. package/test/react-native/xcode.test.ts +90 -0
@@ -1 +1 @@
1
- {"version":3,"file":"xcode.test.js","sourceRoot":"","sources":["../../../test/react-native/xcode.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-useless-escape */\nimport {\n addSentryWithBundledScriptsToBundleShellScript,\n addSentryWithCliToBundleShellScript,\n doesBundlePhaseIncludeSentry,\n findBundlePhase,\n findDebugFilesUploadPhase,\n removeSentryFromBundleShellScript,\n} from '../../src/react-native/xcode';\n\ndescribe('react-native xcode', () => {\n describe('addSentryWithCliToBundleShellScript', () => {\n it('adds sentry cli to rn bundle build phase', () => {\n const input = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"`;\n // actual shell script looks like this:\n // /bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n // but during parsing xcode library removes the quotes\n const expectedOutput = `export SENTRY_PROPERTIES=sentry.properties\nexport EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nset -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\\\"../node_modules/@sentry/cli/bin/sentry-cli react-native xcode $REACT_NATIVE_XCODE\\\\\"\"\n/bin/sh -c \"$WITH_ENVIRONMENT ../node_modules/@sentry/react-native/scripts/collect-modules.sh\"\n`;\n\n expect(addSentryWithCliToBundleShellScript(input)).toBe(expectedOutput);\n });\n });\n\n describe('addSentryBundledScriptsToBundleShellScript', () => {\n it('adds sentry cli to rn bundle build phase', () => {\n const input = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"`;\n // actual shell script looks like this:\n // /bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n // but during parsing xcode library removes the quotes\n const expectedOutput = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\\\"/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode.sh $REACT_NATIVE_XCODE\\\\\"\"`;\n\n expect(addSentryWithBundledScriptsToBundleShellScript(input)).toBe(\n expectedOutput,\n );\n });\n });\n\n describe('removeSentryFromBundleShellScript', () => {\n it('removes sentry cli from rn bundle build phase', () => {\n const input = `export SENTRY_PROPERTIES=sentry.properties\nexport EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nset -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"../node_modules/@sentry/cli/bin/sentry-cli react-native xcode $REACT_NATIVE_XCODE\\\"\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT ../node_modules/@sentry/react-native/scripts/collect-modules.sh\"\n`;\n const expectedOutput = `export EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nset -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`;\n\n expect(removeSentryFromBundleShellScript(input)).toBe(expectedOutput);\n });\n\n it('removes sentry bundled scripts from rn bundle build phase', () => {\n const input = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode.sh $REACT_NATIVE_XCODE\\\"\"`;\n const expectedOutput = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"`;\n\n expect(removeSentryFromBundleShellScript(input)).toBe(expectedOutput);\n });\n });\n\n describe('findBundlePhase', () => {\n it('returns build phase with react native xcode shell script', () => {\n const inputMap = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: 'bar',\n },\n 3: {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`,\n },\n 4: {\n shellScript: 'qux',\n },\n };\n\n const expected = {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`,\n };\n\n expect(findBundlePhase(inputMap)).toEqual(expected);\n });\n\n it('returns undefined if bundle phase not present', () => {\n const inputMap = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: 'bar',\n },\n 3: {\n // note different path to the script\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/unknown/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`,\n },\n 4: {\n shellScript: 'qux',\n },\n };\n\n expect(findBundlePhase(inputMap)).toBeUndefined();\n });\n });\n\n describe('doesBundlePhaseIncludeSentry', () => {\n it('returns true for script containing sentry cli calling react native xcode command', () => {\n const input = {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\nSENTRY_CLI=\"sentry-cli react-native xcode\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$SENTRY_CLI $REACT_NATIVE_XCODE\\\"\"\n`,\n };\n expect(doesBundlePhaseIncludeSentry(input)).toBeTruthy();\n });\n\n it('returns true for script containing sentry bundled script', () => {\n const input = {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\nSENTRY_CLI=\"sentry-cli react-native xcode\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\\\"/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode.sh $REACT_NATIVE_XCODE\"\\\\\"\n`,\n };\n expect(doesBundlePhaseIncludeSentry(input)).toBeTruthy();\n });\n\n it('returns false', () => {\n const input = {\n // note sentry-cli can be part of the script but doesn't call react native xcode script\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\nsentry-cli --version\n`,\n };\n expect(doesBundlePhaseIncludeSentry(input)).toBeFalsy();\n });\n });\n\n describe('findDebugFilesUploadPhase', () => {\n it('returns debug files build phase using debug files command', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `set -e\nsentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `set -e\nsentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns debug files build phase with sentry-cli absolute path', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `set -e\n/path/to/bin/sentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `set -e\n/path/to/bin/sentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns debug files build phase using dsym command', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `set -e\nsentry-cli upload-dsym path/to/dsym --include-sources\n`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `set -e\nsentry-cli upload-dsym path/to/dsym --include-sources\n`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns debug files build phase using bundled scripts', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode-debug-files.sh`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode-debug-files.sh`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns undefined if build phase not present', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n // sentry-cli present but with different command\n shellScript: 'sentry-cli sourcempas upload',\n },\n };\n\n expect(findDebugFilesUploadPhase(input)).toBeUndefined();\n });\n });\n});\n"]}
1
+ {"version":3,"file":"xcode.test.js","sourceRoot":"","sources":["../../../test/react-native/xcode.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-useless-escape */\nimport {\n addSentryWithBundledScriptsToBundleShellScript,\n addSentryWithCliToBundleShellScript,\n doesBundlePhaseIncludeSentry,\n findBundlePhase,\n findDebugFilesUploadPhase,\n removeSentryFromBundleShellScript,\n} from '../../src/react-native/xcode';\n\ndescribe('react-native xcode', () => {\n describe('addSentryWithCliToBundleShellScript', () => {\n it('adds sentry cli to rn bundle build phase', () => {\n const input = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"`;\n // actual shell script looks like this:\n // /bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n // but during parsing xcode library removes the quotes\n const expectedOutput = `export SENTRY_PROPERTIES=sentry.properties\nexport EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nset -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\\\"../node_modules/@sentry/cli/bin/sentry-cli react-native xcode $REACT_NATIVE_XCODE\\\\\"\"\n/bin/sh -c \"$WITH_ENVIRONMENT ../node_modules/@sentry/react-native/scripts/collect-modules.sh\"\n`;\n\n expect(addSentryWithCliToBundleShellScript(input)).toBe(expectedOutput);\n });\n });\n\n describe('addSentryBundledScriptsToBundleShellScript', () => {\n it('adds sentry cli to rn bundle build phase', () => {\n const input = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"`;\n // actual shell script looks like this:\n // /bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n // but during parsing xcode library removes the quotes\n const expectedOutput = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\\\"/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode.sh $REACT_NATIVE_XCODE\\\\\"\"`;\n\n expect(addSentryWithBundledScriptsToBundleShellScript(input)).toBe(\n expectedOutput,\n );\n });\n\n it('adds sentry cli to expo bundle build phase', () => {\n const input = `\nif [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n\\`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"\\`\n`;\n\n const expectedOutput = `\nif [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n/bin/sh \\`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('@sentry/react-native/package.json')) + '/scripts/sentry-xcode.sh'\"\\` \\`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"\\`\n`;\n\n expect(addSentryWithBundledScriptsToBundleShellScript(input)).toBe(\n expectedOutput,\n );\n });\n });\n\n describe('removeSentryFromBundleShellScript', () => {\n it('removes sentry cli from rn bundle build phase', () => {\n const input = `export SENTRY_PROPERTIES=sentry.properties\nexport EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nset -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"../node_modules/@sentry/cli/bin/sentry-cli react-native xcode $REACT_NATIVE_XCODE\\\"\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT ../node_modules/@sentry/react-native/scripts/collect-modules.sh\"\n`;\n const expectedOutput = `export EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nset -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`;\n\n expect(removeSentryFromBundleShellScript(input)).toBe(expectedOutput);\n });\n\n it('removes sentry bundled scripts from rn bundle build phase', () => {\n const input = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode.sh $REACT_NATIVE_XCODE\\\"\"`;\n const expectedOutput = `set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"`;\n\n expect(removeSentryFromBundleShellScript(input)).toBe(expectedOutput);\n });\n });\n\n describe('findBundlePhase', () => {\n it('returns build phase with react native xcode shell script', () => {\n const inputMap = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: 'bar',\n },\n 3: {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`,\n },\n 4: {\n shellScript: 'qux',\n },\n };\n\n const expected = {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`,\n };\n\n expect(findBundlePhase(inputMap)).toEqual(expected);\n });\n\n it('returns undefined if bundle phase not present', () => {\n const inputMap = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: 'bar',\n },\n 3: {\n // note different path to the script\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/unknown/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\n`,\n },\n 4: {\n shellScript: 'qux',\n },\n };\n\n expect(findBundlePhase(inputMap)).toBeUndefined();\n });\n });\n\n describe('doesBundlePhaseIncludeSentry', () => {\n it('returns true for script containing sentry cli calling react native xcode command', () => {\n const input = {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\nSENTRY_CLI=\"sentry-cli react-native xcode\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$SENTRY_CLI $REACT_NATIVE_XCODE\\\"\"\n`,\n };\n expect(doesBundlePhaseIncludeSentry(input)).toBeTruthy();\n });\n\n it('returns true for script containing sentry bundled script', () => {\n const input = {\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\nSENTRY_CLI=\"sentry-cli react-native xcode\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\\\"/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode.sh $REACT_NATIVE_XCODE\"\\\\\"\n`,\n };\n expect(doesBundlePhaseIncludeSentry(input)).toBeTruthy();\n });\n\n it('returns false', () => {\n const input = {\n // note sentry-cli can be part of the script but doesn't call react native xcode script\n shellScript: `set -e\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT \\\"$REACT_NATIVE_XCODE\\\"\"\n\nsentry-cli --version\n`,\n };\n expect(doesBundlePhaseIncludeSentry(input)).toBeFalsy();\n });\n });\n\n describe('findDebugFilesUploadPhase', () => {\n it('returns debug files build phase using debug files command', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `set -e\nsentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `set -e\nsentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns debug files build phase with sentry-cli absolute path', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `set -e\n/path/to/bin/sentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `set -e\n/path/to/bin/sentry-cli debug-files upload path/to/dsym --include-sources\n`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns debug files build phase using dsym command', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `set -e\nsentry-cli upload-dsym path/to/dsym --include-sources\n`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `set -e\nsentry-cli upload-dsym path/to/dsym --include-sources\n`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns debug files build phase using bundled scripts', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n shellScript: `/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode-debug-files.sh`,\n },\n };\n const expected = [\n '2',\n {\n shellScript: `/bin/sh ../node_modules/@sentry/react-native/scripts/sentry-xcode-debug-files.sh`,\n },\n ];\n expect(findDebugFilesUploadPhase(input)).toEqual(expected);\n });\n\n it('returns undefined if build phase not present', () => {\n const input = {\n 1: {\n shellScript: 'foo',\n },\n 2: {\n // sentry-cli present but with different command\n shellScript: 'sentry-cli sourcempas upload',\n },\n };\n\n expect(findDebugFilesUploadPhase(input)).toBeUndefined();\n });\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/wizard",
3
- "version": "3.24.1",
3
+ "version": "3.25.1",
4
4
  "homepage": "https://github.com/getsentry/sentry-wizard",
5
5
  "repository": "https://github.com/getsentry/sentry-wizard",
6
6
  "description": "Sentry wizard helping you to configure your project",
@@ -0,0 +1,55 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import * as clack from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs';
5
+ import * as Sentry from '@sentry/node';
6
+ import { RNCliSetupConfigContent } from './react-native-wizard';
7
+ import { addToGitignore } from './git';
8
+
9
+ const EXPO_ENV_LOCAL_FILE = '.env.local';
10
+
11
+ export async function addExpoEnvLocal(
12
+ options: RNCliSetupConfigContent,
13
+ ): Promise<boolean> {
14
+ const newContent = `#DO NOT COMMIT THIS\nSENTRY_AUTH_TOKEN=${options.authToken}\n`;
15
+
16
+ const added = await addToGitignore(EXPO_ENV_LOCAL_FILE);
17
+ if (added) {
18
+ clack.log.success(
19
+ `Added ${chalk.cyan(EXPO_ENV_LOCAL_FILE)} to .gitignore.`,
20
+ );
21
+ } else {
22
+ clack.log.error(
23
+ `Could not add ${chalk.cyan(
24
+ EXPO_ENV_LOCAL_FILE,
25
+ )} to .gitignore, please add it to not commit your auth key.`,
26
+ );
27
+ }
28
+
29
+ if (!fs.existsSync(EXPO_ENV_LOCAL_FILE)) {
30
+ try {
31
+ await fs.promises.writeFile(EXPO_ENV_LOCAL_FILE, newContent);
32
+ Sentry.setTag('expo-env-local', 'written');
33
+ clack.log.success(`Written ${chalk.cyan(EXPO_ENV_LOCAL_FILE)}.`);
34
+ return true;
35
+ } catch (error) {
36
+ Sentry.setTag('expo-env-local', 'write-error');
37
+ clack.log.error(`Unable to write ${chalk.cyan(EXPO_ENV_LOCAL_FILE)}.`);
38
+ return false;
39
+ }
40
+ }
41
+
42
+ Sentry.setTag('expo-env-local', 'exists');
43
+ clack.log.info(`Updating existing ${chalk.cyan(EXPO_ENV_LOCAL_FILE)}.`);
44
+
45
+ try {
46
+ await fs.promises.appendFile(EXPO_ENV_LOCAL_FILE, newContent);
47
+ Sentry.setTag('expo-env-local', 'updated');
48
+ clack.log.success(`Updated ${chalk.cyan(EXPO_ENV_LOCAL_FILE)}.`);
49
+ return true;
50
+ } catch (error) {
51
+ Sentry.setTag('expo-env-local', 'update-error');
52
+ clack.log.error(`Unable to update ${chalk.cyan(EXPO_ENV_LOCAL_FILE)}.`);
53
+ return false;
54
+ }
55
+ }
@@ -0,0 +1,212 @@
1
+ import * as fs from 'fs';
2
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
3
+ import * as clack from '@clack/prompts';
4
+ // @ts-ignore - magicast is ESM and TS complains about that. It works though
5
+ import { ProxifiedModule } from 'magicast';
6
+ import chalk from 'chalk';
7
+ import * as Sentry from '@sentry/node';
8
+
9
+ import { getLastRequireIndex, hasSentryContent } from '../utils/ast-utils';
10
+ import {
11
+ makeCodeSnippet,
12
+ showCopyPasteInstructions,
13
+ } from '../utils/clack-utils';
14
+
15
+ import { metroConfigPath, parseMetroConfig, writeMetroConfig } from './metro';
16
+
17
+ import * as recast from 'recast';
18
+ import x = recast.types;
19
+ import t = x.namedTypes;
20
+
21
+ const b = recast.types.builders;
22
+
23
+ export async function addSentryToExpoMetroConfig() {
24
+ if (!fs.existsSync(metroConfigPath)) {
25
+ const success = await createSentryExpoMetroConfig();
26
+ if (!success) {
27
+ Sentry.setTag('expo-metro-config', 'create-new-error');
28
+ return await showInstructions();
29
+ }
30
+ Sentry.setTag('expo-metro-config', 'created-new');
31
+ return undefined;
32
+ }
33
+
34
+ const mod = await parseMetroConfig();
35
+
36
+ let didPatch = false;
37
+ try {
38
+ didPatch = patchMetroInMemory(mod);
39
+ } catch (e) {
40
+ // noop
41
+ }
42
+ if (!didPatch) {
43
+ Sentry.setTag('expo-metro-config', 'patch-error');
44
+ clack.log.error(
45
+ `Could not patch ${chalk.cyan(
46
+ metroConfigPath,
47
+ )} with Sentry configuration.`,
48
+ );
49
+ return await showInstructions();
50
+ }
51
+
52
+ const saved = await writeMetroConfig(mod);
53
+ if (saved) {
54
+ Sentry.setTag('expo-metro-config', 'patch-saved');
55
+ clack.log.success(
56
+ chalk.green(`${chalk.cyan(metroConfigPath)} changes saved.`),
57
+ );
58
+ } else {
59
+ Sentry.setTag('expo-metro-config', 'patch-save-error');
60
+ clack.log.warn(
61
+ `Could not save changes to ${chalk.cyan(
62
+ metroConfigPath,
63
+ )}, please follow the manual steps.`,
64
+ );
65
+ return await showInstructions();
66
+ }
67
+ }
68
+
69
+ export function patchMetroInMemory(mod: ProxifiedModule): boolean {
70
+ const ast = mod.$ast as t.Program;
71
+
72
+ if (hasSentryContent(ast)) {
73
+ clack.log.warn(
74
+ `The ${chalk.cyan(
75
+ metroConfigPath,
76
+ )} file already has Sentry configuration.`,
77
+ );
78
+ return false;
79
+ }
80
+
81
+ let didReplaceDefaultConfigCall = false;
82
+
83
+ recast.visit(ast, {
84
+ visitVariableDeclaration(path) {
85
+ const { node } = path;
86
+
87
+ if (
88
+ // path is require("expo/metro-config")
89
+ // and only getDefaultConfig is being destructured
90
+ // then remove the entire declaration
91
+ node.declarations.length > 0 &&
92
+ node.declarations[0].type === 'VariableDeclarator' &&
93
+ node.declarations[0].init &&
94
+ node.declarations[0].init.type === 'CallExpression' &&
95
+ node.declarations[0].init.callee &&
96
+ node.declarations[0].init.callee.type === 'Identifier' &&
97
+ node.declarations[0].init.callee.name === 'require' &&
98
+ node.declarations[0].init.arguments[0].type === 'StringLiteral' &&
99
+ node.declarations[0].init.arguments[0].value === 'expo/metro-config' &&
100
+ node.declarations[0].id.type === 'ObjectPattern' &&
101
+ node.declarations[0].id.properties.length === 1 &&
102
+ node.declarations[0].id.properties[0].type === 'ObjectProperty' &&
103
+ node.declarations[0].id.properties[0].key.type === 'Identifier' &&
104
+ node.declarations[0].id.properties[0].key.name === 'getDefaultConfig'
105
+ ) {
106
+ path.prune();
107
+ return false;
108
+ }
109
+
110
+ this.traverse(path);
111
+ },
112
+
113
+ visitCallExpression(path) {
114
+ const { node } = path;
115
+ if (
116
+ // path is getDefaultConfig
117
+ // then rename it to getSentryExpoConfig
118
+ node.callee.type === 'Identifier' &&
119
+ node.callee.name === 'getDefaultConfig'
120
+ ) {
121
+ node.callee.name = 'getSentryExpoConfig';
122
+ didReplaceDefaultConfigCall = true;
123
+ return false;
124
+ }
125
+
126
+ this.traverse(path);
127
+ },
128
+ });
129
+
130
+ if (!didReplaceDefaultConfigCall) {
131
+ clack.log.warn(
132
+ `Could not find \`getDefaultConfig\` in ${chalk.cyan(metroConfigPath)}.`,
133
+ );
134
+ return false;
135
+ }
136
+
137
+ addSentryExpoConfigRequire(ast);
138
+
139
+ return true;
140
+ }
141
+
142
+ export function addSentryExpoConfigRequire(program: t.Program) {
143
+ const lastRequireIndex = getLastRequireIndex(program);
144
+ const sentryExpoConfigRequire = createSentryExpoConfigRequire();
145
+ program.body.splice(lastRequireIndex + 1, 0, sentryExpoConfigRequire);
146
+ }
147
+
148
+ /**
149
+ * Creates const { getSentryExpoConfig } = require("@sentry/react-native/metro");
150
+ */
151
+ function createSentryExpoConfigRequire() {
152
+ return b.variableDeclaration('const', [
153
+ b.variableDeclarator(
154
+ b.objectPattern([
155
+ b.objectProperty.from({
156
+ key: b.identifier('getSentryExpoConfig'),
157
+ value: b.identifier('getSentryExpoConfig'),
158
+ shorthand: true,
159
+ }),
160
+ ]),
161
+ b.callExpression(b.identifier('require'), [
162
+ b.literal('@sentry/react-native/metro'),
163
+ ]),
164
+ ),
165
+ ]);
166
+ }
167
+
168
+ async function createSentryExpoMetroConfig(): Promise<boolean> {
169
+ const snippet = `const { getSentryExpoConfig } = require("@sentry/react-native/metro");
170
+
171
+ const config = getSentryExpoConfig(__dirname);
172
+
173
+ module.exports = config;
174
+ `;
175
+ try {
176
+ await fs.promises.writeFile(metroConfigPath, snippet);
177
+ } catch (e) {
178
+ clack.log.error(
179
+ `Could not create ${chalk.cyan(
180
+ metroConfigPath,
181
+ )} with Sentry configuration.`,
182
+ );
183
+ return false;
184
+ }
185
+ clack.log.success(
186
+ `Created ${chalk.cyan(metroConfigPath)} with Sentry configuration.`,
187
+ );
188
+ return true;
189
+ }
190
+
191
+ function showInstructions() {
192
+ return showCopyPasteInstructions(
193
+ metroConfigPath,
194
+ getMetroWithSentryExpoConfigSnippet(true),
195
+ );
196
+ }
197
+
198
+ function getMetroWithSentryExpoConfigSnippet(colors: boolean): string {
199
+ return makeCodeSnippet(colors, (unchanged, plus, minus) =>
200
+ unchanged(`${minus(
201
+ `// const { getDefaultConfig } = require("expo/metro-config");`,
202
+ )}
203
+ ${plus(
204
+ `const { getSentryExpoConfig } = require("@sentry/react-native/metro");`,
205
+ )}
206
+
207
+ ${minus(`// const config = getDefaultConfig(__dirname);`)}
208
+ ${plus(`const config = getSentryExpoConfig(__dirname);`)}
209
+
210
+ module.exports = config;`),
211
+ );
212
+ }
@@ -0,0 +1,175 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import * as clack from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import * as fs from 'fs';
5
+ import { EOL } from 'os';
6
+
7
+ import { isPlainObject } from '@sentry/utils';
8
+ import * as Sentry from '@sentry/node';
9
+ import {
10
+ makeCodeSnippet,
11
+ showCopyPasteInstructions,
12
+ } from '../utils/clack-utils';
13
+ import { RNCliSetupConfigContent } from './react-native-wizard';
14
+ import { traceStep } from '../telemetry';
15
+
16
+ export const SENTRY_EXPO_PLUGIN_NAME = '@sentry/react-native/expo';
17
+ export const DEPRECATED_SENTRY_EXPO_PLUGIN_NAME = 'sentry-expo';
18
+
19
+ export const SENTRY_PLUGIN_FUNCTION_NAME = 'withSentry';
20
+
21
+ const APP_CONFIG_JSON = `app.json`;
22
+
23
+ export interface AppConfigJson {
24
+ expo?: {
25
+ plugins?: Array<[string, undefined | Record<string, unknown>]>;
26
+ };
27
+ }
28
+
29
+ export function printSentryExpoMigrationOutro(): void {
30
+ clack.outro(
31
+ `Deprecated ${chalk.cyan(
32
+ 'sentry-expo',
33
+ )} package installed in your dependencies. Please follow the migration guide at ${chalk.cyan(
34
+ 'https://docs.sentry.io/platforms/react-native/migration/sentry-expo/',
35
+ )}`,
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Finds app.json in the project root and add Sentry Expo `withSentry` plugin.
41
+ */
42
+ export async function patchExpoAppConfig(options: RNCliSetupConfigContent) {
43
+ function showInstructions() {
44
+ return showCopyPasteInstructions(
45
+ APP_CONFIG_JSON,
46
+ getSentryAppConfigJsonCodeSnippet(options),
47
+ 'This ensures auto upload of source maps during native app build.',
48
+ );
49
+ }
50
+
51
+ const appConfigJsonExists = fs.existsSync(APP_CONFIG_JSON);
52
+
53
+ Sentry.setTag(
54
+ 'app-config-file-status',
55
+ appConfigJsonExists ? 'found' : 'not-found',
56
+ );
57
+ if (!appConfigJsonExists) {
58
+ return await showInstructions();
59
+ }
60
+
61
+ const patched = await patchAppConfigJson(APP_CONFIG_JSON, options);
62
+ if (!patched) {
63
+ return await showInstructions();
64
+ }
65
+ }
66
+
67
+ async function patchAppConfigJson(
68
+ path: string,
69
+ options: RNCliSetupConfigContent,
70
+ ): Promise<boolean> {
71
+ const appConfigContent = (
72
+ await fs.promises.readFile(path, { encoding: 'utf-8' })
73
+ ).toString();
74
+ const patchedContent = traceStep('app-config-json-patch', () =>
75
+ addWithSentryToAppConfigJson(appConfigContent, options),
76
+ );
77
+ if (patchedContent === null) {
78
+ return false;
79
+ }
80
+
81
+ try {
82
+ await fs.promises.writeFile(path, patchedContent);
83
+ } catch (error) {
84
+ Sentry.setTag('app-config-file-status', 'json-write-error');
85
+ clack.log.error(`Unable to write ${chalk.cyan('app.config.json')}.`);
86
+ return false;
87
+ }
88
+ Sentry.setTag('app-config-file-status', 'json-write-success');
89
+ clack.log.success(
90
+ `Added Sentry Expo plugin to ${chalk.cyan('app.config.json')}.`,
91
+ );
92
+ return true;
93
+ }
94
+
95
+ export function addWithSentryToAppConfigJson(
96
+ appConfigContent: string,
97
+ options: RNCliSetupConfigContent,
98
+ ): string | null {
99
+ try {
100
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
101
+ const parsedAppConfig: AppConfigJson = JSON.parse(appConfigContent);
102
+ const includesWithSentry =
103
+ appConfigContent.includes(SENTRY_EXPO_PLUGIN_NAME) ||
104
+ appConfigContent.includes(DEPRECATED_SENTRY_EXPO_PLUGIN_NAME);
105
+
106
+ if (includesWithSentry) {
107
+ Sentry.setTag('app-config-file-status', 'already-patched');
108
+ clack.log.warn(
109
+ `Your ${chalk.cyan(
110
+ 'app.config.json',
111
+ )} already includes the Sentry Expo plugin.`,
112
+ );
113
+ return null;
114
+ }
115
+
116
+ if (
117
+ parsedAppConfig.expo !== undefined &&
118
+ !isPlainObject(parsedAppConfig.expo)
119
+ ) {
120
+ Sentry.setTag('app-config-file-status', 'invalid-json');
121
+ return null;
122
+ }
123
+ if (
124
+ parsedAppConfig.expo &&
125
+ parsedAppConfig.expo.plugins !== undefined &&
126
+ !Array.isArray(parsedAppConfig.expo.plugins)
127
+ ) {
128
+ Sentry.setTag('app-config-file-status', 'invalid-json');
129
+ return null;
130
+ }
131
+
132
+ parsedAppConfig.expo = parsedAppConfig.expo ?? {};
133
+ parsedAppConfig.expo.plugins = parsedAppConfig.expo.plugins ?? [];
134
+ parsedAppConfig.expo.plugins.push([
135
+ SENTRY_EXPO_PLUGIN_NAME,
136
+ {
137
+ url: options.url,
138
+ project: options.project,
139
+ organization: options.org,
140
+ },
141
+ ]);
142
+
143
+ return JSON.stringify(parsedAppConfig, null, 2) + EOL;
144
+ } catch (error) {
145
+ Sentry.setTag('app-config-file-status', 'invalid-json');
146
+ clack.log.error(
147
+ `Unable to parse your ${chalk.cyan(
148
+ 'app.config.json',
149
+ )}. Make sure it has a valid format!`,
150
+ );
151
+ return null;
152
+ }
153
+ }
154
+
155
+ export function getSentryAppConfigJsonCodeSnippet({
156
+ url,
157
+ project,
158
+ org,
159
+ }: Omit<RNCliSetupConfigContent, 'authToken'>) {
160
+ return makeCodeSnippet(true, (unchanged, plus, _minus) => {
161
+ return unchanged(`{
162
+ "name": "my app",
163
+ "plugins": [
164
+ ${plus(`[
165
+ "@sentry/react-native/expo",
166
+ {
167
+ "url": "${url}",
168
+ "project": "${project}",
169
+ "organization": "${org}"
170
+ }
171
+ ]`)}
172
+ ],
173
+ }`);
174
+ });
175
+ }
@@ -0,0 +1,25 @@
1
+ import * as fs from 'fs';
2
+
3
+ const GITIGNORE_FILENAME = '.gitignore';
4
+
5
+ export async function addToGitignore(filepath: string): Promise<boolean> {
6
+ /**
7
+ * Don't check whether the given file is ignored because:
8
+ * 1. It's tricky to check it without git.
9
+ * 2. Git might not be installed or accessible.
10
+ * 3. It's convenient to use a module to interact with git, but it would
11
+ * increase the size x2 approximately. Docs say to run the Wizard without
12
+ * installing it, and duplicating the size would slow the set-up down.
13
+ * 4. The Wizard is meant to be run once.
14
+ * 5. A message is logged informing users it's been added to the gitignore.
15
+ * 6. It will be added to the gitignore as many times as it runs - not a big
16
+ * deal.
17
+ * 7. It's straightforward to remove it from the gitignore.
18
+ */
19
+ try {
20
+ await fs.promises.appendFile(GITIGNORE_FILENAME, `\n${filepath}\n`);
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
@@ -1,4 +1,71 @@
1
- import { makeCodeSnippet } from '../utils/clack-utils';
1
+ /* eslint-disable max-lines */
2
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
3
+ import clack from '@clack/prompts';
4
+ import chalk from 'chalk';
5
+ import * as path from 'path';
6
+ import * as process from 'process';
7
+ import * as fs from 'fs';
8
+ import * as Sentry from '@sentry/node';
9
+
10
+ import { traceStep } from '../telemetry';
11
+ import {
12
+ makeCodeSnippet,
13
+ showCopyPasteInstructions,
14
+ } from '../utils/clack-utils';
15
+ import { getFirstMatchedPath } from './glob';
16
+ import { RN_SDK_PACKAGE } from './react-native-wizard';
17
+
18
+ export async function addSentryInit({ dsn }: { dsn: string }) {
19
+ const prefixGlob = '{.,./src,./app}';
20
+ const suffixGlob = '@(j|t|cj|mj)s?(x)';
21
+ const universalGlob = `@(App|_layout).${suffixGlob}`;
22
+ const jsFileGlob = `${prefixGlob}/+(${universalGlob})`;
23
+ const jsPath = traceStep('find-app-js-file', () =>
24
+ getFirstMatchedPath(jsFileGlob),
25
+ );
26
+ Sentry.setTag('app-js-file-status', jsPath ? 'found' : 'not-found');
27
+ if (!jsPath) {
28
+ clack.log.warn(
29
+ `Could not find main App file. Place the following code snippet close to the Apps Root component.`,
30
+ );
31
+ await showCopyPasteInstructions(
32
+ 'App.js or _layout.tsx',
33
+ getSentryInitColoredCodeSnippet(dsn),
34
+ 'This ensures the Sentry SDK is ready to capture errors.',
35
+ );
36
+ return;
37
+ }
38
+ const jsRelativePath = path.relative(process.cwd(), jsPath);
39
+
40
+ const js = fs.readFileSync(jsPath, 'utf-8');
41
+ const includesSentry = doesJsCodeIncludeSdkSentryImport(js, {
42
+ sdkPackageName: RN_SDK_PACKAGE,
43
+ });
44
+ if (includesSentry) {
45
+ Sentry.setTag('app-js-file-status', 'already-includes-sentry');
46
+ clack.log.warn(
47
+ `${chalk.cyan(
48
+ jsRelativePath,
49
+ )} already includes Sentry. We wont't add it again.`,
50
+ );
51
+ return;
52
+ }
53
+
54
+ traceStep('add-sentry-init', () => {
55
+ const newContent = addSentryInitWithSdkImport(js, { dsn });
56
+
57
+ clack.log.success(
58
+ `Added ${chalk.cyan('Sentry.init')} to ${chalk.cyan(jsRelativePath)}.`,
59
+ );
60
+
61
+ fs.writeFileSync(jsPath, newContent, 'utf-8');
62
+ });
63
+
64
+ Sentry.setTag('app-js-file-status', 'added-sentry-init');
65
+ clack.log.success(
66
+ chalk.green(`${chalk.cyan(jsRelativePath)} changes saved.`),
67
+ );
68
+ }
2
69
 
3
70
  export function addSentryInitWithSdkImport(
4
71
  js: string,
@@ -23,7 +23,7 @@ import chalk from 'chalk';
23
23
 
24
24
  const b = recast.types.builders;
25
25
 
26
- const metroConfigPath = 'metro.config.js';
26
+ export const metroConfigPath = 'metro.config.js';
27
27
 
28
28
  export async function patchMetroWithSentryConfig() {
29
29
  const mod = await parseMetroConfig();
@@ -259,7 +259,7 @@ export function removeSentryRequire(program: t.Program): boolean {
259
259
  return removeRequire(program, '@sentry');
260
260
  }
261
261
 
262
- async function parseMetroConfig(): Promise<ProxifiedModule> {
262
+ export async function parseMetroConfig(): Promise<ProxifiedModule> {
263
263
  const metroConfigContent = (
264
264
  await fs.promises.readFile(metroConfigPath)
265
265
  ).toString();
@@ -267,7 +267,7 @@ async function parseMetroConfig(): Promise<ProxifiedModule> {
267
267
  return parseModule(metroConfigContent);
268
268
  }
269
269
 
270
- async function writeMetroConfig(mod: ProxifiedModule): Promise<boolean> {
270
+ export async function writeMetroConfig(mod: ProxifiedModule): Promise<boolean> {
271
271
  try {
272
272
  await writeFile(mod.$ast, metroConfigPath);
273
273
  } catch (e) {