@sentry/wizard 3.3.1 → 3.4.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.
@@ -16,14 +16,21 @@ import { SourceMapUploadToolConfigurationOptions } from './tools/types';
16
16
  import { configureVitePlugin } from './tools/vite';
17
17
  import { configureSentryCLI } from './tools/sentry-cli';
18
18
  import { configureWebPackPlugin } from './tools/webpack';
19
+ import { configureTscSourcemapGenerationFlow } from './tools/tsc';
20
+ import { configureRollupPlugin } from './tools/rollup';
21
+ import { configureEsbuildPlugin } from './tools/esbuild';
19
22
 
20
23
  interface SourceMapsWizardOptions {
21
24
  promoCode?: string;
22
25
  }
23
26
 
24
- type SupportedBundlers = 'webpack' | 'vite' | 'rollup' | 'esbuild';
25
- type SupportedTools = 'sentry-cli';
26
- type SupportedBundlersTools = SupportedBundlers | SupportedTools;
27
+ type SupportedTools =
28
+ | 'webpack'
29
+ | 'vite'
30
+ | 'rollup'
31
+ | 'esbuild'
32
+ | 'tsc'
33
+ | 'sentry-cli';
27
34
 
28
35
  export async function runSourcemapsWizard(
29
36
  options: SourceMapsWizardOptions,
@@ -59,7 +66,7 @@ export async function runSourcemapsWizard(
59
66
  });
60
67
 
61
68
  clack.log.step(
62
- 'Add the Sentry auth token as an environment variable to your CI setup:',
69
+ 'Add the Sentry authentication token as an environment variable to your CI setup:',
63
70
  );
64
71
 
65
72
  // Intentially logging directly to console here so that the code can be copied/pasted directly
@@ -103,29 +110,29 @@ SENTRY_AUTH_TOKEN=${apiKeys.token}
103
110
 
104
111
  ${chalk.cyan(`Validate your setup with the following Steps:
105
112
 
106
- 1. Build your application in ${chalk.bold('production mode')}
113
+ 1. Build your application in ${chalk.bold('production mode')}.
107
114
  ${chalk.gray(
108
- `${arrow} You should see source map upload logs in your console when building`,
115
+ `${arrow} You should see source map upload logs in your console.`,
109
116
  )}
110
- 2. Run your application and throw a test error
111
- ${chalk.gray(`${arrow} You should see the error in Sentry`)}
112
- 3. Open the error in Sentry and verify it's source-mapped
117
+ 2. Run your application and throw a test error.
118
+ ${chalk.gray(`${arrow} The error should be visible in Sentry.`)}
119
+ 3. Open the error in Sentry and verify that it's source-mapped.
113
120
  ${chalk.gray(
114
- `${arrow} If your error is source-mapped, the stack trace should show your original source code`,
121
+ `${arrow} The stack trace should show your original source code.`,
115
122
  )}
116
123
  `)}
117
124
  ${chalk.dim(
118
- `If you encounter any issues, follow our Troubleshooting Guide:
125
+ `If you encounter any issues, please refer to the Troubleshooting Guide:
119
126
  https://docs.sentry.io/platforms/javascript/sourcemaps/troubleshooting_js
120
127
 
121
- If the guide didn't help or you encountered a bug, let us know:
128
+ If the guide doesn't help or you encounter a bug, please let us know:
122
129
  https://github.com/getsentry/sentry-javascript/issues`,
123
130
  )}
