@sentry/wizard 3.4.0 → 3.6.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 +20 -0
- package/bin.ts +29 -20
- package/dist/bin.js +27 -19
- package/dist/bin.js.map +1 -1
- package/dist/lib/Constants.d.ts +2 -0
- package/dist/lib/Constants.js +5 -0
- package/dist/lib/Constants.js.map +1 -1
- package/dist/lib/Helper/Wizard.js +2 -9
- package/dist/lib/Helper/Wizard.js.map +1 -1
- package/dist/lib/Helper/__tests__/SentryCli.js +1 -0
- package/dist/lib/Helper/__tests__/SentryCli.js.map +1 -1
- package/dist/lib/Setup.js.map +1 -1
- package/dist/lib/Steps/ChooseIntegration.js +30 -10
- package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
- package/dist/lib/Steps/Integrations/Apple.d.ts +10 -0
- package/dist/lib/Steps/Integrations/Apple.js +92 -0
- package/dist/lib/Steps/Integrations/Apple.js.map +1 -0
- package/dist/lib/Steps/Integrations/{NextJs.d.ts → NextJsShim.d.ts} +1 -1
- package/dist/lib/Steps/Integrations/{NextJs.js → NextJsShim.js} +14 -10
- package/dist/lib/Steps/Integrations/NextJsShim.js.map +1 -0
- package/dist/lib/Steps/Integrations/SourceMapsShim.js +5 -1
- package/dist/lib/Steps/Integrations/SourceMapsShim.js.map +1 -1
- package/dist/lib/Steps/Integrations/{SvelteKit.d.ts → SvelteKitShim.d.ts} +1 -1
- package/dist/lib/Steps/Integrations/{SvelteKit.js → SvelteKitShim.js} +14 -10
- package/dist/lib/Steps/Integrations/SvelteKitShim.js.map +1 -0
- package/dist/package.json +4 -4
- package/dist/src/apple/apple-wizard.d.ts +2 -0
- package/dist/src/apple/apple-wizard.js +197 -0
- package/dist/src/apple/apple-wizard.js.map +1 -0
- package/dist/src/apple/code-tools.d.ts +1 -0
- package/dist/src/apple/code-tools.js +100 -0
- package/dist/src/apple/code-tools.js.map +1 -0
- package/dist/src/apple/templates.d.ts +4 -0
- package/dist/src/apple/templates.js +19 -0
- package/dist/src/apple/templates.js.map +1 -0
- package/dist/src/apple/xcode-manager.d.ts +4 -0
- package/dist/src/apple/xcode-manager.js +145 -0
- package/dist/src/apple/xcode-manager.js.map +1 -0
- package/dist/src/nextjs/nextjs-wizard.d.ts +2 -5
- package/dist/src/nextjs/nextjs-wizard.js +1 -1
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.d.ts +2 -5
- package/dist/src/sourcemaps/sourcemaps-wizard.js +154 -67
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/sourcemaps/tools/angular.d.ts +1 -0
- package/dist/src/sourcemaps/tools/angular.js +76 -0
- package/dist/src/sourcemaps/tools/angular.js.map +1 -0
- package/dist/src/sourcemaps/tools/create-react-app.d.ts +1 -0
- package/dist/src/sourcemaps/tools/create-react-app.js +69 -0
- package/dist/src/sourcemaps/tools/create-react-app.js.map +1 -0
- package/dist/src/sourcemaps/tools/esbuild.js +2 -1
- package/dist/src/sourcemaps/tools/esbuild.js.map +1 -1
- package/dist/src/sourcemaps/tools/rollup.js +2 -1
- package/dist/src/sourcemaps/tools/rollup.js.map +1 -1
- package/dist/src/sourcemaps/tools/sentry-cli.js +7 -1
- package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
- package/dist/src/sourcemaps/tools/vite.js +2 -1
- package/dist/src/sourcemaps/tools/vite.js.map +1 -1
- package/dist/src/sourcemaps/tools/webpack.js +2 -1
- package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
- package/dist/src/sourcemaps/utils/detect-tool.d.ts +3 -0
- package/dist/src/sourcemaps/utils/detect-tool.js +73 -0
- package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -0
- package/dist/src/sourcemaps/utils/other-wizards.d.ts +4 -0
- package/dist/src/sourcemaps/utils/other-wizards.js +183 -0
- package/dist/src/sourcemaps/utils/other-wizards.js.map +1 -0
- package/dist/src/sourcemaps/utils/sdk-version.d.ts +14 -0
- package/dist/src/sourcemaps/utils/sdk-version.js +276 -0
- package/dist/src/sourcemaps/utils/sdk-version.js.map +1 -0
- package/dist/src/sveltekit/sveltekit-wizard.d.ts +2 -5
- package/dist/src/sveltekit/sveltekit-wizard.js +3 -2
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/telemetry.d.ts +1 -0
- package/dist/src/telemetry.js +7 -1
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/bash.d.ts +3 -0
- package/dist/src/utils/bash.js +118 -0
- package/dist/src/utils/bash.js.map +1 -0
- package/dist/src/utils/clack-utils.d.ts +21 -9
- package/dist/src/utils/clack-utils.js +122 -56
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-json.d.ts +19 -0
- package/dist/src/utils/package-json.js +29 -0
- package/dist/src/utils/package-json.js.map +1 -0
- package/dist/src/utils/types.d.ts +16 -0
- package/dist/src/utils/types.js +3 -0
- package/dist/src/utils/types.js.map +1 -0
- package/lib/Constants.ts +6 -0
- package/lib/Helper/Wizard.ts +3 -9
- package/lib/Helper/__tests__/SentryCli.ts +2 -1
- package/lib/Setup.ts +1 -0
- package/lib/Steps/ChooseIntegration.ts +39 -11
- package/lib/Steps/Integrations/Apple.ts +27 -0
- package/lib/Steps/Integrations/{NextJs.ts → NextJsShim.ts} +6 -2
- package/lib/Steps/Integrations/SourceMapsShim.ts +5 -1
- package/lib/Steps/Integrations/{SvelteKit.ts → SvelteKitShim.ts} +6 -2
- package/package-lock.json +8910 -0
- package/package.json +4 -4
- package/src/apple/apple-wizard.ts +150 -0
- package/src/apple/code-tools.ts +81 -0
- package/src/apple/templates.ts +39 -0
- package/src/apple/xcode-manager.ts +147 -0
- package/src/nextjs/nextjs-wizard.ts +3 -8
- package/src/sourcemaps/sourcemaps-wizard.ts +166 -91
- package/src/sourcemaps/tools/angular.ts +42 -0
- package/src/sourcemaps/tools/create-react-app.ts +19 -0
- package/src/sourcemaps/tools/esbuild.ts +1 -1
- package/src/sourcemaps/tools/rollup.ts +2 -4
- package/src/sourcemaps/tools/sentry-cli.ts +6 -1
- package/src/sourcemaps/tools/vite.ts +1 -1
- package/src/sourcemaps/tools/webpack.ts +1 -1
- package/src/sourcemaps/utils/detect-tool.ts +41 -0
- package/src/sourcemaps/utils/other-wizards.ts +148 -0
- package/src/sourcemaps/utils/sdk-version.ts +257 -0
- package/src/sveltekit/sveltekit-wizard.ts +4 -7
- package/src/telemetry.ts +8 -0
- package/src/utils/bash.ts +44 -0
- package/src/utils/clack-utils.ts +100 -51
- package/src/utils/package-json.ts +45 -0
- package/src/utils/types.ts +18 -0
- package/dist/lib/Steps/Integrations/NextJs.js.map +0 -1
- package/dist/lib/Steps/Integrations/SvelteKit.js.map +0 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// @ts-ignore - clack is ESM and TS complains about that. It works though
|
|
2
|
+
import clack from '@clack/prompts';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { minVersion, satisfies } from 'semver';
|
|
5
|
+
import {
|
|
6
|
+
abortIfCancelled,
|
|
7
|
+
getPackageDotJson,
|
|
8
|
+
installPackage,
|
|
9
|
+
} from '../../utils/clack-utils';
|
|
10
|
+
|
|
11
|
+
import * as Sentry from '@sentry/node';
|
|
12
|
+
import { findInstalledPackageFromList } from '../../utils/package-json';
|
|
13
|
+
|
|
14
|
+
const MINIMUM_DEBUG_ID_SDK_VERSION = '7.47.0';
|
|
15
|
+
|
|
16
|
+
// This array is orderd by the SDKs we want to check for first.
|
|
17
|
+
// The reason is that some SDKs depend on others and some users might
|
|
18
|
+
// have added the dependencies to their package.json. We want to make sure
|
|
19
|
+
// that we actually detect the "top-level" SDK first.
|
|
20
|
+
const SENTRY_SDK_PACKAGE_NAMES = [
|
|
21
|
+
// SDKs using other framework SDKs need to be checked first
|
|
22
|
+
'@sentry/gatsby',
|
|
23
|
+
'@sentry/nextjs',
|
|
24
|
+
'@sentry/remix',
|
|
25
|
+
'@sentry/sveltekit',
|
|
26
|
+
|
|
27
|
+
// Framework SDKs
|
|
28
|
+
'@sentry/angular',
|
|
29
|
+
'@sentry/angular-ivy',
|
|
30
|
+
'@sentry/ember',
|
|
31
|
+
'@sentry/react',
|
|
32
|
+
'@sentry/svelte',
|
|
33
|
+
'@sentry/vue',
|
|
34
|
+
'@sentry/serverless',
|
|
35
|
+
|
|
36
|
+
// Base SDKs
|
|
37
|
+
'@sentry/browser',
|
|
38
|
+
'@sentry/node',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check for a minimum SDK version and prompt the user to upgrade if necessary.
|
|
43
|
+
* We distinguish between 4 cases here:
|
|
44
|
+
*
|
|
45
|
+
* 1. Users didn't install any SDK yet
|
|
46
|
+
* -> We tell them to install an SDK and then continue with the wizard
|
|
47
|
+
* 2. Users installed an SDK in the range >=7.47.0
|
|
48
|
+
* -> All good, no need to do anything!
|
|
49
|
+
* 3. Users installed an SDK in the range >=7.0.0 <= 7.46.0
|
|
50
|
+
* -> We ask if they want to auto-update to the latest version
|
|
51
|
+
* 4. Users installed an SDK in the range <7.x
|
|
52
|
+
* -> We tell users to manually upgrade (migrate between majors)
|
|
53
|
+
*/
|
|
54
|
+
export async function ensureMinimumSdkVersionIsInstalled(): Promise<void> {
|
|
55
|
+
const installedSdkPackage = findInstalledPackageFromList(
|
|
56
|
+
SENTRY_SDK_PACKAGE_NAMES,
|
|
57
|
+
await getPackageDotJson(),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Case 1:
|
|
61
|
+
if (!installedSdkPackage) {
|
|
62
|
+
return await handleNoSdkInstalled();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { name: installedSdkName, version: installedSdkVersionOrRange } =
|
|
66
|
+
installedSdkPackage;
|
|
67
|
+
|
|
68
|
+
Sentry.setTag('installed-sdk', installedSdkName);
|
|
69
|
+
|
|
70
|
+
const minInstalledVersion = getMinInstalledVersion(
|
|
71
|
+
installedSdkVersionOrRange,
|
|
72
|
+
installedSdkName,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (!minInstalledVersion) {
|
|
76
|
+
// This is handled in the getMinInstalledVersion function
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const hasDebugIdCompatibleSdkVersion = satisfies(
|
|
81
|
+
minInstalledVersion,
|
|
82
|
+
`>=${MINIMUM_DEBUG_ID_SDK_VERSION}`,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Case 2:
|
|
86
|
+
if (hasDebugIdCompatibleSdkVersion) {
|
|
87
|
+
Sentry.setTag('initial-sdk-version', '>=7.47.0');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const hasV7SdkVersion = satisfies(minInstalledVersion, '>=7.0.0');
|
|
92
|
+
|
|
93
|
+
clack.log.warn(
|
|
94
|
+
`${chalk.yellowBright(
|
|
95
|
+
`It seems like you're using an outdated version (${installedSdkVersionOrRange}) of the ${chalk.bold(
|
|
96
|
+
installedSdkName,
|
|
97
|
+
)} SDK.`,
|
|
98
|
+
)}
|
|
99
|
+
Uploading source maps is easiest with an SDK from version ${chalk.bold(
|
|
100
|
+
MINIMUM_DEBUG_ID_SDK_VERSION,
|
|
101
|
+
)} or newer.
|
|
102
|
+
`,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Case 3:
|
|
106
|
+
if (hasV7SdkVersion) {
|
|
107
|
+
await handleAutoUpdateSdk(installedSdkName);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Case 4:
|
|
112
|
+
await handleManuallyUpdateSdk(minInstalledVersion);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function handleManuallyUpdateSdk(minInstalledVersion: string) {
|
|
116
|
+
Sentry.setTag(
|
|
117
|
+
'initial-sdk-version',
|
|
118
|
+
`${satisfies(minInstalledVersion, '>=6.0.0') ? '6.x' : '<6.0.0'}`,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
clack.log
|
|
122
|
+
.info(`When upgrading from a version older than 7.0.0, make sure to follow the migration guide:
|
|
123
|
+
https://github.com/getsentry/sentry-javascript/blob/develop/MIGRATION.md#upgrading-from-6x-to-7x
|
|
124
|
+
`);
|
|
125
|
+
|
|
126
|
+
const didUpdate = await abortIfCancelled(
|
|
127
|
+
clack.select({
|
|
128
|
+
message: 'Did you update your SDK to the latest version?',
|
|
129
|
+
options: [
|
|
130
|
+
{
|
|
131
|
+
label: 'Yes!',
|
|
132
|
+
value: true,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
label: "No, I'll do it later...",
|
|
136
|
+
value: false,
|
|
137
|
+
hint: chalk.yellow(
|
|
138
|
+
`Remember to update your SDK to at least ${MINIMUM_DEBUG_ID_SDK_VERSION}.`,
|
|
139
|
+
),
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
initialValue: true,
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
Sentry.setTag(
|
|
147
|
+
'resolved-sdk-status',
|
|
148
|
+
didUpdate ? 'updated-manually' : 'update-later',
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function handleAutoUpdateSdk(packageName: string) {
|
|
153
|
+
Sentry.setTag('initial-sdk-version', '>=7.0.0 <7.47.0');
|
|
154
|
+
|
|
155
|
+
const shouldUpdate = await abortIfCancelled(
|
|
156
|
+
clack.select({
|
|
157
|
+
message:
|
|
158
|
+
'Do you want to automatically update your SDK to the latest version?',
|
|
159
|
+
options: [
|
|
160
|
+
{
|
|
161
|
+
label: 'Yes!',
|
|
162
|
+
value: true,
|
|
163
|
+
hint: chalk.green('Recommended'),
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
label: "No, I'll do it later...",
|
|
167
|
+
value: false,
|
|
168
|
+
hint: chalk.yellow(
|
|
169
|
+
`Remember to update your SDK to at least ${MINIMUM_DEBUG_ID_SDK_VERSION}.`,
|
|
170
|
+
),
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
initialValue: true,
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (shouldUpdate) {
|
|
178
|
+
await installPackage({
|
|
179
|
+
packageName,
|
|
180
|
+
alreadyInstalled: true,
|
|
181
|
+
askBeforeUpdating: false, // we already did this above
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Sentry.setTag(
|
|
186
|
+
'resolved-sdk-status',
|
|
187
|
+
shouldUpdate ? 'updated-automatically' : 'update-later',
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function handleNoSdkInstalled(): Promise<void> {
|
|
192
|
+
Sentry.setTag('initial-sdk-version', 'none');
|
|
193
|
+
Sentry.setTag('installed-sdk', 'none');
|
|
194
|
+
|
|
195
|
+
clack.log.warn(
|
|
196
|
+
`${chalk.yellowBright(
|
|
197
|
+
`It seems like you didn't yet install a Sentry SDK in your project.`,
|
|
198
|
+
)}
|
|
199
|
+
We recommend setting up the SDK before continuing with the source maps wizard.
|
|
200
|
+
|
|
201
|
+
${chalk.dim(`Take a look at our docs to get started:
|
|
202
|
+
https://docs.sentry.io/`)}`,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const installedSDK = await abortIfCancelled(
|
|
206
|
+
clack.select({
|
|
207
|
+
message: 'Did you set up your Sentry SDK?',
|
|
208
|
+
options: [
|
|
209
|
+
{ label: 'Yes, continue!', value: true },
|
|
210
|
+
{
|
|
211
|
+
label: "I'll do it later...",
|
|
212
|
+
value: false,
|
|
213
|
+
hint: chalk.yellow(
|
|
214
|
+
'You need to set up an SDK before you can use Sentry',
|
|
215
|
+
),
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
initialValue: true,
|
|
219
|
+
}),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
Sentry.setTag(
|
|
223
|
+
'resolved-sdk-status',
|
|
224
|
+
installedSDK ? 'installed-manually' : 'install-later',
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function getMinInstalledVersion(
|
|
229
|
+
installedSdkVersionOrRange: string,
|
|
230
|
+
installedSdkName: string,
|
|
231
|
+
): string | undefined {
|
|
232
|
+
try {
|
|
233
|
+
// If `minVersion` is unable to parse the version it will throw an error
|
|
234
|
+
// However, it will also return `null` if the parameter is undefined, which
|
|
235
|
+
// we explicitly checked before but the typing doesn't know that.
|
|
236
|
+
const minInstalledVersion = minVersion(installedSdkVersionOrRange)?.version;
|
|
237
|
+
if (minInstalledVersion) {
|
|
238
|
+
return minInstalledVersion;
|
|
239
|
+
}
|
|
240
|
+
} catch {
|
|
241
|
+
// handling this, along with the `null` case below
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
Sentry.setTag('initial-sdk-version', 'unknown');
|
|
245
|
+
clack.log.warn(
|
|
246
|
+
`${chalk.yellow(
|
|
247
|
+
`Could not parse the version of your installed SDK ("${installedSdkName}": "${installedSdkVersionOrRange}")`,
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
Please make sure that your Sentry SDK is updated to version ${chalk.bold(
|
|
251
|
+
MINIMUM_DEBUG_ID_SDK_VERSION,
|
|
252
|
+
)} or newer.
|
|
253
|
+
`,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
@@ -9,21 +9,18 @@ import {
|
|
|
9
9
|
confirmContinueEvenThoughNoGitRepo,
|
|
10
10
|
ensurePackageIsInstalled,
|
|
11
11
|
getPackageDotJson,
|
|
12
|
-
hasPackageInstalled,
|
|
13
12
|
installPackage,
|
|
14
13
|
printWelcome,
|
|
15
14
|
} from '../utils/clack-utils';
|
|
15
|
+
import { hasPackageInstalled } from '../utils/package-json';
|
|
16
|
+
import { WizardOptions } from '../utils/types';
|
|
16
17
|
import { createExamplePage } from './sdk-example';
|
|
17
18
|
import { createOrMergeSvelteKitFiles, loadSvelteConfig } from './sdk-setup';
|
|
18
19
|
|
|
19
20
|
import { setupCLIConfig } from './sentry-cli-setup';
|
|
20
21
|
|
|
21
|
-
interface SvelteKitWizardOptions {
|
|
22
|
-
promoCode?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
22
|
export async function runSvelteKitWizard(
|
|
26
|
-
options:
|
|
23
|
+
options: WizardOptions,
|
|
27
24
|
): Promise<void> {
|
|
28
25
|
printWelcome({
|
|
29
26
|
wizardName: 'Sentry SvelteKit Wizard',
|
|
@@ -35,7 +32,7 @@ export async function runSvelteKitWizard(
|
|
|
35
32
|
const packageJson = await getPackageDotJson();
|
|
36
33
|
await ensurePackageIsInstalled(packageJson, '@sveltejs/kit', 'Sveltekit');
|
|
37
34
|
|
|
38
|
-
const { url: sentryUrl, selfHosted } = await askForSelfHosted();
|
|
35
|
+
const { url: sentryUrl, selfHosted } = await askForSelfHosted(options.url);
|
|
39
36
|
|
|
40
37
|
const { projects, apiKeys } = await askForWizardLogin({
|
|
41
38
|
promoCode: options.promoCode,
|
package/src/telemetry.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
makeNodeTransport,
|
|
7
7
|
NodeClient,
|
|
8
8
|
runWithAsyncContext,
|
|
9
|
+
trace,
|
|
9
10
|
} from '@sentry/node';
|
|
10
11
|
import packageJson from '../package.json';
|
|
11
12
|
|
|
@@ -26,6 +27,7 @@ export async function withTelemetry<F>(
|
|
|
26
27
|
const transaction = sentryHub.startTransaction({
|
|
27
28
|
name: 'sentry-wizard-execution',
|
|
28
29
|
status: 'ok',
|
|
30
|
+
op: 'wizard.flow',
|
|
29
31
|
});
|
|
30
32
|
sentryHub.getScope().setSpan(transaction);
|
|
31
33
|
const sentrySession = sentryHub.startSession();
|
|
@@ -74,6 +76,8 @@ function createSentryInstance(enabled: boolean, integration: string) {
|
|
|
74
76
|
},
|
|
75
77
|
|
|
76
78
|
transport: makeNodeTransport,
|
|
79
|
+
|
|
80
|
+
debug: true,
|
|
77
81
|
});
|
|
78
82
|
|
|
79
83
|
const hub = new Hub(client);
|
|
@@ -84,3 +88,7 @@ function createSentryInstance(enabled: boolean, integration: string) {
|
|
|
84
88
|
|
|
85
89
|
return { sentryHub: hub, sentryClient: client };
|
|
86
90
|
}
|
|
91
|
+
|
|
92
|
+
export function traceStep<T>(step: string, callback: () => T): T {
|
|
93
|
+
return trace({ name: step, op: 'wizard.step' }, () => callback());
|
|
94
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as child_process from 'child_process';
|
|
2
|
+
import * as https from 'https';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
|
|
5
|
+
export function hasSentryCLI(): boolean {
|
|
6
|
+
try {
|
|
7
|
+
child_process.execSync('sentry-cli --version');
|
|
8
|
+
return true;
|
|
9
|
+
} catch (e) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function installSentryCLI(): Promise<void> {
|
|
15
|
+
const httpAsync = new Promise((resolve, reject) => {
|
|
16
|
+
const file = fs.createWriteStream('installcli.sh');
|
|
17
|
+
https.get('https://sentry.io/get-cli/', (response) => {
|
|
18
|
+
response.pipe(file);
|
|
19
|
+
file.on('finish', () => {
|
|
20
|
+
file.close();
|
|
21
|
+
try {
|
|
22
|
+
child_process.execSync('bash ./installcli.sh');
|
|
23
|
+
} catch (e) {
|
|
24
|
+
reject(e);
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
fs.unlinkSync('installcli.sh');
|
|
28
|
+
resolve(null);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
file.on('error', (err) => {
|
|
32
|
+
fs.unlinkSync('installcli.sh');
|
|
33
|
+
reject(err);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await httpAsync;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function execute(command: string): string {
|
|
42
|
+
const output = child_process.execSync(command);
|
|
43
|
+
return output.toString();
|
|
44
|
+
}
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -10,6 +10,11 @@ import { URL } from 'url';
|
|
|
10
10
|
import { promisify } from 'util';
|
|
11
11
|
import * as Sentry from '@sentry/node';
|
|
12
12
|
import { windowedSelect } from './vendor/clack-custom-select';
|
|
13
|
+
import { hasPackageInstalled, PackageDotJson } from './package-json';
|
|
14
|
+
|
|
15
|
+
const opn = require('opn') as (
|
|
16
|
+
url: string,
|
|
17
|
+
) => Promise<childProcess.ChildProcess>;
|
|
13
18
|
|
|
14
19
|
const SAAS_URL = 'https://sentry.io/';
|
|
15
20
|
|
|
@@ -20,16 +25,11 @@ interface WizardProjectData {
|
|
|
20
25
|
projects: SentryProjectData[];
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
export type PackageDotJson = {
|
|
24
|
-
scripts?: Record<string, string>;
|
|
25
|
-
dependencies?: Record<string, string>;
|
|
26
|
-
devDependencies?: Record<string, string>;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
28
|
export interface SentryProjectData {
|
|
30
29
|
id: string;
|
|
31
30
|
slug: string;
|
|
32
31
|
name: string;
|
|
32
|
+
platform: string;
|
|
33
33
|
organization: {
|
|
34
34
|
slug: string;
|
|
35
35
|
};
|
|
@@ -126,10 +126,16 @@ export async function confirmContinueEvenThoughNoGitRepo(): Promise<void> {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
export async function askToInstallSentryCLI(): Promise<boolean> {
|
|
130
|
+
return await abortIfCancelled(clack.confirm({
|
|
131
|
+
message: "You don't have Sentry CLI installed. Do you want to install it?"
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
|
|
129
135
|
export async function askForWizardLogin(options: {
|
|
130
136
|
url: string;
|
|
131
137
|
promoCode?: string;
|
|
132
|
-
platform?: 'javascript-nextjs' | 'javascript-sveltekit';
|
|
138
|
+
platform?: 'javascript-nextjs' | 'javascript-sveltekit' | 'apple-ios';
|
|
133
139
|
}): Promise<WizardProjectData> {
|
|
134
140
|
Sentry.setTag('has-promo-code', !!options.promoCode);
|
|
135
141
|
|
|
@@ -179,14 +185,18 @@ export async function askForWizardLogin(options: {
|
|
|
179
185
|
loginUrl.searchParams.set('code', options.promoCode);
|
|
180
186
|
}
|
|
181
187
|
|
|
188
|
+
const urlToOpen = loginUrl.toString();
|
|
182
189
|
clack.log.info(
|
|
183
190
|
`${chalk.bold(
|
|
184
|
-
`
|
|
185
|
-
hasSentryAccount ? 'log' : 'sign'
|
|
191
|
+
`If the browser window didn't open automatically, please open the following link to ${hasSentryAccount ? 'log' : 'sign'
|
|
186
192
|
} into Sentry:`,
|
|
187
|
-
)}\n\n${chalk.cyan(
|
|
193
|
+
)}\n\n${chalk.cyan(urlToOpen)}`,
|
|
188
194
|
);
|
|
189
195
|
|
|
196
|
+
opn(urlToOpen).catch(() => {
|
|
197
|
+
// opn throws in environments that don't have a browser (e.g. remote shells) so we just noop here
|
|
198
|
+
});
|
|
199
|
+
|
|
190
200
|
const loginSpinner = clack.spinner();
|
|
191
201
|
|
|
192
202
|
loginSpinner.start(
|
|
@@ -225,6 +235,23 @@ export async function askForWizardLogin(options: {
|
|
|
225
235
|
return data;
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
export async function askForItemSelection(items: string[], message: string): Promise<{ value: string, index: number }> {
|
|
239
|
+
const selection: { value: string, index: number } | symbol = await abortIfCancelled(
|
|
240
|
+
windowedSelect({
|
|
241
|
+
maxItems: 12,
|
|
242
|
+
message: message,
|
|
243
|
+
options: items.map((item, index) => {
|
|
244
|
+
return {
|
|
245
|
+
value: { value: item, index: index },
|
|
246
|
+
label: item,
|
|
247
|
+
};
|
|
248
|
+
}),
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
return selection;
|
|
253
|
+
}
|
|
254
|
+
|
|
228
255
|
export async function askForProjectSelection(
|
|
229
256
|
projects: SentryProjectData[],
|
|
230
257
|
): Promise<SentryProjectData> {
|
|
@@ -242,6 +269,7 @@ export async function askForProjectSelection(
|
|
|
242
269
|
);
|
|
243
270
|
|
|
244
271
|
Sentry.setTag('project', selection.slug);
|
|
272
|
+
Sentry.setTag('project-platform', selection.platform);
|
|
245
273
|
Sentry.setUser({ id: selection.organization.slug });
|
|
246
274
|
|
|
247
275
|
return selection;
|
|
@@ -250,11 +278,13 @@ export async function askForProjectSelection(
|
|
|
250
278
|
export async function installPackage({
|
|
251
279
|
packageName,
|
|
252
280
|
alreadyInstalled,
|
|
281
|
+
askBeforeUpdating = true,
|
|
253
282
|
}: {
|
|
254
283
|
packageName: string;
|
|
255
284
|
alreadyInstalled: boolean;
|
|
285
|
+
askBeforeUpdating?: boolean;
|
|
256
286
|
}): Promise<void> {
|
|
257
|
-
if (alreadyInstalled) {
|
|
287
|
+
if (alreadyInstalled && askBeforeUpdating) {
|
|
258
288
|
const shouldUpdatePackage = await abortIfCancelled(
|
|
259
289
|
clack.confirm({
|
|
260
290
|
message: `The ${chalk.bold.cyan(
|
|
@@ -306,34 +336,54 @@ export async function installPackage({
|
|
|
306
336
|
);
|
|
307
337
|
}
|
|
308
338
|
|
|
309
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Asks users if they are using SaaS or self-hosted Sentry and returns the validated URL.
|
|
341
|
+
*
|
|
342
|
+
* If users started the wizard with a --url arg, that URL is used as the default and we skip
|
|
343
|
+
* the self-hosted question. However, the passed url is still validated and in case it's
|
|
344
|
+
* invalid, users are asked to enter a new one until it is valid.
|
|
345
|
+
*
|
|
346
|
+
* @param urlFromArgs the url passed via the --url arg
|
|
347
|
+
*/
|
|
348
|
+
export async function askForSelfHosted(urlFromArgs?: string): Promise<{
|
|
310
349
|
url: string;
|
|
311
350
|
selfHosted: boolean;
|
|
312
351
|
}> {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
352
|
+
if (!urlFromArgs) {
|
|
353
|
+
const choice: 'saas' | 'self-hosted' | symbol = await abortIfCancelled(
|
|
354
|
+
clack.select({
|
|
355
|
+
message: 'Are you using Sentry SaaS or self-hosted Sentry?',
|
|
356
|
+
options: [
|
|
357
|
+
{ value: 'saas', label: 'Sentry SaaS (sentry.io)' },
|
|
358
|
+
{
|
|
359
|
+
value: 'self-hosted',
|
|
360
|
+
label: 'Self-hosted/on-premise/single-tenant',
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
}),
|
|
364
|
+
);
|
|
322
365
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
366
|
+
if (choice === 'saas') {
|
|
367
|
+
Sentry.setTag('url', SAAS_URL);
|
|
368
|
+
Sentry.setTag('self-hosted', false);
|
|
369
|
+
return { url: SAAS_URL, selfHosted: false };
|
|
370
|
+
}
|
|
327
371
|
}
|
|
328
372
|
|
|
329
373
|
let validUrl: string | undefined;
|
|
374
|
+
let tmpUrlFromArgs = urlFromArgs;
|
|
375
|
+
|
|
330
376
|
while (validUrl === undefined) {
|
|
331
|
-
const url =
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
377
|
+
const url =
|
|
378
|
+
tmpUrlFromArgs ||
|
|
379
|
+
(await abortIfCancelled(
|
|
380
|
+
clack.text({
|
|
381
|
+
message: `Please enter the URL of your ${urlFromArgs ? '' : 'self-hosted '
|
|
382
|
+
}Sentry instance.`,
|
|
383
|
+
placeholder: 'https://sentry.io/',
|
|
384
|
+
}),
|
|
385
|
+
));
|
|
386
|
+
tmpUrlFromArgs = undefined;
|
|
337
387
|
|
|
338
388
|
try {
|
|
339
389
|
validUrl = new URL(url).toString();
|
|
@@ -344,13 +394,16 @@ export async function askForSelfHosted(): Promise<{
|
|
|
344
394
|
}
|
|
345
395
|
} catch {
|
|
346
396
|
clack.log.error(
|
|
347
|
-
'Please enter a valid URL. (It should look something like "
|
|
397
|
+
'Please enter a valid URL. (It should look something like "https://sentry.mydomain.com/")',
|
|
348
398
|
);
|
|
349
399
|
}
|
|
350
400
|
}
|
|
351
401
|
|
|
402
|
+
const isSelfHostedUrl = new URL(validUrl).host !== new URL(SAAS_URL).host;
|
|
403
|
+
|
|
352
404
|
Sentry.setTag('url', validUrl);
|
|
353
|
-
Sentry.setTag('self-hosted',
|
|
405
|
+
Sentry.setTag('self-hosted', isSelfHostedUrl);
|
|
406
|
+
|
|
354
407
|
return { url: validUrl, selfHosted: true };
|
|
355
408
|
}
|
|
356
409
|
|
|
@@ -549,25 +602,8 @@ export async function getPackageDotJson(): Promise<PackageDotJson> {
|
|
|
549
602
|
return packageJson || {};
|
|
550
603
|
}
|
|
551
604
|
|
|
552
|
-
export function hasPackageInstalled(
|
|
553
|
-
packageName: string,
|
|
554
|
-
packageJson: PackageDotJson,
|
|
555
|
-
): boolean {
|
|
556
|
-
return (
|
|
557
|
-
!!packageJson?.dependencies?.[packageName] ||
|
|
558
|
-
!!packageJson?.devDependencies?.[packageName]
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
605
|
async function getPackageManager(): Promise<string> {
|
|
563
|
-
|
|
564
|
-
if (fs.existsSync(path.join(process.cwd(), 'yarn.lock'))) {
|
|
565
|
-
detectedPackageManager = 'yarn';
|
|
566
|
-
} else if (fs.existsSync(path.join(process.cwd(), 'package-lock.json'))) {
|
|
567
|
-
detectedPackageManager = 'npm';
|
|
568
|
-
} else if (fs.existsSync(path.join(process.cwd(), 'pnpm-lock.yaml'))) {
|
|
569
|
-
detectedPackageManager = 'pnpm';
|
|
570
|
-
}
|
|
606
|
+
const detectedPackageManager = detectPackageManager();
|
|
571
607
|
|
|
572
608
|
if (detectedPackageManager) {
|
|
573
609
|
return detectedPackageManager;
|
|
@@ -588,3 +624,16 @@ async function getPackageManager(): Promise<string> {
|
|
|
588
624
|
|
|
589
625
|
return selectedPackageManager;
|
|
590
626
|
}
|
|
627
|
+
|
|
628
|
+
export function detectPackageManager(): 'yarn' | 'npm' | 'pnpm' | undefined {
|
|
629
|
+
if (fs.existsSync(path.join(process.cwd(), 'yarn.lock'))) {
|
|
630
|
+
return 'yarn';
|
|
631
|
+
}
|
|
632
|
+
if (fs.existsSync(path.join(process.cwd(), 'package-lock.json'))) {
|
|
633
|
+
return 'npm';
|
|
634
|
+
}
|
|
635
|
+
if (fs.existsSync(path.join(process.cwd(), 'pnpm-lock.yaml'))) {
|
|
636
|
+
return 'pnpm';
|
|
637
|
+
}
|
|
638
|
+
return undefined;
|
|
639
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type PackageDotJson = {
|
|
2
|
+
scripts?: Record<string, string>;
|
|
3
|
+
dependencies?: Record<string, string>;
|
|
4
|
+
devDependencies?: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type NpmPackage = {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Checks if @param packageJson has any of the @param packageNamesList package names
|
|
14
|
+
* listed as a dependency or devDependency.
|
|
15
|
+
* If so, it returns the first package name that is found, including the
|
|
16
|
+
* version (range) specified in the package.json.
|
|
17
|
+
*/
|
|
18
|
+
export function findInstalledPackageFromList(
|
|
19
|
+
packageNamesList: string[],
|
|
20
|
+
packageJson: PackageDotJson,
|
|
21
|
+
): NpmPackage | undefined {
|
|
22
|
+
return packageNamesList
|
|
23
|
+
.map((packageName) => ({
|
|
24
|
+
name: packageName,
|
|
25
|
+
version: getPackageVersion(packageName, packageJson),
|
|
26
|
+
}))
|
|
27
|
+
.find((sdkPackage): sdkPackage is NpmPackage => !!sdkPackage.version);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function hasPackageInstalled(
|
|
31
|
+
packageName: string,
|
|
32
|
+
packageJson: PackageDotJson,
|
|
33
|
+
): boolean {
|
|
34
|
+
return getPackageVersion(packageName, packageJson) !== undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getPackageVersion(
|
|
38
|
+
packageName: string,
|
|
39
|
+
packageJson: PackageDotJson,
|
|
40
|
+
): string | undefined {
|
|
41
|
+
return (
|
|
42
|
+
packageJson?.dependencies?.[packageName] ||
|
|
43
|
+
packageJson?.devDependencies?.[packageName]
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type WizardOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Controls whether the wizard should send telemetry data to Sentry.
|
|
4
|
+
*/
|
|
5
|
+
telemetryEnabled: boolean;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The promo code to use while signing up for Sentry.
|
|
9
|
+
* This can be passed via the --promo-code arg.
|
|
10
|
+
*/
|
|
11
|
+
promoCode?: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The url of the Sentry instance to use.
|
|
15
|
+
* This can be passed via the `-u` or `--url` arg.
|
|
16
|
+
*/
|
|
17
|
+
url?: string;
|
|
18
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NextJs.js","sourceRoot":"","sources":["../../../../lib/Steps/Integrations/NextJs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,mEAAoE;AAGpE,qDAAoD;AAEpD;;;GAGG;AACH;IAA4B,0BAAe;IACzC,gBAA6B,KAAW;QAAxC,YACE,kBAAM,KAAK,CAAC,SACb;QAF4B,WAAK,GAAL,KAAK,CAAM;;IAExC,CAAC;IAEY,qBAAI,GAAjB,UAAkB,QAAiB;;;;4BACjC,qBAAM,IAAA,+BAAe,EAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,EAAA;;wBAA1D,SAA0D,CAAC;wBAC3D,sBAAO,EAAE,EAAC;;;;KACX;IAEY,gCAAe,GAA5B,UAA6B,QAAiB;;;gBAC5C,kEAAkE;gBAClE,IAAI,IAAI,CAAC,gBAAgB,EAAE;oBACzB,sBAAO,IAAI,CAAC,gBAAgB,EAAC;iBAC9B;gBACD,6DAA6D;gBAC7D,sBAAO,IAAI,CAAC,eAAe,EAAC;;;KAC7B;IACH,aAAC;AAAD,CAAC,AAlBD,CAA4B,iCAAe,GAkB1C;AAlBY,wBAAM","sourcesContent":["import type { Answers } from 'inquirer';\nimport { runNextjsWizard } from '../../../src/nextjs/nextjs-wizard';\n\nimport type { Args } from '../../Constants';\nimport { BaseIntegration } from './BaseIntegration';\n\n/**\n * This class just redirects to the new `nextjs-wizard.ts` flow\n * for anyone calling the wizard without the '-i nextjs' flag.\n */\nexport class NextJs extends BaseIntegration {\n public constructor(protected _argv: Args) {\n super(_argv);\n }\n\n public async emit(_answers: Answers): Promise<Answers> {\n await runNextjsWizard({ promoCode: this._argv.promoCode });\n return {};\n }\n\n public async shouldConfigure(_answers: Answers): Promise<Answers> {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n if (this._shouldConfigure) {\n return this._shouldConfigure;\n }\n // eslint-disable-next-line @typescript-eslint/unbound-method\n return this.shouldConfigure;\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SvelteKit.js","sourceRoot":"","sources":["../../../../lib/Steps/Integrations/SvelteKit.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,4EAA6E;AAG7E,qDAAoD;AAEpD;;;GAGG;AACH;IAA+B,6BAAe;IAC5C,mBAA6B,KAAW;QAAxC,YACE,kBAAM,KAAK,CAAC,SACb;QAF4B,WAAK,GAAL,KAAK,CAAM;;IAExC,CAAC;IAEY,wBAAI,GAAjB,UAAkB,QAAiB;;;;4BACjC,qBAAM,IAAA,qCAAkB,EAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,EAAA;;wBAA7D,SAA6D,CAAC;wBAC9D,sBAAO,EAAE,EAAC;;;;KACX;IAEY,mCAAe,GAA5B,UAA6B,QAAiB;;;gBAC5C,kEAAkE;gBAClE,IAAI,IAAI,CAAC,gBAAgB,EAAE;oBACzB,sBAAO,IAAI,CAAC,gBAAgB,EAAC;iBAC9B;gBACD,6DAA6D;gBAC7D,sBAAO,IAAI,CAAC,eAAe,EAAC;;;KAC7B;IACH,gBAAC;AAAD,CAAC,AAlBD,CAA+B,iCAAe,GAkB7C;AAlBY,8BAAS","sourcesContent":["import type { Answers } from 'inquirer';\nimport { runSvelteKitWizard } from '../../../src/sveltekit/sveltekit-wizard';\n\nimport type { Args } from '../../Constants';\nimport { BaseIntegration } from './BaseIntegration';\n\n/**\n * This class just redirects to the new `sveltekit-wizard.ts` flow\n * for anyone calling the wizard without the '-i sveltekit' flag.\n */\nexport class SvelteKit extends BaseIntegration {\n public constructor(protected _argv: Args) {\n super(_argv);\n }\n\n public async emit(_answers: Answers): Promise<Answers> {\n await runSvelteKitWizard({ promoCode: this._argv.promoCode });\n return {};\n }\n\n public async shouldConfigure(_answers: Answers): Promise<Answers> {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n if (this._shouldConfigure) {\n return this._shouldConfigure;\n }\n // eslint-disable-next-line @typescript-eslint/unbound-method\n return this.shouldConfigure;\n }\n}\n"]}
|