@sentry/wizard 3.38.0 → 3.40.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 +10 -1
- package/README.md +3 -3
- package/dist/e2e-tests/tests/flutter.test.d.ts +1 -0
- package/dist/e2e-tests/tests/flutter.test.js +190 -0
- package/dist/e2e-tests/tests/flutter.test.js.map +1 -0
- package/dist/e2e-tests/tests/nextjs.test.js +1 -1
- package/dist/e2e-tests/tests/nextjs.test.js.map +1 -1
- package/dist/e2e-tests/tests/nuxt-3.test.js +1 -1
- package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -1
- package/dist/e2e-tests/tests/nuxt-4.test.js +1 -1
- package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -1
- package/dist/e2e-tests/tests/remix.test.js +1 -2
- package/dist/e2e-tests/tests/remix.test.js.map +1 -1
- package/dist/e2e-tests/tests/sveltekit.test.js +17 -5
- package/dist/e2e-tests/tests/sveltekit.test.js.map +1 -1
- package/dist/e2e-tests/utils/index.d.ts +22 -1
- package/dist/e2e-tests/utils/index.js +58 -3
- package/dist/e2e-tests/utils/index.js.map +1 -1
- package/dist/lib/Constants.d.ts +1 -0
- package/dist/lib/Constants.js +5 -0
- package/dist/lib/Constants.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/src/apple/apple-wizard.js +1 -1
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/apple/xcode-manager.d.ts +4 -4
- package/dist/src/apple/xcode-manager.js.map +1 -1
- package/dist/src/flutter/code-tools.d.ts +17 -0
- package/dist/src/flutter/code-tools.js +263 -0
- package/dist/src/flutter/code-tools.js.map +1 -0
- package/dist/src/flutter/flutter-wizard.d.ts +2 -0
- package/dist/src/flutter/flutter-wizard.js +171 -0
- package/dist/src/flutter/flutter-wizard.js.map +1 -0
- package/dist/src/flutter/templates.d.ts +9 -0
- package/dist/src/flutter/templates.js +40 -0
- package/dist/src/flutter/templates.js.map +1 -0
- package/dist/src/nextjs/nextjs-wizard.js +3 -1
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/run.d.ts +1 -1
- package/dist/src/run.js +39 -32
- package/dist/src/run.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js +2 -3
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/telemetry.d.ts +2 -1
- package/dist/src/telemetry.js +1 -1
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +1 -1
- package/dist/src/utils/clack-utils.js +3 -3
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +0 -1
- package/dist/src/utils/package-manager.js +9 -10
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/test/flutter/code-tools.test.d.ts +1 -0
- package/dist/test/flutter/code-tools.test.js +84 -0
- package/dist/test/flutter/code-tools.test.js.map +1 -0
- package/dist/test/flutter/templates.test.d.ts +1 -0
- package/dist/test/flutter/templates.test.js +41 -0
- package/dist/test/flutter/templates.test.js.map +1 -0
- package/e2e-tests/README.md +5 -1
- package/e2e-tests/test-applications/flutter-test-app/.metadata +45 -0
- package/e2e-tests/test-applications/flutter-test-app/README.md +16 -0
- package/e2e-tests/test-applications/flutter-test-app/analysis_options.yaml +28 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/build.gradle +44 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/debug/AndroidManifest.xml +7 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/AndroidManifest.xml +45 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/kotlin/com/example/flutter_magic/MainActivity.kt +5 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/drawable/launch_background.xml +12 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/values/styles.xml +18 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/values-night/styles.xml +18 -0
- package/e2e-tests/test-applications/flutter-test-app/android/app/src/profile/AndroidManifest.xml +7 -0
- package/e2e-tests/test-applications/flutter-test-app/android/build.gradle +18 -0
- package/e2e-tests/test-applications/flutter-test-app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/e2e-tests/test-applications/flutter-test-app/android/gradle.properties +3 -0
- package/e2e-tests/test-applications/flutter-test-app/android/settings.gradle +25 -0
- package/e2e-tests/test-applications/flutter-test-app/lib/main.dart +125 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/CMakeLists.txt +145 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/flutter/CMakeLists.txt +88 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/flutter/generated_plugin_registrant.cc +11 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/flutter/generated_plugin_registrant.h +15 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/flutter/generated_plugins.cmake +23 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/main.cc +6 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/my_application.cc +124 -0
- package/e2e-tests/test-applications/flutter-test-app/linux/my_application.h +18 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Flutter/Flutter-Release.xcconfig +2 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Flutter/GeneratedPluginRegistrant.swift +10 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Podfile +43 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/AppDelegate.swift +9 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Base.lproj/MainMenu.xib +343 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/Debug.xcconfig +2 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/Release.xcconfig +2 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/Warnings.xcconfig +13 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/DebugProfile.entitlements +12 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Info.plist +32 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/MainFlutterWindow.swift +15 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Release.entitlements +8 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcodeproj/project.pbxproj +705 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +98 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/e2e-tests/test-applications/flutter-test-app/macos/RunnerTests/RunnerTests.swift +12 -0
- package/e2e-tests/test-applications/flutter-test-app/pubspec.lock +213 -0
- package/e2e-tests/test-applications/flutter-test-app/pubspec.yaml +89 -0
- package/e2e-tests/test-applications/flutter-test-app/test/widget_test.dart +30 -0
- package/e2e-tests/test-applications/flutter-test-app/web/favicon.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-192.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-512.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-maskable-192.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-maskable-512.png +0 -0
- package/e2e-tests/test-applications/flutter-test-app/web/index.html +38 -0
- package/e2e-tests/test-applications/flutter-test-app/web/manifest.json +35 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/CMakeLists.txt +108 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/flutter/CMakeLists.txt +109 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/flutter/generated_plugin_registrant.cc +11 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/flutter/generated_plugin_registrant.h +15 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/flutter/generated_plugins.cmake +23 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/CMakeLists.txt +40 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/Runner.rc +121 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/flutter_window.cpp +71 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/flutter_window.h +33 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/main.cpp +43 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/resource.h +16 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/resources/app_icon.ico +0 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/runner.exe.manifest +14 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/utils.cpp +65 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/utils.h +19 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/win32_window.cpp +288 -0
- package/e2e-tests/test-applications/flutter-test-app/windows/runner/win32_window.h +102 -0
- package/e2e-tests/test-applications/nextjs-test-app/package.json +1 -1
- package/e2e-tests/tests/flutter.test.ts +127 -0
- package/e2e-tests/tests/nextjs.test.ts +1 -1
- package/e2e-tests/tests/nuxt-3.test.ts +1 -1
- package/e2e-tests/tests/nuxt-4.test.ts +1 -1
- package/e2e-tests/tests/remix.test.ts +30 -19
- package/e2e-tests/tests/sveltekit.test.ts +79 -50
- package/e2e-tests/utils/index.ts +62 -2
- package/lib/Constants.ts +5 -0
- package/package.json +1 -1
- package/src/apple/apple-wizard.ts +1 -1
- package/src/apple/xcode-manager.ts +5 -5
- package/src/flutter/code-tools.ts +284 -0
- package/src/flutter/flutter-wizard.ts +164 -0
- package/src/flutter/templates.ts +90 -0
- package/src/nextjs/nextjs-wizard.ts +4 -1
- package/src/run.ts +7 -0
- package/src/sourcemaps/sourcemaps-wizard.ts +3 -7
- package/src/telemetry.ts +6 -2
- package/src/utils/clack-utils.ts +8 -5
- package/src/utils/package-manager.ts +8 -11
- package/test/flutter/code-tools.test.ts +212 -0
- package/test/flutter/templates.test.ts +100 -0
|
@@ -41,7 +41,14 @@ export async function handleError({ error, event }) {
|
|
|
41
41
|
}
|
|
42
42
|
`;
|
|
43
43
|
|
|
44
|
-
async function runWizardOnSvelteKitProject(
|
|
44
|
+
async function runWizardOnSvelteKitProject(
|
|
45
|
+
projectDir: string,
|
|
46
|
+
integration: Integration,
|
|
47
|
+
fileModificationFn?: (
|
|
48
|
+
projectDir: string,
|
|
49
|
+
integration: Integration,
|
|
50
|
+
) => unknown,
|
|
51
|
+
) {
|
|
45
52
|
const wizardInstance = startWizardInstance(integration, projectDir);
|
|
46
53
|
let packageManagerPrompted = false;
|
|
47
54
|
|
|
@@ -49,9 +56,7 @@ async function runWizardOnSvelteKitProject(projectDir: string, integration: Inte
|
|
|
49
56
|
fileModificationFn(projectDir, integration);
|
|
50
57
|
|
|
51
58
|
// As we modified project, we have a warning prompt before we get the package manager prompt
|
|
52
|
-
await wizardInstance.waitForOutput(
|
|
53
|
-
'Do you want to continue anyway?',
|
|
54
|
-
);
|
|
59
|
+
await wizardInstance.waitForOutput('Do you want to continue anyway?');
|
|
55
60
|
|
|
56
61
|
packageManagerPrompted = await wizardInstance.sendStdinAndWaitForOutput(
|
|
57
62
|
[KEYS.ENTER],
|
|
@@ -59,7 +64,7 @@ async function runWizardOnSvelteKitProject(projectDir: string, integration: Inte
|
|
|
59
64
|
);
|
|
60
65
|
} else {
|
|
61
66
|
packageManagerPrompted = await wizardInstance.waitForOutput(
|
|
62
|
-
'Please select your package manager'
|
|
67
|
+
'Please select your package manager',
|
|
63
68
|
);
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -72,7 +77,7 @@ async function runWizardOnSvelteKitProject(projectDir: string, integration: Inte
|
|
|
72
77
|
'to track the performance of your application?',
|
|
73
78
|
{
|
|
74
79
|
timeout: 240_000,
|
|
75
|
-
}
|
|
80
|
+
},
|
|
76
81
|
));
|
|
77
82
|
|
|
78
83
|
const replayOptionPrompted =
|
|
@@ -100,10 +105,14 @@ async function runWizardOnSvelteKitProject(projectDir: string, integration: Inte
|
|
|
100
105
|
wizardInstance.kill();
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
function checkSvelteKitProject(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
function checkSvelteKitProject(
|
|
109
|
+
projectDir: string,
|
|
110
|
+
integration: Integration,
|
|
111
|
+
options?: {
|
|
112
|
+
devModeExpectedOutput: string;
|
|
113
|
+
prodModeExpectedOutput: string;
|
|
114
|
+
},
|
|
115
|
+
) {
|
|
107
116
|
test('should have the correct package.json', () => {
|
|
108
117
|
checkPackageJson(projectDir, integration);
|
|
109
118
|
});
|
|
@@ -113,14 +122,21 @@ function checkSvelteKitProject(projectDir: string, integration: Integration, opt
|
|
|
113
122
|
});
|
|
114
123
|
|
|
115
124
|
test('example page exists', () => {
|
|
116
|
-
checkFileExists(
|
|
117
|
-
|
|
125
|
+
checkFileExists(
|
|
126
|
+
path.resolve(projectDir, 'src/routes/sentry-example/+page.svelte'),
|
|
127
|
+
);
|
|
128
|
+
checkFileExists(
|
|
129
|
+
path.resolve(projectDir, 'src/routes/sentry-example/+server.js'),
|
|
130
|
+
);
|
|
118
131
|
});
|
|
119
132
|
|
|
120
133
|
test('vite.config contains sentry plugin', () => {
|
|
121
|
-
checkFileContents(
|
|
134
|
+
checkFileContents(
|
|
135
|
+
path.resolve(projectDir, 'vite.config.ts'),
|
|
136
|
+
`plugins: [sentrySvelteKit({
|
|
122
137
|
sourceMapsUploadOptions: {
|
|
123
|
-
|
|
138
|
+
`,
|
|
139
|
+
);
|
|
124
140
|
});
|
|
125
141
|
|
|
126
142
|
test('hook files created', () => {
|
|
@@ -129,15 +145,22 @@ function checkSvelteKitProject(projectDir: string, integration: Integration, opt
|
|
|
129
145
|
});
|
|
130
146
|
|
|
131
147
|
test('builds successfully', async () => {
|
|
132
|
-
await checkIfBuilds(projectDir
|
|
148
|
+
await checkIfBuilds(projectDir);
|
|
133
149
|
});
|
|
134
150
|
|
|
135
151
|
test('runs on dev mode correctly', async () => {
|
|
136
|
-
await checkIfRunsOnDevMode(
|
|
152
|
+
await checkIfRunsOnDevMode(
|
|
153
|
+
projectDir,
|
|
154
|
+
options?.devModeExpectedOutput || 'ready in',
|
|
155
|
+
);
|
|
137
156
|
});
|
|
138
157
|
|
|
139
158
|
test('runs on prod mode correctly', async () => {
|
|
140
|
-
await checkIfRunsOnProdMode(
|
|
159
|
+
await checkIfRunsOnProdMode(
|
|
160
|
+
projectDir,
|
|
161
|
+
options?.prodModeExpectedOutput || 'to expose',
|
|
162
|
+
'preview',
|
|
163
|
+
);
|
|
141
164
|
});
|
|
142
165
|
}
|
|
143
166
|
|
|
@@ -161,10 +184,9 @@ describe('Sveltekit', () => {
|
|
|
161
184
|
checkSvelteKitProject(projectDir, integration);
|
|
162
185
|
|
|
163
186
|
test('hooks.client.ts contains sentry', () => {
|
|
164
|
-
checkFileContents(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
`Sentry.init({
|
|
187
|
+
checkFileContents(path.resolve(projectDir, 'src/hooks.client.ts'), [
|
|
188
|
+
`import * as Sentry from '@sentry/sveltekit';`,
|
|
189
|
+
`Sentry.init({
|
|
168
190
|
dsn: '${TEST_ARGS.PROJECT_DSN}',
|
|
169
191
|
|
|
170
192
|
tracesSampleRate: 1.0,
|
|
@@ -179,22 +201,24 @@ describe('Sveltekit', () => {
|
|
|
179
201
|
|
|
180
202
|
// If you don't want to use Session Replay, just remove the line below:
|
|
181
203
|
integrations: [replayIntegration()],
|
|
182
|
-
});`,
|
|
204
|
+
});`,
|
|
205
|
+
'export const handleError = handleErrorWithSentry(',
|
|
206
|
+
]);
|
|
183
207
|
});
|
|
184
208
|
|
|
185
209
|
test('hooks.server.ts contains sentry', () => {
|
|
186
|
-
checkFileContents(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
`import * as Sentry from '@sentry/sveltekit';`,
|
|
190
|
-
`Sentry.init({
|
|
210
|
+
checkFileContents(path.resolve(projectDir, 'src/hooks.server.ts'), [
|
|
211
|
+
`import * as Sentry from '@sentry/sveltekit';`,
|
|
212
|
+
`Sentry.init({
|
|
191
213
|
dsn: '${TEST_ARGS.PROJECT_DSN}',
|
|
192
214
|
|
|
193
215
|
tracesSampleRate: 1.0,
|
|
194
216
|
|
|
195
217
|
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
|
196
218
|
// spotlight: import.meta.env.DEV,
|
|
197
|
-
});`,
|
|
219
|
+
});`,
|
|
220
|
+
'export const handleError = handleErrorWithSentry();',
|
|
221
|
+
]);
|
|
198
222
|
});
|
|
199
223
|
});
|
|
200
224
|
|
|
@@ -206,17 +230,21 @@ describe('Sveltekit', () => {
|
|
|
206
230
|
);
|
|
207
231
|
|
|
208
232
|
beforeAll(async () => {
|
|
209
|
-
await runWizardOnSvelteKitProject(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
233
|
+
await runWizardOnSvelteKitProject(
|
|
234
|
+
projectDir,
|
|
235
|
+
integration,
|
|
236
|
+
(projectDir) => {
|
|
237
|
+
createFile(
|
|
238
|
+
path.resolve(projectDir, 'src/hooks.server.ts'),
|
|
239
|
+
SERVER_HOOK_TEMPLATE,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
createFile(
|
|
243
|
+
path.resolve(projectDir, 'src/hooks.client.ts'),
|
|
244
|
+
CLIENT_HOOK_TEMPLATE,
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
);
|
|
220
248
|
});
|
|
221
249
|
|
|
222
250
|
afterAll(() => {
|
|
@@ -229,27 +257,28 @@ describe('Sveltekit', () => {
|
|
|
229
257
|
// These are removed from the common tests as the content is different
|
|
230
258
|
// when the hooks are merged instead of created from the template
|
|
231
259
|
test('hooks.client.ts contains sentry instrumentation', () => {
|
|
232
|
-
checkFileContents(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
`Sentry.init({
|
|
260
|
+
checkFileContents(path.resolve(projectDir, 'src/hooks.client.ts'), [
|
|
261
|
+
`import * as Sentry from '@sentry/sveltekit';`,
|
|
262
|
+
`Sentry.init({
|
|
236
263
|
dsn: "${TEST_ARGS.PROJECT_DSN}",
|
|
237
264
|
tracesSampleRate: 1,
|
|
238
265
|
replaysSessionSampleRate: 0.1,
|
|
239
266
|
replaysOnErrorSampleRate: 1,
|
|
240
267
|
integrations: [Sentry.replayIntegration()]
|
|
241
|
-
})`,
|
|
268
|
+
})`,
|
|
269
|
+
'export const handleError = Sentry.handleErrorWithSentry(',
|
|
270
|
+
]);
|
|
242
271
|
});
|
|
243
272
|
|
|
244
273
|
test('hooks.server.ts contains sentry init', () => {
|
|
245
|
-
checkFileContents(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
`Sentry.init({
|
|
274
|
+
checkFileContents(path.resolve(projectDir, 'src/hooks.server.ts'), [
|
|
275
|
+
`import * as Sentry from '@sentry/sveltekit';`,
|
|
276
|
+
`Sentry.init({
|
|
249
277
|
dsn: "${TEST_ARGS.PROJECT_DSN}",
|
|
250
278
|
tracesSampleRate: 1
|
|
251
|
-
})`,
|
|
279
|
+
})`,
|
|
280
|
+
'export const handleError = Sentry.handleErrorWithSentry();',
|
|
281
|
+
]);
|
|
252
282
|
});
|
|
253
283
|
});
|
|
254
284
|
});
|
|
255
|
-
|
package/e2e-tests/utils/index.ts
CHANGED
|
@@ -80,6 +80,36 @@ export class WizardTestEnv {
|
|
|
80
80
|
return outputPromise;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Waits for the task to exit with a given `statusCode`.
|
|
85
|
+
*
|
|
86
|
+
* @returns a promise that resolves to `true` if the run ends with the status
|
|
87
|
+
* code, or it rejects when the `timeout` was reached.
|
|
88
|
+
*/
|
|
89
|
+
waitForStatusCode(
|
|
90
|
+
statusCode: number | null,
|
|
91
|
+
options: {
|
|
92
|
+
/** Timeout in ms */
|
|
93
|
+
timeout?: number;
|
|
94
|
+
} = {},
|
|
95
|
+
) {
|
|
96
|
+
const { timeout } = {
|
|
97
|
+
timeout: 60_000,
|
|
98
|
+
...options,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
102
|
+
const timeoutId = setTimeout(() => {
|
|
103
|
+
reject(new Error(`Timeout waiting for status code: ${statusCode}`));
|
|
104
|
+
}, timeout);
|
|
105
|
+
|
|
106
|
+
this.taskHandle.on('exit', (code: number | null) => {
|
|
107
|
+
clearTimeout(timeoutId);
|
|
108
|
+
resolve(code === statusCode);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
83
113
|
/**
|
|
84
114
|
* Waits for the provided output with `.includes()` logic.
|
|
85
115
|
*
|
|
@@ -317,16 +347,46 @@ export function checkEnvBuildPlugin(projectDir: string) {
|
|
|
317
347
|
);
|
|
318
348
|
}
|
|
319
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Check if the sentry.properties contains the auth token
|
|
352
|
+
* @param projectDir
|
|
353
|
+
*/
|
|
354
|
+
export function checkSentryProperties(projectDir: string) {
|
|
355
|
+
checkFileContents(
|
|
356
|
+
`${projectDir}/sentry.properties`,
|
|
357
|
+
`auth_token=${TEST_ARGS.AUTH_TOKEN}`,
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
|
|
320
361
|
/**
|
|
321
362
|
* Check if the project builds
|
|
363
|
+
* Check if the project builds and ends with status code 0.
|
|
322
364
|
* @param projectDir
|
|
323
365
|
*/
|
|
324
|
-
export async function checkIfBuilds(
|
|
366
|
+
export async function checkIfBuilds(projectDir: string) {
|
|
367
|
+
const testEnv = new WizardTestEnv('npm', ['run', 'build'], {
|
|
368
|
+
cwd: projectDir,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
await expect(
|
|
372
|
+
testEnv.waitForStatusCode(0, {
|
|
373
|
+
timeout: 120_000,
|
|
374
|
+
}),
|
|
375
|
+
).resolves.toBe(true);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Check if the flutter project builds
|
|
380
|
+
* @param projectDir
|
|
381
|
+
*/
|
|
382
|
+
export async function checkIfFlutterBuilds(
|
|
325
383
|
projectDir: string,
|
|
326
384
|
expectedOutput: string,
|
|
385
|
+
debug = false,
|
|
327
386
|
) {
|
|
328
|
-
const testEnv = new WizardTestEnv('
|
|
387
|
+
const testEnv = new WizardTestEnv('flutter', ['build', 'web'], {
|
|
329
388
|
cwd: projectDir,
|
|
389
|
+
debug: debug,
|
|
330
390
|
});
|
|
331
391
|
|
|
332
392
|
await expect(
|
package/lib/Constants.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Key value should be the same here */
|
|
2
2
|
export enum Integration {
|
|
3
3
|
reactNative = 'reactNative',
|
|
4
|
+
flutter = 'flutter',
|
|
4
5
|
ios = 'ios',
|
|
5
6
|
android = 'android',
|
|
6
7
|
cordova = 'cordova',
|
|
@@ -41,6 +42,8 @@ export function getIntegrationDescription(type: string): string {
|
|
|
41
42
|
return 'Android';
|
|
42
43
|
case Integration.reactNative:
|
|
43
44
|
return 'React Native';
|
|
45
|
+
case Integration.flutter:
|
|
46
|
+
return 'Flutter';
|
|
44
47
|
case Integration.cordova:
|
|
45
48
|
return 'Cordova';
|
|
46
49
|
case Integration.electron:
|
|
@@ -66,6 +69,8 @@ export function mapIntegrationToPlatform(type: string): string | undefined {
|
|
|
66
69
|
return 'android';
|
|
67
70
|
case Integration.reactNative:
|
|
68
71
|
return 'react-native';
|
|
72
|
+
case Integration.flutter:
|
|
73
|
+
return 'flutter';
|
|
69
74
|
case Integration.cordova:
|
|
70
75
|
return 'cordova';
|
|
71
76
|
case Integration.electron:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/wizard",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.40.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",
|
|
@@ -109,7 +109,7 @@ async function runAppleWizardWithTelementry(
|
|
|
109
109
|
const availableTargets = xcProject.getAllTargets();
|
|
110
110
|
|
|
111
111
|
if (availableTargets.length == 0) {
|
|
112
|
-
clack.log.error(`No
|
|
112
|
+
clack.log.error(`No suitable target found in ${xcodeProjFile}`);
|
|
113
113
|
Sentry.setTag('No-Target', true);
|
|
114
114
|
await abort();
|
|
115
115
|
return;
|
|
@@ -10,7 +10,7 @@ import * as templates from './templates';
|
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
const xcode = require('xcode');
|
|
12
12
|
|
|
13
|
-
interface
|
|
13
|
+
interface ProjectFile {
|
|
14
14
|
key: string;
|
|
15
15
|
path: string;
|
|
16
16
|
}
|
|
@@ -190,7 +190,7 @@ export class XcodeProject {
|
|
|
190
190
|
projectPath: string;
|
|
191
191
|
project: any;
|
|
192
192
|
objects: any;
|
|
193
|
-
files:
|
|
193
|
+
files: ProjectFile[] | undefined;
|
|
194
194
|
|
|
195
195
|
public constructor(projectPath: string) {
|
|
196
196
|
this.projectPath = projectPath;
|
|
@@ -282,7 +282,7 @@ export class XcodeProject {
|
|
|
282
282
|
.filter((f: string) => f.length > 0) as string[];
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
projectFiles():
|
|
285
|
+
projectFiles(): ProjectFile[] {
|
|
286
286
|
if (this.files === undefined) {
|
|
287
287
|
const proj = this.project.getFirstProject();
|
|
288
288
|
const mainGroupKey = proj.firstProject.mainGroup;
|
|
@@ -292,8 +292,8 @@ export class XcodeProject {
|
|
|
292
292
|
return this.files;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
buildGroup(group: any, path = ''):
|
|
296
|
-
const result:
|
|
295
|
+
buildGroup(group: any, path = ''): ProjectFile[] {
|
|
296
|
+
const result: ProjectFile[] = [];
|
|
297
297
|
for (const child of group.children) {
|
|
298
298
|
if (this.objects.PBXFileReference[child.value]) {
|
|
299
299
|
const fileReference = this.objects.PBXFileReference[child.value];
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as Sentry from '@sentry/node';
|
|
4
|
+
// @ts-ignore - clack is ESM and TS complains about that. It works though
|
|
5
|
+
import * as clack from '@clack/prompts';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import {
|
|
8
|
+
sentryImport,
|
|
9
|
+
pubspecOptions,
|
|
10
|
+
sentryProperties,
|
|
11
|
+
initSnippet,
|
|
12
|
+
} from './templates';
|
|
13
|
+
import { featureSelectionPrompt } from '../utils/clack-utils';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Recursively finds a file per name in subfolders.
|
|
17
|
+
* @param dir - The directory to start searching.
|
|
18
|
+
* @param name - The name of the file including path extension.
|
|
19
|
+
* @returns The path to the main.dart file or null if not found.
|
|
20
|
+
*/
|
|
21
|
+
export function findFile(dir: string, name: string): string | null {
|
|
22
|
+
const files: string[] = fs.readdirSync(dir);
|
|
23
|
+
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const fullPath: string = path.join(dir, file);
|
|
26
|
+
const stats: fs.Stats = fs.statSync(fullPath);
|
|
27
|
+
|
|
28
|
+
if (stats.isDirectory()) {
|
|
29
|
+
const result: string | null = findFile(fullPath, name);
|
|
30
|
+
if (result) {
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
} else if (file === name) {
|
|
34
|
+
return fullPath;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function patchPubspec(
|
|
42
|
+
pubspecFile: string | null,
|
|
43
|
+
sentryDartFlutterVersion: string,
|
|
44
|
+
sentryDartPluginVersion: string,
|
|
45
|
+
project: string,
|
|
46
|
+
org: string,
|
|
47
|
+
): boolean {
|
|
48
|
+
try {
|
|
49
|
+
if (!pubspecFile) {
|
|
50
|
+
throw new Error('pubspec.yaml is not provided or invalid.');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let pubspecContent = fs.readFileSync(pubspecFile, 'utf8');
|
|
54
|
+
|
|
55
|
+
if (!pubspecContent.includes('sentry_flutter:')) {
|
|
56
|
+
const dependenciesIndex = getDependenciesLocation(pubspecContent);
|
|
57
|
+
|
|
58
|
+
pubspecContent =
|
|
59
|
+
pubspecContent.slice(0, dependenciesIndex) +
|
|
60
|
+
` sentry_flutter: ${sentryDartFlutterVersion}\n` +
|
|
61
|
+
pubspecContent.slice(dependenciesIndex);
|
|
62
|
+
|
|
63
|
+
clack.log.success(
|
|
64
|
+
chalk.greenBright(
|
|
65
|
+
`${chalk.bold('sentry_flutter')} added to pubspec.yaml`,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
} else {
|
|
69
|
+
clack.log.success(
|
|
70
|
+
chalk.greenBright(
|
|
71
|
+
`${chalk.bold('sentry_flutter')} is already included in pubspec.yaml`,
|
|
72
|
+
),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!pubspecContent.includes('sentry_dart_plugin:')) {
|
|
77
|
+
const devDependenciesIndex = getDevDependenciesLocation(pubspecContent);
|
|
78
|
+
pubspecContent =
|
|
79
|
+
pubspecContent.slice(0, devDependenciesIndex) +
|
|
80
|
+
` sentry_dart_plugin: ${sentryDartPluginVersion}\n` +
|
|
81
|
+
pubspecContent.slice(devDependenciesIndex);
|
|
82
|
+
|
|
83
|
+
clack.log.success(
|
|
84
|
+
chalk.greenBright(
|
|
85
|
+
`${chalk.bold('sentry_dart_plugin')} added to pubspec.yaml`,
|
|
86
|
+
),
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
clack.log.success(
|
|
90
|
+
chalk.greenBright(
|
|
91
|
+
`${chalk.bold(
|
|
92
|
+
'sentry_dart_plugin',
|
|
93
|
+
)} is already included in pubspec.yaml`,
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!pubspecContent.includes('sentry:')) {
|
|
99
|
+
pubspecContent += '\n';
|
|
100
|
+
pubspecContent += pubspecOptions(project, org);
|
|
101
|
+
|
|
102
|
+
clack.log.success(
|
|
103
|
+
chalk.greenBright(
|
|
104
|
+
`${chalk.bold('sentry plugin configuration')} added to pubspec.yaml`,
|
|
105
|
+
),
|
|
106
|
+
);
|
|
107
|
+
} else {
|
|
108
|
+
clack.log.success(
|
|
109
|
+
chalk.greenBright(
|
|
110
|
+
`${chalk.bold(
|
|
111
|
+
'sentry plugin configuration',
|
|
112
|
+
)} is already included in pubspec.yaml`,
|
|
113
|
+
),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fs.writeFileSync(pubspecFile, pubspecContent, 'utf8');
|
|
118
|
+
|
|
119
|
+
return true;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
clack.log.warn(`Failed to read/write ${chalk.cyan('pubspec.yaml')} file.`);
|
|
122
|
+
Sentry.captureException(error);
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function addProperties(pubspecFile: string | null, authToken: string) {
|
|
128
|
+
try {
|
|
129
|
+
if (!pubspecFile) {
|
|
130
|
+
throw new Error('pubspec.yaml is not provided or invalid.');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const pubspecDir = path.dirname(pubspecFile);
|
|
134
|
+
const sentryPropertiesFileName = 'sentry.properties';
|
|
135
|
+
const sentryPropertiesFile = path.join(
|
|
136
|
+
pubspecDir,
|
|
137
|
+
sentryPropertiesFileName,
|
|
138
|
+
);
|
|
139
|
+
const sentryPropertiesContent = sentryProperties(authToken);
|
|
140
|
+
|
|
141
|
+
fs.writeFileSync(sentryPropertiesFile, sentryPropertiesContent, 'utf8');
|
|
142
|
+
|
|
143
|
+
const gitignoreFile = path.join(pubspecDir, '.gitignore');
|
|
144
|
+
if (fs.existsSync(gitignoreFile)) {
|
|
145
|
+
fs.appendFileSync(gitignoreFile, `\n${sentryPropertiesFileName}\n`);
|
|
146
|
+
} else {
|
|
147
|
+
fs.writeFileSync(gitignoreFile, `${sentryPropertiesFileName}\n`, 'utf8');
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
clack.log.warn(`Failed to read/write ${chalk.cyan('pubspec.yaml')} file.`);
|
|
152
|
+
Sentry.captureException(error);
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function patchMain(
|
|
158
|
+
mainFile: string | null,
|
|
159
|
+
dsn: string,
|
|
160
|
+
canEnableProfiling: boolean,
|
|
161
|
+
): Promise<boolean> {
|
|
162
|
+
try {
|
|
163
|
+
if (!mainFile) {
|
|
164
|
+
throw new Error('pubspec.yaml is not provided or invalid.');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let mainContent = fs.readFileSync(mainFile, 'utf8');
|
|
168
|
+
if (
|
|
169
|
+
/import\s+['"]package[:]sentry_flutter\/sentry_flutter\.dart['"];?/i.test(
|
|
170
|
+
mainContent,
|
|
171
|
+
)
|
|
172
|
+
) {
|
|
173
|
+
// sentry is already configured
|
|
174
|
+
clack.log.success(
|
|
175
|
+
chalk.greenBright(
|
|
176
|
+
`${chalk.bold('main.dart')} already has Sentry configured.`,
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const features = [
|
|
183
|
+
{
|
|
184
|
+
id: 'tracing',
|
|
185
|
+
prompt: `Do you want to enable ${chalk.bold(
|
|
186
|
+
'Tracing',
|
|
187
|
+
)} to track the performance of your application?`,
|
|
188
|
+
enabledHint: 'recommended',
|
|
189
|
+
},
|
|
190
|
+
];
|
|
191
|
+
if (canEnableProfiling) {
|
|
192
|
+
features.push({
|
|
193
|
+
id: 'profiling',
|
|
194
|
+
prompt: `Do you want to enable ${chalk.bold(
|
|
195
|
+
'Profiling',
|
|
196
|
+
)} to analyze CPU usage and optimize performance-critical code on iOS & macOS?`,
|
|
197
|
+
enabledHint: 'recommended, tracing must be enabled',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const selectedFeatures = await featureSelectionPrompt(features);
|
|
202
|
+
const normalizedSelectedFeatures = {
|
|
203
|
+
tracing: selectedFeatures.tracing ?? false,
|
|
204
|
+
profiling: selectedFeatures.profiling ?? false,
|
|
205
|
+
};
|
|
206
|
+
mainContent = patchMainContent(
|
|
207
|
+
dsn,
|
|
208
|
+
mainContent,
|
|
209
|
+
normalizedSelectedFeatures,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
fs.writeFileSync(mainFile, mainContent, 'utf8');
|
|
213
|
+
|
|
214
|
+
clack.log.success(
|
|
215
|
+
chalk.greenBright(
|
|
216
|
+
`Patched ${chalk.bold(
|
|
217
|
+
'main.dart',
|
|
218
|
+
)} with the Sentry setup and test error snippet.`,
|
|
219
|
+
),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
return true;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
clack.log.warn(`Failed to read/write ${chalk.cyan('main.dart')} file.`);
|
|
225
|
+
Sentry.captureException(error);
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function patchMainContent(
|
|
231
|
+
dsn: string,
|
|
232
|
+
mainContent: string,
|
|
233
|
+
selectedFeatures: {
|
|
234
|
+
tracing: boolean;
|
|
235
|
+
profiling: boolean;
|
|
236
|
+
},
|
|
237
|
+
): string {
|
|
238
|
+
const importIndex = getLastImportLineLocation(mainContent);
|
|
239
|
+
mainContent =
|
|
240
|
+
mainContent.slice(0, importIndex) +
|
|
241
|
+
sentryImport +
|
|
242
|
+
mainContent.slice(importIndex);
|
|
243
|
+
|
|
244
|
+
// Find and replace `runApp(...)`
|
|
245
|
+
mainContent = mainContent.replace(
|
|
246
|
+
/runApp\(([\s\S]*?)\);/g, // Match the `runApp(...)` invocation
|
|
247
|
+
(_, runAppArgs) => initSnippet(dsn, selectedFeatures, runAppArgs as string),
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// Make the `main` function async if it's not already
|
|
251
|
+
mainContent = mainContent.replace(
|
|
252
|
+
/void\s+main\(\)\s*\{/g,
|
|
253
|
+
'Future<void> main() async {',
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
return mainContent;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function getLastImportLineLocation(sourceCode: string): number {
|
|
260
|
+
const importRegex = /import\s+['"].*['"].*;/gim;
|
|
261
|
+
return getLastReqExpLocation(sourceCode, importRegex);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function getDependenciesLocation(sourceCode: string): number {
|
|
265
|
+
const dependencyRegex = /^dependencies:\s*$/gim;
|
|
266
|
+
return getLastReqExpLocation(sourceCode, dependencyRegex);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function getDevDependenciesLocation(sourceCode: string): number {
|
|
270
|
+
const dependencyRegex = /^dev_dependencies:\s*$/gim;
|
|
271
|
+
return getLastReqExpLocation(sourceCode, dependencyRegex);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Helper
|
|
275
|
+
|
|
276
|
+
function getLastReqExpLocation(sourceCode: string, regExp: RegExp): number {
|
|
277
|
+
let match = regExp.exec(sourceCode);
|
|
278
|
+
let importIndex = 0;
|
|
279
|
+
while (match) {
|
|
280
|
+
importIndex = match.index + match[0].length + 1;
|
|
281
|
+
match = regExp.exec(sourceCode);
|
|
282
|
+
}
|
|
283
|
+
return importIndex;
|
|
284
|
+
}
|