124
131
  `);
125
132
  }
126
133
 
127
- async function askForUsedBundlerTool(): Promise<SupportedBundlersTools> {
128
- const selectedTool: SupportedBundlersTools | symbol = await abortIfCancelled(
134
+ async function askForUsedBundlerTool(): Promise<SupportedTools> {
135
+ const selectedTool: SupportedTools | symbol = await abortIfCancelled(
129
136
  clack.select({
130
137
  message: 'Which bundler or build tool are you using?',
131
138
  options: [
@@ -139,17 +146,21 @@ async function askForUsedBundlerTool(): Promise<SupportedBundlersTools> {
139
146
  value: 'vite',
140
147
  hint: 'Configure source maps upload using Vite',
141
148
  },
142
- // TODO: Implement rollup and esbuild flows
143
- // {
144
- // label: 'esbuild',
145
- // value: 'esbuild',
146
- // hint: 'Configure source maps upload using esbuild',
147
- // },
148
- // {
149
- // label: 'Rollup',
150
- // value: 'rollup',
151
- // hint: 'Configure source maps upload using Rollup',
152
- // },
149
+ {
150
+ label: 'esbuild',
151
+ value: 'esbuild',
152
+ hint: 'Configure source maps upload using esbuild',
153
+ },
154
+ {
155
+ label: 'Rollup',
156
+ value: 'rollup',
157
+ hint: 'Configure source maps upload using Rollup',
158
+ },
159
+ {
160
+ label: 'tsc',
161
+ value: 'tsc',
162
+ hint: 'Configure source maps when using tsc as build tool',
163
+ },
153
164
  {
154
165
  label: 'None of the above',
155
166
  value: 'sentry-cli',
@@ -163,17 +174,25 @@ async function askForUsedBundlerTool(): Promise<SupportedBundlersTools> {
163
174
  }
164
175
 
165
176
  async function startToolSetupFlow(
166
- selctedTool: SupportedBundlersTools,
177
+ selctedTool: SupportedTools,
167
178
  options: SourceMapUploadToolConfigurationOptions,
168
179
  ): Promise<void> {
169
180
  switch (selctedTool) {
181
+ case 'webpack':
182
+ await configureWebPackPlugin(options);
183
+ break;
170
184
  case 'vite':
171
185
  await configureVitePlugin(options);
172
186
  break;
173
- case 'webpack':
174
- await configureWebPackPlugin(options);
187
+ case 'esbuild':
188
+ await configureEsbuildPlugin(options);
189
+ break;
190
+ case 'rollup':
191
+ await configureRollupPlugin(options);
192
+ break;
193
+ case 'tsc':
194
+ await configureSentryCLI(options, configureTscSourcemapGenerationFlow);
175
195
  break;
176
- // TODO: implement other bundlers
177
196
  default:
178
197
  await configureSentryCLI(options);
179
198
  break;
@@ -0,0 +1,65 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import clack, { select } from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import {
5
+ abortIfCancelled,
6
+ addDotEnvSentryBuildPluginFile,
7
+ getPackageDotJson,
8
+ hasPackageInstalled,
9
+ installPackage,
10
+ } from '../../utils/clack-utils';
11
+
12
+ import {
13
+ SourceMapUploadToolConfigurationFunction,
14
+ SourceMapUploadToolConfigurationOptions,
15
+ } from './types';
16
+
17
+ const getCodeSnippet = (options: SourceMapUploadToolConfigurationOptions) =>
18
+ chalk.gray(`
19
+ ${chalk.greenBright(
20
+ 'const { sentryEsbuildPlugin } = require("@sentry/esbuild-plugin");',
21
+ )}
22
+
23
+ require("esbuild").build({
24
+ ${chalk.greenBright(
25
+ 'sourcemap: true, // Source map generation must be turned on',
26
+ )}
27
+ plugins: [
28
+ // Put the Sentry esbuild plugin after all other plugins
29
+ ${chalk.greenBright(`sentryEsbuildPlugin({
30
+ authToken: process.env.SENTRY_AUTH_TOKEN,
31
+ org: "${options.orgSlug}",
32
+ project: "${options.projectSlug}",${
33
+ options.selfHosted ? `\n url: "${options.url}",` : ''
34
+ }
35
+ }),`)}
36
+ ],
37
+ });
38
+ `);
39
+
40
+ export const configureEsbuildPlugin: SourceMapUploadToolConfigurationFunction =
41
+ async (options) => {
42
+ await installPackage({
43
+ packageName: '@sentry/esbuild-plugin',
44
+ alreadyInstalled: hasPackageInstalled(
45
+ '@sentry/esbuild-plugin',
46
+ await getPackageDotJson(),
47
+ ),
48
+ });
49
+
50
+ clack.log.step(`Add the following code to your esbuild config:`);
51
+
52
+ // Intentially logging directly to console here so that the code can be copied/pasted directly
53
+ // eslint-disable-next-line no-console
54
+ console.log(getCodeSnippet(options));
55
+
56
+ await abortIfCancelled(
57
+ select({
58
+ message: 'Did you copy the snippet above?',
59
+ options: [{ label: 'Yes, continue!', value: true }],
60
+ initialValue: true,
61
+ }),
62
+ );
63
+
64
+ await addDotEnvSentryBuildPluginFile(options.authToken);
65
+ };
@@ -0,0 +1,69 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import clack, { select } from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import {
5
+ abortIfCancelled,
6
+ addDotEnvSentryBuildPluginFile,
7
+ getPackageDotJson,
8
+ hasPackageInstalled,
9
+ installPackage,
10
+ } from '../../utils/clack-utils';
11
+
12
+ import {
13
+ SourceMapUploadToolConfigurationFunction,
14
+ SourceMapUploadToolConfigurationOptions,
15
+ } from './types';
16
+
17
+ const getCodeSnippet = (options: SourceMapUploadToolConfigurationOptions) =>
18
+ chalk.gray(`
19
+ ${chalk.greenBright(
20
+ 'import { sentryRollupPlugin } from "@sentry/rollup-plugin";',
21
+ )}
22
+
23
+ export default {
24
+ output: {
25
+ ${chalk.greenBright(
26
+ 'sourcemap: true, // Source map generation must be turned on',
27
+ )}
28
+ },
29
+ plugins: [
30
+ // Put the Sentry rollup plugin after all other plugins
31
+ ${chalk.greenBright(`sentryRollupPlugin({
32
+ authToken: process.env.SENTRY_AUTH_TOKEN,
33
+ org: "${options.orgSlug}",
34
+ project: "${options.projectSlug}",${
35
+ options.selfHosted ? `\n url: "${options.url}",` : ''
36
+ }
37
+ }),`)}
38
+ ],
39
+ };
40
+ `);
41
+
42
+ export const configureRollupPlugin: SourceMapUploadToolConfigurationFunction =
43
+ async (options) => {
44
+ await installPackage({
45
+ packageName: '@sentry/rollup-plugin',
46
+ alreadyInstalled: hasPackageInstalled(
47
+ '@sentry/rollup-plugin',
48
+ await getPackageDotJson(),
49
+ ),
50
+ });
51
+
52
+ clack.log.step(
53
+ `Add the following code to your rollup config:`,
54
+ );
55
+
56
+ // Intentially logging directly to console here so that the code can be copied/pasted directly
57
+ // eslint-disable-next-line no-console
58
+ console.log(getCodeSnippet(options));
59
+
60
+ await abortIfCancelled(
61
+ select({
62
+ message: 'Did you copy the snippet above?',
63
+ options: [{ label: 'Yes, continue!', value: true }],
64
+ initialValue: true,
65
+ }),
66
+ );
67
+
68
+ await addDotEnvSentryBuildPluginFile(options.authToken);
69
+ };
@@ -12,117 +12,121 @@ import {
12
12
  installPackage,
13
13
  } from '../../utils/clack-utils';
14
14
 
15
- import { SourceMapUploadToolConfigurationFunction } from './types';
16
-
17
- export const configureSentryCLI: SourceMapUploadToolConfigurationFunction =
18
- async (options) => {
19
- const packageDotJson = await getPackageDotJson();
20
-
21
- await installPackage({
22
- packageName: '@sentry/cli',
23
- alreadyInstalled: hasPackageInstalled('@sentry/cli', packageDotJson),
24
- });
25
-
26
- let validPath = false;
27
- let relativeArtifactPath;
28
- do {
29
- const rawArtifactPath = await abortIfCancelled(
30
- clack.text({
31
- message: 'Where are your build artifacts located?',
32
- placeholder: `.${path.sep}out`,
33
- }),
34
- );
35
-
36
- if (path.isAbsolute(rawArtifactPath)) {
37
- relativeArtifactPath = path.relative(process.cwd(), rawArtifactPath);
38
- } else {
39
- relativeArtifactPath = rawArtifactPath;
40
- }
41
-
42
- try {
43
- await fs.promises.access(
44
- path.join(process.cwd(), relativeArtifactPath),
45
- );
46
- validPath = true;
47
- } catch {
48
- validPath = await abortIfCancelled(
49
- clack.select({
50
- message: `We couldn't find artifacts at ${relativeArtifactPath}. Are you sure that this is the location that contains your build artifacts?`,
51
- options: [
52
- {
53
- label: 'No, let me verify.',
54
- value: false,
55
- },
56
- { label: 'Yes, I am sure!', value: true },
57
- ],
58
- initialValue: false,
59
- }),
60
- );
61
- }
62
- } while (!validPath);
63
-
64
- const relativePosixArtifactPath = relativeArtifactPath
65
- .split(path.sep)
66
- .join(path.posix.sep);
67
-
68
- await abortIfCancelled(
69
- clack.select({
70
- message: `Verify that your build tool is generating source maps. ${chalk.dim(
71
- '(Your build output folder should contain .js.map files after a build)',
72
- )}`,
73
- options: [{ label: 'I checked. Continue!', value: true }],
74
- initialValue: true,
75
- }),
76
- );
15
+ import { SourceMapUploadToolConfigurationOptions } from './types';
77
16
 
