diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml
index 5ccf5bb2..1ae5b277 100644
--- a/.buildkite/pipeline.yml
+++ b/.buildkite/pipeline.yml
@@ -66,7 +66,7 @@ steps:
- --a11y-locator
- --fail-fast
- --retry=2
- concurrency: 9
+ concurrency: 5
concurrency_group: 'browserstack-app'
concurrency_method: eager
@@ -90,7 +90,7 @@ steps:
- --appium-version=1.21.0
- --retry=2
- --order=random
- concurrency: 9
+ concurrency: 5
concurrency_group: 'browserstack-app'
concurrency_method: eager
@@ -114,6 +114,6 @@ steps:
- --appium-version=1.17.0
- --retry=2
- --order=random
- concurrency: 9
+ concurrency: 5
concurrency_group: 'browserstack-app'
concurrency_method: eager
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21572225..216e6e18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,46 @@
# Changelog
+## v49.0.1 (2023-08-03)
+
+### Fixed
+
+- Fix a crash in configuration when Constants.expoGoConfig is null [#145](https://github.com/bugsnag/bugsnag-expo/pull/145)
+
+## v49.0.0 (2023-07-13)
+
+This release adds support for expo 49
+
+### Changed
+
+- Replace deprecated Constants.manifest [#141](https://github.com/bugsnag/bugsnag-expo/pull/141)
+
+## v48.1.0 (2023-03-27)
+
+### Added
+
+- (bugsnag-expo-cli) Updated bugsnag-expo-cli to support Typescript [#98](https://github.com/bugsnag/bugsnag-expo/pull/98)
+- Read API key and app version from `Constants.expoConfig` [#119](https://github.com/bugsnag/bugsnag-expo/pull/119)
+
+### Fixed
+
+- (plugin-expo-eas-sourcemaps) Reinstate API key in Android manifest [#117](https://github.com/bugsnag/bugsnag-expo/pull/117)
+- (plugin-expo-eas-sourcemaps) Support dynamic configuration files in EAS Build lifecycle hook [#117](https://github.com/bugsnag/bugsnag-expo/pull/117)
+
+## v48.0.0 (2023-03-07)
+
+This release adds support for expo 48
+
+### Fixed
+
+- (bugsnag-expo-cli) CLI tool now installs a sourcemap plugin version that matches the Expo SDK version [#111](https://github.com/bugsnag/bugsnag-expo/pull/111)
+- (plugin-expo-eas-sourcemaps) Use EAS Build lifecycle hook for Android source map uploads [#112](https://github.com/bugsnag/bugsnag-expo/pull/112)
+
+## v47.1.1 (2023-03-02)
+
+### Fixed
+
+- (plugin-expo-eas-sourcemaps) Restrict Bugsnag Android Gradle Plugin dependency to v7 [#104](https://github.com/bugsnag/bugsnag-expo/pull/104)
+
## v47.1.0 (2023-01-09)
### Fixed
diff --git a/examples/expo48/.gitignore b/examples/expo48/.gitignore
new file mode 100644
index 00000000..772ef297
--- /dev/null
+++ b/examples/expo48/.gitignore
@@ -0,0 +1,17 @@
+node_modules/
+.expo/
+dist/
+npm-debug.*
+*.jks
+*.p8
+*.p12
+*.key
+*.mobileprovision
+*.orig.*
+web-build/
+
+# macOS
+.DS_Store
+
+# Temporary files created by Metro to check the health of the file watcher
+.metro-health-check*
diff --git a/examples/expo48/App.js b/examples/expo48/App.js
new file mode 100644
index 00000000..9e3a293b
--- /dev/null
+++ b/examples/expo48/App.js
@@ -0,0 +1,48 @@
+import Bugsnag from '@bugsnag/expo';
+import React from 'react';
+import BadButtons from './components/BadButtons';
+import { StatusBar } from 'expo-status-bar';
+import { StyleSheet, Text, View, Button, Image } from 'react-native';
+
+const PlaceholderImage = require('./assets/favicon2-96.png');
+
+Bugsnag.start();
+
+const ErrorBoundary = Bugsnag.getPlugin('react').createErrorBoundary(React)
+
+const onError = (event) => {
+ // callback will only run for errors caught by boundary
+}
+
+const ErrorView = ({ clearError }) =>
+
+ Inform users of an error in the component tree.
+ Use clearError to reset ErrorBoundary state and re-render child tree.
+
+
+
+const App = () => {
+ return (
+
+
+ EXPO EXAMPLE APP
+
+
+ )
+};
+
+export default () =>
+
+
+
+
+
+const styles = StyleSheet.create({
+ screenContainer: {
+ alignItems: "center",
+ padding: 40,
+ },
+ textContainer: {
+ paddingVertical: 20,
+ },
+});
diff --git a/examples/expo48/README.md b/examples/expo48/README.md
new file mode 100644
index 00000000..014f361b
--- /dev/null
+++ b/examples/expo48/README.md
@@ -0,0 +1,13 @@
+# Expo
+
+This is an example project showing how to use `@bugsnag/expo`.
+
+## Usage
+
+Clone the repo and `cd` into the directory of this example.
+
+Replace API_KEY with your own API key in the app.json file.
+
+```
+npx expo start
+```
\ No newline at end of file
diff --git a/examples/expo48/app.json b/examples/expo48/app.json
new file mode 100644
index 00000000..6c0bb122
--- /dev/null
+++ b/examples/expo48/app.json
@@ -0,0 +1,43 @@
+{
+ "expo": {
+ "name": "expo48",
+ "slug": "expo48",
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "userInterfaceStyle": "light",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "ios": {
+ "supportsTablet": true
+ },
+ "android": {
+ "adaptiveIcon": {
+ "foregroundImage": "./assets/adaptive-icon.png",
+ "backgroundColor": "#ffffff"
+ }
+ },
+ "web": {
+ "favicon": "./assets/favicon.png"
+ },
+ "extra": {
+ "bugsnag": {
+ "apiKey": "API_KEY"
+ }
+ },
+ "hooks": {
+ "postPublish": [
+ {
+ "file": "@bugsnag/expo/hooks/post-publish.js",
+ "config": {}
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/expo48/assets/adaptive-icon.png b/examples/expo48/assets/adaptive-icon.png
new file mode 100644
index 00000000..03d6f6b6
Binary files /dev/null and b/examples/expo48/assets/adaptive-icon.png differ
diff --git a/examples/expo48/assets/favicon.png b/examples/expo48/assets/favicon.png
new file mode 100644
index 00000000..e75f697b
Binary files /dev/null and b/examples/expo48/assets/favicon.png differ
diff --git a/examples/expo48/assets/favicon2-96.png b/examples/expo48/assets/favicon2-96.png
new file mode 100644
index 00000000..f46b6314
Binary files /dev/null and b/examples/expo48/assets/favicon2-96.png differ
diff --git a/examples/expo48/assets/icon.png b/examples/expo48/assets/icon.png
new file mode 100644
index 00000000..a0b1526f
Binary files /dev/null and b/examples/expo48/assets/icon.png differ
diff --git a/examples/expo48/assets/splash.png b/examples/expo48/assets/splash.png
new file mode 100644
index 00000000..0e89705a
Binary files /dev/null and b/examples/expo48/assets/splash.png differ
diff --git a/examples/expo48/babel.config.js b/examples/expo48/babel.config.js
new file mode 100644
index 00000000..2900afe9
--- /dev/null
+++ b/examples/expo48/babel.config.js
@@ -0,0 +1,6 @@
+module.exports = function(api) {
+ api.cache(true);
+ return {
+ presets: ['babel-preset-expo'],
+ };
+};
diff --git a/examples/expo48/components/BadButtons.js b/examples/expo48/components/BadButtons.js
new file mode 100644
index 00000000..c5dd19e4
--- /dev/null
+++ b/examples/expo48/components/BadButtons.js
@@ -0,0 +1,62 @@
+import Bugsnag from '@bugsnag/expo';
+import React from 'react';
+import { StatusBar } from 'expo-status-bar';
+import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
+
+class BadButtons extends React.Component {
+ constructor (props) {
+ super(props)
+ this.state = { yeah: false }
+ }
+
+ triggerRenderError = () => {
+ this.setState({ yeah: true })
+ }
+
+ render() {
+ return (
+
+
+
+
+ {this.state.yeah ? { this.state.yeah.non.existent.property } : null}
+
+
+ );
+ }
+}
+export default BadButtons
+
+function unhandledError() {
+ throw new Error('Unhandled error!')
+}
+
+function handledError() {
+ Bugsnag.notify(new Error('Handled error!'))
+}
+
+const AppButton = ({ onPress, title }) => (
+
+
+ {title}
+
+
+);
+
+const styles = StyleSheet.create({
+ button: {
+ backgroundColor: "#003366",
+ borderRadius: 4,
+ paddingVertical: 10,
+ paddingHorizontal: 25,
+ },
+ text: {
+ fontSize: 16,
+ lineHeight: 21,
+ letterSpacing: 0.25,
+ color: 'white',
+ },
+ buttonContainer: {
+ paddingVertical: 10,
+ },
+});
\ No newline at end of file
diff --git a/examples/expo48/package.json b/examples/expo48/package.json
new file mode 100644
index 00000000..c64ac3af
--- /dev/null
+++ b/examples/expo48/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "expo48",
+ "version": "1.0.0",
+ "main": "node_modules/expo/AppEntry.js",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios",
+ "web": "expo start --web"
+ },
+ "dependencies": {
+ "expo": "~48.0.6",
+ "expo-status-bar": "~1.4.4",
+ "react": "18.2.0",
+ "react-native": "0.71.3",
+ "@bugsnag/expo": "^48.0.0",
+ "@react-native-community/netinfo": "9.3.7",
+ "expo-application": "~5.1.1",
+ "expo-constants": "~14.2.1",
+ "expo-crypto": "~12.2.1",
+ "expo-device": "~5.2.1",
+ "expo-file-system": "~15.2.2"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.20.0"
+ },
+ "private": true
+}
diff --git a/features/fixtures/test-app/app.json b/features/fixtures/test-app/app.json
index 27e17453..35dd2033 100644
--- a/features/fixtures/test-app/app.json
+++ b/features/fixtures/test-app/app.json
@@ -34,7 +34,7 @@
"web": {
"favicon": "./assets/favicon.png"
},
- "plugins": ["./config-plugins/withRemoveiOSNotificationEntitlement"],
+ "plugins": ["./config-plugins/withRemoveiOSNotificationEntitlement", "./config-plugins/withAddClearTextTrafficAndroid"],
"extra": {
"eas": {
"projectId": "EXPO_EAS_PROJECT_ID"
diff --git a/features/fixtures/test-app/config-plugins/withAddClearTextTrafficAndroid.js b/features/fixtures/test-app/config-plugins/withAddClearTextTrafficAndroid.js
new file mode 100644
index 00000000..0f663e1b
--- /dev/null
+++ b/features/fixtures/test-app/config-plugins/withAddClearTextTrafficAndroid.js
@@ -0,0 +1,19 @@
+const { AndroidConfig, withAndroidManifest } = require('@expo/config-plugins')
+const { getMainApplicationOrThrow } = AndroidConfig.Manifest
+
+const withAddClearTextTrafficAndroid = config => {
+ config = withAndroidManifest(config, config => {
+ config.modResults = setUsesCleartextTraffic(config, config.modResults)
+ return config
+ })
+
+ return config
+}
+
+function setUsesCleartextTraffic(config, androidManifest) {
+ const mainApplication = getMainApplicationOrThrow(androidManifest);
+ mainApplication.$['android:usesCleartextTraffic'] = 'true'
+ return androidManifest;
+}
+
+module.exports = withAddClearTextTrafficAndroid
\ No newline at end of file
diff --git a/features/fixtures/test-app/eas.json b/features/fixtures/test-app/eas.json
index 8ac3fec1..804a679f 100644
--- a/features/fixtures/test-app/eas.json
+++ b/features/fixtures/test-app/eas.json
@@ -8,6 +8,9 @@
"credentialsSource": "local",
"android": {
"buildType": "apk"
+ },
+ "ios": {
+ "enterpriseProvisioning": "universal"
}
}
},
diff --git a/features/fixtures/test-app/package.json b/features/fixtures/test-app/package.json
index 10d71c3c..f3609a04 100644
--- a/features/fixtures/test-app/package.json
+++ b/features/fixtures/test-app/package.json
@@ -9,23 +9,20 @@
"web": "expo start --web"
},
"dependencies": {
- "@react-native-community/netinfo": "9.3.5",
- "expo": "~47.0.3",
- "expo-application": "~5.0.1",
- "expo-constants": "~14.0.2",
- "expo-crypto": "~12.0.0",
- "expo-device": "~5.0.0",
- "expo-file-system": "~15.1.1",
- "expo-screen-orientation": "~5.0.1",
- "expo-status-bar": "~1.4.2",
- "react": "18.1.0",
- "react-native": "0.70.5"
- },
- "resolutions": {
- "expo-modules-core": "1.0.4"
+ "@react-native-community/netinfo": "9.3.10",
+ "expo": "^49.0.0",
+ "expo-application": "~5.3.0",
+ "expo-constants": "~14.4.2",
+ "expo-crypto": "~12.4.1",
+ "expo-device": "~5.4.0",
+ "expo-file-system": "~15.4.2",
+ "expo-screen-orientation": "~6.0.2",
+ "expo-status-bar": "~1.6.0",
+ "react": "18.2.0",
+ "react-native": "0.72.3"
},
"devDependencies": {
- "@babel/core": "^7.19.3"
+ "@babel/core": "^7.20.0"
},
"private": true
}
diff --git a/features/fixtures/test-app/run-bugsnag-expo-cli-install b/features/fixtures/test-app/run-bugsnag-expo-cli-install
index 9948135c..e05e0a3a 100755
--- a/features/fixtures/test-app/run-bugsnag-expo-cli-install
+++ b/features/fixtures/test-app/run-bugsnag-expo-cli-install
@@ -5,7 +5,7 @@ set timeout -1
# add-hook
spawn npx bugsnag-expo-cli upload-sourcemaps
-expect "Do you want to automatically upload source maps to Bugsnag? (this will modify your app.json)"
+expect "Do you want to automatically upload source maps to Bugsnag? (this will modify your app.json and package.json)"
send -- "\r"
expect eof
diff --git a/features/scripts/build-common.sh b/features/scripts/build-common.sh
index e6bfafee..021c43b2 100755
--- a/features/scripts/build-common.sh
+++ b/features/scripts/build-common.sh
@@ -36,6 +36,6 @@ yarn import
./run-bugsnag-expo-cli-install
-cp $EXPO_CREDENTIALS_DIR/* .
+cp $EXPO_UNIVERSAL_CREDENTIALS_DIR/* .
echo "Common setup complete"
diff --git a/lerna.json b/lerna.json
index 3436beba..6ff5ebe9 100644
--- a/lerna.json
+++ b/lerna.json
@@ -3,5 +3,5 @@
"packages": [
"packages/*"
],
- "version": "47.1.0"
+ "version": "49.0.1"
}
diff --git a/package.json b/package.json
index 87dbbe10..78deb6c5 100644
--- a/package.json
+++ b/package.json
@@ -1,26 +1,26 @@
{
- "devDependencies": {
- "eslint": "^6.8.0",
- "eslint-config-standard": "^14.1.0",
- "eslint-plugin-import": "^2.20.1",
- "eslint-plugin-jest": "^23.7.0",
- "eslint-plugin-node": "^11.0.0",
- "eslint-plugin-promise": "^4.2.1",
- "eslint-plugin-react": "^7.18.3",
- "eslint-plugin-standard": "^4.0.1",
- "expo": "^47.0.0",
- "jest": "^26.6.3",
- "jest-expo": "^44.0.1",
- "lerna": "^6.0.1",
- "react": "18.1.0",
- "react-native": "0.70.5",
- "verdaccio": "^5.10.2"
- },
- "scripts": {
- "bootstrap": "lerna bootstrap",
- "test:unit": "jest",
- "test:lint": "eslint --report-unused-disable-directives --max-warnings=0 .",
- "local-npm:start": "verdaccio --config ./verdaccio-config.yml",
- "local-npm:publish-all": "lerna publish --yes --force-publish --exact --no-push --no-git-reset --no-git-tag-version --registry 'http://localhost:4873'"
- }
+ "devDependencies": {
+ "eslint": "^6.8.0",
+ "eslint-config-standard": "^14.1.0",
+ "eslint-plugin-import": "^2.20.1",
+ "eslint-plugin-jest": "^23.7.0",
+ "eslint-plugin-node": "^11.0.0",
+ "eslint-plugin-promise": "^4.2.1",
+ "eslint-plugin-react": "^7.18.3",
+ "eslint-plugin-standard": "^4.0.1",
+ "expo": "^49.0.0",
+ "jest": "^26.6.3",
+ "jest-expo": "^48.0.1",
+ "lerna": "^6.0.1",
+ "react": "18.2.0",
+ "react-native": "0.72.3",
+ "verdaccio": "^5.10.2"
+ },
+ "scripts": {
+ "bootstrap": "lerna bootstrap",
+ "test:unit": "jest",
+ "test:lint": "eslint --report-unused-disable-directives --max-warnings=0 .",
+ "local-npm:start": "verdaccio --config ./verdaccio-config.yml",
+ "local-npm:publish-all": "lerna publish --yes --force-publish --exact --no-push --no-git-reset --no-git-tag-version --registry 'http://localhost:4873'"
+ }
}
diff --git a/packages/delivery-expo/package.json b/packages/delivery-expo/package.json
index f08b48b7..8975d61e 100644
--- a/packages/delivery-expo/package.json
+++ b/packages/delivery-expo/package.json
@@ -1,6 +1,6 @@
{
"name": "@bugsnag/delivery-expo",
- "version": "47.0.0",
+ "version": "49.0.0",
"main": "delivery.js",
"description": "@bugsnag/expo delivery mechanism to send events and sessions from Expo, using the FileSystem API to cache and retry sending failed payloads",
"homepage": "https://www.bugsnag.com/",
@@ -18,14 +18,14 @@
"license": "MIT",
"devDependencies": {
"@bugsnag/core": "^7.16.0",
- "@react-native-community/netinfo": "9.3.5",
- "expo-crypto": "~12.0.0",
- "expo-file-system": "~15.1.1"
+ "@react-native-community/netinfo": "9.3.10",
+ "expo-crypto": "~12.4.0",
+ "expo-file-system": "~15.4.2"
},
"peerDependencies": {
"@bugsnag/core": "^7.0.0",
- "@react-native-community/netinfo": "9.3.5",
- "expo-crypto": "~12.0.0",
- "expo-file-system": "~15.1.1"
+ "@react-native-community/netinfo": "9.3.10",
+ "expo-crypto": "~12.4.0",
+ "expo-file-system": "~15.4.2"
}
}
diff --git a/packages/expo-cli/commands/upload-sourcemaps.js b/packages/expo-cli/commands/upload-sourcemaps.js
index 6d65ef92..22dc2323 100644
--- a/packages/expo-cli/commands/upload-sourcemaps.js
+++ b/packages/expo-cli/commands/upload-sourcemaps.js
@@ -2,7 +2,7 @@ const prompts = require('prompts')
const addPlugin = require('../lib/configure-plugin')
const installPlugin = require('../lib/install-plugin')
const { onCancel, getDependencies } = require('../lib/utils')
-const { isEarlierVersionThan } = require('../lib/version-information')
+const { isEarlierVersionThan, getBugsnagVersionForExpoVersion } = require('../lib/version-information')
const { blue, yellow } = require('kleur')
const PLUGIN_NAME = '@bugsnag/plugin-expo-eas-sourcemaps'
@@ -23,7 +23,7 @@ module.exports = async (argv, globalOpts) => {
const res = await prompts({
type: 'confirm',
name: 'addPlugin',
- message: 'Do you want to automatically upload source maps to Bugsnag? (this will modify your app.json)',
+ message: 'Do you want to automatically upload source maps to Bugsnag? (this will modify your app.json and package.json)',
initial: true
}, { onCancel })
@@ -38,7 +38,12 @@ module.exports = async (argv, globalOpts) => {
yarn: globalOpts.yarn
}
- await installPlugin(projectRoot, options)
+ // install a plugin version that matches the SDK version, i.e. SDK 48 -> @bugsnag/plugin-expo-eas-sourcemaps@^48.0.0
+ // if there is no suitable bugsnag version we haven't yet released support for this Expo version, so install the latest
+ const versionInformation = getBugsnagVersionForExpoVersion(installedExpoVersion)
+ const pluginVersion = versionInformation ? versionInformation.bugsnagVersion : 'latest'
+
+ await installPlugin(pluginVersion, projectRoot, options)
}
console.log(blue('> Inserting EAS plugin into app.json'))
diff --git a/packages/expo-cli/lib/configure-plugin.js b/packages/expo-cli/lib/configure-plugin.js
index 0573b3aa..c06183e9 100644
--- a/packages/expo-cli/lib/configure-plugin.js
+++ b/packages/expo-cli/lib/configure-plugin.js
@@ -59,23 +59,38 @@ module.exports = async (projectRoot) => {
conf.expo = conf.expo || {}
conf.expo.plugins = conf.expo.plugins || []
if (conf.expo.plugins.includes(plugin)) {
- return plugin + ' is already installed'
+ console.log(blue('Plugin is already configured in app.json'))
+ } else {
+ conf.expo.plugins.push(plugin)
+ await promisify(writeFile)(appJsonPath, JSON.stringify(conf, null, 2), 'utf8')
}
- conf.expo.plugins.push(plugin)
- await promisify(writeFile)(appJsonPath, JSON.stringify(conf, null, 2), 'utf8')
+ // update package.json
+ try {
+ const packageJsonPath = join(projectRoot, 'package.json')
+ const packageJson = JSON.parse(await promisify(readFile)(packageJsonPath))
+
+ // add the post-build hook (if it doesn't already exist)
+ const sourceMapBuildHook = 'npx bugsnag-eas-build-on-success'
+ packageJson.scripts = packageJson.scripts || {}
+ const existingBuildHook = packageJson.scripts['eas-build-on-success']
+
+ if (existingBuildHook && existingBuildHook.includes(sourceMapBuildHook)) {
+ console.log(blue('EAS Build hook already configured in package.json'))
+ } else if (existingBuildHook) {
+ packageJson.scripts['eas-build-on-success'] = `${existingBuildHook} && ${sourceMapBuildHook}`
+ } else {
+ packageJson.scripts['eas-build-on-success'] = sourceMapBuildHook
+ }
- // do we need to add monorepo configuration?
- const withYarnClassic = await usingYarnClassic(projectRoot)
- const addMonorepoConfig = await usingWorkspaces(projectRoot, withYarnClassic)
+ // do we need to add monorepo configuration?
+ const withYarnClassic = await usingYarnClassic(projectRoot)
+ const addMonorepoConfig = await usingWorkspaces(projectRoot, withYarnClassic)
- if (addMonorepoConfig) {
- console.log(blue('> yarn workspaces detected, updating config'))
+ if (addMonorepoConfig) {
+ console.log(blue('> yarn workspaces detected, updating config'))
- try {
const sourceMaps = '@bugsnag/source-maps'
- const packageJsonPath = join(projectRoot, 'package.json')
- const packageJson = JSON.parse(await promisify(readFile)(packageJsonPath))
if (withYarnClassic) {
packageJson.workspaces = packageJson.workspaces || {}
@@ -86,17 +101,17 @@ module.exports = async (projectRoot) => {
packageJson.installConfig = packageJson.installConfig || {}
packageJson.installConfig.hoistingLimits = 'workspaces'
}
+ }
- await promisify(writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8')
- } catch (e) {
- // swallow and rethrow for errors that we can produce better messaging
- if (e.code === 'ENOENT') {
- throw new Error(`Couldn’t find package.json in "${projectRoot}".`)
- }
- if (e.name === 'SyntaxError') {
- throw new Error(`Couldn’t parse package.json because it wasn’t valid JSON: "${e.message}"`)
- }
- throw e
+ await promisify(writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8')
+ } catch (e) {
+ // swallow and rethrow for errors that we can produce better messaging
+ if (e.code === 'ENOENT') {
+ throw new Error(`Couldn’t find package.json in "${projectRoot}".`)
+ }
+ if (e.name === 'SyntaxError') {
+ throw new Error(`Couldn’t parse package.json because it wasn’t valid JSON: "${e.message}"`)
}
+ throw e
}
}
diff --git a/packages/expo-cli/lib/insert.js b/packages/expo-cli/lib/insert.js
index 829b41bf..653d2d85 100644
--- a/packages/expo-cli/lib/insert.js
+++ b/packages/expo-cli/lib/insert.js
@@ -1,5 +1,5 @@
const { join } = require('path')
-const { readFile, writeFile } = require('fs')
+const { readFile, writeFile, existsSync } = require('fs')
const { promisify } = require('util')
const { detectInstalledVersion } = require('./detect-installed')
const semver = require('semver')
@@ -8,19 +8,28 @@ const importRe = /from ["']@bugsnag\/expo["']/
const requireRe = /require\(["']@bugsnag\/expo["']\)/
module.exports = async (projectRoot) => {
- try {
- const appJsPath = join(projectRoot, 'App.js')
- const appJs = await promisify(readFile)(appJsPath, 'utf8')
- if (importRe.test(appJs) || requireRe.test(appJs)) {
- return '@bugsnag/expo is already imported in App.js'
- }
- await promisify(writeFile)(appJsPath, `${await getCode(projectRoot)}\n${appJs}`, 'utf8')
- } catch (e) {
- // swallow and rethrow for errors that we can produce better messaging for
- if (e.code === 'ENOENT') {
- throw new Error(`Couldn’t find App.js in "${projectRoot}". Is this the root of your Expo project?`)
+ function checkFileExists (filename) {
+ const appPath = join(projectRoot, filename)
+ return existsSync(appPath)
+ }
+
+ const writeBugsnagImport = async (filename) => {
+ // check if import statement has already been added and return
+ const appPath = join(projectRoot, filename)
+ const app = await promisify(readFile)(appPath, 'utf8')
+ if (importRe.test(app) || requireRe.test(app)) {
+ return `@bugsnag/expo is already imported in ${filename}`
}
- throw e
+ // write to file
+ await promisify(writeFile)(appPath, `${await getCode(projectRoot)}\n${app}`, 'utf8')
+ }
+
+ if (checkFileExists('App.ts')) {
+ return await writeBugsnagImport('App.ts')
+ } else if (checkFileExists('App.js')) {
+ return await writeBugsnagImport('App.js')
+ } else {
+ throw new Error(`Couldn’t find App.js or App.ts in "${projectRoot}". Is this the root of your Expo project?`)
}
}
diff --git a/packages/expo-cli/lib/install-plugin.js b/packages/expo-cli/lib/install-plugin.js
index 3cd4f1a7..8b9b3989 100644
--- a/packages/expo-cli/lib/install-plugin.js
+++ b/packages/expo-cli/lib/install-plugin.js
@@ -1,46 +1,14 @@
-const { spawn } = require('child_process')
-
-function resolveCommand (options) {
- const command = ['install', '@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps']
-
- if (options.npm) {
- command.push('--npm')
- command.push('--')
- command.push('--save-dev')
- }
-
- if (options.yarn) {
- command.push('--yarn')
- command.push('--')
- command.push('--dev')
- }
-
- return command
-}
-
-module.exports = (projectRoot, options) => {
- return new Promise((resolve, reject) => {
- const command = resolveCommand(options)
- const proc = spawn('expo', command, { cwd: projectRoot })
-
- // buffer output in case of an error
- let stdout = ''
- let stderr = ''
- proc.stdout.on('data', d => { stdout += d })
- proc.stderr.on('data', d => { stderr += d })
-
- proc.on('error', err => { reject(err) })
-
- proc.on('close', code => {
- if (code === 0) {
- return resolve()
- }
-
- reject(
- new Error(
- `Command exited with non-zero exit code (${code}) "expo ${command.join(' ')}"\nstdout:\n${stdout}\n\nstderr:\n${stderr}`
- )
- )
- })
+const { createForProject } = require('@expo/package-manager')
+const { resolvePackageName } = require('./utils')
+
+module.exports = (version, projectRoot, options) => {
+ const packages = [resolvePackageName('@bugsnag/plugin-expo-eas-sourcemaps', version), '@bugsnag/source-maps']
+
+ // Expo's package manager will reject with an error if the child process exits with a non-zero code
+ // it also buffers the output and attaches it to any errors - https://github.com/expo/spawn-async/blob/main/src/spawnAsync.ts
+ const packageManager = createForProject(projectRoot, options)
+ return packageManager.addDevAsync(packages).catch(error => {
+ error.message += `\nstdout:\n${error.stdout}\n\nstderr:\n${error.stderr}`
+ throw error
})
}
diff --git a/packages/expo-cli/lib/install.js b/packages/expo-cli/lib/install.js
index 1425a2e5..1f2bd098 100644
--- a/packages/expo-cli/lib/install.js
+++ b/packages/expo-cli/lib/install.js
@@ -1,8 +1,8 @@
const { spawn } = require('child_process')
-const { DEPENDENCIES } = require('./utils')
+const { DEPENDENCIES, resolvePackageName } = require('./utils')
function resolveCommand (version, options) {
- const command = ['install', resolvePackageName(version)].concat(DEPENDENCIES)
+ const command = ['install', resolvePackageName('@bugsnag/expo', version)].concat(DEPENDENCIES)
if (options.npm) {
command.push('--npm')
@@ -15,14 +15,6 @@ function resolveCommand (version, options) {
return command
}
-function resolvePackageName (version) {
- if (version === 'latest') {
- return '@bugsnag/expo'
- }
-
- return `@bugsnag/expo@${version}`
-}
-
module.exports = (version, projectRoot, options) => {
return new Promise((resolve, reject) => {
const command = resolveCommand(version, options)
diff --git a/packages/expo-cli/lib/test/add-hook.test.js b/packages/expo-cli/lib/test/add-hook.test.js
index bb976ed2..c1cc2a64 100644
--- a/packages/expo-cli/lib/test/add-hook.test.js
+++ b/packages/expo-cli/lib/test/add-hook.test.js
@@ -4,7 +4,7 @@ const { readFile } = require('fs/promises')
describe('expo-cli: add-hook', () => {
it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const msg = await addHook(projectRoot)
expect(msg).toBe(undefined)
@@ -16,7 +16,7 @@ describe('expo-cli: add-hook', () => {
})
it('shouldn’t duplicate the hook config', async () => {
- await withFixture('already-configured-00', async (projectRoot) => {
+ await withFixture('already-configured-js-import', async (projectRoot) => {
const msg = await addHook(projectRoot)
expect(msg).toMatch(/already/)
diff --git a/packages/expo-cli/lib/test/configure-plugin.test.js b/packages/expo-cli/lib/test/configure-plugin.test.js
index f406ed0c..7cfd3450 100644
--- a/packages/expo-cli/lib/test/configure-plugin.test.js
+++ b/packages/expo-cli/lib/test/configure-plugin.test.js
@@ -1,34 +1,68 @@
const withFixture = require('./lib/with-fixture')
const configurePlugin = require('../configure-plugin')
const { readFile } = require('fs/promises')
+const { blue } = require('kleur')
describe('expo-cli: upload sourcemaps configure-plugin', () => {
it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const msg = await configurePlugin(projectRoot)
expect(msg).toBe(undefined)
const appJsonRaw = await readFile(`${projectRoot}/app.json`, 'utf8')
const appJson = JSON.parse(appJsonRaw)
-
expect(appJson.expo.plugins).toContain('@bugsnag/plugin-expo-eas-sourcemaps')
+
+ const packageJsonRaw = await readFile(`${projectRoot}/package.json`, 'utf8')
+ const packageJson = JSON.parse(packageJsonRaw)
+ expect(packageJson.scripts['eas-build-on-success']).toContain('npx bugsnag-eas-build-on-success')
})
})
it('shouldn’t duplicate the hook config', async () => {
await withFixture('already-installed-02', async (projectRoot) => {
- const msg = await configurePlugin(projectRoot)
- expect(msg).toMatch(/ is already installed/)
+ const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
+
+ await configurePlugin(projectRoot)
+ expect(logSpy).toHaveBeenCalledWith(blue('Plugin is already configured in app.json'))
const appJsonRaw = await readFile(`${projectRoot}/app.json`, 'utf8')
const appJson = JSON.parse(appJsonRaw)
-
expect(appJson.expo.plugins.length).toBe(1)
})
})
- it('should create a basic file when there is no app.json', async () => {
+ it('shouldn’t duplicate the EAS build hook', async () => {
+ await withFixture('already-installed-postv7-js', async (projectRoot) => {
+ const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
+
+ await configurePlugin(projectRoot)
+ expect(logSpy).toHaveBeenCalledWith(blue('EAS Build hook already configured in package.json'))
+
+ const packageJsonRaw = await readFile(`${projectRoot}/package.json`, 'utf8')
+ const packageJson = JSON.parse(packageJsonRaw)
+ expect(packageJson.scripts['eas-build-on-success']).toStrictEqual('npx bugsnag-eas-build-on-success')
+ })
+ })
+
+ it('should chain to an existing EAS build hook if present', async () => {
+ await withFixture('already-installed-02', async (projectRoot) => {
+ await configurePlugin(projectRoot)
+
+ const packageJsonRaw = await readFile(`${projectRoot}/package.json`, 'utf8')
+ const packageJson = JSON.parse(packageJsonRaw)
+ expect(packageJson.scripts['eas-build-on-success']).toStrictEqual('pre-existing-command && npx bugsnag-eas-build-on-success')
+ })
+ })
+
+ it('should provide a reasonable error when there is no package.json', async () => {
await withFixture('empty-00', async (projectRoot) => {
+ await expect(configurePlugin(projectRoot)).rejects.toThrow(/Couldn’t find package\.json/)
+ })
+ })
+
+ it('should create a basic file when there is no app.json', async () => {
+ await withFixture('empty-01', async (projectRoot) => {
const msg = await configurePlugin(projectRoot)
expect(msg).toBe(undefined)
diff --git a/packages/expo-cli/lib/test/detect-installed.test.js b/packages/expo-cli/lib/test/detect-installed.test.js
index 90a42d3e..542504c7 100644
--- a/packages/expo-cli/lib/test/detect-installed.test.js
+++ b/packages/expo-cli/lib/test/detect-installed.test.js
@@ -4,19 +4,19 @@ const { InstalledState, detectInstalledState, detectInstalledVersion } = require
describe('expo-cli: detect-installed', () => {
describe('detectInstalledVersion', () => {
it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const version = await detectInstalledVersion(projectRoot)
expect(version).toBe(undefined)
})
})
it('should work on project with Bugsnag installed', async () => {
- await withFixture('already-configured-00', async (projectRoot) => {
+ await withFixture('already-configured-js-import', async (projectRoot) => {
const version = await detectInstalledVersion(projectRoot)
expect(version).toBe('^7.0.0')
})
- await withFixture('already-configured-01', async (projectRoot) => {
+ await withFixture('already-configured-js-require', async (projectRoot) => {
const version = await detectInstalledVersion(projectRoot)
expect(version).toBe('7.0.0')
})
@@ -25,14 +25,14 @@ describe('expo-cli: detect-installed', () => {
describe('detectInstalledState', () => {
it('should return "NONE" when Bugsnag and dependencies are missing', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const state = await detectInstalledState(projectRoot)
expect(state).toBe(InstalledState.NONE)
})
})
it('should return "BUGSNAG_EXPO" when Bugsnag is installed but dependencies are missing', async () => {
- await withFixture('already-installed-00', async (projectRoot) => {
+ await withFixture('already-installed-prev7-js', async (projectRoot) => {
const state = await detectInstalledState(projectRoot)
expect(state).toBe(InstalledState.BUGSNAG_EXPO)
})
@@ -46,7 +46,7 @@ describe('expo-cli: detect-installed', () => {
})
it('should return "BUGSNAG_EXPO | ALL_DEPENDENCIES" when both Bugsnag and dependencies are installed', async () => {
- await withFixture('already-installed-01', async (projectRoot) => {
+ await withFixture('already-installed-postv7-js', async (projectRoot) => {
const state = await detectInstalledState(projectRoot)
expect(state).toBe(InstalledState.BUGSNAG_EXPO | InstalledState.ALL_DEPENDENCIES)
})
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-00/App.js b/packages/expo-cli/lib/test/fixtures/already-configured-js-import/App.js
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-configured-00/App.js
rename to packages/expo-cli/lib/test/fixtures/already-configured-js-import/App.js
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-00/app.json b/packages/expo-cli/lib/test/fixtures/already-configured-js-import/app.json
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-configured-00/app.json
rename to packages/expo-cli/lib/test/fixtures/already-configured-js-import/app.json
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-00/package.json b/packages/expo-cli/lib/test/fixtures/already-configured-js-import/package.json
similarity index 70%
rename from packages/expo-cli/lib/test/fixtures/already-configured-00/package.json
rename to packages/expo-cli/lib/test/fixtures/already-configured-js-import/package.json
index fddc53f5..90190f5c 100644
--- a/packages/expo-cli/lib/test/fixtures/already-configured-00/package.json
+++ b/packages/expo-cli/lib/test/fixtures/already-configured-js-import/package.json
@@ -1,5 +1,5 @@
{
- "name": "bugsnag-test-fixture-00",
+ "name": "already-configured-js-import",
"private": "true",
"version": "0.0.0",
"dependencies": {
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-01/App.js b/packages/expo-cli/lib/test/fixtures/already-configured-js-require/App.js
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-configured-01/App.js
rename to packages/expo-cli/lib/test/fixtures/already-configured-js-require/App.js
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-01/app.json b/packages/expo-cli/lib/test/fixtures/already-configured-js-require/app.json
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-configured-01/app.json
rename to packages/expo-cli/lib/test/fixtures/already-configured-js-require/app.json
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-js-require/package.json b/packages/expo-cli/lib/test/fixtures/already-configured-js-require/package.json
new file mode 100644
index 00000000..b63357f4
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-configured-js-require/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "already-configured-js-require",
+ "private": "true",
+ "version": "0.0.0",
+ "dependencies": {
+ "@bugsnag/expo": "7.0.0"
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/App.ts b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/App.ts
new file mode 100644
index 00000000..bbab26dc
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/App.ts
@@ -0,0 +1,24 @@
+import Bugsnag from '@bugsnag/expo'
+import React from 'react'
+import { StyleSheet, Text, View } from 'react-native'
+
+Bugsnag.start()
+
+export default class App extends React.Component {
+ render () {
+ return (
+
+ Hello Expo!
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ alignItems: 'center',
+ justifyContent: 'center'
+ }
+})
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-02/app.json b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/app.json
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-configured-02/app.json
rename to packages/expo-cli/lib/test/fixtures/already-configured-ts-import/app.json
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-01/package.json b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/package.json
similarity index 70%
rename from packages/expo-cli/lib/test/fixtures/already-configured-01/package.json
rename to packages/expo-cli/lib/test/fixtures/already-configured-ts-import/package.json
index 7e3a7a9f..903f973c 100644
--- a/packages/expo-cli/lib/test/fixtures/already-configured-01/package.json
+++ b/packages/expo-cli/lib/test/fixtures/already-configured-ts-import/package.json
@@ -1,5 +1,5 @@
{
- "name": "bugsnag-test-fixture-01",
+ "name": "already-configured-ts-import",
"private": "true",
"version": "0.0.0",
"dependencies": {
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-02/App.js b/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/App.ts
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-configured-02/App.js
rename to packages/expo-cli/lib/test/fixtures/already-configured-ts-require/App.ts
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-00/app.json b/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/app.json
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-installed-00/app.json
rename to packages/expo-cli/lib/test/fixtures/already-configured-ts-require/app.json
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/package.json b/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/package.json
new file mode 100644
index 00000000..d1a6e79e
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-configured-ts-require/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "already-configured-ts-require",
+ "private": "true",
+ "version": "0.0.0",
+ "dependencies": {
+ "@bugsnag/expo": "7.0.0"
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-02/package.json b/packages/expo-cli/lib/test/fixtures/already-installed-02/package.json
index fb4e3011..e0da8ba1 100644
--- a/packages/expo-cli/lib/test/fixtures/already-installed-02/package.json
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-02/package.json
@@ -11,5 +11,8 @@
"expo-crypto": "*",
"expo-device": "*",
"expo-file-system": "*"
+ },
+ "scripts": {
+ "eas-build-on-success": "pre-existing-command"
}
}
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-00/App.js b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/App.js
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-installed-00/App.js
rename to packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/App.js
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-01/app.json b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/app.json
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-installed-01/app.json
rename to packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/app.json
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-01/package.json b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/package.json
similarity index 69%
rename from packages/expo-cli/lib/test/fixtures/already-installed-01/package.json
rename to packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/package.json
index c74db847..6b7cd404 100644
--- a/packages/expo-cli/lib/test/fixtures/already-installed-01/package.json
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-js/package.json
@@ -1,5 +1,5 @@
{
- "name": "already-installed-01",
+ "name": "already-installed-postv7-js",
"private": "true",
"version": "0.0.0",
"dependencies": {
@@ -10,5 +10,8 @@
"expo-crypto": "*",
"expo-device": "*",
"expo-file-system": "*"
+ },
+ "scripts": {
+ "eas-build-on-success": "npx bugsnag-eas-build-on-success"
}
}
diff --git a/packages/expo-cli/lib/test/fixtures/blank-00/App.js b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/App.ts
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/blank-00/App.js
rename to packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/App.ts
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/app.json b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/app.json
new file mode 100644
index 00000000..e22e88e7
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/app.json
@@ -0,0 +1,39 @@
+{
+ "expo": {
+ "name": "Bugsnag test fixture",
+ "slug": "bugsnag-test-fixture",
+ "privacy": "unlisted",
+ "sdkVersion": "32.0.0",
+ "platforms": [
+ "ios",
+ "android"
+ ],
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "updates": {
+ "fallbackToCacheTimeout": 0
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "extra": {
+ "bugsnag": {
+ "apiKey": "XoXoXoXoXoXo"
+ }
+ },
+ "hooks": {
+ "postPublish": [
+ {
+ "file": "@bugsnag/expo/hooks/post-publish.js",
+ "config": {}
+ }
+ ]
+ }
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/package.json b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/package.json
new file mode 100644
index 00000000..4c15ce1e
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-postv7-ts/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "already-installed-postv7-ts",
+ "private": "true",
+ "version": "0.0.0",
+ "dependencies": {
+ "@bugsnag/expo": "^7.0.1",
+ "@react-native-community/netinfo": "*",
+ "expo-application": "*",
+ "expo-constants": "*",
+ "expo-crypto": "*",
+ "expo-device": "*",
+ "expo-file-system": "*"
+ },
+ "scripts": {
+ "eas-build-on-success": "npx bugsnag-eas-build-on-success"
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-01/App.js b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/App.js
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/already-installed-01/App.js
rename to packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/App.js
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/app.json b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/app.json
new file mode 100644
index 00000000..e22e88e7
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/app.json
@@ -0,0 +1,39 @@
+{
+ "expo": {
+ "name": "Bugsnag test fixture",
+ "slug": "bugsnag-test-fixture",
+ "privacy": "unlisted",
+ "sdkVersion": "32.0.0",
+ "platforms": [
+ "ios",
+ "android"
+ ],
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "updates": {
+ "fallbackToCacheTimeout": 0
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "extra": {
+ "bugsnag": {
+ "apiKey": "XoXoXoXoXoXo"
+ }
+ },
+ "hooks": {
+ "postPublish": [
+ {
+ "file": "@bugsnag/expo/hooks/post-publish.js",
+ "config": {}
+ }
+ ]
+ }
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-00/package.json b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/package.json
similarity index 71%
rename from packages/expo-cli/lib/test/fixtures/already-installed-00/package.json
rename to packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/package.json
index 98bdf96a..590d504f 100644
--- a/packages/expo-cli/lib/test/fixtures/already-installed-00/package.json
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-js/package.json
@@ -1,5 +1,5 @@
{
- "name": "bugsnag-test-fixture-03",
+ "name": "already-installed-prev7-js",
"private": "true",
"version": "0.0.0",
"dependencies": {
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/App.ts b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/App.ts
new file mode 100644
index 00000000..6d256168
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/App.ts
@@ -0,0 +1,21 @@
+import React from 'react'
+import { StyleSheet, Text, View } from 'react-native'
+
+export default class App extends React.Component {
+ render () {
+ return (
+
+ Hello Expo!
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ alignItems: 'center',
+ justifyContent: 'center'
+ }
+})
diff --git a/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/app.json b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/app.json
new file mode 100644
index 00000000..e22e88e7
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/app.json
@@ -0,0 +1,39 @@
+{
+ "expo": {
+ "name": "Bugsnag test fixture",
+ "slug": "bugsnag-test-fixture",
+ "privacy": "unlisted",
+ "sdkVersion": "32.0.0",
+ "platforms": [
+ "ios",
+ "android"
+ ],
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "updates": {
+ "fallbackToCacheTimeout": 0
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "extra": {
+ "bugsnag": {
+ "apiKey": "XoXoXoXoXoXo"
+ }
+ },
+ "hooks": {
+ "postPublish": [
+ {
+ "file": "@bugsnag/expo/hooks/post-publish.js",
+ "config": {}
+ }
+ ]
+ }
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/already-configured-02/package.json b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/package.json
similarity index 50%
rename from packages/expo-cli/lib/test/fixtures/already-configured-02/package.json
rename to packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/package.json
index 1b4b0c92..77f28fb0 100644
--- a/packages/expo-cli/lib/test/fixtures/already-configured-02/package.json
+++ b/packages/expo-cli/lib/test/fixtures/already-installed-prev7-ts/package.json
@@ -1,8 +1,8 @@
{
- "name": "bugsnag-test-fixture-02",
+ "name": "already-installed-prev7-ts",
"private": "true",
"version": "0.0.0",
"dependencies": {
- "@bugsnag/expo": "6.5.1"
+ "@bugsnag/expo": "^6.5.1"
}
}
diff --git a/packages/expo-cli/lib/test/fixtures/blank-js/App.js b/packages/expo-cli/lib/test/fixtures/blank-js/App.js
new file mode 100644
index 00000000..6d256168
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/blank-js/App.js
@@ -0,0 +1,21 @@
+import React from 'react'
+import { StyleSheet, Text, View } from 'react-native'
+
+export default class App extends React.Component {
+ render () {
+ return (
+
+ Hello Expo!
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ alignItems: 'center',
+ justifyContent: 'center'
+ }
+})
diff --git a/packages/expo-cli/lib/test/fixtures/blank-00/app.json b/packages/expo-cli/lib/test/fixtures/blank-js/app.json
similarity index 100%
rename from packages/expo-cli/lib/test/fixtures/blank-00/app.json
rename to packages/expo-cli/lib/test/fixtures/blank-js/app.json
diff --git a/packages/expo-cli/lib/test/fixtures/blank-js/package.json b/packages/expo-cli/lib/test/fixtures/blank-js/package.json
new file mode 100644
index 00000000..bb272fe1
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/blank-js/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "bugsnag-test-fixture-blank-js",
+ "private": "true",
+ "version": "0.0.0"
+}
diff --git a/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/App.js b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/App.js
new file mode 100644
index 00000000..6d256168
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/App.js
@@ -0,0 +1,21 @@
+import React from 'react'
+import { StyleSheet, Text, View } from 'react-native'
+
+export default class App extends React.Component {
+ render () {
+ return (
+
+ Hello Expo!
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ alignItems: 'center',
+ justifyContent: 'center'
+ }
+})
diff --git a/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/App.ts b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/App.ts
new file mode 100644
index 00000000..6d256168
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/App.ts
@@ -0,0 +1,21 @@
+import React from 'react'
+import { StyleSheet, Text, View } from 'react-native'
+
+export default class App extends React.Component {
+ render () {
+ return (
+
+ Hello Expo!
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ alignItems: 'center',
+ justifyContent: 'center'
+ }
+})
diff --git a/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/app.json b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/app.json
new file mode 100644
index 00000000..d88f23f9
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/app.json
@@ -0,0 +1,26 @@
+{
+ "expo": {
+ "name": "Bugsnag test fixture",
+ "slug": "bugsnag-test-fixture",
+ "privacy": "unlisted",
+ "sdkVersion": "32.0.0",
+ "platforms": [
+ "ios",
+ "android"
+ ],
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#ffffff"
+ },
+ "updates": {
+ "fallbackToCacheTimeout": 0
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ]
+ }
+}
diff --git a/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/package.json b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/package.json
new file mode 100644
index 00000000..b70fda29
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/blank-ts-and-js/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "bugsnag-test-fixture-blank-ts-and-js",
+ "private": "true",
+ "version": "0.0.0"
+}
diff --git a/packages/expo-cli/lib/test/fixtures/empty-00/README.md b/packages/expo-cli/lib/test/fixtures/empty-00/README.md
index 1dc26376..4f78e47e 100644
--- a/packages/expo-cli/lib/test/fixtures/empty-00/README.md
+++ b/packages/expo-cli/lib/test/fixtures/empty-00/README.md
@@ -1 +1 @@
-This project has no app.json or App.js
+This project has no app.json, App.js or package.json
diff --git a/packages/expo-cli/lib/test/fixtures/empty-01/README.md b/packages/expo-cli/lib/test/fixtures/empty-01/README.md
new file mode 100644
index 00000000..1dc26376
--- /dev/null
+++ b/packages/expo-cli/lib/test/fixtures/empty-01/README.md
@@ -0,0 +1 @@
+This project has no app.json or App.js
diff --git a/packages/expo-cli/lib/test/fixtures/blank-00/package.json b/packages/expo-cli/lib/test/fixtures/empty-01/package.json
similarity index 55%
rename from packages/expo-cli/lib/test/fixtures/blank-00/package.json
rename to packages/expo-cli/lib/test/fixtures/empty-01/package.json
index 5fd7ebe0..e11fc6c0 100644
--- a/packages/expo-cli/lib/test/fixtures/blank-00/package.json
+++ b/packages/expo-cli/lib/test/fixtures/empty-01/package.json
@@ -1,5 +1,5 @@
{
- "name": "bugsnag-test-fixture-04",
+ "name": "empty-01",
"private": "true",
"version": "0.0.0"
}
diff --git a/packages/expo-cli/lib/test/insert.test.js b/packages/expo-cli/lib/test/insert.test.js
index f640d33d..cb98a599 100644
--- a/packages/expo-cli/lib/test/insert.test.js
+++ b/packages/expo-cli/lib/test/insert.test.js
@@ -3,8 +3,8 @@ const insert = require('../insert')
const { readFile } = require('fs/promises')
describe('expo-cli: insert', () => {
- it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ it('should work on a fresh javascript project', async () => {
+ await withFixture('blank-js', async (projectRoot) => {
const msg = await insert(projectRoot)
expect(msg).toBe(undefined)
@@ -13,31 +13,66 @@ describe('expo-cli: insert', () => {
})
})
- it('shouldn’t insert if @bugsnag/expo is already imported (import)', async () => {
- await withFixture('already-configured-00', async (projectRoot) => {
- const appJsBefore = await readFile(`${projectRoot}/app.json`, 'utf8')
+ it('should work on a fresh typescript project and prioritise .ts over .js', async () => {
+ await withFixture('blank-ts-and-js', async (projectRoot) => {
+ const appJsBefore = await readFile(`${projectRoot}/App.js`, 'utf8')
+ const msg = await insert(projectRoot)
+ expect(msg).toBe(undefined)
+
+ const appTs = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ const appJsAfter = await readFile(`${projectRoot}/App.js`, 'utf8')
+ expect(appTs).toMatch(/^import Bugsnag from '@bugsnag\/expo';\sBugsnag.start\(\);\s/)
+ expect(appJsAfter).toBe(appJsBefore)
+ })
+ })
+
+ it('shouldn’t insert if @bugsnag/expo is already imported (import, js)', async () => {
+ await withFixture('already-configured-js-import', async (projectRoot) => {
+ const appJsBefore = await readFile(`${projectRoot}/App.js`, 'utf8')
const msg = await insert(projectRoot)
expect(msg).toMatch(/already/)
- const appJsAfter = await readFile(`${projectRoot}/app.json`, 'utf8')
+ const appJsAfter = await readFile(`${projectRoot}/App.js`, 'utf8')
expect(appJsAfter).toBe(appJsBefore)
})
})
- it('shouldn’t insert if @bugsnag/expo is already imported (require)', async () => {
- await withFixture('already-configured-00', async (projectRoot) => {
- const appJsBefore = await readFile(`${projectRoot}/app.json`, 'utf8')
+ it('shouldn’t insert if @bugsnag/expo is already imported (require, js)', async () => {
+ await withFixture('already-configured-js-require', async (projectRoot) => {
+ const appJsBefore = await readFile(`${projectRoot}/App.js`, 'utf8')
const msg = await insert(projectRoot)
expect(msg).toMatch(/already/)
- const appJsAfter = await readFile(`${projectRoot}/app.json`, 'utf8')
+ const appJsAfter = await readFile(`${projectRoot}/App.js`, 'utf8')
expect(appJsAfter).toBe(appJsBefore)
})
})
- it('should provide a reasonable error when there is no App.js', async () => {
+ it('shouldn’t insert if @bugsnag/expo is already imported (import, ts)', async () => {
+ await withFixture('already-configured-ts-import', async (projectRoot) => {
+ const appTsBefore = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ const msg = await insert(projectRoot)
+ expect(msg).toMatch(/already/)
+
+ const appTsAfter = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ expect(appTsAfter).toBe(appTsBefore)
+ })
+ })
+
+ it('shouldn’t insert if @bugsnag/expo is already imported (require, ts)', async () => {
+ await withFixture('already-configured-ts-require', async (projectRoot) => {
+ const appTsBefore = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ const msg = await insert(projectRoot)
+ expect(msg).toMatch(/already/)
+
+ const appTsAfter = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ expect(appTsAfter).toBe(appTsBefore)
+ })
+ })
+
+ it('should provide a reasonable error when there is no App.js or App.ts', async () => {
await withFixture('empty-00', async (projectRoot) => {
- await expect(insert(projectRoot)).rejects.toThrow(/^Couldn’t find App\.js in/)
+ await expect(insert(projectRoot)).rejects.toThrow(/^Couldn’t find App\.js or App\.ts in/)
})
})
@@ -45,8 +80,8 @@ describe('expo-cli: insert', () => {
await expect(insert(/* projectRoot is required */)).rejects.toThrow(/The "path" argument must be of type string/)
})
- it('inserts correct code for pre v7 versions of Bugsnag', async () => {
- await withFixture('already-installed-00', async (projectRoot) => {
+ it('inserts correct code for pre v7 versions of Bugsnag (js)', async () => {
+ await withFixture('already-installed-prev7-js', async (projectRoot) => {
const msg = await insert(projectRoot)
expect(msg).toBe(undefined)
@@ -55,8 +90,8 @@ describe('expo-cli: insert', () => {
})
})
- it('inserts correct code for post v7.0.0 versions of Bugsnag', async () => {
- await withFixture('already-installed-01', async (projectRoot) => {
+ it('inserts correct code for post v7.0.0 versions of Bugsnag (js)', async () => {
+ await withFixture('already-installed-postv7-js', async (projectRoot) => {
const msg = await insert(projectRoot)
expect(msg).toBe(undefined)
@@ -64,4 +99,24 @@ describe('expo-cli: insert', () => {
expect(appJs).toMatch(/^import Bugsnag from '@bugsnag\/expo';\sBugsnag\.start\(\);\s/)
})
})
+
+ it('inserts correct code for pre v7 versions of Bugsnag (ts)', async () => {
+ await withFixture('already-installed-prev7-ts', async (projectRoot) => {
+ const msg = await insert(projectRoot)
+ expect(msg).toBe(undefined)
+
+ const appJs = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ expect(appJs).toMatch(/^import bugsnag from '@bugsnag\/expo';\sconst bugsnagClient = bugsnag\(\);\s/)
+ })
+ })
+
+ it('inserts correct code for post v7.0.0 versions of Bugsnag (ts)', async () => {
+ await withFixture('already-installed-postv7-ts', async (projectRoot) => {
+ const msg = await insert(projectRoot)
+ expect(msg).toBe(undefined)
+
+ const appJs = await readFile(`${projectRoot}/App.ts`, 'utf8')
+ expect(appJs).toMatch(/^import Bugsnag from '@bugsnag\/expo';\sBugsnag\.start\(\);\s/)
+ })
+ })
})
diff --git a/packages/expo-cli/lib/test/install-plugin.test.js b/packages/expo-cli/lib/test/install-plugin.test.js
index 87be295c..d610d04c 100644
--- a/packages/expo-cli/lib/test/install-plugin.test.js
+++ b/packages/expo-cli/lib/test/install-plugin.test.js
@@ -1,6 +1,4 @@
const withFixture = require('./lib/with-fixture')
-const { EventEmitter } = require('events')
-const { Readable } = require('stream')
describe('expo-cli: upload-sourcemaps install plugin', () => {
beforeEach(() => {
@@ -8,188 +6,168 @@ describe('expo-cli: upload-sourcemaps install plugin', () => {
})
it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
- const spawn = (cmd, args, opts) => {
- expect(cmd).toBe('expo')
- expect(args).toEqual(['install', '@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
- expect(opts).toEqual({ cwd: projectRoot })
-
- const proc = new EventEmitter()
- proc.stdout = new Readable({
- read () {}
- })
- proc.stderr = new Readable({
- read () {}
- })
- setTimeout(() => proc.emit('close', 0), 10)
- return proc
+ await withFixture('blank-js', async (projectRoot) => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
+ return Promise.resolve()
+ }
+ }
+
+ const createForProject = (root, options) => {
+ expect(root).toEqual(projectRoot)
+ expect(options).toEqual({ npm: false, yarn: false })
+ return packageManager
}
- jest.doMock('child_process', () => ({ spawn }))
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
const installPlugin = require('../install-plugin')
- const msg = await installPlugin(projectRoot, { npm: false, yarn: false })
+ const msg = await installPlugin('latest', projectRoot, { npm: false, yarn: false })
expect(msg).toBe(undefined)
})
})
it('should allow forcing install with NPM', async () => {
- await withFixture('blank-00', async (projectRoot) => {
- const spawn = (cmd, args, opts) => {
- expect(cmd).toBe('expo')
- expect(args).toEqual([
- 'install',
- '@bugsnag/plugin-expo-eas-sourcemaps',
- '@bugsnag/source-maps',
- '--npm',
- '--',
- '--save-dev'
- ])
- expect(opts).toEqual({ cwd: projectRoot })
-
- const proc = new EventEmitter()
- proc.stdout = new Readable({
- read () {}
- })
- proc.stderr = new Readable({
- read () {}
- })
- setTimeout(() => proc.emit('close', 0), 10)
- return proc
+ await withFixture('blank-js', async (projectRoot) => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
+ return Promise.resolve()
+ }
+ }
+
+ const createForProject = (root, options) => {
+ expect(root).toEqual(projectRoot)
+ expect(options).toEqual({ npm: true })
+ return packageManager
}
- jest.doMock('child_process', () => ({ spawn }))
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
const installPlugin = require('../install-plugin')
- const msg = await installPlugin(projectRoot, { npm: true })
+ const msg = await installPlugin('latest', projectRoot, { npm: true })
expect(msg).toBe(undefined)
})
})
it('should allow forcing install with Yarn', async () => {
- await withFixture('blank-00', async (projectRoot) => {
- const spawn = (cmd, args, opts) => {
- expect(cmd).toBe('expo')
- expect(args).toEqual([
- 'install',
- '@bugsnag/plugin-expo-eas-sourcemaps',
- '@bugsnag/source-maps',
- '--yarn',
- '--',
- '--dev'
- ])
- expect(opts).toEqual({ cwd: projectRoot })
-
- const proc = new EventEmitter()
- proc.stdout = new Readable({
- read () {}
- })
- proc.stderr = new Readable({
- read () {}
- })
- setTimeout(() => proc.emit('close', 0), 10)
- return proc
+ await withFixture('blank-js', async (projectRoot) => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
+ return Promise.resolve()
+ }
+ }
+
+ const createForProject = (root, options) => {
+ expect(root).toEqual(projectRoot)
+ expect(options).toEqual({ yarn: true })
+ return packageManager
}
- jest.doMock('child_process', () => ({ spawn }))
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
const installPlugin = require('../install-plugin')
- const msg = await installPlugin(projectRoot, { yarn: true })
+ const msg = await installPlugin('latest', projectRoot, { yarn: true })
expect(msg).toBe(undefined)
})
})
- // highly doubt this will ever fail, assuming one of npm or yarn will take precedence over the other
- // if test begins to fail, might need to consider additonal error messages
+ // not sure if this test is really necessary any more?
it('should allow forcing install with both NPM and Yarn', async () => {
- await withFixture('blank-00', async (projectRoot) => {
- const spawn = (cmd, args, opts) => {
- expect(cmd).toBe('expo')
- expect(args).toEqual([
- 'install',
- '@bugsnag/plugin-expo-eas-sourcemaps',
- '@bugsnag/source-maps',
- '--npm',
- '--',
- '--save-dev',
- '--yarn',
- '--',
- '--dev'
- ])
-
- expect(opts).toEqual({ cwd: projectRoot })
-
- const proc = new EventEmitter()
- proc.stdout = new Readable({
- read () {}
- })
- proc.stderr = new Readable({
- read () {}
- })
- setTimeout(() => proc.emit('close', 0), 10)
- return proc
+ await withFixture('blank-js', async (projectRoot) => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
+ return Promise.resolve()
+ }
}
- jest.doMock('child_process', () => ({ spawn }))
+ const createForProject = (root, options) => {
+ expect(root).toEqual(projectRoot)
+ expect(options).toEqual({ npm: true, yarn: true })
+ return packageManager
+ }
+
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
const installPlugin = require('../install-plugin')
- const msg = await installPlugin(projectRoot, { npm: true, yarn: true })
+ const msg = await installPlugin('latest', projectRoot, { npm: true, yarn: true })
expect(msg).toBe(undefined)
})
})
- it('should add stderr/stdout output onto error if there is one (non-zero exit code)', async () => {
- const spawn = (cmd, args, opts) => {
- const proc = new EventEmitter()
- proc.stdout = new Readable({
- read () {
- this.push('some data on stdout')
- this.push(null)
- }
- })
- proc.stderr = new Readable({
- read () {
- this.push('some data on stderr')
- this.push(null)
+ it('should allow specifying a package version', async () => {
+ await withFixture('blank-js', async (projectRoot) => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps@^48.0.0', '@bugsnag/source-maps'])
+ return Promise.resolve()
}
- })
- setTimeout(() => proc.emit('close', 1), 10)
- return proc
- }
+ }
- jest.doMock('child_process', () => ({ spawn }))
- const installPlugin = require('../install-plugin')
+ const createForProject = (root, options) => {
+ expect(root).toEqual(projectRoot)
+ expect(options).toEqual({ yarn: false })
+ return packageManager
+ }
- await withFixture('blank-00', async (projectRoot) => {
- const expected = `Command exited with non-zero exit code (1) "expo install @bugsnag/plugin-expo-eas-sourcemaps @bugsnag/source-maps"
-stdout:
-some data on stdout
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
+ const installPlugin = require('../install-plugin')
+ const msg = await installPlugin('^48.0.0', projectRoot, { yarn: false })
+ expect(msg).toBe(undefined)
+ })
+ })
-stderr:
-some data on stderr`
+ it('should throw an error if the command does', async () => {
+ await withFixture('blank-js', async (projectRoot) => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
+ return Promise.reject(new Error('floop'))
+ }
+ }
- await expect(installPlugin(projectRoot, { npm: false })).rejects.toThrow(expected)
+ const createForProject = (root, options) => {
+ expect(root).toEqual(projectRoot)
+ expect(options).toEqual({ yarn: false })
+ return packageManager
+ }
+
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
+ const installPlugin = require('../install-plugin')
+ await expect(installPlugin('latest', projectRoot, { yarn: false })).rejects.toThrow(/floop/)
})
})
- it('should throw an error if the command does', async () => {
- const spawn = (cmd, args, opts) => {
- const proc = new EventEmitter()
- proc.stdout = new Readable({
- read () {}
- })
- proc.stderr = new Readable({
- read () {}
- })
- setTimeout(() => proc.emit('error', new Error('floop')), 10)
- return proc
+ it('should add stderr/stdout output onto error if there is one', async () => {
+ const packageManager = {
+ addDevAsync: async (packages) => {
+ expect(packages).toEqual(['@bugsnag/plugin-expo-eas-sourcemaps', '@bugsnag/source-maps'])
+ const error = new Error('floop')
+ error.stdout = 'some data on stdout'
+ error.stderr = 'some data on stderr'
+ return Promise.reject(error)
+ }
}
- jest.doMock('child_process', () => ({ spawn }))
+ const createForProject = (root, options) => {
+ return packageManager
+ }
+
+ jest.doMock('@expo/package-manager', () => ({ createForProject }))
const installPlugin = require('../install-plugin')
- await withFixture('blank-00', async (projectRoot) => {
- await expect(installPlugin(projectRoot, { yarn: false })).rejects.toThrow(/floop/)
+ await withFixture('blank-js', async (projectRoot) => {
+ const expected = `floop
+stdout:
+some data on stdout
+
+stderr:
+some data on stderr`
+
+ await expect(installPlugin('latest', projectRoot, { npm: false })).rejects.toThrow(expected)
})
})
})
diff --git a/packages/expo-cli/lib/test/install.test.js b/packages/expo-cli/lib/test/install.test.js
index a66a75fa..0f65783d 100644
--- a/packages/expo-cli/lib/test/install.test.js
+++ b/packages/expo-cli/lib/test/install.test.js
@@ -8,7 +8,7 @@ describe('expo-cli: install', () => {
})
it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const spawn = (cmd, args, opts) => {
expect(cmd).toBe('expo')
expect(args).toEqual([
@@ -43,7 +43,7 @@ describe('expo-cli: install', () => {
})
it('should allow forcing install with NPM', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const spawn = (cmd, args, opts) => {
expect(cmd).toBe('expo')
expect(args).toEqual([
@@ -79,7 +79,7 @@ describe('expo-cli: install', () => {
})
it('should allow forcing install with Yarn', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const spawn = (cmd, args, opts) => {
expect(cmd).toBe('expo')
expect(args).toEqual([
@@ -115,7 +115,7 @@ describe('expo-cli: install', () => {
})
it('should allow forcing install with both NPM and Yarn', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const spawn = (cmd, args, opts) => {
expect(cmd).toBe('expo')
expect(args).toEqual([
@@ -174,7 +174,7 @@ describe('expo-cli: install', () => {
jest.doMock('child_process', () => ({ spawn }))
const install = require('../install')
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const expected = `Command exited with non-zero exit code (1) "expo install @bugsnag/expo @react-native-community/netinfo expo-application expo-constants expo-crypto expo-device expo-file-system"
stdout:
some data on stdout
@@ -202,7 +202,7 @@ some data on stderr`
jest.doMock('child_process', () => ({ spawn }))
const install = require('../install')
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
await expect(install('latest', projectRoot, { yarn: false })).rejects.toThrow(/floop/)
})
})
diff --git a/packages/expo-cli/lib/test/set-api-key.test.js b/packages/expo-cli/lib/test/set-api-key.test.js
index 50ed7e68..bcb2d72c 100644
--- a/packages/expo-cli/lib/test/set-api-key.test.js
+++ b/packages/expo-cli/lib/test/set-api-key.test.js
@@ -4,7 +4,7 @@ const { readFile } = require('fs/promises')
describe('expo-cli: set-api-key', () => {
it('should work on a fresh project', async () => {
- await withFixture('blank-00', async (projectRoot) => {
+ await withFixture('blank-js', async (projectRoot) => {
const msg = await setApiKey('AABBCCDD', projectRoot)
expect(msg).toBe(undefined)
@@ -15,7 +15,7 @@ describe('expo-cli: set-api-key', () => {
})
it('shouldn’t replace an existing API key', async () => {
- await withFixture('already-configured-00', async (projectRoot) => {
+ await withFixture('already-configured-js-import', async (projectRoot) => {
const msg = await setApiKey('AABBCCDD', projectRoot)
expect(msg).toBe(undefined)
diff --git a/packages/expo-cli/lib/utils.js b/packages/expo-cli/lib/utils.js
index 60b9e0cd..953ec2a1 100644
--- a/packages/expo-cli/lib/utils.js
+++ b/packages/expo-cli/lib/utils.js
@@ -22,9 +22,18 @@ async function getDependencies (directory) {
return cachedDependencies.get(directory)
}
+function resolvePackageName (packageName, version) {
+ if (version === 'latest') {
+ return packageName
+ }
+
+ return `${packageName}@${version}`
+}
+
module.exports = {
onCancel: () => process.exit(),
getDependencies,
+ resolvePackageName,
DEPENDENCIES: [
'@react-native-community/netinfo',
'expo-application',
diff --git a/packages/expo-cli/lib/version-information.js b/packages/expo-cli/lib/version-information.js
index cd2e8ce5..0582c65c 100644
--- a/packages/expo-cli/lib/version-information.js
+++ b/packages/expo-cli/lib/version-information.js
@@ -1,7 +1,7 @@
const semver = require('semver')
// the major version number of the latest Expo SDK we support
-const LATEST_SUPPORTED_EXPO_SDK = 47
+const LATEST_SUPPORTED_EXPO_SDK = 49
class Version {
constructor (expoSdkVersion, bugsnagVersion, isLegacy = false) {
diff --git a/packages/expo-cli/package.json b/packages/expo-cli/package.json
index 98bbcd68..1f74da39 100644
--- a/packages/expo-cli/package.json
+++ b/packages/expo-cli/package.json
@@ -1,6 +1,6 @@
{
"name": "bugsnag-expo-cli",
- "version": "47.0.0",
+ "version": "49.0.0",
"description": "A tool to help integrate Bugsnag with an Expo app",
"bin": "cli.js",
"files": [
@@ -11,6 +11,7 @@
"author": "Bugsnag",
"license": "MIT",
"dependencies": {
+ "@expo/package-manager": "^1.0.2",
"command-line-args": "^5.0.2",
"kleur": "^3.0.2",
"prompts": "^2.0.4",
diff --git a/packages/expo/package.json b/packages/expo/package.json
index 384f2c58..084115e5 100644
--- a/packages/expo/package.json
+++ b/packages/expo/package.json
@@ -1,6 +1,6 @@
{
"name": "@bugsnag/expo",
- "version": "47.1.0",
+ "version": "49.0.1",
"main": "src/notifier.js",
"types": "types/bugsnag.d.ts",
"description": "Bugsnag error reporter for Expo applications",
@@ -32,29 +32,29 @@
"author": "Bugsnag",
"license": "MIT",
"dependencies": {
- "@bugsnag/core": "^7.16.0",
- "@bugsnag/delivery-expo": "^47.0.0",
- "@bugsnag/plugin-browser-session": "^7.16.0",
- "@bugsnag/plugin-console-breadcrumbs": "^7.16.0",
- "@bugsnag/plugin-expo-app": "^47.1.0",
- "@bugsnag/plugin-expo-app-state-breadcrumbs": "^47.0.0",
- "@bugsnag/plugin-expo-connectivity-breadcrumbs": "^47.0.0",
- "@bugsnag/plugin-expo-device": "^47.0.0",
- "@bugsnag/plugin-network-breadcrumbs": "^7.16.0",
- "@bugsnag/plugin-react": "^7.16.0",
- "@bugsnag/plugin-react-native-global-error-handler": "^7.16.0",
- "@bugsnag/plugin-react-native-orientation-breadcrumbs": "^7.16.0",
- "@bugsnag/plugin-react-native-unhandled-rejection": "^7.16.0",
- "@bugsnag/source-maps": "^2.3.0",
- "bugsnag-build-reporter": "^1.0.1"
+ "@bugsnag/core": "^7.19.0",
+ "@bugsnag/delivery-expo": "^49.0.0",
+ "@bugsnag/plugin-browser-session": "^7.19.0",
+ "@bugsnag/plugin-console-breadcrumbs": "^7.19.0",
+ "@bugsnag/plugin-expo-app": "^49.0.0",
+ "@bugsnag/plugin-expo-app-state-breadcrumbs": "^49.0.0",
+ "@bugsnag/plugin-expo-connectivity-breadcrumbs": "^49.0.0",
+ "@bugsnag/plugin-expo-device": "^49.0.1",
+ "@bugsnag/plugin-network-breadcrumbs": "^7.19.0",
+ "@bugsnag/plugin-react": "^7.19.0",
+ "@bugsnag/plugin-react-native-global-error-handler": "^7.19.0",
+ "@bugsnag/plugin-react-native-orientation-breadcrumbs": "^7.19.0",
+ "@bugsnag/plugin-react-native-unhandled-rejection": "^7.19.0",
+ "@bugsnag/source-maps": "^2.3.1",
+ "bugsnag-build-reporter": "^2.0.0"
},
"devDependencies": {
- "expo-constants": "~14.0.2"
+ "expo-constants": "~14.4.2"
},
"peerDependencies": {
- "expo": "^47.0.0",
- "expo-constants": "~14.0.2",
- "promise": "^8",
+ "expo": "^49.0.0",
+ "expo-constants": "~14.4.2",
+ "promise": "^8.3.0",
"react": "*"
}
}
diff --git a/packages/expo/src/config.js b/packages/expo/src/config.js
index 6584dfb7..c61dbec1 100644
--- a/packages/expo/src/config.js
+++ b/packages/expo/src/config.js
@@ -4,16 +4,10 @@ const { schema } = require('@bugsnag/core/config')
const Constants = require('expo-constants').default
const stringWithLength = require('@bugsnag/core/lib/validators/string-with-length')
-// If the developer property is not present in the manifest, it means the app is
+// If the developer property is not present it means the app is
// not connected to a development tool and is either a published app running in
// the Expo client, or a standalone app
-let IS_PRODUCTION = true
-
-if (Constants.manifest) {
- IS_PRODUCTION = !Constants.manifest.developer
-} else if (Constants.manifest2) {
- IS_PRODUCTION = !Constants.manifest2?.extra?.expoGo?.developer
-}
+const IS_PRODUCTION = !Constants.expoConfig?.developer && !Constants.expoGoConfig?.developer
// The app can still run in production "mode" in development environments, in which
// cases the global boolean __DEV__ will be set to true
diff --git a/packages/expo/src/notifier.js b/packages/expo/src/notifier.js
index ba07db37..016e5a0c 100644
--- a/packages/expo/src/notifier.js
+++ b/packages/expo/src/notifier.js
@@ -28,7 +28,7 @@ const internalPlugins = [
require('@bugsnag/plugin-expo-device'),
require('@bugsnag/plugin-expo-app'),
require('@bugsnag/plugin-console-breadcrumbs'),
- require('@bugsnag/plugin-network-breadcrumbs')([NET_INFO_REACHABILITY_URL, Constants.manifest?.logUrl || Constants.manifest2?.extra?.expoGo?.logUrl]),
+ require('@bugsnag/plugin-network-breadcrumbs')([NET_INFO_REACHABILITY_URL, Constants.expoConfig?.logUrl || Constants.expoGoConfig?.logUrl]),
require('@bugsnag/plugin-expo-app-state-breadcrumbs'),
require('@bugsnag/plugin-expo-connectivity-breadcrumbs'),
require('@bugsnag/plugin-react-native-orientation-breadcrumbs'),
@@ -45,20 +45,12 @@ const Bugsnag = {
// read the api key from app.json if one is not explicitly passed
if (!opts.apiKey) {
- if (Constants.manifest?.extra?.bugsnag?.apiKey) {
- opts.apiKey = Constants.manifest.extra.bugsnag.apiKey
- } else if (Constants.manifest2?.extra?.expoClient?.extra?.bugsnag?.apiKey) {
- opts.apiKey = Constants.manifest2.extra.expoClient.extra.bugsnag.apiKey
- }
+ opts.apiKey = Constants.expoConfig?.extra?.bugsnag?.apiKey
}
// read the version from app.json if one is not explicitly passed
if (!opts.appVersion) {
- if (Constants.manifest?.version) {
- opts.appVersion = Constants.manifest.version
- } else if (Constants.manifest2?.extra?.expoClient?.version) {
- opts.appVersion = Constants.manifest2.extra.expoClient.version
- }
+ opts.appVersion = Constants.expoConfig?.version
}
const bugsnag = new Client(opts, schema, internalPlugins, { name, version, url })
diff --git a/packages/expo/test/index.test.js b/packages/expo/test/index.test.js
index 75a75123..3fdf43d2 100644
--- a/packages/expo/test/index.test.js
+++ b/packages/expo/test/index.test.js
@@ -3,14 +3,16 @@ const delivery = require('@bugsnag/delivery-expo')
jest.mock('expo-constants', () => ({
default: {
platform: {},
- manifest: {}
+ expoConfig: {},
+ expoGoConfig: null
}
}))
jest.mock('../../plugin-expo-device/node_modules/expo-constants', () => ({
default: {
platform: {},
- manifest: {}
+ expoConfig: {},
+ expoGoConfig: null
}
}))
@@ -19,7 +21,8 @@ jest.mock('../../plugin-expo-app/node_modules/expo-application', () => ({}))
jest.mock('../../plugin-expo-app/node_modules/expo-constants', () => ({
default: {
platform: {},
- manifest: {}
+ expoConfig: {},
+ expoGoConfig: null
}
}))
@@ -230,4 +233,59 @@ describe('expo notifier', () => {
done()
})
})
+
+ describe('configuration', () => {
+ beforeEach(() => {
+ jest.resetModules()
+ })
+
+ it('sets a default value for releaseStage correctly (production)', () => {
+ jest.mock('expo-constants', () => ({
+ default: {
+ platform: {},
+ expoConfig: {},
+ expoGoConfig: null
+ }
+ }))
+
+ const config = require('../src/config')
+ expect(config.releaseStage.defaultValue()).toBe('production')
+ })
+
+ it('sets a default value for releaseStage correctly (local-dev)', () => {
+ jest.mock('expo-constants', () => ({
+ default: {
+ platform: {},
+ expoConfig: null,
+ expoGoConfig: {
+ developer: {
+ tool: 'expo-cli'
+ }
+ }
+ }
+ }))
+
+ global.__DEV__ = true
+ const config = require('../src/config')
+ expect(config.releaseStage.defaultValue()).toBe('local-dev')
+ })
+
+ it('sets a default value for releaseStage correctly (local-prod)', () => {
+ jest.mock('expo-constants', () => ({
+ default: {
+ platform: {},
+ expoConfig: {
+ developer: {
+ tool: 'expo-cli'
+ }
+ },
+ expoGoConfig: null
+ }
+ }))
+
+ global.__DEV__ = false
+ const config = require('../src/config')
+ expect(config.releaseStage.defaultValue()).toBe('local-prod')
+ })
+ })
})
diff --git a/packages/plugin-expo-app-state-breadcrumbs/package.json b/packages/plugin-expo-app-state-breadcrumbs/package.json
index 96a132ef..4161cf1d 100644
--- a/packages/plugin-expo-app-state-breadcrumbs/package.json
+++ b/packages/plugin-expo-app-state-breadcrumbs/package.json
@@ -1,6 +1,6 @@
{
"name": "@bugsnag/plugin-expo-app-state-breadcrumbs",
- "version": "47.0.0",
+ "version": "49.0.0",
"main": "app-state.js",
"description": "@bugsnag/expo plugin to create breadcrumbs when a React Native app enters the foreground/background",
"homepage": "https://www.bugsnag.com/",
diff --git a/packages/plugin-expo-app/package.json b/packages/plugin-expo-app/package.json
index 8cfa5449..d3e4ff6c 100644
--- a/packages/plugin-expo-app/package.json
+++ b/packages/plugin-expo-app/package.json
@@ -1,6 +1,6 @@
{
"name": "@bugsnag/plugin-expo-app",
- "version": "47.1.0",
+ "version": "49.0.0",
"main": "app.js",
"description": "@bugsnag/expo plugin to provide information about an Expo app",
"homepage": "https://www.bugsnag.com/",
@@ -17,13 +17,13 @@
"author": "Bugsnag",
"license": "MIT",
"devDependencies": {
- "@bugsnag/core": "^7.16.0",
- "expo-application": "~5.0.1",
- "expo-constants": "~14.0.2"
+ "@bugsnag/core": "^7.19.0",
+ "expo-application": "~5.3.0",
+ "expo-constants": "~14.4.2"
},
"peerDependencies": {
"@bugsnag/core": "^7.0.0",
- "expo-application": "~5.0.1",
- "expo-constants": "~14.0.2"
+ "expo-application": "~5.3.0",
+ "expo-constants": "~14.4.2"
}
}
diff --git a/packages/plugin-expo-connectivity-breadcrumbs/package.json b/packages/plugin-expo-connectivity-breadcrumbs/package.json
index 38f6d21d..2db960b5 100644
--- a/packages/plugin-expo-connectivity-breadcrumbs/package.json
+++ b/packages/plugin-expo-connectivity-breadcrumbs/package.json
@@ -1,6 +1,6 @@
{
"name": "@bugsnag/plugin-expo-connectivity-breadcrumbs",
- "version": "47.0.0",
+ "version": "49.0.0",
"main": "connectivity.js",
"description": "@bugsnag/expo plugin to create breadcrumbs when the network status changes in an Expo app",
"homepage": "https://www.bugsnag.com/",
@@ -18,10 +18,10 @@
"license": "MIT",
"devDependencies": {
"@bugsnag/core": "^7.16.0",
- "@react-native-community/netinfo": "9.3.5"
+ "@react-native-community/netinfo": "9.3.10"
},
"peerDependencies": {
"@bugsnag/core": "^7.0.0",
- "@react-native-community/netinfo": "9.3.5"
+ "@react-native-community/netinfo": "9.3.10"
}
}
diff --git a/packages/plugin-expo-device/device.js b/packages/plugin-expo-device/device.js
index a8a517da..86fac499 100644
--- a/packages/plugin-expo-device/device.js
+++ b/packages/plugin-expo-device/device.js
@@ -31,7 +31,7 @@ module.exports = {
runtimeVersions: {
reactNative: rnVersion,
expoApp: Constants.expoVersion,
- expoSdk: Constants.manifest?.sdkVersion || Constants.manifest2?.extra?.expoClient?.sdkVersion,
+ expoSdk: Constants.expoConfig?.sdkVersion,
androidApiLevel: Constants.platform.android ? String(Platform.Version) : undefined
},
totalMemory: Device.totalMemory
diff --git a/packages/plugin-expo-device/package.json b/packages/plugin-expo-device/package.json
index c62debe4..292e20d8 100644
--- a/packages/plugin-expo-device/package.json
+++ b/packages/plugin-expo-device/package.json
@@ -1,6 +1,6 @@
{
"name": "@bugsnag/plugin-expo-device",
- "version": "47.0.0",
+ "version": "49.0.1",
"main": "device.js",
"description": "@bugsnag/expo plugin to attach Expo-specific device info to events",
"homepage": "https://www.bugsnag.com/",
@@ -18,12 +18,12 @@
"license": "MIT",
"devDependencies": {
"@bugsnag/core": "^7.16.0",
- "expo-constants": "~14.0.2",
- "expo-device": "~5.0.0"
+ "expo-constants": "~14.4.2",
+ "expo-device": "~5.4.0"
},
"peerDependencies": {
"@bugsnag/core": "^7.0.0",
- "expo-constants": "~14.0.2",
- "expo-device": "~5.0.0"
+ "expo-constants": "~14.4.2",
+ "expo-device": "~5.4.0"
}
}
diff --git a/packages/plugin-expo-device/test/device.test.js b/packages/plugin-expo-device/test/device.test.js
index 86578e80..9c570c70 100644
--- a/packages/plugin-expo-device/test/device.test.js
+++ b/packages/plugin-expo-device/test/device.test.js
@@ -16,7 +16,7 @@ describe('plugin: expo device', () => {
default: {
installationId: '123',
platform: { android: {} },
- manifest: { sdkVersion: SDK_VERSION },
+ expoConfig: { sdkVersion: SDK_VERSION },
expoVersion: EXPO_VERSION,
appOwnership: 'standalone'
}
@@ -84,7 +84,7 @@ describe('plugin: expo device', () => {
jest.doMock('expo-constants', () => ({
default: {
platform: { ios: {} },
- manifest: { sdkVersion: SDK_VERSION },
+ expoConfig: { sdkVersion: SDK_VERSION },
expoVersion: EXPO_VERSION,
appOwnership: 'expo'
}
@@ -148,7 +148,7 @@ describe('plugin: expo device', () => {
jest.doMock('expo-constants', () => ({
default: {
platform: { ios: {} },
- manifest: { sdkVersion: SDK_VERSION },
+ expoConfig: { sdkVersion: SDK_VERSION },
expoVersion: EXPO_VERSION,
appOwnership: 'expo'
}
@@ -195,7 +195,7 @@ describe('plugin: expo device', () => {
default: {
installationId: '123',
platform: { ios: {} },
- manifest: { sdkVersion: SDK_VERSION },
+ expoConfig: { sdkVersion: SDK_VERSION },
expoVersion: EXPO_VERSION,
appOwnership: 'expo'
}
@@ -269,7 +269,7 @@ describe('plugin: expo device', () => {
jest.doMock('expo-constants', () => ({
default: {
platform: { ios: {} },
- manifest: { sdkVersion: SDK_VERSION },
+ expoConfig: { sdkVersion: SDK_VERSION },
expoVersion: EXPO_VERSION,
appOwnership: 'guest'
}
diff --git a/packages/plugin-expo-eas-sourcemaps/lib/eas-build-on-success.js b/packages/plugin-expo-eas-sourcemaps/lib/eas-build-on-success.js
new file mode 100755
index 00000000..c6cb0866
--- /dev/null
+++ b/packages/plugin-expo-eas-sourcemaps/lib/eas-build-on-success.js
@@ -0,0 +1,61 @@
+#!/usr/bin/env node
+
+const { access } = require('fs').promises
+const { reactNative } = require('@bugsnag/source-maps')
+const { exit } = require('process')
+const { getConfig } = require('@expo/config')
+
+const PROJECT_ROOT = process.cwd()
+
+if (process.env.EAS_BUILD_PLATFORM !== 'android') {
+ console.log('Skipping Android source map upload: Android build not detected')
+ exit(0)
+} else if (process.env.EAS_BUILD_PROFILE === 'development') {
+ console.log('Skipping Android source map upload: Development build detected')
+ exit(0)
+}
+
+const uploadSourceMaps = async () => {
+ const bundle = `${PROJECT_ROOT}/android/app/build/generated/assets/createBundleReleaseJsAndAssets/index.android.bundle`
+ await access(bundle).catch((error) => {
+ console.log(`Skipping Android source map upload: App bundle ${bundle} could not be found.\n${error}`)
+ exit(0)
+ })
+
+ const sourceMap = `${PROJECT_ROOT}/android/app/build/generated/sourcemaps/react/release/index.android.bundle.map`
+ await access(sourceMap).catch((error) => {
+ console.error(`Error: source map ${sourceMap} could not be found.\n${error}`)
+ exit(1)
+ })
+
+ let appConfig, apiKey
+ try {
+ appConfig = getConfig(PROJECT_ROOT)
+ apiKey = appConfig?.exp?.extra?.bugsnag?.apiKey
+ } catch (error) {
+ console.error(`Error: Failed to read app config in ${PROJECT_ROOT}.\n${error}`)
+ exit(1)
+ }
+
+ if (!apiKey) {
+ console.error('Error: No Bugsnag API key detected in app config')
+ exit(1)
+ }
+
+ console.log('Uploading Android source map to Bugsnag...')
+ await reactNative.uploadOne({
+ apiKey,
+ bundle,
+ sourceMap,
+ platform: 'android',
+ appVersion: appConfig?.exp?.version,
+ appVersionCode: appConfig?.exp?.android?.versionCode?.toString()
+ }).then(() => {
+ console.log(`Successfully uploaded the following files:\n${[bundle, sourceMap].join('\n')}`)
+ }).catch(error => {
+ console.error(`Error uploading source map: ${error}`)
+ exit(1)
+ })
+}
+
+uploadSourceMaps()
diff --git a/packages/plugin-expo-eas-sourcemaps/package.json b/packages/plugin-expo-eas-sourcemaps/package.json
index 48eda64f..587f31ad 100644
--- a/packages/plugin-expo-eas-sourcemaps/package.json
+++ b/packages/plugin-expo-eas-sourcemaps/package.json
@@ -1,8 +1,11 @@
{
"name": "@bugsnag/plugin-expo-eas-sourcemaps",
- "version": "47.1.0",
+ "version": "49.0.0",
"description": "Plugin to handle uploading sourcemaps to bugsnag when using the EAS build system",
"main": "index.js",
+ "bin": {
+ "bugsnag-eas-build-on-success": "lib/eas-build-on-success.js"
+ },
"homepage": "https://www.bugsnag.com/",
"repository": {
"type": "git",
@@ -20,7 +23,8 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"peerDependencies": {
- "@bugsnag/source-maps": "^2.3.1"
+ "@bugsnag/source-maps": "^2.3.1",
+ "@expo/config": "^8.1.1"
},
"author": "Bugsnag",
"license": "MIT"
diff --git a/packages/plugin-expo-eas-sourcemaps/src/android.js b/packages/plugin-expo-eas-sourcemaps/src/android.js
index 5f6279cf..35612f01 100644
--- a/packages/plugin-expo-eas-sourcemaps/src/android.js
+++ b/packages/plugin-expo-eas-sourcemaps/src/android.js
@@ -1,31 +1,16 @@
-const {
- AndroidConfig,
- withAppBuildGradle,
- withAndroidManifest
-} = require('@expo/config-plugins')
+const { AndroidConfig, withAndroidManifest } = require('@expo/config-plugins')
// Using helpers keeps error messages unified and helps cut down on XML format changes.
const { addMetaDataItemToMainApplication, getMainApplicationOrThrow } = AndroidConfig.Manifest
const withAndroidPlugin = (config, onPremConfig) => {
- // Update android manifest with bugsnag config
+// Set the Bugsnag API key in the android manifest - note that this isn't required for source map uploads
+// but is added here to support reporting builds using the fastlane plugin
config = withAndroidManifest(config, config => {
config.modResults = setBugsnagConfig(config, config.modResults)
return config
})
- // Inject gradle dependencies
- config = withAppBuildGradle(config, (config) => {
- if (config.modResults.language === 'groovy') {
- config.modResults.contents = injectDependencies(config.modResults.contents)
- } else {
- throw new Error(
- 'Cannot configure Bugsnag in the app gradle because the build.gradle is not groovy'
- )
- }
- return config
- })
-
return config
}
@@ -37,34 +22,17 @@ function setBugsnagConfig (config, androidManifest) {
// Get the tag and assert if it doesn't exist.
const mainApplication = getMainApplicationOrThrow(androidManifest)
- addMetaDataItemToMainApplication(
- mainApplication,
- apiKeyName,
- apiKeyValue
- )
+ if (apiKeyValue) {
+ addMetaDataItemToMainApplication(
+ mainApplication,
+ apiKeyName,
+ apiKeyValue
+ )
+ }
return androidManifest
}
-function injectDependencies (script) {
- return `buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath 'com.bugsnag:bugsnag-android-gradle-plugin:[7.3.0,)'
- }
- }
-
- ${script}
-
- apply plugin: 'com.bugsnag.android.gradle'
-
- bugsnag {
- uploadReactNativeMappings = true
- }`
-}
-
module.exports = {
withAndroidPlugin
}