@sentry/wizard 3.7.1 → 3.9.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.
- package/CHANGELOG.md +21 -0
- package/bin.ts +14 -0
- package/dist/bin.js +9 -0
- package/dist/bin.js.map +1 -1
- package/dist/lib/Helper/Logging.d.ts +1 -0
- package/dist/lib/Helper/Logging.js +2 -1
- package/dist/lib/Helper/Logging.js.map +1 -1
- package/dist/lib/Helper/__tests__/MergeConfig.js.map +1 -1
- package/dist/lib/Setup.js +4 -0
- package/dist/lib/Setup.js.map +1 -1
- package/dist/lib/Steps/ChooseIntegration.js +12 -26
- package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
- package/dist/lib/Steps/Integrations/Cordova.js.map +1 -1
- package/dist/lib/Steps/Integrations/Electron.js.map +1 -1
- package/dist/lib/Steps/Integrations/MobileProject.js.map +1 -1
- package/dist/lib/Steps/Integrations/ReactNative.js +5 -5
- package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
- package/dist/lib/Steps/Integrations/__tests__/ReactNative.js +5 -6
- package/dist/lib/Steps/Integrations/__tests__/ReactNative.js.map +1 -1
- package/dist/package.json +11 -7
- package/dist/src/apple/apple-wizard.js +31 -2
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/apple/cocoapod.d.ts +2 -0
- package/dist/src/apple/cocoapod.js +122 -0
- package/dist/src/apple/cocoapod.js.map +1 -0
- package/dist/src/apple/code-tools.js +22 -12
- package/dist/src/apple/code-tools.js.map +1 -1
- package/dist/src/apple/fastlane.d.ts +2 -0
- package/dist/src/apple/fastlane.js +179 -0
- package/dist/src/apple/fastlane.js.map +1 -0
- package/dist/src/apple/templates.d.ts +1 -0
- package/dist/src/apple/templates.js +7 -3
- package/dist/src/apple/templates.js.map +1 -1
- package/dist/src/apple/xcode-manager.d.ts +1 -1
- package/dist/src/apple/xcode-manager.js +35 -28
- package/dist/src/apple/xcode-manager.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +71 -81
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js +61 -46
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/sourcemaps/tools/nextjs.d.ts +3 -0
- package/dist/src/sourcemaps/tools/nextjs.js +135 -0
- package/dist/src/sourcemaps/tools/nextjs.js.map +1 -0
- package/dist/src/sourcemaps/tools/sentry-cli.js +120 -16
- package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
- package/dist/src/sourcemaps/tools/vite.js +102 -12
- package/dist/src/sourcemaps/tools/vite.js.map +1 -1
- package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
- package/dist/src/sourcemaps/utils/detect-tool.js +1 -0
- package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
- package/dist/src/sourcemaps/utils/other-wizards.js +35 -12
- package/dist/src/sourcemaps/utils/other-wizards.js.map +1 -1
- package/dist/src/sveltekit/sdk-setup.d.ts +9 -1
- package/dist/src/sveltekit/sdk-setup.js +73 -29
- package/dist/src/sveltekit/sdk-setup.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +23 -13
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/utils/ast-utils.d.ts +8 -0
- package/dist/src/utils/ast-utils.js +45 -0
- package/dist/src/utils/ast-utils.js.map +1 -0
- package/dist/src/utils/bash.d.ts +2 -1
- package/dist/src/utils/bash.js +14 -2
- package/dist/src/utils/bash.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +7 -14
- package/dist/src/utils/clack-utils.js +46 -2
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/debug.d.ts +2 -0
- package/dist/src/utils/debug.js +51 -0
- package/dist/src/utils/debug.js.map +1 -0
- package/dist/src/utils/package-json.d.ts +1 -1
- package/dist/src/utils/package-json.js.map +1 -1
- package/dist/src/utils/types.d.ts +24 -0
- package/dist/src/utils/types.js.map +1 -1
- package/dist/test/utils/ast-utils.test.d.ts +1 -0
- package/dist/test/utils/ast-utils.test.js +21 -0
- package/dist/test/utils/ast-utils.test.js.map +1 -0
- package/lib/Helper/Logging.ts +1 -1
- package/lib/Helper/__tests__/MergeConfig.ts +9 -4
- package/lib/Setup.ts +5 -0
- package/lib/Steps/ChooseIntegration.ts +13 -3
- package/lib/Steps/Integrations/Cordova.ts +3 -3
- package/lib/Steps/Integrations/Electron.ts +1 -2
- package/lib/Steps/Integrations/MobileProject.ts +1 -1
- package/lib/Steps/Integrations/ReactNative.ts +23 -17
- package/lib/Steps/Integrations/__tests__/ReactNative.ts +24 -15
- package/package.json +11 -7
- package/src/apple/apple-wizard.ts +35 -3
- package/src/apple/cocoapod.ts +57 -0
- package/src/apple/code-tools.ts +80 -57
- package/src/apple/fastlane.ts +160 -0
- package/src/apple/templates.ts +26 -10
- package/src/apple/xcode-manager.ts +137 -120
- package/src/nextjs/nextjs-wizard.ts +4 -13
- package/src/sourcemaps/sourcemaps-wizard.ts +40 -28
- package/src/sourcemaps/tools/nextjs.ts +114 -0
- package/src/sourcemaps/tools/sentry-cli.ts +134 -8
- package/src/sourcemaps/tools/vite.ts +101 -12
- package/src/sourcemaps/utils/detect-tool.ts +3 -1
- package/src/sourcemaps/utils/other-wizards.ts +32 -13
- package/src/sveltekit/sdk-setup.ts +122 -43
- package/src/sveltekit/sveltekit-wizard.ts +15 -6
- package/src/utils/ast-utils.ts +20 -0
- package/src/utils/bash.ts +43 -30
- package/src/utils/clack-utils.ts +42 -14
- package/src/utils/debug.ts +20 -0
- package/src/utils/package-json.ts +1 -1
- package/src/utils/types.ts +22 -0
- package/test/utils/ast-utils.test.ts +44 -0
- package/dist/src/sveltekit/sentry-cli-setup.d.ts +0 -2
- package/dist/src/sveltekit/sentry-cli-setup.js +0 -71
- package/dist/src/sveltekit/sentry-cli-setup.js.map +0 -1
- package/package-lock.json +0 -8910
- package/src/sveltekit/sentry-cli-setup.ts +0 -27
|
@@ -31,7 +31,6 @@ function configFileNames(num: number): {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
describe('Merging next.config.js', () => {
|
|
34
|
-
|
|
35
34
|
afterEach(() => {
|
|
36
35
|
fs.unlinkSync(configPath);
|
|
37
36
|
});
|
|
@@ -49,7 +48,9 @@ describe('Merging next.config.js', () => {
|
|
|
49
48
|
|
|
50
49
|
mergeConfigFile(configPath, templatePath);
|
|
51
50
|
|
|
52
|
-
expect(fs.readFileSync(configPath, 'utf8')).toEqual(
|
|
51
|
+
expect(fs.readFileSync(configPath, 'utf8')).toEqual(
|
|
52
|
+
fs.readFileSync(mergedPath, 'utf8'),
|
|
53
|
+
);
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
test('merge invalid javascript config return false', () => {
|
|
@@ -72,7 +73,9 @@ describe('Merging next.config.js', () => {
|
|
|
72
73
|
|
|
73
74
|
mergeConfigFile(configPath, templatePath);
|
|
74
75
|
|
|
75
|
-
expect(fs.readFileSync(configPath, 'utf8')).toEqual(
|
|
76
|
+
expect(fs.readFileSync(configPath, 'utf8')).toEqual(
|
|
77
|
+
fs.readFileSync(mergedPath, 'utf8'),
|
|
78
|
+
);
|
|
76
79
|
});
|
|
77
80
|
|
|
78
81
|
test('merge next.config.js with function return true', () => {
|
|
@@ -88,6 +91,8 @@ describe('Merging next.config.js', () => {
|
|
|
88
91
|
|
|
89
92
|
mergeConfigFile(configPath, templatePath);
|
|
90
93
|
|
|
91
|
-
expect(fs.readFileSync(configPath, 'utf8')).toEqual(
|
|
94
|
+
expect(fs.readFileSync(configPath, 'utf8')).toEqual(
|
|
95
|
+
fs.readFileSync(mergedPath, 'utf8'),
|
|
96
|
+
);
|
|
92
97
|
});
|
|
93
98
|
});
|
package/lib/Setup.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _ from 'lodash';
|
|
2
|
+
import { enableDebugLogs } from '../src/utils/debug';
|
|
2
3
|
|
|
3
4
|
import { readEnvironment } from './Helper/Env';
|
|
4
5
|
import { startWizard } from './Helper/Wizard';
|
|
@@ -7,6 +8,10 @@ import * as Step from './Steps';
|
|
|
7
8
|
export async function run(argv: any): Promise<any> {
|
|
8
9
|
const args = { ...argv, ...readEnvironment() };
|
|
9
10
|
|
|
11
|
+
if (argv.debug) {
|
|
12
|
+
enableDebugLogs();
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
if (args.uninstall === undefined) {
|
|
11
16
|
args.uninstall = false;
|
|
12
17
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Answers } from 'inquirer';
|
|
2
2
|
import { prompt } from 'inquirer';
|
|
3
|
-
import * as _ from 'lodash';
|
|
4
3
|
import { dim } from 'picocolors';
|
|
5
4
|
|
|
6
5
|
import {
|
|
@@ -17,6 +16,7 @@ import { ReactNative } from './Integrations/ReactNative';
|
|
|
17
16
|
import { SourceMapsShim } from './Integrations/SourceMapsShim';
|
|
18
17
|
import { Apple } from './Integrations/Apple';
|
|
19
18
|
import { SvelteKitShim } from './Integrations/SvelteKitShim';
|
|
19
|
+
import { hasPackageInstalled } from '../../src/utils/package-json';
|
|
20
20
|
|
|
21
21
|
let projectPackage: any = {};
|
|
22
22
|
|
|
@@ -65,12 +65,22 @@ export class ChooseIntegration extends BaseStep {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
public tryDetectingIntegration(): Integration | undefined {
|
|
68
|
-
if (
|
|
68
|
+
if (hasPackageInstalled('react-native', projectPackage)) {
|
|
69
69
|
return Integration.reactNative;
|
|
70
70
|
}
|
|
71
|
-
if (
|
|
71
|
+
if (hasPackageInstalled('cordova', projectPackage)) {
|
|
72
72
|
return Integration.cordova;
|
|
73
73
|
}
|
|
74
|
+
if (hasPackageInstalled('electron', projectPackage)) {
|
|
75
|
+
return Integration.electron;
|
|
76
|
+
}
|
|
77
|
+
if (hasPackageInstalled('next', projectPackage)) {
|
|
78
|
+
return Integration.nextjs;
|
|
79
|
+
}
|
|
80
|
+
if (hasPackageInstalled('@sveltejs/kit', projectPackage)) {
|
|
81
|
+
return Integration.sveltekit;
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
return;
|
|
75
85
|
}
|
|
76
86
|
|
|
@@ -12,6 +12,7 @@ const xcode = require('xcode');
|
|
|
12
12
|
|
|
13
13
|
export class Cordova extends BaseIntegration {
|
|
14
14
|
protected _sentryCli: SentryCli;
|
|
15
|
+
|
|
15
16
|
protected _folderPrefix = 'platforms';
|
|
16
17
|
protected _pluginFolder: string[] = ['.'];
|
|
17
18
|
|
|
@@ -25,9 +26,8 @@ export class Cordova extends BaseIntegration {
|
|
|
25
26
|
return this.uninstall(answers);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const sentryCliProperties =
|
|
29
|
-
answers
|
|
30
|
-
);
|
|
29
|
+
const sentryCliProperties =
|
|
30
|
+
this._sentryCli.convertAnswersToProperties(answers);
|
|
31
31
|
|
|
32
32
|
await patchMatchingFile(
|
|
33
33
|
`${this._folderPrefix}/ios/*.xcodeproj/project.pbxproj`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import type { Answers} from 'inquirer';
|
|
2
|
+
import type { Answers } from 'inquirer';
|
|
3
3
|
import { prompt } from 'inquirer';
|
|
4
4
|
import * as _ from 'lodash';
|
|
5
5
|
import * as path from 'path';
|
|
@@ -21,7 +21,6 @@ Sentry.init({
|
|
|
21
21
|
dsn: '___DSN___',
|
|
22
22
|
});`;
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
let appPackage: any = {};
|
|
26
25
|
|
|
27
26
|
function printExample(example: string, title = ''): void {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
import { exec } from 'child_process';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
|
-
import type { Answers} from 'inquirer';
|
|
4
|
+
import type { Answers } from 'inquirer';
|
|
5
5
|
import { prompt } from 'inquirer';
|
|
6
6
|
import * as _ from 'lodash';
|
|
7
7
|
import * as path from 'path';
|
|
@@ -44,7 +44,6 @@ export class ReactNative extends MobileProject {
|
|
|
44
44
|
protected _answers: Answers;
|
|
45
45
|
protected _sentryCli: SentryCli;
|
|
46
46
|
|
|
47
|
-
|
|
48
47
|
public constructor(protected _argv: Args) {
|
|
49
48
|
super(_argv);
|
|
50
49
|
this.url = _argv.url;
|
|
@@ -71,7 +70,8 @@ export class ReactNative extends MobileProject {
|
|
|
71
70
|
);
|
|
72
71
|
if (!hasCompatibleReactNativeVersion && !this._argv.quiet) {
|
|
73
72
|
userAnswers = await prompt({
|
|
74
|
-
message:
|
|
73
|
+
message:
|
|
74
|
+
"Your version of React Native is not compatible with Sentry's React Native SDK. Do you want to continue?",
|
|
75
75
|
name: 'continue',
|
|
76
76
|
default: false,
|
|
77
77
|
type: 'confirm',
|
|
@@ -111,9 +111,8 @@ export class ReactNative extends MobileProject {
|
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
const sentryCliProperties =
|
|
115
|
-
answers
|
|
116
|
-
);
|
|
114
|
+
const sentryCliProperties =
|
|
115
|
+
this._sentryCli.convertAnswersToProperties(answers);
|
|
117
116
|
|
|
118
117
|
const promises = this.getPlatforms(answers).map(
|
|
119
118
|
async (platform: string) => {
|
|
@@ -146,17 +145,18 @@ export class ReactNative extends MobileProject {
|
|
|
146
145
|
|
|
147
146
|
await Promise.all(promises);
|
|
148
147
|
|
|
149
|
-
let host: string | null = null
|
|
148
|
+
let host: string | null = null;
|
|
150
149
|
try {
|
|
151
|
-
host =
|
|
150
|
+
host = new URL(this.url || '').host;
|
|
152
151
|
} catch (_error) {
|
|
153
152
|
// ignore
|
|
154
153
|
}
|
|
155
154
|
const orgSlug = _.get(answers, 'config.organization.slug', null);
|
|
156
155
|
const projectId = _.get(answers, 'config.project.id', null);
|
|
157
|
-
const projectIssuesUrl =
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
const projectIssuesUrl =
|
|
157
|
+
host && orgSlug && projectId
|
|
158
|
+
? `https://${orgSlug}.${host}/issues/?project=${projectId}`
|
|
159
|
+
: null;
|
|
160
160
|
|
|
161
161
|
l(`
|
|
162
162
|
To make sure everything is set up correctly, put the following code snippet into your application.
|
|
@@ -169,7 +169,9 @@ The snippet will create a button that, when tapped, sends a test event to Sentry
|
|
|
169
169
|
nl();
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
l(
|
|
172
|
+
l(
|
|
173
|
+
`<Button title='Try!' onPress={ () => { Sentry.captureException(new Error('First error')) }}/>`,
|
|
174
|
+
);
|
|
173
175
|
nl();
|
|
174
176
|
|
|
175
177
|
if (!this._argv.quiet) {
|
|
@@ -337,7 +339,7 @@ The snippet will create a button that, when tapped, sends a test event to Sentry
|
|
|
337
339
|
return Promise.resolve(
|
|
338
340
|
contents.replace(
|
|
339
341
|
/^([^]*)(import\s+[^;]*?;$)/m,
|
|
340
|
-
match =>
|
|
342
|
+
(match) =>
|
|
341
343
|
// eslint-disable-next-line prefer-template
|
|
342
344
|
match +
|
|
343
345
|
"\n\nimport * as Sentry from '@sentry/react-native';\n\n" +
|
|
@@ -361,7 +363,7 @@ The snippet will create a button that, when tapped, sends a test event to Sentry
|
|
|
361
363
|
contents.replace(
|
|
362
364
|
ReactNative._buildGradleAndroidSectionBeginning,
|
|
363
365
|
// eslint-disable-next-line prefer-template
|
|
364
|
-
match => applyFrom + '\n' + match,
|
|
366
|
+
(match) => applyFrom + '\n' + match,
|
|
365
367
|
),
|
|
366
368
|
);
|
|
367
369
|
}
|
|
@@ -396,7 +398,7 @@ The snippet will create a button that, when tapped, sends a test event to Sentry
|
|
|
396
398
|
// eslint-disable-next-line no-useless-escape
|
|
397
399
|
'\\"../node_modules/@sentry/cli/bin/sentry-cli react-native xcode $REACT_NATIVE_XCODE\\"',
|
|
398
400
|
) +
|
|
399
|
-
'\n/bin/sh ../node_modules/@sentry/react-native/scripts/collect-modules.sh\n';
|
|
401
|
+
'\n/bin/sh -c "$WITH_ENVIRONMENT ../node_modules/@sentry/react-native/scripts/collect-modules.sh"\n';
|
|
400
402
|
script.shellScript = JSON.stringify(code);
|
|
401
403
|
}
|
|
402
404
|
}
|
|
@@ -420,8 +422,12 @@ The snippet will create a button that, when tapped, sends a test event to Sentry
|
|
|
420
422
|
{
|
|
421
423
|
shellPath: '/bin/sh',
|
|
422
424
|
shellScript: `
|
|
425
|
+
WITH_ENVIRONMENT="../node_modules/react-native/scripts/xcode/with-environment.sh"
|
|
426
|
+
if [ -f "$WITH_ENVIRONMENT" ]; then
|
|
427
|
+
. "$WITH_ENVIRONMENT"
|
|
428
|
+
fi
|
|
423
429
|
export SENTRY_PROPERTIES=sentry.properties
|
|
424
|
-
[
|
|
430
|
+
[ "$SENTRY_INCLUDE_NATIVE_SOURCES" = "true" ] && INCLUDE_SOURCES_FLAG="--include-sources" || INCLUDE_SOURCES_FLAG=""
|
|
425
431
|
../node_modules/@sentry/cli/bin/sentry-cli debug-files upload "$INCLUDE_SOURCES_FLAG" "$DWARF_DSYM_FOLDER_PATH"
|
|
426
432
|
`,
|
|
427
433
|
},
|
|
@@ -507,7 +513,7 @@ export SENTRY_PROPERTIES=sentry.properties
|
|
|
507
513
|
// remove sentry properties export
|
|
508
514
|
.replace(/^export SENTRY_PROPERTIES=sentry.properties\r?\n/m, '')
|
|
509
515
|
.replace(
|
|
510
|
-
/^\/bin\/sh
|
|
516
|
+
/^\/bin\/sh .*?..\/node_modules\/@sentry\/react-native\/scripts\/collect-modules.sh"?\r?\n/m,
|
|
511
517
|
'',
|
|
512
518
|
)
|
|
513
519
|
// unwrap react-native-xcode.sh command. In case someone replaced it
|
|
@@ -7,7 +7,7 @@ import * as path from 'path';
|
|
|
7
7
|
import * as process from 'process';
|
|
8
8
|
import * as rimraf from 'rimraf';
|
|
9
9
|
|
|
10
|
-
import type { Args} from '../../../Constants';
|
|
10
|
+
import type { Args } from '../../../Constants';
|
|
11
11
|
import { Integration, Platform } from '../../../Constants';
|
|
12
12
|
import { ReactNative } from '../ReactNative';
|
|
13
13
|
|
|
@@ -18,7 +18,8 @@ const appBuildGradle = 'android/app/build.gradle';
|
|
|
18
18
|
const yarnLock = 'yarn.lock';
|
|
19
19
|
|
|
20
20
|
const dummyJsContent = 'import React from "react";\n';
|
|
21
|
-
const dummyAppBuildGradleContent =
|
|
21
|
+
const dummyAppBuildGradleContent =
|
|
22
|
+
'apply plugin: "com.facebook.react"\n\nandroid {\n}\n';
|
|
22
23
|
|
|
23
24
|
const testArgs = {
|
|
24
25
|
debug: false,
|
|
@@ -31,7 +32,7 @@ const testArgs = {
|
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
const mockIosAnswers: Answers = {
|
|
34
|
-
shouldConfigurePlatforms: {
|
|
35
|
+
shouldConfigurePlatforms: { ios: true },
|
|
35
36
|
config: {
|
|
36
37
|
dsn: {
|
|
37
38
|
public: 'dns.public.com',
|
|
@@ -40,7 +41,7 @@ const mockIosAnswers: Answers = {
|
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
const mockAndroidAnswers: Answers = {
|
|
43
|
-
shouldConfigurePlatforms: {
|
|
44
|
+
shouldConfigurePlatforms: { android: true },
|
|
44
45
|
config: {
|
|
45
46
|
dsn: {
|
|
46
47
|
public: 'dns.public.com',
|
|
@@ -52,15 +53,15 @@ const originalExec = child_process.exec;
|
|
|
52
53
|
|
|
53
54
|
const restoreExec = (): void => {
|
|
54
55
|
(child_process as any).exec = originalExec;
|
|
55
|
-
}
|
|
56
|
+
};
|
|
56
57
|
|
|
57
58
|
const mockExec = (): void => {
|
|
58
|
-
(child_process.exec as unknown as jest.Mock)
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
(child_process.exec as unknown as jest.Mock).mockImplementation(
|
|
60
|
+
(_command, callback) => callback(null, { stdout: '' }),
|
|
61
|
+
);
|
|
62
|
+
};
|
|
61
63
|
|
|
62
64
|
describe('ReactNative', () => {
|
|
63
|
-
|
|
64
65
|
const defaultCwd = process.cwd();
|
|
65
66
|
|
|
66
67
|
beforeEach(() => {
|
|
@@ -88,10 +89,11 @@ describe('ReactNative', () => {
|
|
|
88
89
|
|
|
89
90
|
const patchedIosIndexJs = fs.readFileSync(iosIndexJs, 'utf8');
|
|
90
91
|
const patchedAppTsx = fs.readFileSync(appTsx, 'utf8');
|
|
91
|
-
const expectedPatch =
|
|
92
|
-
'import
|
|
92
|
+
const expectedPatch =
|
|
93
|
+
'import React from "react";\n\n' +
|
|
94
|
+
"import * as Sentry from '@sentry/react-native';\n\n" +
|
|
93
95
|
'Sentry.init({ \n' +
|
|
94
|
-
|
|
96
|
+
" dsn: 'dns.public.com', \n" +
|
|
95
97
|
'});\n\n';
|
|
96
98
|
expect(patchedIosIndexJs).toEqual(expectedPatch);
|
|
97
99
|
expect(patchedAppTsx).toEqual(expectedPatch);
|
|
@@ -103,7 +105,8 @@ describe('ReactNative', () => {
|
|
|
103
105
|
await project.emit(mockAndroidAnswers);
|
|
104
106
|
|
|
105
107
|
const patchedAppBuildGradle = fs.readFileSync(appBuildGradle, 'utf8');
|
|
106
|
-
const expectedPatch =
|
|
108
|
+
const expectedPatch =
|
|
109
|
+
'apply plugin: "com.facebook.react"\n\n' +
|
|
107
110
|
'apply from: "../../node_modules/@sentry/react-native/sentry.gradle"\n' +
|
|
108
111
|
'android {\n}\n';
|
|
109
112
|
expect(patchedAppBuildGradle).toEqual(expectedPatch);
|
|
@@ -114,7 +117,10 @@ describe('ReactNative', () => {
|
|
|
114
117
|
|
|
115
118
|
await project.emit(mockIosAnswers);
|
|
116
119
|
|
|
117
|
-
expect(child_process.exec).toHaveBeenCalledWith(
|
|
120
|
+
expect(child_process.exec).toHaveBeenCalledWith(
|
|
121
|
+
'yarn add @sentry/react-native',
|
|
122
|
+
expect.anything(),
|
|
123
|
+
);
|
|
118
124
|
});
|
|
119
125
|
|
|
120
126
|
test('executes pod install', async () => {
|
|
@@ -122,6 +128,9 @@ describe('ReactNative', () => {
|
|
|
122
128
|
|
|
123
129
|
await project.emit(mockIosAnswers);
|
|
124
130
|
|
|
125
|
-
expect(child_process.exec).toHaveBeenCalledWith(
|
|
131
|
+
expect(child_process.exec).toHaveBeenCalledWith(
|
|
132
|
+
'npx --yes pod-install --non-interactive --quiet',
|
|
133
|
+
expect.anything(),
|
|
134
|
+
);
|
|
126
135
|
});
|
|
127
136
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/wizard",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"homepage": "https://github.com/getsentry/sentry-wizard",
|
|
5
5
|
"repository": "https://github.com/getsentry/sentry-wizard",
|
|
6
6
|
"description": "Sentry wizard helping you to configure your project",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"glob": "^7.1.3",
|
|
33
33
|
"inquirer": "^6.2.0",
|
|
34
34
|
"lodash": "^4.17.15",
|
|
35
|
-
"magicast": "^0.2.
|
|
35
|
+
"magicast": "^0.2.10",
|
|
36
36
|
"opn": "^5.4.0",
|
|
37
37
|
"r2": "^2.0.1",
|
|
38
38
|
"read-env": "^1.3.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"**/xmldom": "^0.6.0"
|
|
66
66
|
},
|
|
67
67
|
"engines": {
|
|
68
|
-
"node": ">=14.
|
|
68
|
+
"node": ">=14.18.0",
|
|
69
69
|
"npm": ">=3.10.7",
|
|
70
70
|
"yarn": ">=1.0.2"
|
|
71
71
|
},
|
|
@@ -76,15 +76,15 @@
|
|
|
76
76
|
"build": "yarn tsc",
|
|
77
77
|
"postbuild": "chmod +x ./dist/bin.js && cp -r scripts/** dist",
|
|
78
78
|
"lint": "yarn lint:prettier && yarn lint:eslint",
|
|
79
|
-
"lint:prettier": "prettier --check lib/**/*.ts",
|
|
79
|
+
"lint:prettier": "prettier --check \"{lib,src,test}/**/*.ts\"",
|
|
80
80
|
"lint:eslint": "eslint . --cache --format stylish",
|
|
81
81
|
"fix": "yarn fix:eslint && yarn fix:prettier",
|
|
82
|
-
"fix:prettier": "prettier --write lib/**/*.ts",
|
|
82
|
+
"fix:prettier": "prettier --write \"{lib,src,test}/**/*.ts\"",
|
|
83
83
|
"fix:eslint": "eslint . --format stylish --fix",
|
|
84
84
|
"test": "yarn build && jest",
|
|
85
85
|
"try": "ts-node bin.ts",
|
|
86
86
|
"try:uninstall": "ts-node bin.ts --uninstall",
|
|
87
|
-
"test:watch": "jest --watch
|
|
87
|
+
"test:watch": "jest --watch"
|
|
88
88
|
},
|
|
89
89
|
"jest": {
|
|
90
90
|
"collectCoverage": true,
|
|
@@ -114,5 +114,9 @@
|
|
|
114
114
|
"testEnvironment": "node"
|
|
115
115
|
},
|
|
116
116
|
"author": "Sentry",
|
|
117
|
-
"license": "MIT"
|
|
117
|
+
"license": "MIT",
|
|
118
|
+
"volta": {
|
|
119
|
+
"node": "14.18.3",
|
|
120
|
+
"yarn": "1.22.19"
|
|
121
|
+
}
|
|
118
122
|
}
|
|
@@ -10,9 +10,11 @@ import * as path from 'path';
|
|
|
10
10
|
import * as xcManager from './xcode-manager';
|
|
11
11
|
import * as codeTools from './code-tools';
|
|
12
12
|
import * as bash from '../utils/bash';
|
|
13
|
-
import { WizardOptions } from '../utils/types';
|
|
13
|
+
import { SentryProjectData, WizardOptions } from '../utils/types';
|
|
14
14
|
import * as Sentry from '@sentry/node';
|
|
15
15
|
import { traceStep, withTelemetry } from '../telemetry';
|
|
16
|
+
import * as cocoapod from './cocoapod';
|
|
17
|
+
import * as fastlane from './fastlane';
|
|
16
18
|
|
|
17
19
|
const xcode = require('xcode');
|
|
18
20
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
@@ -22,7 +24,6 @@ import {
|
|
|
22
24
|
askForSelfHosted,
|
|
23
25
|
askForWizardLogin,
|
|
24
26
|
askToInstallSentryCLI,
|
|
25
|
-
SentryProjectData,
|
|
26
27
|
printWelcome,
|
|
27
28
|
abort,
|
|
28
29
|
askForItemSelection,
|
|
@@ -102,10 +103,24 @@ async function runAppleWizardWithTelementry(
|
|
|
102
103
|
options.url,
|
|
103
104
|
);
|
|
104
105
|
|
|
106
|
+
const hasCocoa = cocoapod.usesCocoaPod(projectDir);
|
|
107
|
+
|
|
108
|
+
if (hasCocoa) {
|
|
109
|
+
const podAdded = await traceStep('Add CocoaPods reference', () =>
|
|
110
|
+
cocoapod.addCocoaPods(projectDir),
|
|
111
|
+
);
|
|
112
|
+
if (!podAdded) {
|
|
113
|
+
clack.log.warn(
|
|
114
|
+
"Could not add Sentry pod to your Podfile. You'll have to add it manually.\nPlease follow the instructions at https://docs.sentry.io/platforms/apple/guides/ios/#install",
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
105
119
|
traceStep('Update Xcode project', () => {
|
|
106
|
-
xcManager.updateXcodeProject(pbxproj, project, apiKey,
|
|
120
|
+
xcManager.updateXcodeProject(pbxproj, project, apiKey, !hasCocoa, true);
|
|
107
121
|
});
|
|
108
122
|
|
|
123
|
+
Sentry.setTag('package-manager', hasCocoa ? 'cocoapods' : 'SPM');
|
|
109
124
|
const projSource = path.join(
|
|
110
125
|
projectDir,
|
|
111
126
|
xcodeProjFile.replace('.xcodeproj', ''),
|
|
@@ -123,6 +138,23 @@ async function runAppleWizardWithTelementry(
|
|
|
123
138
|
return;
|
|
124
139
|
}
|
|
125
140
|
|
|
141
|
+
if (fastlane.fastFile(projectDir)) {
|
|
142
|
+
const addLane = await clack.confirm({
|
|
143
|
+
message:
|
|
144
|
+
'Found a Fastfile in your project. Do you want to configure a lane to upload debug symbols to Sentry?',
|
|
145
|
+
});
|
|
146
|
+
if (addLane) {
|
|
147
|
+
await traceStep('Configure fastlane', () =>
|
|
148
|
+
fastlane.addSentryToFastlane(
|
|
149
|
+
projectDir,
|
|
150
|
+
project.organization.slug,
|
|
151
|
+
project.slug,
|
|
152
|
+
apiKey.token,
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
126
158
|
clack.log.success('Sentry was successfully added to your project!');
|
|
127
159
|
}
|
|
128
160
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as bash from '../utils/bash';
|
|
4
|
+
import * as Sentry from '@sentry/node';
|
|
5
|
+
// @ts-ignore - clack is ESM and TS complains about that. It works though
|
|
6
|
+
import * as clack from '@clack/prompts';
|
|
7
|
+
|
|
8
|
+
export function usesCocoaPod(projPath: string): boolean {
|
|
9
|
+
return fs.existsSync(path.join(projPath, 'Podfile'));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function addCocoaPods(projPath: string): Promise<boolean> {
|
|
13
|
+
const podfile = path.join(projPath, 'Podfile');
|
|
14
|
+
|
|
15
|
+
const podContent = fs.readFileSync(podfile, 'utf8');
|
|
16
|
+
|
|
17
|
+
if (
|
|
18
|
+
/^\s*pod\s+(['"]Sentry['"]|['"]SentrySwiftUI['"])\s*$/im.test(podContent)
|
|
19
|
+
) {
|
|
20
|
+
// Already have Sentry pod
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let podMatch = /^( *)pod\s+['"](\w+)['"] *$/im.exec(podContent);
|
|
25
|
+
if (!podMatch) {
|
|
26
|
+
// No Podfile is empty, will try to add Sentry pod after "use_frameworks!"
|
|
27
|
+
const frameworkMatch = /^( *)use_frameworks![^\n]* *$/im.exec(podContent);
|
|
28
|
+
if (!frameworkMatch) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
podMatch = frameworkMatch;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const insertIndex = podMatch.index + podMatch[0].length;
|
|
35
|
+
const newFileContent =
|
|
36
|
+
podContent.slice(0, insertIndex) +
|
|
37
|
+
'\n' +
|
|
38
|
+
podMatch[1] +
|
|
39
|
+
"pod 'Sentry'\n" +
|
|
40
|
+
podContent.slice(insertIndex);
|
|
41
|
+
fs.writeFileSync(podfile, newFileContent, 'utf8');
|
|
42
|
+
|
|
43
|
+
const loginSpinner = clack.spinner();
|
|
44
|
+
|
|
45
|
+
loginSpinner.start("Running 'pod install'. This may take a few minutes...");
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await bash.execute('pod install --silent');
|
|
49
|
+
loginSpinner.stop('Sentry pod added to the project.');
|
|
50
|
+
} catch (e) {
|
|
51
|
+
clack.log.error("'pod install' failed. You will need to run it manually.");
|
|
52
|
+
loginSpinner.stop();
|
|
53
|
+
Sentry.captureException('Sentry pod install failed.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return true;
|
|
57
|
+
}
|