78
- packageDotJson.scripts = packageDotJson.scripts || {};
79
- packageDotJson.scripts['sentry:ci'] = `sentry-cli sourcemaps inject --org ${
80
- options.orgSlug
81
- } --project ${
82
- options.projectSlug
83
- } ${relativePosixArtifactPath} && sentry-cli${
84
- options.selfHosted ? ` --url ${options.url}` : ''
85
- } sourcemaps upload --org ${options.orgSlug} --project ${
86
- options.projectSlug
87
- } ${relativePosixArtifactPath}`;
88
-
89
- await fs.promises.writeFile(
90
- path.join(process.cwd(), 'package.json'),
91
- JSON.stringify(packageDotJson, null, 2),
92
- );
17
+ export async function configureSentryCLI(
18
+ options: SourceMapUploadToolConfigurationOptions,
19
+ configureSourcemapGenerationFlow: () => Promise<void> = defaultConfigureSourcemapGenerationFlow,
20
+ ): Promise<void> {
21
+ const packageDotJson = await getPackageDotJson();
93
22
 
94
- clack.log.info(
95
- `Added a ${chalk.cyan('sentry:ci')} script to your ${chalk.cyan(
96
- 'package.json',
97
- )}. Make sure to run this script ${chalk.bold(
98
- 'after',
99
- )} building your application but ${chalk.bold('before')} deploying!`,
100
- );
23
+ await installPackage({
24
+ packageName: '@sentry/cli',
25
+ alreadyInstalled: hasPackageInstalled('@sentry/cli', packageDotJson),
26
+ });
101
27
 
102
- const addedToCI = await abortIfCancelled(
103
- clack.select({
104
- message: `Did you add running the ${chalk.cyan(
105
- 'sentry:ci',
106
- )} script to your CI pipeline ${chalk.bold('after the build step')}?`,
107
- options: [
108
- { label: 'Yes, continue!', value: true },
109
- {
110
- label: "I'll do it later...",
111
- value: false,
112
- hint: chalk.yellow(
113
- 'You need to run the command after each build for source maps to work properly.',
114
- ),
115
- },
116
- ],
117
- initialValue: true,
28
+ let validPath = false;
29
+ let relativeArtifactPath;
30
+ do {
31
+ const rawArtifactPath = await abortIfCancelled(
32
+ clack.text({
33
+ message: 'Where are your build artifacts located?',
34
+ placeholder: `.${path.sep}out`,
118
35
  }),
119
36
  );
120
37
 
121
- Sentry.setTag('added-ci-script', addedToCI);
38
+ if (path.isAbsolute(rawArtifactPath)) {
39
+ relativeArtifactPath = path.relative(process.cwd(), rawArtifactPath);
40
+ } else {
41
+ relativeArtifactPath = rawArtifactPath;
42
+ }
122
43
 
123
- if (!addedToCI) {
124
- clack.log.info("Don't forget! :)");
44
+ try {
45
+ await fs.promises.access(path.join(process.cwd(), relativeArtifactPath));
46
+ validPath = true;
47
+ } catch {
48
+ validPath = await abortIfCancelled(
49
+ clack.select({
50
+ message: `We couldn't find artifacts at ${relativeArtifactPath}. Are you sure that this is the location that contains your build artifacts?`,
51
+ options: [
52
+ {
53
+ label: 'No, let me verify.',
54
+ value: false,
55
+ },
56
+ { label: 'Yes, I am sure!', value: true },
57
+ ],
58
+ initialValue: false,
59
+ }),
60
+ );
125
61
  }
62
+ } while (!validPath);
63
+
64
+ const relativePosixArtifactPath = relativeArtifactPath
65
+ .split(path.sep)
66
+ .join(path.posix.sep);
67
+
68
+ await configureSourcemapGenerationFlow();
69
+
70
+ packageDotJson.scripts = packageDotJson.scripts || {};
71
+ packageDotJson.scripts['sentry:ci'] = `sentry-cli sourcemaps inject --org ${
72
+ options.orgSlug
73
+ } --project ${
74
+ options.projectSlug
75
+ } ${relativePosixArtifactPath} && sentry-cli${
76
+ options.selfHosted ? ` --url ${options.url}` : ''
77
+ } sourcemaps upload --org ${options.orgSlug} --project ${
78
+ options.projectSlug
79
+ } ${relativePosixArtifactPath}`;
80
+
81
+ await fs.promises.writeFile(
82
+ path.join(process.cwd(), 'package.json'),
83
+ JSON.stringify(packageDotJson, null, 2),
84
+ );
85
+
86
+ clack.log.info(
87
+ `Added a ${chalk.cyan('sentry:ci')} script to your ${chalk.cyan(
88
+ 'package.json',
89
+ )}. Make sure to run this script ${chalk.bold(
90
+ 'after',
91
+ )} building your application but ${chalk.bold('before')} deploying!`,
92
+ );
93
+
94
+ const addedToCI = await abortIfCancelled(
95
+ clack.select({
96
+ message: `Did you add a step to your CI pipeline that runs the ${chalk.cyan(
97
+ 'sentry:ci',
98
+ )} script ${chalk.bold('right after')} building your application?`,
99
+ options: [
100
+ { label: 'Yes, continue!', value: true },
101
+ {
102
+ label: "I'll do it later...",
103
+ value: false,
104
+ hint: chalk.yellow(
105
+ 'You need to run the command after each build for source maps to work properly.',
106
+ ),
107
+ },
108
+ ],
109
+ initialValue: true,
110
+ }),
111
+ );
112
+
113
+ Sentry.setTag('added-ci-script', addedToCI);
114
+
115
+ if (!addedToCI) {
116
+ clack.log.info("Don't forget! :)");
117
+ }
118
+
119
+ await addSentryCliRc(options.authToken);
120
+ }
126
121
 
127
- await addSentryCliRc(options.authToken);
128
- };
122
+ async function defaultConfigureSourcemapGenerationFlow(): Promise<void> {
123
+ await abortIfCancelled(
124
+ clack.select({
125
+ message: `Verify that your build tool is generating source maps. ${chalk.dim(
126
+ '(Your build output folder should contain .js.map files after a build)',
127
+ )}`,
128
+ options: [{ label: 'I checked. Continue!', value: true }],
129
+ initialValue: true,
130
+ }),
131
+ );
132
+ }
@@ -0,0 +1,39 @@
1
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
2
+ import clack, { select } from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+ import { abortIfCancelled } from '../../utils/clack-utils';
5
+
6
+ export async function configureTscSourcemapGenerationFlow(): Promise<void> {
7
+ clack.log.step(
8
+ `Add the following code to your ${chalk.bold(
9
+ 'tsconfig.json',
10
+ )} file: ${chalk.dim(
11
+ '(This ensures that source maps are generated correctly)',
12
+ )}`,
13
+ );
14
+
15
+ // Intentially logging directly to console here so that the code can be copied/pasted directly
16
+ // eslint-disable-next-line no-console
17
+ console.log(codeSnippet);
18
+
19
+ await abortIfCancelled(
20
+ select({
21
+ message: 'Did you update your config as shown in the snippet above?',
22
+ options: [{ label: 'Yes, continue!', value: true }],
23
+ initialValue: true,
24
+ }),
25
+ );
26
+ }
27
+
28
+ const codeSnippet = chalk.gray(`
29
+ {
30
+ "compilerOptions": {
31
+ ${chalk.greenBright('"sourceMap": true,')}
32
+ ${chalk.greenBright('"inlineSources": true,')}
33
+
34
+ // Set \`sourceRoot\` to "/" to strip the build path prefix from
35
+ // generated source code references. This will improve issue grouping in Sentry.
36
+ ${chalk.greenBright('"sourceRoot": "/"')}
37
+ }
38
+ }
39
+ `);
@@ -92,7 +92,7 @@ export function printWelcome(options: {
92
92
 
93
93
  let welcomeText =
94
94
  options.message ||
95
- 'This Wizard will help you to set up Sentry for your application.\nThank you for using Sentry :)';
95
+ 'This Wizard will help you set up Sentry for your application.\nThank you for using Sentry :)';
96
96
 
97
97
  if (options.promoCode) {
98
98
  welcomeText += `\n\nUsing promo-code: ${options.promoCode}`;
@@ -190,7 +190,7 @@ export async function askForWizardLogin(options: {
190
190
  const loginSpinner = clack.spinner();
191
191
 
192
192
  loginSpinner.start(
193
- 'Waiting for you to click the link above 👆. Take your time.',
193
+ "Waiting for you to log in using the link above. Once you're logged in, return to this wizard.",
194
194
  );
195
195
 
196
196
  const data = await new Promise<WizardProjectData>((resolve) => {
@@ -413,7 +413,7 @@ export async function addSentryCliRc(authToken: string): Promise<void> {
413
413
  }
414
414
  }
415
415
 
416
- await addAuthTokenFileToGitIgnore('.sentyclirc');
416
+ await addAuthTokenFileToGitIgnore('.sentryclirc');
417
417
  }
418
418
 
419
419
  export async function addDotEnvSentryBuildPluginFile(