@sentry/wizard 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/lib/Helper/Package.d.ts +1 -0
  3. package/dist/lib/Helper/Package.js +46 -0
  4. package/dist/lib/Helper/Package.js.map +1 -0
  5. package/dist/lib/Helper/PackageManager.d.ts +22 -0
  6. package/dist/lib/Helper/PackageManager.js +135 -0
  7. package/dist/lib/Helper/PackageManager.js.map +1 -0
  8. package/dist/lib/Helper/Wizard.js +2 -1
  9. package/dist/lib/Helper/Wizard.js.map +1 -1
  10. package/dist/lib/Helper/__tests__/MergeConfig.js +25 -14
  11. package/dist/lib/Helper/__tests__/MergeConfig.js.map +1 -1
  12. package/dist/lib/Steps/Integrations/NextJs.d.ts +0 -5
  13. package/dist/lib/Steps/Integrations/NextJs.js +6 -85
  14. package/dist/lib/Steps/Integrations/NextJs.js.map +1 -1
  15. package/dist/lib/Steps/Integrations/ReactNative.d.ts +7 -0
  16. package/dist/lib/Steps/Integrations/ReactNative.js +120 -51
  17. package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
  18. package/dist/lib/Steps/Integrations/__tests__/ReactNative.js +42 -0
  19. package/dist/lib/Steps/Integrations/__tests__/ReactNative.js.map +1 -1
  20. package/dist/lib/__tests__/Setup.js +15 -0
  21. package/dist/lib/__tests__/Setup.js.map +1 -1
  22. package/lib/Helper/Package.ts +61 -0
  23. package/lib/Helper/PackageManager.ts +64 -0
  24. package/lib/Helper/Wizard.ts +1 -1
  25. package/lib/Helper/__tests__/MergeConfig.ts +36 -20
  26. package/lib/Steps/Integrations/NextJs.ts +8 -108
  27. package/lib/Steps/Integrations/ReactNative.ts +108 -37
  28. package/lib/Steps/Integrations/__tests__/ReactNative.ts +34 -0
  29. package/lib/__tests__/Setup.ts +23 -0
  30. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ReactNative.js","sourceRoot":"","sources":["../../../../../lib/Steps/Integrations/__tests__/ReactNative.ts"],"names":[],"mappings":"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","sourcesContent":["jest.mock('../../../Helper/Logging.ts'); // We mock logging to not pollute the output\nimport * as fs from 'fs';\nimport { Answers } from 'inquirer';\nimport * as path from 'path';\nimport * as process from 'process';\nimport * as rimraf from 'rimraf';\n\nimport { Args, Integration, Platform } from '../../../Constants';\nimport { ReactNative } from '../ReactNative';\n\nconst testDir = 'rn-test';\nconst iosIndexJs = 'index.ios.js';\nconst appTsx = 'src/App.tsx';\nconst appBuildGradle = 'android/app/build.gradle';\n\nconst dummyJsContent = 'import React from \"react\";\\n';\nconst dummyAppBuildGradleContent = 'apply plugin: \"com.facebook.react\"\\n\\nandroid {\\n}\\n';\n\nconst testArgs = {\n debug: false,\n integration: Integration.reactNative,\n platform: [Platform.ios],\n quiet: true,\n skipConnect: true,\n uninstall: false,\n url: 'https://not.used',\n};\n\nconst mockIosAnswers: Answers = {\n shouldConfigurePlatforms: { 'ios': true },\n config: {\n dsn: {\n public: 'dns.public.com',\n },\n },\n};\n\nconst mockAndroidAnswers: Answers = {\n shouldConfigurePlatforms: { 'android': true },\n config: {\n dsn: {\n public: 'dns.public.com',\n },\n },\n};\n\ndescribe('ReactNative', () => {\n\n const defaultCwd = process.cwd();\n\n beforeEach(() => {\n rimraf.sync(testDir);\n fs.mkdirSync(testDir);\n process.chdir(testDir);\n fs.writeFileSync(iosIndexJs, dummyJsContent);\n fs.mkdirSync(path.dirname(appTsx), { recursive: true });\n fs.writeFileSync(appTsx, dummyJsContent);\n fs.mkdirSync(path.dirname(appBuildGradle), { recursive: true });\n fs.writeFileSync(appBuildGradle, dummyAppBuildGradleContent);\n });\n\n afterEach(() => {\n process.chdir(defaultCwd);\n rimraf.sync(testDir);\n });\n\n test('patches js files', async () => {\n const project = new ReactNative(testArgs as Args);\n await project.emit(mockIosAnswers);\n\n const patchedIosIndexJs = fs.readFileSync(iosIndexJs, 'utf8');\n const patchedAppTsx = fs.readFileSync(appTsx, 'utf8');\n const expectedPatch = 'import React from \"react\";\\n\\n' +\n 'import * as Sentry from \\'@sentry/react-native\\';\\n\\n' +\n 'Sentry.init({ \\n' +\n ' dsn: \\'dns.public.com\\', \\n' +\n '});\\n\\n';\n expect(patchedIosIndexJs).toEqual(expectedPatch);\n expect(patchedAppTsx).toEqual(expectedPatch);\n });\n\n test('patches android app build gradle file', async () => {\n const project = new ReactNative(testArgs as Args);\n await project.emit(mockAndroidAnswers);\n\n const patchedAppBuildGradle = fs.readFileSync(appBuildGradle, 'utf8');\n const expectedPatch = 'apply plugin: \"com.facebook.react\"\\n\\n' +\n 'apply from: \"../../node_modules/@sentry/react-native/sentry.gradle\"\\n' +\n 'android {\\n}\\n';\n expect(patchedAppBuildGradle).toEqual(expectedPatch);\n });\n});\n"]}
