@sentry/wizard 3.10.0 → 3.12.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 +54 -7
- 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/lib/Steps/ChooseIntegration.js +8 -4
- package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
- package/dist/lib/Steps/Integrations/Android.d.ts +9 -0
- package/dist/lib/Steps/Integrations/Android.js +86 -0
- package/dist/lib/Steps/Integrations/Android.js.map +1 -0
- package/dist/lib/Steps/Integrations/ReactNative.js +3 -3
- package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
- package/dist/lib/Steps/PromptForParameters.js +36 -3
- package/dist/lib/Steps/PromptForParameters.js.map +1 -1
- package/dist/lib/Steps/SentryProjectSelector.js +1 -1
- package/dist/lib/Steps/SentryProjectSelector.js.map +1 -1
- package/dist/package.json +4 -3
- package/dist/src/android/android-wizard.d.ts +2 -0
- package/dist/src/android/android-wizard.js +225 -0
- package/dist/src/android/android-wizard.js.map +1 -0
- package/dist/src/android/code-tools.d.ts +47 -0
- package/dist/src/android/code-tools.js +173 -0
- package/dist/src/android/code-tools.js.map +1 -0
- package/dist/src/android/gradle.d.ts +62 -0
- package/dist/src/android/gradle.js +286 -0
- package/dist/src/android/gradle.js.map +1 -0
- package/dist/src/android/manifest.d.ts +57 -0
- package/dist/src/android/manifest.js +183 -0
- package/dist/src/android/manifest.js.map +1 -0
- package/dist/src/android/templates.d.ts +11 -0
- package/dist/src/android/templates.js +34 -0
- package/dist/src/android/templates.js.map +1 -0
- package/dist/src/apple/apple-wizard.js +123 -64
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/apple/cocoapod.js +4 -3
- package/dist/src/apple/cocoapod.js.map +1 -1
- package/dist/src/apple/code-tools.d.ts +1 -1
- package/dist/src/apple/code-tools.js +43 -19
- package/dist/src/apple/code-tools.js.map +1 -1
- package/dist/src/apple/fastlane.d.ts +1 -1
- package/dist/src/apple/fastlane.js +12 -6
- package/dist/src/apple/fastlane.js.map +1 -1
- package/dist/src/apple/templates.d.ts +2 -2
- package/dist/src/apple/templates.js +4 -4
- package/dist/src/apple/templates.js.map +1 -1
- package/dist/src/apple/xcode-manager.d.ts +19 -3
- package/dist/src/apple/xcode-manager.js +126 -24
- package/dist/src/apple/xcode-manager.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +49 -11
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +2 -0
- package/dist/src/nextjs/templates.js +6 -2
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/remix/remix-wizard.js +10 -20
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js +26 -13
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/sourcemaps/tools/nextjs.js +1 -1
- package/dist/src/sourcemaps/tools/nextjs.js.map +1 -1
- package/dist/src/sourcemaps/tools/sentry-cli.js +19 -16
- package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
- package/dist/src/sourcemaps/tools/vite.d.ts +2 -1
- package/dist/src/sourcemaps/tools/vite.js +123 -111
- package/dist/src/sourcemaps/tools/vite.js.map +1 -1
- package/dist/src/sourcemaps/tools/webpack.d.ts +6 -1
- package/dist/src/sourcemaps/tools/webpack.js +290 -25
- package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
- package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
- package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
- package/dist/src/sveltekit/sdk-setup.js +5 -5
- package/dist/src/sveltekit/sdk-setup.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +34 -44
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/telemetry.js +1 -0
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/ast-utils.d.ts +9 -5
- package/dist/src/utils/ast-utils.js +26 -11
- package/dist/src/utils/ast-utils.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +74 -28
- package/dist/src/utils/clack-utils.js +427 -264
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +10 -0
- package/dist/{lib/Helper/PackageManager.js → src/utils/package-manager.js} +42 -74
- package/dist/src/utils/package-manager.js.map +1 -0
- package/dist/src/utils/release-registry.d.ts +1 -0
- package/dist/src/utils/release-registry.js +68 -0
- package/dist/src/utils/release-registry.js.map +1 -0
- package/dist/src/utils/sentrycli-utils.d.ts +4 -0
- package/dist/src/utils/sentrycli-utils.js +41 -0
- package/dist/src/utils/sentrycli-utils.js.map +1 -0
- package/dist/test/android/code-tools.test.d.ts +1 -0
- package/dist/test/android/code-tools.test.js +34 -0
- package/dist/test/android/code-tools.test.js.map +1 -0
- package/dist/test/sourcemaps/tools/vite.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/vite.test.js +132 -0
- package/dist/test/sourcemaps/tools/vite.test.js.map +1 -0
- package/dist/test/sourcemaps/tools/webpack.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/webpack.test.js +179 -0
- package/dist/test/sourcemaps/tools/webpack.test.js.map +1 -0
- package/dist/test/utils/ast-utils.test.js +42 -7
- package/dist/test/utils/ast-utils.test.js.map +1 -1
- package/dist/test/utils/clack-utils.test.d.ts +1 -0
- package/dist/test/utils/clack-utils.test.js +200 -0
- package/dist/test/utils/clack-utils.test.js.map +1 -0
- package/lib/Constants.ts +5 -0
- package/lib/Steps/ChooseIntegration.ts +7 -3
- package/lib/Steps/Integrations/Android.ts +23 -0
- package/lib/Steps/Integrations/ReactNative.ts +9 -3
- package/lib/Steps/PromptForParameters.ts +48 -3
- package/lib/Steps/SentryProjectSelector.ts +3 -1
- package/package.json +4 -3
- package/src/android/android-wizard.ts +204 -0
- package/src/android/code-tools.ts +170 -0
- package/src/android/gradle.ts +250 -0
- package/src/android/manifest.ts +180 -0
- package/src/android/templates.ts +88 -0
- package/src/apple/apple-wizard.ts +113 -35
- package/src/apple/cocoapod.ts +6 -3
- package/src/apple/code-tools.ts +46 -18
- package/src/apple/fastlane.ts +6 -12
- package/src/apple/templates.ts +2 -8
- package/src/apple/xcode-manager.ts +167 -25
- package/src/nextjs/nextjs-wizard.ts +72 -8
- package/src/nextjs/templates.ts +16 -2
- package/src/remix/remix-wizard.ts +10 -15
- package/src/sourcemaps/sourcemaps-wizard.ts +19 -5
- package/src/sourcemaps/tools/nextjs.ts +2 -2
- package/src/sourcemaps/tools/sentry-cli.ts +8 -7
- package/src/sourcemaps/tools/vite.ts +143 -79
- package/src/sourcemaps/tools/webpack.ts +369 -30
- package/src/sourcemaps/utils/detect-tool.ts +2 -1
- package/src/sveltekit/sdk-setup.ts +10 -6
- package/src/sveltekit/sveltekit-wizard.ts +5 -14
- package/src/telemetry.ts +2 -0
- package/src/utils/ast-utils.ts +29 -11
- package/src/utils/clack-utils.ts +485 -283
- package/src/utils/package-manager.ts +61 -0
- package/src/utils/release-registry.ts +19 -0
- package/src/utils/sentrycli-utils.ts +22 -0
- package/test/android/code-tools.test.ts +49 -0
- package/test/sourcemaps/tools/vite.test.ts +149 -0
- package/test/sourcemaps/tools/webpack.test.ts +303 -0
- package/test/utils/ast-utils.test.ts +28 -9
- package/test/utils/clack-utils.test.ts +142 -0
- package/dist/lib/Helper/PackageManager.d.ts +0 -22
- package/dist/lib/Helper/PackageManager.js.map +0 -1
- package/dist/src/utils/vendor/clack-custom-select.d.ts +0 -21
- package/dist/src/utils/vendor/clack-custom-select.js +0 -137
- package/dist/src/utils/vendor/clack-custom-select.js.map +0 -1
- package/lib/Helper/PackageManager.ts +0 -59
- package/src/utils/vendor/clack-custom-select.ts +0 -160
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
|
|
1
4
|
// @ts-ignore - clack is ESM and TS complains about that. It works though
|
|
2
|
-
import
|
|
5
|
+
import * as clack from '@clack/prompts';
|
|
3
6
|
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
import * as recast from 'recast';
|
|
9
|
+
import x = recast.types;
|
|
10
|
+
import t = x.namedTypes;
|
|
11
|
+
|
|
12
|
+
import * as Sentry from '@sentry/node';
|
|
13
|
+
|
|
4
14
|
import {
|
|
5
15
|
abortIfCancelled,
|
|
6
16
|
addDotEnvSentryBuildPluginFile,
|
|
17
|
+
askForToolConfigPath,
|
|
18
|
+
createNewConfigFile,
|
|
7
19
|
getPackageDotJson,
|
|
8
20
|
installPackage,
|
|
21
|
+
showCopyPasteInstructions,
|
|
9
22
|
} from '../../utils/clack-utils';
|
|
10
23
|
import { hasPackageInstalled } from '../../utils/package-json';
|
|
11
24
|
|
|
@@ -14,28 +27,57 @@ import {
|
|
|
14
27
|
SourceMapUploadToolConfigurationOptions,
|
|
15
28
|
} from './types';
|
|
16
29
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
${chalk.greenBright(
|
|
20
|
-
'const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");',
|
|
21
|
-
)}
|
|
30
|
+
import { findFile, hasSentryContent } from '../../utils/ast-utils';
|
|
31
|
+
import { debug } from '../../utils/debug';
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
const getCodeSnippet = (
|
|
34
|
+
options: SourceMapUploadToolConfigurationOptions,
|
|
35
|
+
colors: boolean,
|
|
36
|
+
) => {
|
|
37
|
+
const rawImportStmt =
|
|
38
|
+
'const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");';
|
|
39
|
+
const rawGenerateSourceMapsOption =
|
|
40
|
+
'devtool: "source-map", // Source map generation must be turned on';
|
|
41
|
+
const rawSentryWebpackPluginFunction = `sentryWebpackPlugin({
|
|
30
42
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
31
43
|
org: "${options.orgSlug}",
|
|
32
44
|
project: "${options.projectSlug}",${
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
})
|
|
36
|
-
|
|
45
|
+
options.selfHosted ? `\n url: "${options.url}",` : ''
|
|
46
|
+
}
|
|
47
|
+
})`;
|
|
48
|
+
|
|
49
|
+
const importStmt = colors ? chalk.greenBright(rawImportStmt) : rawImportStmt;
|
|
50
|
+
const generateSourceMapsOption = colors
|
|
51
|
+
? chalk.greenBright(rawGenerateSourceMapsOption)
|
|
52
|
+
: rawGenerateSourceMapsOption;
|
|
53
|
+
const sentryWebpackPluginFunction = colors
|
|
54
|
+
? chalk.greenBright(rawSentryWebpackPluginFunction)
|
|
55
|
+
: rawSentryWebpackPluginFunction;
|
|
56
|
+
|
|
57
|
+
const code = getWebpackConfigContent(
|
|
58
|
+
importStmt,
|
|
59
|
+
generateSourceMapsOption,
|
|
60
|
+
sentryWebpackPluginFunction,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return colors ? chalk.gray(code) : code;
|
|
37
64
|
};
|
|
38
|
-
|
|
65
|
+
|
|
66
|
+
const getWebpackConfigContent = (
|
|
67
|
+
importStmt: string,
|
|
68
|
+
generateSourceMapsOption: string,
|
|
69
|
+
sentryWebpackPluginFunction: string,
|
|
70
|
+
) => `${importStmt}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
// ... other options
|
|
74
|
+
${generateSourceMapsOption},
|
|
75
|
+
plugins: [
|
|
76
|
+
// Put the Sentry Webpack plugin after all other plugins
|
|
77
|
+
${sentryWebpackPluginFunction},
|
|
78
|
+
],
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
39
81
|
|
|
40
82
|
export const configureWebPackPlugin: SourceMapUploadToolConfigurationFunction =
|
|
41
83
|
async (options) => {
|
|
@@ -47,21 +89,318 @@ export const configureWebPackPlugin: SourceMapUploadToolConfigurationFunction =
|
|
|
47
89
|
),
|
|
48
90
|
});
|
|
49
91
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
92
|
+
const webpackConfigPath =
|
|
93
|
+
findFile(path.resolve(process.cwd(), 'webpack.config')) ??
|
|
94
|
+
(await askForToolConfigPath('Webpack', 'webpack.config.js'));
|
|
95
|
+
|
|
96
|
+
let successfullyAdded = false;
|
|
97
|
+
if (webpackConfigPath) {
|
|
98
|
+
successfullyAdded = await modifyWebpackConfig(webpackConfigPath, options);
|
|
99
|
+
} else {
|
|
100
|
+
successfullyAdded = await createNewConfigFile(
|
|
101
|
+
path.join(process.cwd(), 'webpack.config.js'),
|
|
102
|
+
getCodeSnippet(options, false),
|
|
103
|
+
'More information about Webpack configs: https://vitejs.dev/config/',
|
|
104
|
+
);
|
|
105
|
+
Sentry.setTag(
|
|
106
|
+
'created-new-config',
|
|
107
|
+
successfullyAdded ? 'success' : 'fail',
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (successfullyAdded) {
|
|
112
|
+
clack.log.info(
|
|
113
|
+
`We recommend checking the ${
|
|
114
|
+
webpackConfigPath ? 'modified' : 'added'
|
|
115
|
+
} file after the wizard finished to ensure it works with your build setup.`,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
Sentry.setTag('ast-mod', 'success');
|
|
119
|
+
} else {
|
|
120
|
+
Sentry.setTag('ast-mod', 'fail');
|
|
121
|
+
await showCopyPasteInstructions(
|
|
122
|
+
path.basename(webpackConfigPath || 'webpack.config.js'),
|
|
123
|
+
getCodeSnippet(options, true),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await addDotEnvSentryBuildPluginFile(options.authToken);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Modifies a webpack config file to enable source map generation and add the Sentry webpack plugin
|
|
132
|
+
* exported only for testing
|
|
133
|
+
*/
|
|
134
|
+
export async function modifyWebpackConfig(
|
|
135
|
+
webpackConfigPath: string,
|
|
136
|
+
options: SourceMapUploadToolConfigurationOptions,
|
|
137
|
+
): Promise<boolean> {
|
|
138
|
+
try {
|
|
139
|
+
const webpackConfig = await fs.promises.readFile(webpackConfigPath, {
|
|
140
|
+
encoding: 'utf-8',
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const prettyConfigFilename = chalk.cyan(path.basename(webpackConfigPath));
|
|
144
|
+
|
|
145
|
+
// no idea why recast returns any here, this is dumb :/
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
147
|
+
const program = recast.parse(webpackConfig.toString()).program as t.Program;
|
|
148
|
+
|
|
149
|
+
if (!(await shouldModifyWebpackConfig(program, prettyConfigFilename))) {
|
|
150
|
+
// Sentry tag is set in shouldModifyWebpackConfig
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const exportStmt = getCjsModuleExports(program);
|
|
155
|
+
if (!exportStmt) {
|
|
156
|
+
// We only care about CJS at the moment since it's probably the most widely used format for webpack configs.
|
|
157
|
+
debug(`Could not find module.exports = {...} in ${webpackConfigPath}.`);
|
|
158
|
+
Sentry.setTag('ast-mod-fail-reason', 'config-object-not-found');
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const configObject = getWebpackConfigObject(exportStmt, program);
|
|
163
|
+
|
|
164
|
+
if (!configObject) {
|
|
165
|
+
debug(`Couldn't find config object in ${webpackConfigPath}`);
|
|
166
|
+
Sentry.setTag('ast-mod-fail-reason', 'config-object-not-found');
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
53
169
|
|
|
54
|
-
|
|
55
|
-
// eslint-disable-next-line no-console
|
|
56
|
-
console.log(getCodeSnippet(options));
|
|
170
|
+
const enabledSourcemaps = enableSourcemapsGeneration(configObject);
|
|
57
171
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
172
|
+
if (enabledSourcemaps) {
|
|
173
|
+
clack.log.success(
|
|
174
|
+
`Enabled source map generation in ${prettyConfigFilename}.`,
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
clack.log.warn(
|
|
178
|
+
`Couldn't enable source maps generation in ${prettyConfigFilename} Please follow the instructions below.`,
|
|
179
|
+
);
|
|
180
|
+
Sentry.setTag('ast-mod-fail-reason', 'insertion-fail');
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const addedPlugin = addSentryWebpackPlugin(program, configObject, options);
|
|
185
|
+
if (addedPlugin) {
|
|
186
|
+
clack.log.success(
|
|
187
|
+
`Added Sentry webpack plugin to ${prettyConfigFilename}.`,
|
|
188
|
+
);
|
|
189
|
+
} else {
|
|
190
|
+
clack.log.warn(
|
|
191
|
+
`Couldn't add Sentry webpack plugin to ${prettyConfigFilename}. Please follow the instructions below.`,
|
|
192
|
+
);
|
|
193
|
+
Sentry.setTag('ast-mod-fail-reason', 'insertion-fail');
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const code = recast.print(program).code;
|
|
198
|
+
await fs.promises.writeFile(webpackConfigPath, code);
|
|
199
|
+
|
|
200
|
+
return true;
|
|
201
|
+
} catch (e) {
|
|
202
|
+
Sentry.setTag('ast-mod-fail-reason', 'insertion-fail');
|
|
203
|
+
debug(e);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function shouldModifyWebpackConfig(
|
|
209
|
+
program: t.Program,
|
|
210
|
+
prettyConfigFilename: string,
|
|
211
|
+
) {
|
|
212
|
+
if (hasSentryContent(program)) {
|
|
213
|
+
const shouldContinue = await abortIfCancelled(
|
|
214
|
+
clack.select({
|
|
215
|
+
message: `Seems like ${prettyConfigFilename} already contains Sentry-related code. Should the wizard modify it anyway?`,
|
|
216
|
+
options: [
|
|
217
|
+
{
|
|
218
|
+
label: 'Yes, add the Sentry Webpack plugin',
|
|
219
|
+
value: true,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
label: 'No, show me instructions to manually add the plugin',
|
|
223
|
+
value: false,
|
|
224
|
+
},
|
|
225
|
+
],
|
|
62
226
|
initialValue: true,
|
|
63
227
|
}),
|
|
64
228
|
);
|
|
65
229
|
|
|
66
|
-
|
|
67
|
-
|
|
230
|
+
if (!shouldContinue) {
|
|
231
|
+
Sentry.setTag('ast-mod-fail-reason', 'has-sentry-content');
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function addSentryWebpackPlugin(
|
|
240
|
+
program: t.Program,
|
|
241
|
+
configObj: t.ObjectExpression,
|
|
242
|
+
options: SourceMapUploadToolConfigurationOptions,
|
|
243
|
+
) {
|
|
244
|
+
const b = addSentryWebpackPluginImport(program);
|
|
245
|
+
|
|
246
|
+
const sentryPluginCall = b.callExpression(
|
|
247
|
+
b.identifier('sentryWebpackPlugin'),
|
|
248
|
+
[
|
|
249
|
+
b.objectExpression([
|
|
250
|
+
b.objectProperty(
|
|
251
|
+
b.identifier('authToken'),
|
|
252
|
+
b.identifier('process.env.SENTRY_AUTH_TOKEN'),
|
|
253
|
+
),
|
|
254
|
+
b.objectProperty(b.identifier('org'), b.stringLiteral(options.orgSlug)),
|
|
255
|
+
b.objectProperty(
|
|
256
|
+
b.identifier('project'),
|
|
257
|
+
b.stringLiteral(options.projectSlug),
|
|
258
|
+
),
|
|
259
|
+
...(options.selfHosted
|
|
260
|
+
? [
|
|
261
|
+
b.objectProperty(
|
|
262
|
+
b.identifier('url'),
|
|
263
|
+
b.stringLiteral(options.url),
|
|
264
|
+
),
|
|
265
|
+
]
|
|
266
|
+
: []),
|
|
267
|
+
]),
|
|
268
|
+
],
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const pluginsProp = configObj.properties.find(
|
|
272
|
+
(p): p is t.Property =>
|
|
273
|
+
p.type === 'Property' &&
|
|
274
|
+
p.key.type === 'Identifier' &&
|
|
275
|
+
p.key.name === 'plugins',
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
if (pluginsProp) {
|
|
279
|
+
if (pluginsProp.value.type === 'ArrayExpression') {
|
|
280
|
+
pluginsProp.value.elements.push(sentryPluginCall);
|
|
281
|
+
} else {
|
|
282
|
+
pluginsProp.value = b.arrayExpression([sentryPluginCall]);
|
|
283
|
+
}
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
configObj.properties.push(
|
|
288
|
+
b.objectProperty(
|
|
289
|
+
b.identifier('plugins'),
|
|
290
|
+
b.arrayExpression([sentryPluginCall]),
|
|
291
|
+
),
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function addSentryWebpackPluginImport(program: t.Program) {
|
|
298
|
+
const b = recast.types.builders;
|
|
299
|
+
|
|
300
|
+
const sentryPluginRequireStmt = b.variableDeclaration('const', [
|
|
301
|
+
b.variableDeclarator(
|
|
302
|
+
b.objectPattern([
|
|
303
|
+
b.objectProperty.from({
|
|
304
|
+
key: b.identifier('sentryWebpackPlugin'),
|
|
305
|
+
value: b.identifier('sentryWebpackPlugin'),
|
|
306
|
+
shorthand: true,
|
|
307
|
+
}),
|
|
308
|
+
]),
|
|
309
|
+
b.callExpression(b.identifier('require'), [
|
|
310
|
+
b.stringLiteral('@sentry/webpack-plugin'),
|
|
311
|
+
]),
|
|
312
|
+
),
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
program.body.unshift(sentryPluginRequireStmt);
|
|
316
|
+
return b;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function enableSourcemapsGeneration(configObj: t.ObjectExpression): boolean {
|
|
320
|
+
const b = recast.types.builders;
|
|
321
|
+
|
|
322
|
+
const devtoolProp = configObj.properties.find(
|
|
323
|
+
(p): p is t.Property =>
|
|
324
|
+
p.type === 'Property' &&
|
|
325
|
+
p.key.type === 'Identifier' &&
|
|
326
|
+
p.key.name === 'devtool',
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
if (devtoolProp) {
|
|
330
|
+
// devtool can have quite a lot of source maps values.
|
|
331
|
+
// see: https://webpack.js.org/configuration/devtool/#devtool
|
|
332
|
+
// For Sentry to work best, we should set it to "source-map" or "hidden-source-map"
|
|
333
|
+
// Heuristic:
|
|
334
|
+
// - all values that contain "hidden" will be set to "hidden-source-map"
|
|
335
|
+
// - all other values will be set to "source-map"
|
|
336
|
+
if (
|
|
337
|
+
(devtoolProp.value.type === 'Literal' ||
|
|
338
|
+
devtoolProp.value.type === 'StringLiteral') &&
|
|
339
|
+
devtoolProp.value.value?.toString().startsWith('hidden-')
|
|
340
|
+
) {
|
|
341
|
+
devtoolProp.value = b.stringLiteral('hidden-source-map');
|
|
342
|
+
} else {
|
|
343
|
+
devtoolProp.value = b.stringLiteral('source-map');
|
|
344
|
+
}
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
configObj.properties.push(
|
|
349
|
+
b.objectProperty(b.identifier('devtool'), b.stringLiteral('source-map')),
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function getWebpackConfigObject(
|
|
356
|
+
moduleExports: t.AssignmentExpression,
|
|
357
|
+
program: t.Program,
|
|
358
|
+
): t.ObjectExpression | undefined {
|
|
359
|
+
const rhs = moduleExports.right;
|
|
360
|
+
if (rhs.type === 'ObjectExpression') {
|
|
361
|
+
return rhs;
|
|
362
|
+
}
|
|
363
|
+
if (rhs.type === 'Identifier') {
|
|
364
|
+
const configId = rhs.name;
|
|
365
|
+
|
|
366
|
+
const configDeclaration = program.body.find(
|
|
367
|
+
(s): s is t.VariableDeclaration =>
|
|
368
|
+
s.type === 'VariableDeclaration' &&
|
|
369
|
+
!!s.declarations.find(
|
|
370
|
+
(d) =>
|
|
371
|
+
d.type === 'VariableDeclarator' &&
|
|
372
|
+
d.id.type === 'Identifier' &&
|
|
373
|
+
d.id.name === configId,
|
|
374
|
+
),
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
const declarator = configDeclaration?.declarations.find(
|
|
378
|
+
(d): d is t.VariableDeclarator =>
|
|
379
|
+
d.type === 'VariableDeclarator' &&
|
|
380
|
+
d.id.type === 'Identifier' &&
|
|
381
|
+
d.id.name === configId,
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
return declarator?.init?.type === 'ObjectExpression'
|
|
385
|
+
? declarator.init
|
|
386
|
+
: undefined;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function getCjsModuleExports(
|
|
393
|
+
program: t.Program,
|
|
394
|
+
): t.AssignmentExpression | undefined {
|
|
395
|
+
const moduleExports = program.body.find(
|
|
396
|
+
(s): s is t.ExpressionStatement =>
|
|
397
|
+
s.type === 'ExpressionStatement' &&
|
|
398
|
+
s.expression.type === 'AssignmentExpression' &&
|
|
399
|
+
s.expression.left.type === 'MemberExpression' &&
|
|
400
|
+
s.expression.left.object.type === 'Identifier' &&
|
|
401
|
+
s.expression.left.object.name === 'module' &&
|
|
402
|
+
s.expression.left.property.type === 'Identifier' &&
|
|
403
|
+
s.expression.left.property.name === 'exports',
|
|
404
|
+
);
|
|
405
|
+
return moduleExports?.expression as t.AssignmentExpression;
|
|
406
|
+
}
|
|
@@ -11,7 +11,8 @@ export type SupportedTools =
|
|
|
11
11
|
| 'create-react-app'
|
|
12
12
|
| 'angular'
|
|
13
13
|
| 'nextjs'
|
|
14
|
-
| 'remix'
|
|
14
|
+
| 'remix'
|
|
15
|
+
| 'no-tool';
|
|
15
16
|
|
|
16
17
|
// A map of package names pointing to the tool slug.
|
|
17
18
|
// The order is important, because we want to detect the most specific tool first.
|
|
@@ -15,7 +15,11 @@ import { addVitePlugin } from 'magicast/helpers';
|
|
|
15
15
|
import { getClientHooksTemplate, getServerHooksTemplate } from './templates';
|
|
16
16
|
import { abortIfCancelled, isUsingTypeScript } from '../utils/clack-utils';
|
|
17
17
|
import { debug } from '../utils/debug';
|
|
18
|
-
import {
|
|
18
|
+
import { findFile, hasSentryContent } from '../utils/ast-utils';
|
|
19
|
+
|
|
20
|
+
import * as recast from 'recast';
|
|
21
|
+
import x = recast.types;
|
|
22
|
+
import t = x.namedTypes;
|
|
19
23
|
|
|
20
24
|
const SVELTE_CONFIG_FILE = 'svelte.config.js';
|
|
21
25
|
|
|
@@ -46,10 +50,10 @@ export async function createOrMergeSvelteKitFiles(
|
|
|
46
50
|
const { clientHooksPath, serverHooksPath } = getHooksConfigDirs(svelteConfig);
|
|
47
51
|
|
|
48
52
|
// full file paths with correct file ending (or undefined if not found)
|
|
49
|
-
const originalClientHooksFile =
|
|
50
|
-
const originalServerHooksFile =
|
|
53
|
+
const originalClientHooksFile = findFile(clientHooksPath);
|
|
54
|
+
const originalServerHooksFile = findFile(serverHooksPath);
|
|
51
55
|
|
|
52
|
-
const viteConfig =
|
|
56
|
+
const viteConfig = findFile(path.resolve(process.cwd(), 'vite.config'));
|
|
53
57
|
|
|
54
58
|
const fileEnding = isUsingTypeScript() ? 'ts' : 'js';
|
|
55
59
|
|
|
@@ -139,7 +143,7 @@ async function mergeHooksFile(
|
|
|
139
143
|
dsn: string,
|
|
140
144
|
): Promise<void> {
|
|
141
145
|
const originalHooksMod = await loadFile(hooksFile);
|
|
142
|
-
if (hasSentryContent(originalHooksMod)) {
|
|
146
|
+
if (hasSentryContent(originalHooksMod.$ast as t.Program)) {
|
|
143
147
|
// We don't want to mess with files that already have Sentry content.
|
|
144
148
|
// Let's just bail out at this point.
|
|
145
149
|
clack.log.warn(
|
|
@@ -399,7 +403,7 @@ async function modifyViteConfig(
|
|
|
399
403
|
try {
|
|
400
404
|
const viteModule = parseModule(viteConfigContent);
|
|
401
405
|
|
|
402
|
-
if (hasSentryContent(viteModule)) {
|
|
406
|
+
if (hasSentryContent(viteModule.$ast as t.Program)) {
|
|
403
407
|
clack.log.warn(
|
|
404
408
|
`File ${chalk.cyan(
|
|
405
409
|
path.basename(viteConfigPath),
|
|
@@ -4,12 +4,10 @@ import chalk from 'chalk';
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
abort,
|
|
7
|
-
|
|
8
|
-
askForProjectSelection,
|
|
9
|
-
askForSelfHosted,
|
|
10
|
-
askForWizardLogin,
|
|
7
|
+
addSentryCliConfig,
|
|
11
8
|
confirmContinueEvenThoughNoGitRepo,
|
|
12
9
|
ensurePackageIsInstalled,
|
|
10
|
+
getOrAskForProjectData,
|
|
13
11
|
getPackageDotJson,
|
|
14
12
|
installPackage,
|
|
15
13
|
printWelcome,
|
|
@@ -32,22 +30,15 @@ export async function runSvelteKitWizard(
|
|
|
32
30
|
const packageJson = await getPackageDotJson();
|
|
33
31
|
await ensurePackageIsInstalled(packageJson, '@sveltejs/kit', 'Sveltekit');
|
|
34
32
|
|
|
35
|
-
const {
|
|
36
|
-
|
|
37
|
-
const { projects, apiKeys } = await askForWizardLogin({
|
|
38
|
-
promoCode: options.promoCode,
|
|
39
|
-
url: sentryUrl,
|
|
40
|
-
platform: 'javascript-sveltekit',
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const selectedProject = await askForProjectSelection(projects);
|
|
33
|
+
const { selectedProject, selfHosted, sentryUrl, authToken } =
|
|
34
|
+
await getOrAskForProjectData(options, 'javascript-sveltekit');
|
|
44
35
|
|
|
45
36
|
await installPackage({
|
|
46
37
|
packageName: '@sentry/sveltekit',
|
|
47
38
|
alreadyInstalled: hasPackageInstalled('@sentry/sveltekit', packageJson),
|
|
48
39
|
});
|
|
49
40
|
|
|
50
|
-
await
|
|
41
|
+
await addSentryCliConfig(authToken);
|
|
51
42
|
|
|
52
43
|
const svelteConfig = await loadSvelteConfig();
|
|
53
44
|
|
package/src/telemetry.ts
CHANGED
|
@@ -52,6 +52,8 @@ function createSentryInstance(enabled: boolean, integration: string) {
|
|
|
52
52
|
dsn: 'https://8871d3ff64814ed8960c96d1fcc98a27@o1.ingest.sentry.io/4505425820712960',
|
|
53
53
|
enabled: enabled,
|
|
54
54
|
|
|
55
|
+
environment: `production-${integration}`,
|
|
56
|
+
|
|
55
57
|
tracesSampleRate: 1,
|
|
56
58
|
sampleRate: 1,
|
|
57
59
|
|
package/src/utils/ast-utils.ts
CHANGED
|
@@ -1,20 +1,38 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
|
|
3
|
-
import
|
|
2
|
+
|
|
3
|
+
import * as recast from 'recast';
|
|
4
|
+
import x = recast.types;
|
|
5
|
+
import t = x.namedTypes;
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* Checks if a
|
|
8
|
+
* Checks if a file where we don't know its concrete file type yet exists
|
|
7
9
|
* and returns the full path to the file with the correct file type.
|
|
8
10
|
*/
|
|
9
|
-
export function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
export function findFile(
|
|
12
|
+
filePath: string,
|
|
13
|
+
fileTypes: string[] = ['.js', '.ts', '.mjs', '.cjs'],
|
|
14
|
+
): string | undefined {
|
|
15
|
+
return fileTypes
|
|
16
|
+
.map((type) => `${filePath}${type}`)
|
|
13
17
|
.find((file) => fs.existsSync(file));
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
/**
|
|
21
|
+
* checks for require('@sentry/*') syntax
|
|
22
|
+
*/
|
|
23
|
+
export function hasSentryContent(program: t.Program): boolean {
|
|
24
|
+
let foundSentry: boolean | undefined = false;
|
|
25
|
+
recast.visit(program, {
|
|
26
|
+
visitStringLiteral(path) {
|
|
27
|
+
foundSentry = foundSentry || path.node.value.startsWith('@sentry/');
|
|
28
|
+
this.traverse(path);
|
|
29
|
+
},
|
|
30
|
+
visitLiteral(path) {
|
|
31
|
+
foundSentry =
|
|
32
|
+
foundSentry || path.node.value?.toString().startsWith('@sentry/');
|
|
33
|
+
this.traverse(path);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return !!foundSentry;
|
|
20
38
|
}
|