diff --git a/.buildkite/basic/browser-pipeline.yml b/.buildkite/basic/browser-pipeline.yml index 030cd9d896..9844d45200 100644 --- a/.buildkite/basic/browser-pipeline.yml +++ b/.buildkite/basic/browser-pipeline.yml @@ -58,8 +58,8 @@ steps: artifacts#v1.5.0: upload: - "./test/browser/maze_output/failed/**/*" - concurrency: 5 - concurrency_group: "bitbar-web" + concurrency: 25 + concurrency_group: "bitbar" concurrency_method: eager # Skipped pending PLAT-10590 @@ -85,8 +85,8 @@ steps: # artifacts#v1.5.0: # upload: # - "./test/browser/maze_output/failed/**/*" -# concurrency: 5 -# concurrency_group: "bitbar-web" +# concurrency: 25 +# concurrency_group: "bitbar" # concurrency_method: eager - label: ":bitbar: ie_11 Browser tests" @@ -106,8 +106,8 @@ steps: artifacts#v1.5.0: upload: - "./test/browser/maze_output/failed/**/*" - concurrency: 5 - concurrency_group: "bitbar-web" + concurrency: 25 + concurrency_group: "bitbar" concurrency_method: eager env: HOST: "localhost" # IE11 needs the host set to localhost for some reason diff --git a/.buildkite/basic/react-native-android-pipeline.yml b/.buildkite/basic/react-native-android-pipeline.yml index 575e487d26..f534d2d1f7 100644 --- a/.buildkite/basic/react-native-android-pipeline.yml +++ b/.buildkite/basic/react-native-android-pipeline.yml @@ -77,7 +77,7 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: "bitbar-app" + concurrency_group: "bitbar" concurrency_method: eager - label: ":bitbar: :android: RN 0.72 (New Arch) Android 12 end-to-end tests" @@ -103,5 +103,5 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: "bitbar-app" + concurrency_group: "bitbar" concurrency_method: eager diff --git a/.buildkite/full/react-native-android-pipeline.full.yml b/.buildkite/full/react-native-android-pipeline.full.yml index 85e6661125..3f2d309ce5 100644 --- a/.buildkite/full/react-native-android-pipeline.full.yml +++ b/.buildkite/full/react-native-android-pipeline.full.yml @@ -187,17 +187,17 @@ steps: run: react-native-maze-runner service-ports: true command: - - --app=build/rn0.60.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --fail-fast - - --no-tunnel - - --aws-public-ip + - --app=build/rn0.60.apk + - --farm=bb + - --device=ANDROID_10|ANDROID_11|ANDROID_12 + - --a11y-locator + - --fail-fast + - --no-tunnel + - --aws-public-ip env: SKIP_NAVIGATION_SCENARIOS: "true" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.66 Android end-to-end tests" @@ -212,17 +212,17 @@ steps: run: react-native-maze-runner service-ports: true command: - - --app=build/rn0.66.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --fail-fast - - --no-tunnel - - --aws-public-ip + - --app=build/rn0.66.apk + - --farm=bb + - --device=ANDROID_10|ANDROID_11|ANDROID_12 + - --a11y-locator + - --fail-fast + - --no-tunnel + - --aws-public-ip env: SKIP_NAVIGATION_SCENARIOS: "true" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.67 Android end-to-end tests" @@ -248,7 +248,7 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.69 Android end-to-end tests" @@ -274,7 +274,7 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.68 (Hermes) Android end-to-end tests" @@ -300,7 +300,7 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.71 (Old Arch) Android 12 end-to-end tests" @@ -326,7 +326,7 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: "bitbar-app" + concurrency_group: "bitbar" concurrency_method: eager - label: ":bitbar: :android: RN 0.71 (New Arch) Android 12 end-to-end tests" @@ -352,7 +352,7 @@ steps: SKIP_NAVIGATION_SCENARIOS: "true" HERMES: "true" concurrency: 25 - concurrency_group: "bitbar-app" + concurrency_group: "bitbar" concurrency_method: eager - label: ":bitbar: :android: react-navigation 0.60 Android end-to-end tests" @@ -367,16 +367,16 @@ steps: run: react-native-maze-runner service-ports: true command: - - --app=build/r_navigation_0.60.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --fail-fast - - --no-tunnel - - --aws-public-ip - - features/navigation.feature + - --app=build/r_navigation_0.60.apk + - --farm=bb + - --device=ANDROID_10|ANDROID_11|ANDROID_12 + - --a11y-locator + - --fail-fast + - --no-tunnel + - --aws-public-ip + - features/navigation.feature concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: react-navigation 0.69 Android end-to-end tests" @@ -391,16 +391,16 @@ steps: run: react-native-maze-runner service-ports: true command: - - --app=build/r_navigation_0.69.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --fail-fast - - --no-tunnel - - --aws-public-ip - - features/navigation.feature + - --app=build/r_navigation_0.69.apk + - --farm=bb + - --device=ANDROID_10|ANDROID_11|ANDROID_12 + - --a11y-locator + - --fail-fast + - --no-tunnel + - --aws-public-ip + - features/navigation.feature concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: react-native-navigation 0.60 Android end-to-end tests" @@ -415,16 +415,16 @@ steps: run: react-native-maze-runner service-ports: true command: - - --app=build/r_native_navigation_0.60.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --fail-fast - - --no-tunnel - - --aws-public-ip - - features/navigation.feature + - --app=build/r_native_navigation_0.60.apk + - --farm=bb + - --device=ANDROID_10|ANDROID_11|ANDROID_12 + - --a11y-locator + - --fail-fast + - --no-tunnel + - --aws-public-ip + - features/navigation.feature concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: react-native-navigation 0.66 Android end-to-end tests" @@ -439,14 +439,14 @@ steps: run: react-native-maze-runner service-ports: true command: - - --app=build/r_native_navigation_0.66.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --fail-fast - - --no-tunnel - - --aws-public-ip - - features/navigation.feature + - --app=build/r_native_navigation_0.66.apk + - --farm=bb + - --device=ANDROID_10|ANDROID_11|ANDROID_12 + - --a11y-locator + - --fail-fast + - --no-tunnel + - --aws-public-ip + - features/navigation.feature concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager diff --git a/.buildkite/full/react-native-cli-pipeline.full.yml b/.buildkite/full/react-native-cli-pipeline.full.yml index b9823b470c..7169d0f166 100644 --- a/.buildkite/full/react-native-cli-pipeline.full.yml +++ b/.buildkite/full/react-native-cli-pipeline.full.yml @@ -339,22 +339,6 @@ steps: artifact_paths: - build/rn0_67.apk - - label: ":android: Init and build RN 0.67 apk (Hermes)" - key: "rn-cli-0-67-hermes-apk" - depends_on: - - "android-builder-cli-image" - timeout_in_minutes: 15 - env: - DEBUG: true - REACT_NATIVE_VERSION: rn0_67_hermes - plugins: - - docker-compose#v4.12.0: - run: react-native-cli-android-builder - command: ["features/build-app-tests/build-android-app.feature"] - artifact_paths: - - build/rn0_67_hermes.apk - - - label: ":android: Init and build RN 0.69 apk (Non-hermes)" key: "rn-cli-0-69-apk" depends_on: @@ -490,19 +474,6 @@ steps: commands: - test/react-native-cli/scripts/init-and-build-test.sh rn0_67 - - label: ":ios: Init and build RN 0.67 ipa (Hermes)" - key: "rn-cli-0-67-hermes-ipa" - timeout_in_minutes: 60 - agents: - queue: "opensource-arm-mac-cocoa-12" - env: - DEBUG: true - LANG: "en_US.UTF-8" - DEVELOPER_DIR: "/Applications/Xcode13.app" - artifact_paths: build/rn0_67_hermes.ipa - commands: - - test/react-native-cli/scripts/init-and-build-test.sh rn0_67_hermes - - label: ":ios: Init and build RN 0.69 ipa (Non-hermes)" key: "rn-cli-0-69-ipa" timeout_in_minutes: 30 @@ -539,7 +510,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.61 Android end-to-end tests" @@ -562,7 +533,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.62 Android end-to-end tests" @@ -585,7 +556,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.63 Android end-to-end tests" @@ -608,7 +579,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.63 Expo (ejected) Android end-to-end tests" @@ -631,7 +602,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.64 Android end-to-end tests" @@ -654,7 +625,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.65 Android end-to-end tests" @@ -677,7 +648,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.66 Android end-to-end tests" @@ -700,7 +671,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - label: ":bitbar: :android: RN 0.67 Android end-to-end tests (Non-hermes)" @@ -723,33 +694,10 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager - - label: ":bitbar: :android: RN 0.67 Android end-to-end tests (Hermes)" - depends_on: "rn-cli-0-67-hermes-apk" - timeout_in_minutes: 10 - plugins: - artifacts#v1.9.0: - download: "build/rn0_67_hermes.apk" - upload: ./test/react-native-cli/maze_output/**/* - docker-compose#v4.12.0: - pull: react-native-cli-maze-runner - run: react-native-cli-maze-runner - service-ports: true - command: - - --app=build/rn0_67_hermes.apk - - --farm=bb - - --device=ANDROID_10|ANDROID_11|ANDROID_12 - - --a11y-locator - - --no-tunnel - - --aws-public-ip - - features/run-app-tests - concurrency: 25 - concurrency_group: 'bitbar-app' - concurrency_method: eager - - - label: ":bitbar: :android: RN 0.69 Android end-to-end tests (Non-hermes)" + - label: ":runner: RN 0.69 Android end-to-end tests (Non-hermes)" depends_on: "rn-cli-0-69-apk" timeout_in_minutes: 10 plugins: @@ -769,7 +717,7 @@ steps: - --aws-public-ip - features/run-app-tests concurrency: 25 - concurrency_group: 'bitbar-app' + concurrency_group: 'bitbar' concurrency_method: eager # @@ -964,27 +912,6 @@ steps: concurrency_group: "browserstack-app" concurrency_method: eager - - label: ":browserstack: :ios: RN 0.67 iOS end-to-end tests (Hermes)" - depends_on: "rn-cli-0-67-hermes-ipa" - timeout_in_minutes: 10 - plugins: - artifacts#v1.5.0: - download: "build/rn0_67_hermes.ipa" - upload: ./test/react-native-cli/maze_output/**/* - docker-compose#v4.12.0: - pull: react-native-cli-maze-runner - run: react-native-cli-maze-runner - use-aliases: true - command: - - --app=build/rn0_67_hermes.ipa - - --farm=bs - - --device=IOS_14 - - --a11y-locator - - features/run-app-tests - concurrency: 5 - concurrency_group: "browserstack-app" - concurrency_method: eager - - label: ":browserstack: :ios: RN 0.69 iOS end-to-end tests (Non-hermes)" depends_on: "rn-cli-0-69-ipa" timeout_in_minutes: 10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 89042b8e14..ebb983d17b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ ## TBD +## 7.22.0 (2023-09-13) + +### Changes + +(react-native-cli) Update the react native cli to install and configure the `@bugsnag/cli` package to upload javascript source maps for react native android [#1990](https://github.com/bugsnag/bugsnag-js/pull/1990) + ## 7.21.0 (2023-08-15) This release adds support for apps using React Native New Architecture diff --git a/dockerfiles/Dockerfile.browser b/dockerfiles/Dockerfile.browser index 3eacfbc43f..d8cdc6737e 100644 --- a/dockerfiles/Dockerfile.browser +++ b/dockerfiles/Dockerfile.browser @@ -11,8 +11,8 @@ RUN npm install COPY babel.config.js lerna.json .eslintignore .eslintrc.js jest.config.js tsconfig.json ./ ADD min_packages.tar . COPY bin ./bin -RUN npx lerna bootstrap COPY packages ./packages +RUN npx lerna bootstrap RUN npm run build RUN npm pack --verbose packages/js/ diff --git a/dockerfiles/Dockerfile.ci b/dockerfiles/Dockerfile.ci index ea9eb0a447..2c44d4bed5 100644 --- a/dockerfiles/Dockerfile.ci +++ b/dockerfiles/Dockerfile.ci @@ -11,8 +11,8 @@ RUN npm install --unsafe-perm COPY babel.config.js lerna.json .eslintignore .eslintrc.js jest.config.js tsconfig.json ./ ADD min_packages.tar . COPY bin ./bin -RUN npx lerna bootstrap COPY scripts ./scripts COPY test ./test COPY packages ./packages +RUN npx lerna bootstrap RUN npm run build diff --git a/dockerfiles/Dockerfile.node b/dockerfiles/Dockerfile.node index eb25763019..d273244d26 100644 --- a/dockerfiles/Dockerfile.node +++ b/dockerfiles/Dockerfile.node @@ -11,8 +11,8 @@ RUN npm install COPY babel.config.js lerna.json .eslintignore .eslintrc.js jest.config.js tsconfig.json ./ ADD min_packages.tar . COPY bin ./bin -RUN npx lerna bootstrap COPY packages ./packages +RUN npx lerna bootstrap RUN npm run build RUN npm pack --verbose packages/node/ diff --git a/lerna.json b/lerna.json index 16a26c454c..7cf32f844c 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "packages": [ "packages/*" ], - "version": "7.21.0" + "version": "7.22.0" } diff --git a/packages/react-native-cli/package-lock.json b/packages/react-native-cli/package-lock.json index 38ef6320e2..0c62ef082d 100644 --- a/packages/react-native-cli/package-lock.json +++ b/packages/react-native-cli/package-lock.json @@ -1,876 +1,988 @@ { - "name": "@bugsnag/react-native-cli", - "version": "7.16.5", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@bugsnag/react-native-cli", - "version": "7.14.2", - "license": "MIT", - "dependencies": { - "command-line-args": "^5.1.1", - "command-line-usage": "^6.1.0", - "consola": "^2.15.0", - "glob": "^7.1.6", - "plist": "^3.0.1", - "prompts": "^2.4.0", - "xcode": "^3.0.1" - }, - "bin": { - "bugsnag-react-native-cli": "bin/cli" - }, - "devDependencies": { - "@types/command-line-args": "^5.0.0", - "@types/command-line-usage": "^5.0.1", - "@types/prompts": "^2.0.9", - "typescript": "^4.1.3" - } - }, - "node_modules/@types/command-line-args": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.0.0.tgz", - "integrity": "sha512-4eOPXyn5DmP64MCMF8ePDvdlvlzt2a+F8ZaVjqmh2yFCpGjc1kI3kGnCFYX9SCsGTjQcWIyVZ86IHCEyjy/MNg==", - "dev": true - }, - "node_modules/@types/command-line-usage": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.1.tgz", - "integrity": "sha512-/xUgezxxYePeXhg5S04hUjxG9JZi+rJTs1+4NwpYPfSaS7BeDa6tVJkH6lN9Cb6rl8d24Fi2uX0s0Ngg2JT6gg==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.14.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", - "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", - "dev": true - }, - "node_modules/@types/prompts": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.9.tgz", - "integrity": "sha512-TORZP+FSjTYMWwKadftmqEn6bziN5RnfygehByGsjxoK5ydnClddtv6GikGWPvCm24oI+YBwck5WDxIIyNxUrA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/big-integer": { - "version": "1.6.48", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", - "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/bplist-creator": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", - "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==", - "dependencies": { - "stream-buffers": "~2.2.0" - } - }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/command-line-args": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", - "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", - "dependencies": { - "array-back": "^3.0.1", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-usage": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", - "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", - "dependencies": { - "array-back": "^4.0.0", - "chalk": "^2.4.2", - "table-layout": "^1.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/consola": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", - "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", - "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", - "dependencies": { - "base64-js": "^1.2.3", - "xmlbuilder": "^9.0.7", - "xmldom": "0.1.x" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/simple-plist": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz", - "integrity": "sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg==", - "dependencies": { - "bplist-creator": "0.0.8", - "bplist-parser": "0.2.0", - "plist": "^3.0.1" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "node_modules/stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=", - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/table-layout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", - "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", - "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/table-layout/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/wordwrapjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", - "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", - "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/wordwrapjs/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/xcode": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", - "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", - "dependencies": { - "simple-plist": "^1.1.0", - "uuid": "^7.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xmldom": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", - "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==", - "deprecated": "Deprecated due to CVE-2021-21366 resolved in 0.5.0", - "engines": { - "node": ">=0.1" - } - } - }, - "dependencies": { - "@types/command-line-args": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.0.0.tgz", - "integrity": "sha512-4eOPXyn5DmP64MCMF8ePDvdlvlzt2a+F8ZaVjqmh2yFCpGjc1kI3kGnCFYX9SCsGTjQcWIyVZ86IHCEyjy/MNg==", - "dev": true - }, - "@types/command-line-usage": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.1.tgz", - "integrity": "sha512-/xUgezxxYePeXhg5S04hUjxG9JZi+rJTs1+4NwpYPfSaS7BeDa6tVJkH6lN9Cb6rl8d24Fi2uX0s0Ngg2JT6gg==", - "dev": true - }, - "@types/node": { - "version": "14.14.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", - "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", - "dev": true - }, - "@types/prompts": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.9.tgz", - "integrity": "sha512-TORZP+FSjTYMWwKadftmqEn6bziN5RnfygehByGsjxoK5ydnClddtv6GikGWPvCm24oI+YBwck5WDxIIyNxUrA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "big-integer": { - "version": "1.6.48", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", - "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" - }, - "bplist-creator": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", - "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==", - "requires": { - "stream-buffers": "~2.2.0" - } - }, - "bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "requires": { - "big-integer": "^1.6.44" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "command-line-args": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", - "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", - "requires": { - "array-back": "^3.0.1", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - } - }, - "command-line-usage": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", - "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", - "requires": { - "array-back": "^4.0.0", - "chalk": "^2.4.2", - "table-layout": "^1.0.0", - "typical": "^5.2.0" - }, - "dependencies": { - "array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==" - }, - "typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "consola": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", - "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "requires": { - "array-back": "^3.0.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "plist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", - "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", - "requires": { - "base64-js": "^1.2.3", - "xmlbuilder": "^9.0.7", - "xmldom": "0.1.x" - } - }, - "prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" - }, - "simple-plist": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz", - "integrity": "sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg==", - "requires": { - "bplist-creator": "0.0.8", - "bplist-parser": "0.2.0", - "plist": "^3.0.1" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "table-layout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", - "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", - "requires": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "dependencies": { - "array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==" - }, - "typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" - } - } - }, - "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", - "dev": true - }, - "typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" - }, - "uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" - }, - "wordwrapjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", - "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", - "requires": { - "reduce-flatten": "^2.0.0", - "typical": "^5.0.0" - }, - "dependencies": { - "typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xcode": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", - "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", - "requires": { - "simple-plist": "^1.1.0", - "uuid": "^7.0.3" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - }, - "xmldom": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", - "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" - } - } + "name": "@bugsnag/react-native-cli", + "version": "7.22.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@bugsnag/react-native-cli", + "version": "7.16.5", + "license": "MIT", + "dependencies": { + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "consola": "^2.15.0", + "detect-indent": "^6.1.0", + "glob": "^7.1.6", + "plist": "^3.0.1", + "prompts": "^2.4.0", + "semver": "^7.5.4", + "xcode": "^3.0.1" + }, + "bin": { + "bugsnag-react-native-cli": "bin/cli" + }, + "devDependencies": { + "@types/command-line-args": "^5.0.0", + "@types/command-line-usage": "^5.0.1", + "@types/glob": "^8.1.0", + "@types/prompts": "^2.0.9", + "@types/semver": "^7.5.0", + "typescript": "^4.1.3" + } + }, + "node_modules/@types/command-line-args": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.0.0.tgz", + "integrity": "sha512-4eOPXyn5DmP64MCMF8ePDvdlvlzt2a+F8ZaVjqmh2yFCpGjc1kI3kGnCFYX9SCsGTjQcWIyVZ86IHCEyjy/MNg==", + "dev": true + }, + "node_modules/@types/command-line-usage": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.1.tgz", + "integrity": "sha512-/xUgezxxYePeXhg5S04hUjxG9JZi+rJTs1+4NwpYPfSaS7BeDa6tVJkH6lN9Cb6rl8d24Fi2uX0s0Ngg2JT6gg==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.14.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", + "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", + "dev": true + }, + "node_modules/@types/prompts": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.9.tgz", + "integrity": "sha512-TORZP+FSjTYMWwKadftmqEn6bziN5RnfygehByGsjxoK5ydnClddtv6GikGWPvCm24oI+YBwck5WDxIIyNxUrA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-creator": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", + "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==", + "dependencies": { + "stream-buffers": "~2.2.0" + } + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/command-line-args": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", + "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", + "dependencies": { + "array-back": "^3.0.1", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", + "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", + "dependencies": { + "array-back": "^4.0.0", + "chalk": "^2.4.2", + "table-layout": "^1.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/consola": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", + "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", + "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", + "dependencies": { + "base64-js": "^1.2.3", + "xmlbuilder": "^9.0.7", + "xmldom": "0.1.x" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-plist": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz", + "integrity": "sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg==", + "dependencies": { + "bplist-creator": "0.0.8", + "bplist-parser": "0.2.0", + "plist": "^3.0.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table-layout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", + "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/wordwrapjs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", + "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "dependencies": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmldom": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", + "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==", + "deprecated": "Deprecated due to CVE-2021-21366 resolved in 0.5.0", + "engines": { + "node": ">=0.1" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "@types/command-line-args": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.0.0.tgz", + "integrity": "sha512-4eOPXyn5DmP64MCMF8ePDvdlvlzt2a+F8ZaVjqmh2yFCpGjc1kI3kGnCFYX9SCsGTjQcWIyVZ86IHCEyjy/MNg==", + "dev": true + }, + "@types/command-line-usage": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.1.tgz", + "integrity": "sha512-/xUgezxxYePeXhg5S04hUjxG9JZi+rJTs1+4NwpYPfSaS7BeDa6tVJkH6lN9Cb6rl8d24Fi2uX0s0Ngg2JT6gg==", + "dev": true + }, + "@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "requires": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/node": { + "version": "14.14.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", + "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", + "dev": true + }, + "@types/prompts": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.0.9.tgz", + "integrity": "sha512-TORZP+FSjTYMWwKadftmqEn6bziN5RnfygehByGsjxoK5ydnClddtv6GikGWPvCm24oI+YBwck5WDxIIyNxUrA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" + }, + "bplist-creator": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", + "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==", + "requires": { + "stream-buffers": "~2.2.0" + } + }, + "bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "requires": { + "big-integer": "^1.6.44" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "command-line-args": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", + "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", + "requires": { + "array-back": "^3.0.1", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", + "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", + "requires": { + "array-back": "^4.0.0", + "chalk": "^2.4.2", + "table-layout": "^1.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "consola": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", + "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "requires": { + "array-back": "^3.0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "plist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", + "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", + "requires": { + "base64-js": "^1.2.3", + "xmlbuilder": "^9.0.7", + "xmldom": "0.1.x" + } + }, + "prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "simple-plist": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz", + "integrity": "sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg==", + "requires": { + "bplist-creator": "0.0.8", + "bplist-parser": "0.2.0", + "plist": "^3.0.1" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "table-layout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", + "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" + }, + "wordwrapjs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", + "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.0.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "requires": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, + "xmldom": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", + "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } } diff --git a/packages/react-native-cli/package.json b/packages/react-native-cli/package.json index e5a66c5462..7439e1fbfa 100644 --- a/packages/react-native-cli/package.json +++ b/packages/react-native-cli/package.json @@ -1,6 +1,6 @@ { "name": "@bugsnag/react-native-cli", - "version": "7.16.5", + "version": "7.22.0", "description": "A tool to help integrate Bugsnag with a React Native app", "bin": { "bugsnag-react-native-cli": "bin/cli" @@ -23,15 +23,19 @@ "command-line-args": "^5.1.1", "command-line-usage": "^6.1.0", "consola": "^2.15.0", + "detect-indent": "^6.1.0", "glob": "^7.1.6", "plist": "^3.0.1", "prompts": "^2.4.0", + "semver": "^7.5.4", "xcode": "^3.0.1" }, "devDependencies": { "@types/command-line-args": "^5.0.0", "@types/command-line-usage": "^5.0.1", + "@types/glob": "^8.1.0", "@types/prompts": "^2.0.9", + "@types/semver": "^7.5.0", "typescript": "^4.1.3" } } diff --git a/packages/react-native-cli/src/commands/AutomateSymbolicationCommand.ts b/packages/react-native-cli/src/commands/AutomateSymbolicationCommand.ts index d2a63b7abd..3895accf66 100644 --- a/packages/react-native-cli/src/commands/AutomateSymbolicationCommand.ts +++ b/packages/react-native-cli/src/commands/AutomateSymbolicationCommand.ts @@ -1,10 +1,14 @@ import prompts from 'prompts' +import { promises as fs } from 'fs' +import { join } from 'path' import logger from '../Logger' import { updateXcodeProject } from '../lib/Xcode' -import { install, detectInstalled, guessPackageManager } from '../lib/Npm' +import { install, detectInstalledVersion, detectInstalled, guessPackageManager } from '../lib/Npm' import onCancel from '../lib/OnCancel' -import { enableReactNativeMappings } from '../lib/Gradle' +import { checkReactNativeMappings, addUploadEndpoint, addBuildEndpoint } from '../lib/Gradle' import { UrlType, OnPremiseUrls } from '../lib/OnPremise' +import detectIndent from 'detect-indent' +import semver from 'semver' const DSYM_INSTRUCTIONS = `To configure your project to upload dSYMs, follow the iOS symbolication guide: @@ -14,6 +18,20 @@ const DSYM_INSTRUCTIONS = `To configure your project to upload dSYMs, follow the ` +const HERMES_INSTRUCTIONS = `You are running a version of React Native that we cannot automatically integrate with due to known issues with the build when Hermes is enabled. + + If you cannot upgrade to a later version of React Native (version 0.68 or above), you can use an older version of this CLI (version 7.20.x or earlier) + + or follow the manual integration instructions in our online docs: https://docs.bugsnag.com/platforms/react-native/react-native/manual-setup/') + +` + +const BUGSNAG_CLI_INSTRUCTIONS = `bugsnag:upload-android task added to your package.json - run this task to upload Android source maps after a build. + + See https://docs.bugsnag.com/platforms/react-native/react-native/showing-full-stacktraces for details. + +` + export default async function run (projectRoot: string, urls: OnPremiseUrls): Promise { try { const { iosIntegration } = await prompts({ @@ -38,17 +56,48 @@ export default async function run (projectRoot: string, urls: OnPremiseUrls): Pr const { androidIntegration } = await prompts({ type: 'confirm', name: 'androidIntegration', - message: 'Do you want to automatically upload JavaScript source maps as part of the Gradle build?', + message: 'Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps?', initial: true }, { onCancel }) - if (androidIntegration) { - await enableReactNativeMappings(projectRoot, urls[UrlType.UPLOAD], urls[UrlType.BUILD], logger) + if (iosIntegration) { + await installJavaScriptPackage(projectRoot) } - if (androidIntegration || iosIntegration) { - await installJavaScriptPackage(projectRoot) + if (androidIntegration) { + await installBugsnagCliPackage(projectRoot, urls) + const reactNativeVersion = await detectInstalledVersion('react-native', projectRoot) + + if (reactNativeVersion) { + if (semver.lt(reactNativeVersion, '0.68.0')) { + await prompts({ + type: 'text', + name: 'hermesInstructions', + message: HERMES_INSTRUCTIONS, + initial: 'Hit enter to continue …' + }, { onCancel }) + } + } + + const { packageJsonIntegration } = await prompts({ + type: 'confirm', + name: 'packageJsonIntegration', + message: 'Do you want to add an NPM task to your package.json that you can run to upload Android source maps?', + initial: true + }, { onCancel }) + + if (packageJsonIntegration) { + await writeToPackageJson(join(projectRoot, 'package.json'), urls[UrlType.UPLOAD], urls[UrlType.BUILD]) + } + + await prompts({ + type: 'text', + name: 'bugsnagCliInstructions', + message: BUGSNAG_CLI_INSTRUCTIONS, + initial: 'Hit enter to continue …' + }, { onCancel }) } + return true } catch (e) { logger.error(e) @@ -56,6 +105,40 @@ export default async function run (projectRoot: string, urls: OnPremiseUrls): Pr } } +async function installBugsnagCliPackage (projectRoot: string, urls: OnPremiseUrls): Promise { + await checkReactNativeMappings(projectRoot, logger) + + if (urls[UrlType.BUILD]) { + await addBuildEndpoint(projectRoot, urls[UrlType.BUILD] as string, logger) + } + + if (urls[UrlType.UPLOAD]) { + await addUploadEndpoint(projectRoot, urls[UrlType.UPLOAD] as string, logger) + } + + const alreadyInstalled = await detectInstalled('@bugsnag/cli', projectRoot) + + if (alreadyInstalled) { + logger.warn('@bugsnag/cli is already installed, skipping') + return + } + + logger.info('Adding @bugsnag/cli dependency') + + const packageManager = await guessPackageManager(projectRoot) + + const { version } = await prompts({ + type: 'text', + name: 'version', + message: 'If you want the latest version of @bugsnag/cli hit enter, otherwise type the version you want', + initial: 'latest' + }, { onCancel }) + + await install(packageManager, '@bugsnag/cli', version, true, projectRoot) + + logger.success('@bugsnag/cli dependency is installed') +} + async function installJavaScriptPackage (projectRoot: string): Promise { const alreadyInstalled = await detectInstalled('@bugsnag/source-maps', projectRoot) @@ -79,3 +162,36 @@ async function installJavaScriptPackage (projectRoot: string): Promise { logger.success('@bugsnag/source-maps dependency is installed') } + +async function writeToPackageJson (packageJsonPath: string, uploadUrl?: string, buildUrl?: string): Promise { + try { + const data = await fs.readFile(packageJsonPath, 'utf8') + const packageJson = JSON.parse(data) + + // Default to two spaces if indent cannot be detected + const existingIndent = detectIndent(data).indent || ' ' + + let uploadCommand = 'bugsnag-cli upload react-native-android' + let buildCommand = 'bugsnag-cli create-build' + + if (uploadUrl) { + uploadCommand += ` --upload-api-root-url=${uploadUrl}` + } + + if (buildUrl) { + buildCommand += ` --build-api-root-url=${buildUrl}` + } + + packageJson.scripts = { + ...packageJson.scripts, + 'bugsnag:create-build': buildCommand, + 'bugsnag:upload-android': uploadCommand + } + + const updatedPackageJson = JSON.stringify(packageJson, null, existingIndent) + + await fs.writeFile(packageJsonPath, updatedPackageJson, 'utf8') + } catch (err) { + console.error(`Error writing package.json: ${err}`) + } +} diff --git a/packages/react-native-cli/src/lib/Gradle.ts b/packages/react-native-cli/src/lib/Gradle.ts index 4fce6e413f..e96d8b4eaa 100644 --- a/packages/react-native-cli/src/lib/Gradle.ts +++ b/packages/react-native-cli/src/lib/Gradle.ts @@ -8,8 +8,8 @@ const GRADLE_PLUGIN_APPLY = 'apply plugin: "com.bugsnag.android.gradle"' const GRADLE_PLUGIN_APPLY_REGEX = /apply plugin: ["']com\.bugsnag\.android\.gradle["']/ const GRADLE_ANDROID_PLUGIN_REGEX = /classpath\(["']com.android.tools.build:gradle:[^0-9]*([^'"]+)["']\)/ const DOCS_LINK = 'https://docs.bugsnag.com/build-integrations/gradle/#installation' -const ENABLE_REACT_NATIVE_MAPPINGS = 'bugsnag {\n uploadReactNativeMappings = true\n}\n' -const ENABLE_REACT_NATIVE_MAPPINGS_REGEX = /^\s*bugsnag {[^}]*uploadReactNativeMappings[^}]*?}/m +const BUGSNAG_CONFIGURATION_BLOCK = 'bugsnag {\n}\n' +const BUGSNAG_CONFIGURATION_BLOCK_REGEX = /^\s*bugsnag {[^}]*?}/m const UPLOAD_ENDPOINT_REGEX = /^\s*bugsnag {[^}]*endpoint[^}]*?}/m const BUILD_ENDPOINT_REGEX = /^\s*bugsnag {[^}]*releasesEndpoint[^}]*?}/m @@ -30,6 +30,10 @@ export async function getSuggestedBugsnagGradleVersion (projectRoot: string, log } else if (major === 7) { return '7.+' } else { + const versionMatchResult = fileContents.match(/classpath\(["']com.android.tools.build:gradle["']\)/) + if (versionMatchResult) { + return '7.+' + } logger.warn(`Cannot determine an appropriate version of the Bugsnag Android Gradle plugin for use in this project. Please see ${DOCS_LINK} for information on Gradle and the Android Gradle Plugin (AGP) compatibility`) @@ -44,7 +48,7 @@ export async function modifyRootBuildGradle (projectRoot: string, pluginVersion: try { await insertValueAfterPattern( topLevelBuildGradlePath, - /[\r\n]\s*classpath\(["']com.android.tools.build:gradle:.+["']\)/, + [/[\r\n]\s*classpath\(["']com.android.tools.build:gradle:.+["']\)/, /[\r\n]\s*classpath\(["']com.android.tools.build:gradle["']\)/], GRADLE_PLUGIN_IMPORT(pluginVersion), GRADLE_PLUGIN_IMPORT_REGEX, logger @@ -81,7 +85,7 @@ export async function modifyAppBuildGradle (projectRoot: string, logger: Logger) try { await insertValueAfterPattern( appBuildGradlePath, - /^apply from: ["']\.\.\/\.\.\/node_modules\/react-native\/react\.gradle["']$/m, + [/^apply from: ["']\.\.\/\.\.\/node_modules\/react-native\/react\.gradle["']$/m, /^apply from: file\(["']..\/\.\.\/node_modules\/@react-native-community\/cli-platform-android\/native_modules\.gradle["']\); applyNativeModulesAppBuildGradle\(project\)$/m], GRADLE_PLUGIN_APPLY, GRADLE_PLUGIN_APPLY_REGEX, logger @@ -111,10 +115,8 @@ See ${DOCS_LINK} for more information` logger.success('Finished modifying android/app/build.gradle') } -export async function enableReactNativeMappings ( +export async function checkReactNativeMappings ( projectRoot: string, - uploadEndpoint: string|undefined, - buildEndpoint: string|undefined, logger: Logger ): Promise { logger.debug('Enabling Bugsnag Android Gradle plugin React Native mappings') @@ -123,75 +125,45 @@ export async function enableReactNativeMappings ( try { const fileContents = await fs.readFile(appBuildGradlePath, 'utf8') - // If the file contains a 'bugsnag' configuration section already, add the - // 'uploadReactNativeMappings' flag to it - if (/^\s*bugsnag {/m.test(fileContents)) { - await insertValueAfterPattern( - appBuildGradlePath, - /^\s*bugsnag {[^}]*?(?=})/m, - ' uploadReactNativeMappings = true\n', - ENABLE_REACT_NATIVE_MAPPINGS_REGEX, - logger - ) - } else { - // If the file doesn't contain bugsnag config already, add it now - await insertValueAfterPattern( - appBuildGradlePath, - /$/, - ENABLE_REACT_NATIVE_MAPPINGS, - ENABLE_REACT_NATIVE_MAPPINGS_REGEX, - logger - ) - } - } catch (e) { - if (e.message === 'Pattern not found') { - logger.warn( - `The gradle file was in an unexpected format and so couldn't be updated automatically. - -Enable React Native mappings to your app module's build.gradle: - -${ENABLE_REACT_NATIVE_MAPPINGS} - -See ${DOCS_LINK} for more information` - ) - - return - } - - if (e.code === 'ENOENT') { + if (/^\s*uploadReactNativeMappings\s*=\s*true/m.test(fileContents)) { logger.warn( - `A gradle file was not found at the expected location and so couldn't be updated automatically. - -Enable React Native mappings to your app module's build.gradle: + `The uploadReactNativeMappings option for the Bugsnag Gradle plugin is currently enabled in ${appBuildGradlePath}. -${ENABLE_REACT_NATIVE_MAPPINGS} +This is no longer required as mappings will be uploaded by the BugSnag CLI. -See ${DOCS_LINK} for more information` +Please remove this line or disable it in your builds to prevent duplicate uploads.` ) - - return } - - throw e - } - - if (uploadEndpoint) { - await addUploadEndpoint(appBuildGradlePath, uploadEndpoint, logger) - } - - if (buildEndpoint) { - await addBuildEndpoint(appBuildGradlePath, buildEndpoint, logger) + } catch (e) { + // No action required } +} - logger.success('React Native mappings enabled in android/app/build.gradle') +async function insertBugsnagConfigBlock ( + appBuildGradlePath: string, + logger: Logger +): Promise { + logger.debug('Inserting Bugsnag config block') + + await insertValueAfterPattern( + appBuildGradlePath, + [/$/], + BUGSNAG_CONFIGURATION_BLOCK, + BUGSNAG_CONFIGURATION_BLOCK_REGEX, + logger + ) + logger.success('Bugsnag config block inserted into android/app/build.gradle') } -async function addUploadEndpoint (appBuildGradlePath: string, uploadEndpoint: string, logger: Logger): Promise { +export async function addUploadEndpoint (projectRoot: string, uploadEndpoint: string, logger: Logger): Promise { try { - // We know the 'bugsnag' section must exist after enabling RN mappings + const appBuildGradlePath = path.join(projectRoot, 'android', 'app', 'build.gradle') + + await insertBugsnagConfigBlock(appBuildGradlePath, logger) + await insertValueAfterPattern( appBuildGradlePath, - /^\s*bugsnag {[^}]*?(?=})/m, + [/^\s*bugsnag {[^}]*?(?=})/m], ` endpoint = "${uploadEndpoint}"\n`, UPLOAD_ENDPOINT_REGEX, logger @@ -227,12 +199,15 @@ See ${DOCS_LINK} for more information` } } -async function addBuildEndpoint (appBuildGradlePath: string, buildEndpoint: string, logger: Logger): Promise { +export async function addBuildEndpoint (projectRoot: string, buildEndpoint: string, logger: Logger): Promise { try { - // We know the 'bugsnag' section must exist after enabling RN mappings + const appBuildGradlePath = path.join(projectRoot, 'android', 'app', 'build.gradle') + + await insertBugsnagConfigBlock(appBuildGradlePath, logger) + await insertValueAfterPattern( appBuildGradlePath, - /^\s*bugsnag {[^}]*?(?=})/m, + [/^\s*bugsnag {[^}]*?(?=})/m, /''/], ` releasesEndpoint = "${buildEndpoint}"\n`, BUILD_ENDPOINT_REGEX, logger @@ -268,7 +243,7 @@ See ${DOCS_LINK} for more information` } } -async function insertValueAfterPattern (file: string, pattern: RegExp, value: string, presencePattern: RegExp, logger: Logger): Promise { +async function insertValueAfterPattern (file: string, patterns: RegExp[], value: string, presencePattern: RegExp, logger: Logger): Promise { const fileContents = await fs.readFile(file, 'utf8') if (presencePattern.test(fileContents)) { @@ -276,7 +251,7 @@ async function insertValueAfterPattern (file: string, pattern: RegExp, value: st return } - const match = fileContents.match(pattern) + const match = patterns.map(search => fileContents.match(search)).find(m => !!m) if (!match || match.index === undefined || !match.input) { throw new Error('Pattern not found') } diff --git a/packages/react-native-cli/src/lib/Npm.ts b/packages/react-native-cli/src/lib/Npm.ts index c0ef1befba..23dcf12f07 100644 --- a/packages/react-native-cli/src/lib/Npm.ts +++ b/packages/react-native-cli/src/lib/Npm.ts @@ -44,6 +44,28 @@ const npmCommand = (module: string, version: string, dev: boolean): Command => [ !dev ? ['install', '--save', `${module}@${version}`] : ['install', '--save-dev', `${module}@${version}`] ] +export async function detectInstalledVersion (module: string, projectRoot: string): Promise { + try { + const pkg = JSON.parse(await fs.readFile(join(projectRoot, 'package.json'), 'utf8')) + + if (pkg.dependencies && pkg.dependencies[module]) { + return pkg.dependencies[module] + } + + if (pkg.devDependencies && pkg.devDependencies[module]) { + return pkg.devDependencies[module] + } + + if (pkg.peerDependencies && pkg.peerDependencies[module]) { + return pkg.peerDependencies[module] + } + + return undefined + } catch (e) { + throw new Error('Could not load package.json. Is this the project root?') + } +} + export async function detectInstalled (module: string, projectRoot: string): Promise { try { const pkg = JSON.parse(await fs.readFile(join(projectRoot, 'package.json'), 'utf8')) diff --git a/packages/react-native-cli/src/lib/__test__/Gradle.test.ts b/packages/react-native-cli/src/lib/__test__/Gradle.test.ts index 6b6c3d03c4..e6092f17b7 100644 --- a/packages/react-native-cli/src/lib/__test__/Gradle.test.ts +++ b/packages/react-native-cli/src/lib/__test__/Gradle.test.ts @@ -1,4 +1,4 @@ -import { getSuggestedBugsnagGradleVersion, modifyAppBuildGradle, modifyRootBuildGradle, enableReactNativeMappings } from '../Gradle' +import { getSuggestedBugsnagGradleVersion, modifyAppBuildGradle, modifyRootBuildGradle, checkReactNativeMappings, addUploadEndpoint, addBuildEndpoint } from '../Gradle' import logger from '../../Logger' import path from 'path' import { promises as fs } from 'fs' @@ -152,9 +152,9 @@ test('modifyAppBuildGradle(): passes on unknown errors', async () => { await expect(modifyAppBuildGradle('/random/path', logger)).rejects.toThrowError('Unknown error') }) -test('enableReactNativeMappings(): success without initial bugsnag config', async () => { +test('checkReactNativeMappings(): success without initial bugsnag config', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before.gradle')) - const expected = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings.gradle')) + const expected = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-no-mappings.gradle')) const readFileMock = fs.readFile as jest.MockedFunction readFileMock.mockResolvedValue(buildGradle) @@ -166,13 +166,14 @@ test('enableReactNativeMappings(): success without initial bugsnag config', asyn expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', undefined, undefined, logger) + await checkReactNativeMappings('/random/path', logger) expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', expected, 'utf8') + expect(writeFileMock).not.toHaveBeenCalled() + expect(buildGradle).toStrictEqual(expected) }) -test('enableReactNativeMappings(): success with initial bugsnag config', async () => { +test('checkReactNativeMappings(): success with initial bugsnag config', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-bugsnag-config.gradle')) const expected = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-bugsnag-config.gradle')) @@ -180,19 +181,21 @@ test('enableReactNativeMappings(): success with initial bugsnag config', async ( readFileMock.mockResolvedValue(buildGradle) const writeFileMock = fs.writeFile as jest.MockedFunction + writeFileMock.mockImplementation((file, contents, encoding) => { expect(file).toBe('/random/path/android/app/build.gradle') expect(contents).toBe(expected) expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', undefined, undefined, logger) + await checkReactNativeMappings('/random/path', logger) expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', expected, 'utf8') + expect(writeFileMock).not.toHaveBeenCalled() + expect(buildGradle).toStrictEqual(expected) }) -test('enableReactNativeMappings(): success with empty initial bugsnag config', async () => { +test('checkReactNativeMappings(): success with empty initial bugsnag config', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-empty-bugsnag-config.gradle')) const expected = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-empty-bugsnag-config.gradle')) @@ -206,13 +209,14 @@ test('enableReactNativeMappings(): success with empty initial bugsnag config', a expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', undefined, undefined, logger) + await checkReactNativeMappings('/random/path', logger) expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', expected, 'utf8') + expect(writeFileMock).not.toHaveBeenCalled() + expect(buildGradle).toStrictEqual(expected) }) -test('enableReactNativeMappings(): failure mappings already enabled', async () => { +test('checkReactNativeMappings(): failure mappings already enabled', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-mappings.gradle')) const expected = buildGradle @@ -226,61 +230,27 @@ test('enableReactNativeMappings(): failure mappings already enabled', async () = expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', undefined, undefined, logger) + await checkReactNativeMappings('/random/path', logger) expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith('Value already found in file, skipping.') }) -test('enableReactNativeMappings(): failure gradle file not found', async () => { +test('checkReactNativeMappings(): failure gradle file not found', async () => { const readFileMock = fs.readFile as jest.MockedFunction readFileMock.mockRejectedValue(await generateNotFoundError()) const writeFileMock = fs.writeFile as jest.MockedFunction writeFileMock.mockResolvedValue() - await enableReactNativeMappings('/random/path', undefined, undefined, logger) - - expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining( - "A gradle file was not found at the expected location and so couldn't be updated automatically." - )) -}) - -test('enableReactNativeMappings(): failure pattern not found', async () => { - const readFileMock = fs.readFile as jest.MockedFunction - readFileMock.mockRejectedValue(new Error('Pattern not found')) - - const writeFileMock = fs.writeFile as jest.MockedFunction - writeFileMock.mockResolvedValue() - - await enableReactNativeMappings('/random/path', undefined, undefined, logger) - - expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining( - "The gradle file was in an unexpected format and so couldn't be updated automatically." - )) -}) - -test('enableReactNativeMappings(): failure unexpected error', async () => { - const error = new Error('oops!') - - const readFileMock = fs.readFile as jest.MockedFunction - readFileMock.mockRejectedValue(error) - - const writeFileMock = fs.writeFile as jest.MockedFunction - writeFileMock.mockResolvedValue() - - await expect(enableReactNativeMappings('/random/path', undefined, undefined, logger)).rejects.toThrow(error) + await checkReactNativeMappings('/random/path', logger) expect(readFileMock).toHaveBeenCalledWith('/random/path/android/app/build.gradle', 'utf8') expect(writeFileMock).not.toHaveBeenCalled() + expect(logger.warn).not.toHaveBeenCalled() }) -test('enableReactNativeMappings(): success without initial bugsnag config and custom upload endpoint', async () => { +test('addUploadEndpoint(): success without initial bugsnag config and custom upload endpoint', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before.gradle')) const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings.gradle')) const expectedUploadEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-upload-endpoint.gradle')) @@ -302,7 +272,8 @@ test('enableReactNativeMappings(): success without initial bugsnag config and cu expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', 'https://upload.example.com', undefined, logger) + await checkReactNativeMappings('/random/path', logger) + await addUploadEndpoint('/random/path', 'https://upload.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') @@ -311,7 +282,7 @@ test('enableReactNativeMappings(): success without initial bugsnag config and cu expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedUploadEndpoint, 'utf8') }) -test('enableReactNativeMappings(): success with initial bugsnag config and custom upload endpoint', async () => { +test('addUploadEndpoint(): success with initial bugsnag config and custom upload endpoint', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-bugsnag-config.gradle')) const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-bugsnag-config.gradle')) const expectedUploadEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-upload-endpoint-and-bugsnag-config.gradle')) @@ -333,16 +304,17 @@ test('enableReactNativeMappings(): success with initial bugsnag config and custo expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', 'https://upload.example.com', undefined, logger) + await addUploadEndpoint('/random/path', 'https://upload.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedMappings, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedUploadEndpoint, 'utf8') + expect(writeFileMock).not.toHaveBeenCalled() + expect(buildGradle).toStrictEqual(expectedMappings) + expect(buildGradle).toStrictEqual(expectedUploadEndpoint) }) -test('enableReactNativeMappings(): success with initial bugsnag config and custom build endpoint', async () => { +test('addBuildEndpoint(): success with initial bugsnag config and custom build endpoint', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-bugsnag-config.gradle')) const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-bugsnag-config.gradle')) const expectedBuildEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-build-endpoint-and-bugsnag-config.gradle')) @@ -364,18 +336,19 @@ test('enableReactNativeMappings(): success with initial bugsnag config and custo expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', undefined, 'https://build.example.com', logger) + await addBuildEndpoint('/random/path', 'https://build.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedMappings, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedBuildEndpoint, 'utf8') + expect(writeFileMock).not.toHaveBeenCalled() + expect(buildGradle).toStrictEqual(expectedMappings) + expect(buildGradle).toStrictEqual(expectedBuildEndpoint) }) -test('enableReactNativeMappings(): success with empty initial bugsnag config and custom upload endpoint', async () => { +test('addUploadEndpoint(): success with empty initial bugsnag config and custom upload endpoint', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-empty-bugsnag-config.gradle')) - const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-empty-bugsnag-config.gradle')) + const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-upload-endpoint-and-empty-bugsnag-config.gradle')) const expectedUploadEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-upload-endpoint-and-empty-bugsnag-config.gradle')) const readFileMock = fs.readFile as jest.MockedFunction @@ -395,18 +368,18 @@ test('enableReactNativeMappings(): success with empty initial bugsnag config and expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', 'https://upload.example.com', undefined, logger) + await addUploadEndpoint('/random/path', 'https://upload.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedMappings, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedUploadEndpoint, 'utf8') + expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedUploadEndpoint, 'utf8') }) -test('enableReactNativeMappings(): success with empty initial bugsnag config and custom build endpoint', async () => { +test('addBuildEndpoint(): success with empty initial bugsnag config and custom build endpoint', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-empty-bugsnag-config.gradle')) - const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-empty-bugsnag-config.gradle')) + const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-build-endpoint-and-empty-bugsnag-config.gradle')) const expectedBuildEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-build-endpoint-and-empty-bugsnag-config.gradle')) const readFileMock = fs.readFile as jest.MockedFunction @@ -426,16 +399,16 @@ test('enableReactNativeMappings(): success with empty initial bugsnag config and expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', undefined, 'https://build.example.com', logger) + await addBuildEndpoint('/random/path', 'https://build.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedMappings, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedBuildEndpoint, 'utf8') + expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedBuildEndpoint, 'utf8') }) -test('enableReactNativeMappings(): success with initial bugsnag config and custom endpoints', async () => { +test('addUploadEndpoint() and addBuildEndpoint(): success with initial bugsnag config and custom endpoints', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before-with-bugsnag-config.gradle')) const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-bugsnag-config.gradle')) const expectedUploadEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-upload-endpoint-and-bugsnag-config.gradle')) @@ -463,18 +436,20 @@ test('enableReactNativeMappings(): success with initial bugsnag config and custo expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', 'https://upload.example.com', 'https://build.example.com', logger) + await addUploadEndpoint('/random/path', 'https://upload.example.com', logger) + await addBuildEndpoint('/random/path', 'https://build.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(3, '/random/path/android/app/build.gradle', 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedMappings, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedUploadEndpoint, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(3, '/random/path/android/app/build.gradle', expectedFinal, 'utf8') + expect(writeFileMock).not.toHaveBeenCalled() + expect(buildGradle).toStrictEqual(expectedMappings) + expect(buildGradle).toStrictEqual(expectedUploadEndpoint) + expect(buildGradle).toStrictEqual(expectedFinal) }) -test('enableReactNativeMappings(): success without initial bugsnag config and custom endpoints', async () => { +test('addUploadEndpoint() and addBuildEndpoint(: success without initial bugsnag config and custom endpoints', async () => { const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-before.gradle')) const expectedMappings = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings.gradle')) const expectedUploadEndpoint = await loadFixture(path.join(__dirname, 'fixtures', 'app-build-after-with-mappings-and-upload-endpoint.gradle')) @@ -492,25 +467,20 @@ test('enableReactNativeMappings(): success without initial bugsnag config and cu expect(file).toBe('/random/path/android/app/build.gradle') expect(contents).toBe(expectedMappings) expect(encoding).toBe('utf8') - }).mockImplementationOnce((file, contents, encoding) => { - expect(file).toBe('/random/path/android/app/build.gradle') - expect(contents).toBe(expectedUploadEndpoint) - expect(encoding).toBe('utf8') }).mockImplementationOnce((file, contents, encoding) => { expect(file).toBe('/random/path/android/app/build.gradle') expect(contents).toBe(expectedFinal) expect(encoding).toBe('utf8') }) - await enableReactNativeMappings('/random/path', 'https://upload.example.com', 'https://build.example.com', logger) + await addUploadEndpoint('/random/path', 'https://upload.example.com', logger) + await addBuildEndpoint('/random/path', 'https://build.example.com', logger) expect(readFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', 'utf8') expect(readFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', 'utf8') - expect(readFileMock).toHaveBeenNthCalledWith(3, '/random/path/android/app/build.gradle', 'utf8') expect(writeFileMock).toHaveBeenNthCalledWith(1, '/random/path/android/app/build.gradle', expectedMappings, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedUploadEndpoint, 'utf8') - expect(writeFileMock).toHaveBeenNthCalledWith(3, '/random/path/android/app/build.gradle', expectedFinal, 'utf8') + expect(writeFileMock).toHaveBeenNthCalledWith(2, '/random/path/android/app/build.gradle', expectedFinal, 'utf8') }) test('getSuggestedBugsnagGradleVersion(): success', async () => { diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-both-endpoints.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-both-endpoints.gradle index a5154824fa..e115815166 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-both-endpoints.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-both-endpoints.gradle @@ -219,7 +219,6 @@ task copyDownloadableDepsToLibs(type: Copy) { apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) bugsnag { - uploadReactNativeMappings = true endpoint = "https://upload.example.com" diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-bugsnag-config.gradle index ac4c457c95..4a04a4bc92 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-bugsnag-config.gradle @@ -222,5 +222,7 @@ bugsnag { config = yes options = set to things - uploadReactNativeMappings = true + endpoint = "https://upload.example.com" + + releasesEndpoint = "https://build.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-empty-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-empty-bugsnag-config.gradle index 7d3d8f8b9e..959f528b86 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-empty-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-empty-bugsnag-config.gradle @@ -219,6 +219,4 @@ task copyDownloadableDepsToLibs(type: Copy) { apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) bugsnag { - - uploadReactNativeMappings = true } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-upload-endpoint.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-upload-endpoint.gradle index 0b2410a1e5..c723991ab4 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-upload-endpoint.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-and-upload-endpoint.gradle @@ -219,7 +219,6 @@ task copyDownloadableDepsToLibs(type: Copy) { apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) bugsnag { - uploadReactNativeMappings = true endpoint = "https://upload.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-both-endpoints-and-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-both-endpoints-and-bugsnag-config.gradle index 1764b74ae1..4a04a4bc92 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-both-endpoints-and-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-both-endpoints-and-bugsnag-config.gradle @@ -222,8 +222,6 @@ bugsnag { config = yes options = set to things - uploadReactNativeMappings = true - endpoint = "https://upload.example.com" releasesEndpoint = "https://build.example.com" diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-bugsnag-config.gradle index ea46301ca0..4a04a4bc92 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-bugsnag-config.gradle @@ -222,7 +222,7 @@ bugsnag { config = yes options = set to things - uploadReactNativeMappings = true + endpoint = "https://upload.example.com" releasesEndpoint = "https://build.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-empty-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-empty-bugsnag-config.gradle index 9592eac5e3..f03d5f7bb1 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-empty-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-build-endpoint-and-empty-bugsnag-config.gradle @@ -220,7 +220,5 @@ apply from: file("../../node_modules/@react-native-community/cli-platform-androi bugsnag { - uploadReactNativeMappings = true - releasesEndpoint = "https://build.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-bugsnag-config.gradle index a429f7c1d5..4a04a4bc92 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-bugsnag-config.gradle @@ -222,7 +222,7 @@ bugsnag { config = yes options = set to things - uploadReactNativeMappings = true - endpoint = "https://upload.example.com" + + releasesEndpoint = "https://build.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-empty-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-empty-bugsnag-config.gradle index aafbc63214..c723991ab4 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-empty-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings-upload-endpoint-and-empty-bugsnag-config.gradle @@ -220,7 +220,5 @@ apply from: file("../../node_modules/@react-native-community/cli-platform-androi bugsnag { - uploadReactNativeMappings = true - endpoint = "https://upload.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings.gradle index b5487fbea4..959f528b86 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-mappings.gradle @@ -219,5 +219,4 @@ task copyDownloadableDepsToLibs(type: Copy) { apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) bugsnag { - uploadReactNativeMappings = true } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-no-mappings.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-no-mappings.gradle new file mode 100644 index 0000000000..675cca427d --- /dev/null +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-after-with-no-mappings.gradle @@ -0,0 +1,219 @@ +apply plugin: "com.android.application" + +import com.android.build.OutputFile + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "../../node_modules/react-native/react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation. If none specified and + * // "index.android.js" exists, it will be used. Otherwise "index.js" is + * // default. Can be overridden with ENTRY_FILE environment variable. + * entryFile: "index.android.js", + * + * // https://reactnative.dev/docs/performance#enable-the-ram-format + * bundleCommand: "ram-bundle", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // whether to disable dev mode in custom build variants (by default only disabled in release) + * // for example: to disable dev mode in the staging build type (if configured) + * devDisabledInStaging: true, + * // The configuration property can be in the following formats + * // 'devDisabledIn${productFlavor}${buildType}' + * // 'devDisabledIn${buildType}' + * + * // the root of your project, i.e. where "package.json" lives + * root: "../../", + * + * // where to put the JS bundle asset in debug mode + * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", + * + * // where to put the JS bundle asset in release mode + * jsBundleDirRelease: "$buildDir/intermediates/assets/release", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in debug mode + * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in release mode + * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", + * + * // by default the gradle tasks are skipped if none of the JS files or assets change; this means + * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to + * // date; if you have any other folders that you want to ignore for performance reasons (gradle + * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ + * // for example, you might want to remove it from here. + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"], + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] + * ] + */ + +project.ext.react = [ + enableHermes: true, // clean and rebuild if changing +] + +apply from: "../../node_modules/react-native/react.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = true + +/** + * The preferred build flavor of JavaScriptCore. + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +/** + * Whether to enable the Hermes VM. + * + * This should be set on project.ext.react and mirrored here. If it is not set + * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode + * and the benefits of using Hermes will therefore be sharply reduced. + */ +def enableHermes = project.ext.react.get("enableHermes", false); + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + applicationId "com.reactnativetest" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" + } + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // https://developer.android.com/studio/build/configure-apk-splits.html + def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + } + + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + //noinspection GradleDynamicVersion + implementation "com.facebook.react:react-native:+" // From node_modules + + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { + exclude group:'com.facebook.fbjni' + } + + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group:'com.facebook.flipper' + exclude group:'com.squareup.okhttp3', module:'okhttp' + } + + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { + exclude group:'com.facebook.flipper' + } + + if (enableHermes) { + def hermesPath = "../../node_modules/hermes-engine/android/"; + debugImplementation files(hermesPath + "hermes-debug.aar") + releaseImplementation files(hermesPath + "hermes-release.aar") + } else { + implementation jscFlavor + } +} + +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' +} + +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-bugsnag-config.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-bugsnag-config.gradle index d40d08de24..4a04a4bc92 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-bugsnag-config.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-bugsnag-config.gradle @@ -221,4 +221,8 @@ apply from: file("../../node_modules/@react-native-community/cli-platform-androi bugsnag { config = yes options = set to things + + endpoint = "https://upload.example.com" + + releasesEndpoint = "https://build.example.com" } diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-mappings.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-mappings.gradle index b5487fbea4..959f528b86 100644 --- a/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-mappings.gradle +++ b/packages/react-native-cli/src/lib/__test__/fixtures/app-build-before-with-mappings.gradle @@ -219,5 +219,4 @@ task copyDownloadableDepsToLibs(type: Copy) { apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) bugsnag { - uploadReactNativeMappings = true } diff --git a/scripts/react-native-cli-helper.js b/scripts/react-native-cli-helper.js index 1b2ee6e13e..85547a01ca 100644 --- a/scripts/react-native-cli-helper.js +++ b/scripts/react-native-cli-helper.js @@ -48,6 +48,10 @@ module.exports = { common.run('./gradlew assembleRelease', true) } + common.changeDir(`${destFixtures}/${rnVersion}`) + const bugsnagCliCommand = './node_modules/.bin/bugsnag-cli upload react-native-android --upload-api-root-url=http://localhost:9339 --overwrite' + common.run(bugsnagCliCommand, true) + // Finally, copy the APK back to the host common.run(`mkdir -p ${baseDir}/build`) fs.copyFileSync(`${destFixtures}/${rnVersion}/android/app/build/outputs/apk/release/app-release.apk`, diff --git a/test/react-native-cli/Gemfile b/test/react-native-cli/Gemfile index c703a18be5..840eaa18fd 100644 --- a/test/react-native-cli/Gemfile +++ b/test/react-native-cli/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' gem 'cocoapods' -gem 'bugsnag-maze-runner', '~>8.4.0' +gem 'bugsnag-maze-runner', '~>8.5.0' # Use a branch of Maze Runner #gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'tms/use-maze-check' diff --git a/test/react-native-cli/Gemfile.lock b/test/react-native-cli/Gemfile.lock index f203f7f864..dde68cba10 100644 --- a/test/react-native-cli/Gemfile.lock +++ b/test/react-native-cli/Gemfile.lock @@ -24,7 +24,7 @@ GEM atomos (0.1.3) bugsnag (6.26.0) concurrent-ruby (~> 1.0) - bugsnag-maze-runner (8.4.0) + bugsnag-maze-runner (8.5.0) appium_lib (~> 12.0.0) appium_lib_core (~> 5.4.0) bugsnag (~> 6.24) @@ -141,7 +141,7 @@ GEM regexp_parser (~> 2.0) simpleidn (~> 0.2) uri_template (~> 0.7) - mime-types (3.5.0) + mime-types (3.5.1) mime-types-data (~> 3.2015) mime-types-data (3.2023.0808) mini_portile2 (2.8.4) @@ -203,8 +203,8 @@ PLATFORMS ruby DEPENDENCIES - bugsnag-maze-runner (~> 8.4.0) + bugsnag-maze-runner (~> 8.5.0) cocoapods BUNDLED WITH - 2.4.8 + 2.3.18 diff --git a/test/react-native-cli/features/build-app-tests/build-android-app.feature b/test/react-native-cli/features/build-app-tests/build-android-app.feature index c1b2b4091d..5fd46a45e2 100644 --- a/test/react-native-cli/features/build-app-tests/build-android-app.feature +++ b/test/react-native-cli/features/build-app-tests/build-android-app.feature @@ -2,12 +2,11 @@ Feature: Tests for building a React Native app (for Android only) that was initi Scenario: A CLI initialized React Native Android app invokes a source map upload When I build the Android app - And I wait to receive 2 builds + And I wait to receive 1 sourcemaps - Then the build is valid for the Build API - And I discard the oldest build + Then the sourcemap is valid for the Build API - Then the Content-Type header is valid multipart form-data - And the build payload field "apiKey" equals "1234567890ABCDEF1234567890ABCDEF" - And the build payload field "platform" equals "android" - And the build payload field "overwrite" equals "true" + Then the sourcemaps Content-Type header is valid multipart form-data + And the sourcemap payload field "apiKey" equals "1234567890ABCDEF1234567890ABCDEF" + And the sourcemap payload field "platform" equals "android" + And the sourcemap payload field "overwrite" equals "true" diff --git a/test/react-native-cli/features/cli-tests/automate-symbolication.feature b/test/react-native-cli/features/cli-tests/automate-symbolication.feature index 6e7f24763f..4cd487d120 100644 --- a/test/react-native-cli/features/cli-tests/automate-symbolication.feature +++ b/test/react-native-cli/features/cli-tests/automate-symbolication.feature @@ -25,13 +25,18 @@ Scenario: successfully modify project """ And I wait for the current stdout line to match the regex "Hit enter to continue" When I input a return interactively - And I wait for the current stdout line to match the regex "Do you want to automatically upload JavaScript source maps as part of the Gradle build\?" + And I wait for the current stdout line to match the regex "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps\?" When I input a return interactively And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" When I input a return interactively - Then I wait for the shell to output a match for the regex "@bugsnag/source-maps dependency is installed" to stdout + And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/cli hit enter, otherwise type the version you want" + When I input a return interactively + Then I wait for the shell to output a match for the regex "@bugsnag/cli dependency is installed" to stdout + When RN version is 0.68 or lower dismiss the warning message + And I wait for the current stdout line to match the regex "Do you want to add an NPM task to your package.json that you can run to upload Android source maps\?" + When I input "n" interactively Then the last interactive command exited successfully - And bugsnag source maps library is in the package.json file + And bugsnag cli library is in the package.json file And the iOS build has been modified to upload source maps And the Bugsnag Android Gradle plugin is not installed And the Android build has been modified to upload source maps @@ -61,13 +66,18 @@ Scenario: successfully modify project, choosing source-maps version """ And I wait for the current stdout line to match the regex "Hit enter to continue" When I input a return interactively - And I wait for the current stdout line to match the regex "Do you want to automatically upload JavaScript source maps as part of the Gradle build\?" + And I wait for the current stdout line to match the regex "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps\?" When I input a return interactively And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" - When I input "1.0.0-beta.1" interactively - Then I wait for the shell to output a match for the regex "@bugsnag/source-maps dependency is installed" to stdout + When I input a return interactively + And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/cli hit enter, otherwise type the version you want" + When I input "1.1.8" interactively + Then I wait for the shell to output a match for the regex "@bugsnag/cli dependency is installed" to stdout + When RN version is 0.68 or lower dismiss the warning message + And I wait for the current stdout line to match the regex "Do you want to add an NPM task to your package.json that you can run to upload Android source maps\?" + When I input "n" interactively Then the last interactive command exited successfully - And bugsnag source maps library version "^1.0.0-beta.1" is in the package.json file + And bugsnag cli library version "^1.1.8" is in the package.json file And the iOS build has been modified to upload source maps And the Bugsnag Android Gradle plugin is not installed And the Android build has been modified to upload source maps @@ -101,13 +111,18 @@ Scenario: successfully modify project with custom endpoints """ And I wait for the current stdout line to match the regex "Hit enter to continue" When I input a return interactively - And I wait for the current stdout line to match the regex "Do you want to automatically upload JavaScript source maps as part of the Gradle build\?" + And I wait for the current stdout line to match the regex "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps\?" When I input a return interactively And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" When I input a return interactively - Then I wait for the shell to output a match for the regex "@bugsnag/source-maps dependency is installed" to stdout + And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/cli hit enter, otherwise type the version you want" + When I input a return interactively + Then I wait for the shell to output a match for the regex "@bugsnag/cli dependency is installed" to stdout + When RN version is 0.68 or lower dismiss the warning message + And I wait for the current stdout line to match the regex "Do you want to add an NPM task to your package.json that you can run to upload Android source maps\?" + When I input "n" interactively Then the last interactive command exited successfully - And bugsnag source maps library is in the package.json file + And bugsnag cli library is in the package.json file And the iOS build has been modified to upload source maps to "https://upload.example.com" And the Bugsnag Android Gradle plugin is not installed And the Android build has been modified to upload source maps to "https://upload.example.com" @@ -138,7 +153,7 @@ Scenario: opt not to modify the Android project """ And I wait for the current stdout line to match the regex "Hit enter to continue" When I input a return interactively - And I wait for the current stdout line to match the regex "Do you want to automatically upload JavaScript source maps as part of the Gradle build\?" + And I wait for the current stdout line to match the regex "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps\?" When I input "n" interactively And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" When I input a return interactively @@ -174,13 +189,16 @@ Scenario: opt not to modify the iOS project """ And I wait for the current stdout line to match the regex "Hit enter to continue" When I input a return interactively - And I wait for the current stdout line to match the regex "Do you want to automatically upload JavaScript source maps as part of the Gradle build\?" + And I wait for the current stdout line to match the regex "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps\?" When I input "y" interactively - And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" + And I wait for the current stdout line to match the regex "If you want the latest version of @bugsnag/cli hit enter, otherwise type the version you want" When I input a return interactively - Then I wait for the shell to output a match for the regex "@bugsnag/source-maps dependency is installed" to stdout + Then I wait for the shell to output a match for the regex "@bugsnag/cli dependency is installed" to stdout + When RN version is 0.68 or lower dismiss the warning message + And I wait for the current stdout line to match the regex "Do you want to add an NPM task to your package.json that you can run to upload Android source maps\?" + When I input "n" interactively Then the last interactive command exited successfully - And bugsnag source maps library is in the package.json file + And bugsnag cli library is in the package.json file And the iOS build has not been modified to upload source maps And the Bugsnag Android Gradle plugin is not installed And the Android build has been modified to upload source maps @@ -210,7 +228,7 @@ Scenario: opt not to modify either project """ And I wait for the current stdout line to match the regex "Hit enter to continue" When I input a return interactively - And I wait for the current stdout line to match the regex "Do you want to automatically upload JavaScript source maps as part of the Gradle build\?" + And I wait for the current stdout line to match the regex "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps\?" When I input "n" interactively And I wait for the current stdout line to match the regex "\/app #" Then the last interactive command exited successfully diff --git a/test/react-native-cli/features/fixtures/rn-cli-init-android.sh b/test/react-native-cli/features/fixtures/rn-cli-init-android.sh index 40c827158a..fa4ce730c5 100755 --- a/test/react-native-cli/features/fixtures/rn-cli-init-android.sh +++ b/test/react-native-cli/features/fixtures/rn-cli-init-android.sh @@ -3,6 +3,19 @@ set timeout -1 set notifierVersion [lindex $argv 0]; set rnVersion [lindex $argv 1]; +set rnVersionInt "" +set substringToTrim ".expo.ejected" + +# Extract the substring starting from the third character +set rnVersionInt [string range $rnVersion 2 end] + +# Replace underscore (_) with a period (.) +set rnVersionInt2 [string map {_ .} $rnVersionInt] + +set rnVersionInt3 [string map [list $substringToTrim ""] $rnVersionInt2] + +# Convert float string to float value using bc +regsub -all {^0+} $rnVersionInt3 "" $rnVersionInt3 puts "Using notifier version: $notifierVersion" puts "Using React Native version: $rnVersion" @@ -43,10 +56,21 @@ send -- n expect "This will enable you to see full native stacktraces. It can't be done automatically." send -- \r -expect "Do you want to automatically upload JavaScript source maps as part of the Gradle build?" +expect "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps?" send -- y -expect "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" +expect "If you want the latest version of @bugsnag/cli hit enter, otherwise type the version you want" send -- latest\r +if {[expr $rnVersionInt3 < 0.68]} { + expect "or follow the manual integration instructions in our online docs: https://docs.bugsnag.com/platforms/react-native/react-native/manual-setup/')" + send -- \r +} + +expect "Do you want to add an NPM task to your package.json that you can run to upload Android source maps?" +send -- \r + +expect "See https://docs.bugsnag.com/platforms/react-native/react-native/showing-full-stacktraces for details." +send -- \r + expect eof diff --git a/test/react-native-cli/features/fixtures/rn-cli-init-ios.sh b/test/react-native-cli/features/fixtures/rn-cli-init-ios.sh index 3ef39e4707..09ae24e5bb 100755 --- a/test/react-native-cli/features/fixtures/rn-cli-init-ios.sh +++ b/test/react-native-cli/features/fixtures/rn-cli-init-ios.sh @@ -43,7 +43,7 @@ send -- y expect "This will enable you to see full native stacktraces. It can't be done automatically." send -- \r -expect "Do you want to automatically upload JavaScript source maps as part of the Gradle build?" +expect "Do you want to install the BugSnag CLI to allow you to upload JavaScript source maps?" send -- n expect "If you want the latest version of @bugsnag/source-maps hit enter, otherwise type the version you want" diff --git a/test/react-native-cli/features/steps/react-native-source-maps-steps.rb b/test/react-native-cli/features/steps/react-native-source-maps-steps.rb new file mode 100644 index 0000000000..d6ec593a8e --- /dev/null +++ b/test/react-native-cli/features/steps/react-native-source-maps-steps.rb @@ -0,0 +1,8 @@ +# Tests whether the top-most payload is valid for the Bugsnag build API +# APIKey fields and headers are tested against the '$api_key' global variable +Then('the sourcemap is valid for the Build API') do + steps %( + And the sourcemap payload field "apiKey" equals "#{$api_key}" + And the sourcemap payload field "appVersion" is not null + ) +end diff --git a/test/react-native-cli/features/steps/steps.rb b/test/react-native-cli/features/steps/steps.rb index e22c5c0046..ac13e270aa 100644 --- a/test/react-native-cli/features/steps/steps.rb +++ b/test/react-native-cli/features/steps/steps.rb @@ -94,6 +94,13 @@ def parse_package_json Maze.check.include(json['devDependencies'], '@bugsnag/source-maps') end +Then('bugsnag cli library is in the package.json file') do + json = parse_package_json + + Maze.check.include(json, 'devDependencies') + Maze.check.include(json['devDependencies'], '@bugsnag/cli') +end + Then('bugsnag source maps library version {string} is in the package.json file') do |expected| json = parse_package_json @@ -102,6 +109,15 @@ def parse_package_json Maze.check.equal(json['devDependencies']['@bugsnag/source-maps'], expected) end +Then('bugsnag cli library version {string} is in the package.json file') do |expected| + json = parse_package_json + + Maze.check.include(json, 'devDependencies') + Maze.check.include(json['devDependencies'], '@bugsnag/cli') + Maze.check.equal(json['devDependencies']['@bugsnag/cli'], expected) +end + + Then('bugsnag source maps library is not in the package.json file') do json = parse_package_json @@ -424,3 +440,35 @@ def parse_xml_file(path) actual = Maze::Server.builds.current[:request]['content-type'] Maze.check.match(expected, actual) end + +Then('the sourcemaps Content-Type header is valid multipart form-data') do + expected = /^multipart\/form-data; boundary=([^;]+)/ + actual = Maze::Server.sourcemaps.current[:request]['content-type'] + Maze.check.match(expected, actual) +end + +def rn_version_less_than(string_value, float_value) + stripped_string = string_value[2..-1] + replaced_string = stripped_string.gsub("_", ".") + converted_float = replaced_string.to_f + return converted_float < float_value +end + +When('RN version is 0.68 or lower dismiss the warning message') do + rn_version_lower = rn_version_less_than(ENV['REACT_NATIVE_VERSION'], 0.69) + case rn_version_lower + when true + steps %Q{ + And I wait for the interactive shell to output the following lines in stdout + """ + You are running a version of React Native that we cannot automatically integrate with due to known issues with the build when Hermes is enabled. + + If you cannot upgrade to a later version of React Native (version 0.68 or above), you can use an older version of this CLI (version 7.20.x or earlier) + + or follow the manual integration instructions in our online docs: https://docs.bugsnag.com/platforms/react-native/react-native/manual-setup/') + """ + And I wait for the current stdout line to match the regex "Hit enter to continue" + When I input a return interactively + } + end +end