1
+ {"version":3,"file":"ReactNative.js","sourceRoot":"","sources":["../../../../../lib/Steps/Integrations/__tests__/ReactNative.ts"],"names":[],"mappings":"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","sourcesContent":["jest.mock('../../../Helper/Logging.ts'); // We mock logging to not pollute the output\njest.mock('child_process');\nimport * as child_process from 'child_process';\nimport * as fs from 'fs';\nimport { Answers } from 'inquirer';\nimport * as path from 'path';\nimport * as process from 'process';\nimport * as rimraf from 'rimraf';\n\nimport { Args, Integration, Platform } from '../../../Constants';\nimport { ReactNative } from '../ReactNative';\n\nconst testDir = 'rn-test';\nconst iosIndexJs = 'index.ios.js';\nconst appTsx = 'src/App.tsx';\nconst appBuildGradle = 'android/app/build.gradle';\nconst yarnLock = 'yarn.lock';\n\nconst dummyJsContent = 'import React from \"react\";\\n';\nconst dummyAppBuildGradleContent = 'apply plugin: \"com.facebook.react\"\\n\\nandroid {\\n}\\n';\n\nconst testArgs = {\n debug: false,\n integration: Integration.reactNative,\n platform: [Platform.ios],\n quiet: true,\n skipConnect: true,\n uninstall: false,\n url: 'https://not.used',\n};\n\nconst mockIosAnswers: Answers = {\n shouldConfigurePlatforms: { 'ios': true },\n config: {\n dsn: {\n public: 'dns.public.com',\n },\n },\n};\n\nconst mockAndroidAnswers: Answers = {\n shouldConfigurePlatforms: { 'android': true },\n config: {\n dsn: {\n public: 'dns.public.com',\n },\n },\n};\n\nconst originalExec = child_process.exec;\n\nconst restoreExec = (): void => {\n (child_process as any).exec = originalExec;\n}\n\nconst mockExec = (): void => {\n (child_process.exec as unknown as jest.Mock)\n .mockImplementation((_command, callback) => callback(null, { stdout: '' }));\n}\n\ndescribe('ReactNative', () => {\n\n const defaultCwd = process.cwd();\n\n beforeEach(() => {\n rimraf.sync(testDir);\n fs.mkdirSync(testDir);\n process.chdir(testDir);\n fs.writeFileSync(iosIndexJs, dummyJsContent);\n fs.mkdirSync(path.dirname(appTsx), { recursive: true });\n fs.writeFileSync(appTsx, dummyJsContent);\n fs.mkdirSync(path.dirname(appBuildGradle), { recursive: true });\n fs.writeFileSync(appBuildGradle, dummyAppBuildGradleContent);\n fs.writeFileSync(yarnLock, '');\n mockExec();\n });\n\n afterEach(() => {\n restoreExec();\n process.chdir(defaultCwd);\n rimraf.sync(testDir);\n });\n\n test('patches js files', async () => {\n const project = new ReactNative(testArgs as Args);\n await project.emit(mockIosAnswers);\n\n const patchedIosIndexJs = fs.readFileSync(iosIndexJs, 'utf8');\n const patchedAppTsx = fs.readFileSync(appTsx, 'utf8');\n const expectedPatch = 'import React from \"react\";\\n\\n' +\n 'import * as Sentry from \\'@sentry/react-native\\';\\n\\n' +\n 'Sentry.init({ \\n' +\n ' dsn: \\'dns.public.com\\', \\n' +\n '});\\n\\n';\n expect(patchedIosIndexJs).toEqual(expectedPatch);\n expect(patchedAppTsx).toEqual(expectedPatch);\n });\n\n test('patches android app build gradle file', async () => {\n const project = new ReactNative(testArgs as Args);\n\n await project.emit(mockAndroidAnswers);\n\n const patchedAppBuildGradle = fs.readFileSync(appBuildGradle, 'utf8');\n const expectedPatch = 'apply plugin: \"com.facebook.react\"\\n\\n' +\n 'apply from: \"../../node_modules/@sentry/react-native/sentry.gradle\"\\n' +\n 'android {\\n}\\n';\n expect(patchedAppBuildGradle).toEqual(expectedPatch);\n });\n\n test('does install sentry sdk', async () => {\n const project = new ReactNative(testArgs as Args);\n\n await project.emit(mockIosAnswers);\n\n expect(child_process.exec).toHaveBeenCalledWith('yarn add @sentry/react-native', expect.anything());\n });\n\n test('executes pod install', async () => {\n const project = new ReactNative(testArgs as Args);\n\n await project.emit(mockIosAnswers);\n\n expect(child_process.exec).toHaveBeenCalledWith('npx --yes pod-install --non-interactive --quiet', expect.anything());\n });\n});\n"]}
@@ -1,9 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  jest.mock('../Helper/Logging'); // We mock logging to not pollute the output
4
+ jest.mock('child_process');
5
+ var child_process = require("child_process");
4
6
  var Constants_1 = require("../Constants");
5
7
  var Setup_1 = require("../Setup");
8
+ var originalExec = child_process.exec;
9
+ var restoreExec = function () {
10
+ child_process.exec = originalExec;
11
+ };
12
+ var mockExec = function () {
13
+ child_process.exec.mockImplementation(function (_command, callback) { return callback(null, { stdout: '' }); });
14
+ };
6
15
  describe('Wizard', function () {
16
+ beforeEach(function () {
17
+ mockExec();
18
+ });
19
+ afterEach(function () {
20
+ restoreExec();
21
+ });
7
22
  describe('React Native', function () {
8
23
  test('run', function () {
9
24
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -1 +1 @@
1
- {"version":3,"file":"Setup.js","sourceRoot":"","sources":["../../../lib/__tests__/Setup.ts"],"names":[],"mappings":";;AAAA,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,4CAA4C;AAC5E,0CAAqD;AACrD,kCAA+B;AAE/B,QAAQ,CAAC,QAAQ,EAAE;IACjB,QAAQ,CAAC,cAAc,EAAE;QACvB,IAAI,CAAC,KAAK,EAAE;YACV,mEAAmE;YACnE,MAAM,CACJ,WAAG,CAAC;gBACF,KAAK,EAAE,IAAI;gBACX,WAAW,EAAE,uBAAW,CAAC,WAAW;gBACpC,QAAQ,EAAE,CAAC,oBAAQ,CAAC,GAAG,EAAE,oBAAQ,CAAC,OAAO,CAAC;gBAC1C,WAAW,EAAE,IAAI;aAClB,CAAC,CACH,CAAC,UAAU,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["jest.mock('../Helper/Logging'); // We mock logging to not pollute the output\nimport { Integration, Platform } from '../Constants';\nimport { run } from '../Setup';\n\ndescribe('Wizard', () => {\n describe('React Native', () => {\n test('run', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n expect(\n run({\n quiet: true,\n integration: Integration.reactNative,\n platform: [Platform.ios, Platform.android],\n skipConnect: true,\n }),\n ).toBeTruthy();\n });\n });\n});\n"]}
1
+ {"version":3,"file":"Setup.js","sourceRoot":"","sources":["../../../lib/__tests__/Setup.ts"],"names":[],"mappings":";;AAAA,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,4CAA4C;AAC5E,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAC3B,6CAA+C;AAE/C,0CAAqD;AACrD,kCAA+B;AAE/B,IAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC;AAExC,IAAM,WAAW,GAAG;IACjB,aAAqB,CAAC,IAAI,GAAG,YAAY,CAAC;AAC7C,CAAC,CAAC;AAEF,IAAM,QAAQ,GAAG;IACb,aAAa,CAAC,IAA8B,CAAC,kBAAkB,CAC/D,UAAC,QAAQ,EAAE,QAAQ,IAAK,OAAA,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAA9B,CAA8B,CACvD,CAAC;AACJ,CAAC,CAAC;AAEF,QAAQ,CAAC,QAAQ,EAAE;IACjB,UAAU,CAAC;QACT,QAAQ,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC;QACR,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE;QACvB,IAAI,CAAC,KAAK,EAAE;YACV,mEAAmE;YACnE,MAAM,CACJ,WAAG,CAAC;gBACF,KAAK,EAAE,IAAI;gBACX,WAAW,EAAE,uBAAW,CAAC,WAAW;gBACpC,QAAQ,EAAE,CAAC,oBAAQ,CAAC,GAAG,EAAE,oBAAQ,CAAC,OAAO,CAAC;gBAC1C,WAAW,EAAE,IAAI;aAClB,CAAC,CACH,CAAC,UAAU,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["jest.mock('../Helper/Logging'); // We mock logging to not pollute the output\njest.mock('child_process');\nimport * as child_process from 'child_process';\n\nimport { Integration, Platform } from '../Constants';\nimport { run } from '../Setup';\n\nconst originalExec = child_process.exec;\n\nconst restoreExec = (): void => {\n (child_process as any).exec = originalExec;\n};\n\nconst mockExec = (): void => {\n ((child_process.exec as unknown) as jest.Mock).mockImplementation(\n (_command, callback) => callback(null, { stdout: '' }),\n );\n};\n\ndescribe('Wizard', () => {\n beforeEach(() => {\n mockExec();\n });\n\n afterEach(() => {\n restoreExec();\n });\n\n describe('React Native', () => {\n test('run', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n expect(\n run({\n quiet: true,\n integration: Integration.reactNative,\n platform: [Platform.ios, Platform.android],\n skipConnect: true,\n }),\n ).toBeTruthy();\n });\n });\n});\n"]}
@@ -0,0 +1,61 @@
1
+ import * as _ from 'lodash';
2
+ import { satisfies, subset, valid, validRange } from 'semver';
3
+
4
+ import { green, red } from './Logging';
5
+
6
+ export function checkPackageVersion(
7
+ appPackage: unknown,
8
+ packageName: string,
9
+ acceptableVersions: string,
10
+ canBeLatest: boolean,
11
+ ): boolean {
12
+ const depsVersion = _.get(appPackage, ['dependencies', packageName]);
13
+ const devDepsVersion = _.get(appPackage, ['devDependencies', packageName]);
14
+
15
+ if (!depsVersion && !devDepsVersion) {
16
+ red(`✗ ${packageName} isn't in your dependencies.`);
17
+ red(' Please install it with yarn/npm.');
18
+ return false;
19
+ } else if (
20
+ !fulfillsVersionRange(depsVersion, acceptableVersions, canBeLatest) &&
21
+ !fulfillsVersionRange(devDepsVersion, acceptableVersions, canBeLatest)
22
+ ) {
23
+ red(
24
+ `✗ Your \`package.json\` specifies a version of \`${packageName}\` outside of the compatible version range ${acceptableVersions}.\n`,
25
+ );
26
+ return false;
27
+ } else {
28
+ green(
29
+ `✓ A compatible version of \`${packageName}\` is specified in \`package.json\`.`,
30
+ );
31
+ return true;
32
+ }
33
+ }
34
+
35
+ function fulfillsVersionRange(
36
+ version: string,
37
+ acceptableVersions: string,
38
+ canBeLatest: boolean,
39
+ ): boolean {
40
+ if (version === 'latest') {
41
+ return canBeLatest;
42
+ }
43
+
44
+ let cleanedUserVersion, isRange;
45
+
46
+ if (valid(version)) {
47
+ cleanedUserVersion = valid(version);
48
+ isRange = false;
49
+ } else if (validRange(version)) {
50
+ cleanedUserVersion = validRange(version);
51
+ isRange = true;
52
+ }
53
+
54
+ return (
55
+ // If the given version is a bogus format, this will still be undefined and we'll automatically reject it
56
+ !!cleanedUserVersion &&
57
+ (isRange
58
+ ? subset(cleanedUserVersion, acceptableVersions)
59
+ : satisfies(cleanedUserVersion, acceptableVersions))
60
+ );
61
+ }
@@ -0,0 +1,64 @@
1
+ /* eslint-disable @typescript-eslint/typedef */
2
+ import { exec } from 'child_process';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import { promisify } from 'util';
6
+
7
+ import { green } from './Logging';
8
+
9
+ export function getPackageMangerChoice(): PackageManager | null {
10
+ if (fs.existsSync(path.join(process.cwd(), Yarn.LOCK_FILE))) {
11
+ return new Yarn();
12
+ }
13
+ if (fs.existsSync(path.join(process.cwd(), Pnpm.LOCK_FILE))) {
14
+ return new Pnpm();
15
+ }
16
+ if (fs.existsSync(path.join(process.cwd(), Npm.LOCK_FILE))) {
17
+ return new Npm();
18
+ }
19
+ return null;
20
+ }
21
+
22
+ export interface PackageManager {
23
+ installPackage(packageName: string): Promise<void>;
24
+ }
25
+
26
+ export class Npm implements PackageManager {
27
+ public static LOCK_FILE = 'package-lock.json';
28
+ public static LABEL = 'npm';
29
+ public static INSTALL_COMMAND = 'npm install';
30
+
31
+ public async installPackage(packageName: string): Promise<void> {
32
+ await installPackage(Npm.INSTALL_COMMAND, packageName, Npm.LABEL);
33
+ }
34
+ }
35
+
36
+ export class Yarn implements PackageManager {
37
+ public static LOCK_FILE = 'yarn.lock';
38
+ public static LABEL = 'yarn';
39
+ public static INSTALL_COMMAND = 'yarn add';
40
+
41
+ public async installPackage(packageName: string): Promise<void> {
42
+ await installPackage(Yarn.INSTALL_COMMAND, packageName, Yarn.LABEL);
43
+ }
44
+ }
45
+
46
+ export class Pnpm implements PackageManager {
47
+ public static LOCK_FILE = 'pnpm-lock.yaml';
48
+ public static LABEL = 'pnpm';
49
+ public static INSTALL_COMMAND = 'pnpm add';
50
+
51
+ public async installPackage(packageName: string): Promise<void> {
52
+ await installPackage(Pnpm.INSTALL_COMMAND, packageName, Pnpm.LABEL);
53
+ }
54
+ }
55
+
56
+ async function installPackage(
57
+ command: string,
58
+ packageName: string,
59
+ label: string,
60
+ ): Promise<void> {
61
+ await promisify(exec)(`${command} ${packageName}`);
62
+ green(`✓ Added \`${packageName}\` using \`${label}\`.`);
63
+ return;
64
+ }
@@ -62,6 +62,6 @@ export async function startWizard<M extends IStep>(
62
62
  nl();
63
63
  red('Protip: Add --debug to see whats going on');
64
64
  red('OR use --help to see your options');
65
- return {};
65
+ process.exit(1);
66
66
  }
67
67
  }
@@ -10,7 +10,7 @@ const templatePath = path.join(
10
10
  '..',
11
11
  '..',
12
12
  '..',
13
- 'scripts/NextJS/configs/next.config.template.js',
13
+ 'scripts/NextJs/configs/next.config.template.js',
14
14
  );
15
15
 
16
16
  function configFileNames(num: number): {
@@ -31,47 +31,63 @@ function configFileNames(num: number): {
31
31
  }
32
32
 
33
33
  describe('Merging next.config.js', () => {
34
+
35
+ afterEach(() => {
36
+ fs.unlinkSync(configPath);
37
+ });
38
+
39
+ test('merge basic next.config.js return true', () => {
40
+ const { sourcePath } = configFileNames(1);
41
+ fs.copyFileSync(sourcePath, configPath);
42
+
43
+ expect(mergeConfigFile(configPath, templatePath)).toBe(true);
44
+ });
45
+
34
46
  test('merge basic next.config.js', () => {
35
47
  const { sourcePath, mergedPath } = configFileNames(1);
36
48
  fs.copyFileSync(sourcePath, configPath);
37
49
 
38
- expect(mergeConfigFile(configPath, templatePath)).toBe(true);
39
- expect(
40
- fs.readFileSync(configPath, 'utf8') ===
41
- fs.readFileSync(mergedPath, 'utf8'),
42
- ).toBe(true);
43
- fs.unlinkSync(configPath);
50
+ mergeConfigFile(configPath, templatePath);
51
+
52
+ expect(fs.readFileSync(configPath, 'utf8')).toEqual(fs.readFileSync(mergedPath, 'utf8'));
44
53
  });
45
54
 
46
- test('merge invalid javascript config', () => {
55
+ test('merge invalid javascript config return false', () => {
47
56
  const { sourcePath } = configFileNames(2);
48
57
  fs.copyFileSync(sourcePath, configPath);
49
58
 
50
59
  expect(mergeConfigFile(configPath, templatePath)).toBe(false);
51
- fs.unlinkSync(configPath);
60
+ });
61
+
62
+ test('merge more complicated next.config.js return true', () => {
63
+ const { sourcePath } = configFileNames(3);
64
+ fs.copyFileSync(sourcePath, configPath);
65
+
66
+ expect(mergeConfigFile(configPath, templatePath)).toBe(true);
52
67
  });
53
68
 
54
69
  test('merge more complicated next.config.js', () => {
55
70
  const { sourcePath, mergedPath } = configFileNames(3);
56
71
  fs.copyFileSync(sourcePath, configPath);
57
72
 
73
+ mergeConfigFile(configPath, templatePath);
74
+
75
+ expect(fs.readFileSync(configPath, 'utf8')).toEqual(fs.readFileSync(mergedPath, 'utf8'));
76
+ });
77
+
78
+ test('merge next.config.js with function return true', () => {
79
+ const { sourcePath } = configFileNames(4);
80
+ fs.copyFileSync(sourcePath, configPath);
81
+
58
82
  expect(mergeConfigFile(configPath, templatePath)).toBe(true);
59
- expect(
60
- fs.readFileSync(configPath, 'utf8') ===
61
- fs.readFileSync(mergedPath, 'utf8'),
62
- ).toBe(true);
63
- fs.unlinkSync(configPath);
64
83
  });
65
84
 
66
85
  test('merge next.config.js with function', () => {
67
86
  const { sourcePath, mergedPath } = configFileNames(4);
68
87
  fs.copyFileSync(sourcePath, configPath);
69
88
 
70
- expect(mergeConfigFile(configPath, templatePath)).toBe(true);
71
- expect(
72
- fs.readFileSync(configPath, 'utf8') ===
73
- fs.readFileSync(mergedPath, 'utf8'),
74
- ).toBe(true);
75
- fs.unlinkSync(configPath);
89
+ mergeConfigFile(configPath, templatePath);
90
+
91
+ expect(fs.readFileSync(configPath, 'utf8')).toEqual(fs.readFileSync(mergedPath, 'utf8'));
76
92
  });
77
93
  });
@@ -1,21 +1,19 @@
1
1
  /* eslint-disable max-lines */
2
2
  import Chalk from 'chalk';
3
- import { exec } from 'child_process';
4
3
  import * as fs from 'fs';
5
4
  import { Answers, prompt } from 'inquirer';
6
5
  import * as _ from 'lodash';
7
6
  import * as path from 'path';
8
7
  import { satisfies, subset, valid, validRange } from 'semver';
9
- import { promisify } from 'util';
10
8
 
11
9
  import { Args } from '../../Constants';
12
10
  import { debug, green, l, nl, red } from '../../Helper/Logging';
13
11
  import { mergeConfigFile } from '../../Helper/MergeConfig';
12
+ import { checkPackageVersion } from '../../Helper/Package';
13
+ import { getPackageMangerChoice } from '../../Helper/PackageManager';
14
14
  import { SentryCli, SentryCliProps } from '../../Helper/SentryCli';
15
15
  import { BaseIntegration } from './BaseIntegration';
16
16
 
17
- type PackageManager = 'yarn' | 'npm' | 'pnpm';
18
-
19
17
  const COMPATIBLE_NEXTJS_VERSIONS = '>=10.0.8 <14.0.0';
20
18
  const COMPATIBLE_SDK_VERSIONS = '>=7.3.0';
21
19
  const PROPERTIES_FILENAME = 'sentry.properties';
@@ -110,24 +108,26 @@ export class NextJs extends BaseIntegration {
110
108
  nl();
111
109
 
112
110
  let userAnswers: Answers = { continue: true };
113
- const hasCompatibleNextjsVersion = this._checkPackageVersion(
111
+ const hasCompatibleNextjsVersion = checkPackageVersion(
112
+ appPackage,
114
113
  'next',
115
114
  COMPATIBLE_NEXTJS_VERSIONS,
116
115
  true,
117
116
  );
118
117
 
119
- const packageManager = this._getPackageMangerChoice();
118
+ const packageManager = getPackageMangerChoice();
120
119
  const hasSdkInstalled = this._hasPackageInstalled('@sentry/nextjs');
121
120
 
122
121
  let hasCompatibleSdkVersion = false;
123
122
  // if no package but we have nextjs, let's add it if we can
124
123
  if (!hasSdkInstalled && packageManager && hasCompatibleNextjsVersion) {
125
- await this._installPackage('@sentry/nextjs', packageManager);
124
+ await packageManager.installPackage('@sentry/nextjs');
126
125
  // can assume it's compatible since we just installed it
127
126
  hasCompatibleSdkVersion = true;
128
127
  } else {
129
128
  // otherwise, let's check the version and spit out the appropriate error
130
- hasCompatibleSdkVersion = this._checkPackageVersion(
129
+ hasCompatibleSdkVersion = checkPackageVersion(
130
+ appPackage,
131
131
  '@sentry/nextjs',
132
132
  COMPATIBLE_SDK_VERSIONS,
133
133
  true,
@@ -348,106 +348,6 @@ export class NextJs extends BaseIntegration {
348
348
  return !!depsVersion || !!devDepsVersion;
349
349
  }
350
350
 
351
- private _getPackageMangerChoice(): PackageManager | null {
352
- if (fs.existsSync(path.join(process.cwd(), 'yarn.lock'))) {
353
- return 'yarn';
354
- }
355
- if (fs.existsSync(path.join(process.cwd(), 'pnpm-lock.yaml'))) {
356
- return 'pnpm';
357
- }
358
- if (fs.existsSync(path.join(process.cwd(), 'package-lock.json'))) {
359
- return 'npm';
360
- }
361
- return null;
362
- }
363
-
364
- private _getInstallCommand(packageManager: PackageManager): string {
365
- switch (packageManager) {
366
- case 'yarn':
367
- return 'yarn add';
368
- case 'pnpm':
369
- return 'pnpm add';
370
- case 'npm':
371
- return 'npm install';
372
- default:
373
- throw new Error(`Unknown package manager: ${packageManager}`);
374
- }
375
- }
376
-
377
- private async _installPackage(
378
- packageName: string,
379
- packageManager: PackageManager,
380
- ): Promise<void> {
381
- const command = this._getInstallCommand(packageManager);
382
- await promisify(exec)(`${command} ${packageName}`);
383
- green(`✓ Added \`${packageName}\` using \`${command}\`.`);
384
- return;
385
- }
386
-
387
- private _checkPackageVersion(
388
- packageName: string,
389
- acceptableVersions: string,
390
- canBeLatest: boolean,
391
- ): boolean {
392
- const depsVersion = _.get(appPackage, ['dependencies', packageName]);
393
- const devDepsVersion = _.get(appPackage, ['devDependencies', packageName]);
394
-
395
- if (!depsVersion && !devDepsVersion) {
396
- red(`✗ ${packageName} isn't in your dependencies.`);
397
- red(' Please install it with yarn/npm.');
398
- return false;
399
- } else if (
400
- !this._fulfillsVersionRange(
401
- depsVersion,
402
- acceptableVersions,
403
- canBeLatest,
404
- ) &&
405
- !this._fulfillsVersionRange(
406
- devDepsVersion,
407
- acceptableVersions,
408
- canBeLatest,
409
- )
410
- ) {
411
- red(
412
- `✗ Your \`package.json\` specifies a version of \`${packageName}\` outside of the compatible version range ${acceptableVersions}.\n`,
413
- );
414
- return false;
415
- } else {
416
- green(
417
- `✓ A compatible version of \`${packageName}\` is specified in \`package.json\`.`,
418
- );
419
- return true;
420
- }
421
- }
422
-
423
- private _fulfillsVersionRange(
424
- version: string,
425
- acceptableVersions: string,
426
- canBeLatest: boolean,
427
- ): boolean {
428
- if (version === 'latest') {
429
- return canBeLatest;
430
- }
431
-
432
- let cleanedUserVersion, isRange;
433
-
434
- if (valid(version)) {
435
- cleanedUserVersion = valid(version);
436
- isRange = false;
437
- } else if (validRange(version)) {
438
- cleanedUserVersion = validRange(version);
439
- isRange = true;
440
- }
441
-
442
- return (
443
- // If the given version is a bogus format, this will still be undefined and we'll automatically reject it
444
- !!cleanedUserVersion &&
445
- (isRange
446
- ? subset(cleanedUserVersion, acceptableVersions)
447
- : satisfies(cleanedUserVersion, acceptableVersions))
448
- );
449
- }
450
-
451
351
  private _spliceInPlace(
452
352
  arr: Array<any>,
453
353
  start: number,
@@ -1,17 +1,29 @@
1
1
  /* eslint-disable max-lines */
2
+ import { exec } from 'child_process';
2
3
  import * as fs from 'fs';
3
- import { Answers } from 'inquirer';
4
+ import { Answers, prompt } from 'inquirer';
4
5
  import * as _ from 'lodash';
5
6
  import * as path from 'path';
7
+ import { promisify } from 'util';
6
8
 
7
9
  import { Args } from '../../Constants';
8
10
  import { exists, matchesContent, matchFiles, patchMatchingFile } from '../../Helper/File';
9
- import { dim, green, red, yellow } from '../../Helper/Logging';
11
+ import { dim, green, nl, red } from '../../Helper/Logging';
12
+ import { checkPackageVersion } from '../../Helper/Package';
13
+ import { getPackageMangerChoice } from '../../Helper/PackageManager';
10
14
  import { SentryCli } from '../../Helper/SentryCli';
11
15
  import { MobileProject } from './MobileProject';
12
16
 
13
17
  const xcode = require('xcode');
14
18
 
19
+ export const COMPATIBLE_REACT_NATIVE_VERSIONS = '>=0.69.0';
20
+ export const COMPATIBLE_SDK_VERSION = '>= 5.0.0';
21
+
22
+ export const SENTRY_REACT_NATIVE_PACKAGE = '@sentry/react-native';
23
+ export const REACT_NATIVE_PACKAGE = 'react-native';
24
+
25
+ export const DOCS_MANUAL_STEPS = 'https://docs.sentry.io/platforms/react-native/manual-setup/manual-setup/'
26
+
15
27
  export class ReactNative extends MobileProject {
16
28
 
17
29
  /**
@@ -34,43 +46,86 @@ export class ReactNative extends MobileProject {
34
46
  if (!(await this.shouldEmit(answers))) {
35
47
  return {};
36
48
  }
49
+ nl();
50
+
51
+ let userAnswers: Answers = { continue: true };
52
+ const packageManager = getPackageMangerChoice();
53
+
54
+ const hasCompatibleReactNativeVersion = checkPackageVersion(
55
+ this._readAppPackage(),
56
+ REACT_NATIVE_PACKAGE,
57
+ COMPATIBLE_REACT_NATIVE_VERSIONS,
58
+ true,
59
+ );
60
+ if (!hasCompatibleReactNativeVersion && !this._argv.quiet) {
61
+ userAnswers = await prompt({
62
+ message: `Your version of React Native is not compatible with Sentry's React Native SDK. Do you want to continue?`,
63
+ name: 'continue',
64
+ default: false,
65
+ type: 'confirm',
66
+ });
67
+ nl();
68
+ }
69
+ if (!userAnswers.continue) {
70
+ throw new Error(`Please upgrade to a version that is compatible with ${COMPATIBLE_REACT_NATIVE_VERSIONS}. Or use ${DOCS_MANUAL_STEPS}`);
71
+ }
72
+
73
+ if (packageManager) {
74
+ await packageManager.installPackage(SENTRY_REACT_NATIVE_PACKAGE);
75
+ }
76
+ const hasCompatibleSentryReactNativeVersion = checkPackageVersion(
77
+ this._readAppPackage(),
78
+ SENTRY_REACT_NATIVE_PACKAGE,
79
+ COMPATIBLE_SDK_VERSION,
80
+ true,
81
+ );
82
+ if (!hasCompatibleSentryReactNativeVersion && !this._argv.quiet) {
83
+ userAnswers = await prompt({
84
+ message: `Your version of ${SENTRY_REACT_NATIVE_PACKAGE} is not compatible with this wizard. Do you want to continue?`,
85
+ name: 'continue',
86
+ default: false,
87
+ type: 'confirm',
88
+ });
89
+ nl();
90
+ }
91
+ if (!userAnswers.continue) {
92
+ throw new Error(`Please upgrade to a version that is compatible with ${COMPATIBLE_SDK_VERSION}.`);
93
+ }
37
94
 
38
95
  const sentryCliProperties = this._sentryCli.convertAnswersToProperties(
39
96
  answers,
40
97
  );
41
98
 
42
- // eslint-disable-next-line no-async-promise-executor
43
- return new Promise(async (resolve, reject) => {
44
- const promises = this.getPlatforms(answers).map(
45
- async (platform: string) => {
46
- try {
47
- if (platform === 'ios') {
48
- await patchMatchingFile(
49
- 'ios/*.xcodeproj/project.pbxproj',
50
- this._patchXcodeProj.bind(this),
51
- );
52
- dim(`✅ Patched build script in Xcode project.`);
53
- } else {
54
- await patchMatchingFile(
55
- '**/app/build.gradle',
56
- this._patchBuildGradle.bind(this),
57
- );
58
- dim(`✅ Patched build.gradle file.`);
59
- }
60
- await this._patchJsSentryInit(platform, answers);
61
- await this._addSentryProperties(platform, sentryCliProperties);
62
- dim(`✅ Added sentry.properties file to ${platform}`);
63
-
64
- green(`Successfully set up ${platform} for react-native`);
65
- } catch (e) {
66
- red(e);
99
+ const promises = this.getPlatforms(answers).map(
100
+ async (platform: string) => {
101
+ try {
102
+ if (platform === 'ios') {
103
+ await patchMatchingFile(
104
+ 'ios/*.xcodeproj/project.pbxproj',
105
+ this._patchXcodeProj.bind(this),
106
+ );
107
+ green(`✓ Patched build script in Xcode project.`);
108
+ await this._podInstall();
109
+ green(`✓ Pods installed.`);
110
+ } else {
111
+ await patchMatchingFile(
112
+ '**/app/build.gradle',
113
+ this._patchBuildGradle.bind(this),
114
+ );
115
+ green(`✓ Patched build.gradle file.`);
67
116
  }
68
- },
69
- );
70
- Promise.all(promises)
71
- .then(resolve)
72
- .catch(reject);
73
- });
117
+ await this._patchJsSentryInit(platform, answers);
118
+ await this._addSentryProperties(platform, sentryCliProperties);
119
+ green(`✓ Added sentry.properties file to ${platform}`);
120
+ } catch (e) {
121
+ red(e);
122
+ }
123
+ },
124
+ );
125
+
126
+ await Promise.all(promises);
127
+
128
+ return answers;
74
129
  }
75
130
 
76
131
  public async uninstall(_answers: Answers): Promise<Answers> {
@@ -125,6 +180,22 @@ export class ReactNative extends MobileProject {
125
180
  return result;
126
181
  }
127
182
 
183
+ private _readAppPackage(): Record<string, unknown> {
184
+ let appPackage: Record<string, unknown> = {};
185
+
186
+ try {
187
+ appPackage = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
188
+ } catch {
189
+ // We don't need to have this
190
+ }
191
+
192
+ return appPackage;
193
+ }
194
+
195
+ private async _podInstall(): Promise<void> {
196
+ await promisify(exec)('npx --yes pod-install --non-interactive --quiet');
197
+ }
198
+
128
199
  private async _patchJsSentryInit(
129
200
  platform: string,
130
201
  answers: Answers,
@@ -144,10 +215,10 @@ export class ReactNative extends MobileProject {
144
215
  answers,
145
216
  platform,
146
217
  );
147
- dim(`✅ Patched ${jsFileToPatch.join(', ')} file(s).`);
218
+ green(`✓ Patched ${jsFileToPatch.join(', ')} file(s).`);
148
219
  } else {
149
- dim(`🚨 Could not find ${platformGlob} nor ${universalGlob} files.`);
150
- yellow(' Please, visit https://docs.sentry.io/platforms/react-native');
220
+ red(`✗ Could not find ${platformGlob} nor ${universalGlob} files.`);
221
+ red(' Please, visit https://docs.sentry.io/platforms/react-native');
151
222
  }
152
223
  }
153
224
 
@@ -290,7 +361,7 @@ export class ReactNative extends MobileProject {
290
361
  shellScript:`
291
362
  export SENTRY_PROPERTIES=sentry.properties
292
363
  [[ $SENTRY_INCLUDE_NATIVE_SOURCES == "true" ]] && INCLUDE_SOURCES_FLAG="--include-sources" || INCLUDE_SOURCES_FLAG=""
293
- ../node_modules/@sentry/cli/bin/sentry-cli debug-files upload "$INCLUDE_SOURCES_FLAG"
364
+ ../node_modules/@sentry/cli/bin/sentry-cli debug-files upload "$INCLUDE_SOURCES_FLAG" "$DWARF_DSYM_FOLDER_PATH"
294
365
  `,
295
366
  },
296
367
  );