@sentry/wizard 3.13.0 → 3.14.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 +7 -1
- package/dist/package.json +2 -2
- package/dist/src/android/android-wizard.js +2 -4
- package/dist/src/android/android-wizard.js.map +1 -1
- package/dist/src/apple/apple-wizard.js +1 -1
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.d.ts +1 -0
- package/dist/src/nextjs/nextjs-wizard.js +252 -161
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/utils.d.ts +1 -0
- package/dist/src/nextjs/utils.js +25 -0
- package/dist/src/nextjs/utils.js.map +1 -0
- package/dist/src/remix/remix-wizard.js +5 -7
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/remix/sdk-setup.js +10 -4
- package/dist/src/remix/sdk-setup.js.map +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js +1 -1
- package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +6 -10
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/telemetry.d.ts +1 -0
- package/dist/src/telemetry.js +27 -12
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +11 -1
- package/dist/src/utils/clack-utils.js +190 -126
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.js +12 -7
- package/dist/src/utils/package-manager.js.map +1 -1
- package/package.json +2 -2
- package/src/android/android-wizard.ts +4 -5
- package/src/apple/apple-wizard.ts +2 -2
- package/src/nextjs/nextjs-wizard.ts +262 -195
- package/src/nextjs/utils.ts +21 -0
- package/src/remix/remix-wizard.ts +7 -9
- package/src/remix/sdk-setup.ts +12 -3
- package/src/sourcemaps/sourcemaps-wizard.ts +2 -2
- package/src/sveltekit/sveltekit-wizard.ts +9 -12
- package/src/telemetry.ts +22 -11
- package/src/utils/clack-utils.ts +177 -107
- package/src/utils/package-manager.ts +12 -6
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
abort,
|
|
9
9
|
abortIfCancelled,
|
|
10
10
|
addSentryCliConfig,
|
|
11
|
-
|
|
11
|
+
confirmContinueIfNoOrDirtyGitRepo,
|
|
12
12
|
ensurePackageIsInstalled,
|
|
13
13
|
getOrAskForProjectData,
|
|
14
14
|
getPackageDotJson,
|
|
@@ -43,12 +43,11 @@ export async function runSvelteKitWizardWithTelemetry(
|
|
|
43
43
|
telemetryEnabled: options.telemetryEnabled,
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
await
|
|
46
|
+
await confirmContinueIfNoOrDirtyGitRepo();
|
|
47
47
|
|
|
48
48
|
const packageJson = await getPackageDotJson();
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
49
|
+
|
|
50
|
+
await ensurePackageIsInstalled(packageJson, '@sveltejs/kit', 'Sveltekit');
|
|
52
51
|
|
|
53
52
|
const kitVersion = getPackageVersion('@sveltejs/kit', packageJson);
|
|
54
53
|
const kitVersionBucket = getKitVersionBucket(kitVersion);
|
|
@@ -91,14 +90,12 @@ export async function runSvelteKitWizardWithTelemetry(
|
|
|
91
90
|
);
|
|
92
91
|
Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
|
|
93
92
|
|
|
94
|
-
await
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}),
|
|
99
|
-
);
|
|
93
|
+
await installPackage({
|
|
94
|
+
packageName: '@sentry/sveltekit',
|
|
95
|
+
alreadyInstalled: sdkAlreadyInstalled,
|
|
96
|
+
});
|
|
100
97
|
|
|
101
|
-
await
|
|
98
|
+
await addSentryCliConfig(authToken);
|
|
102
99
|
|
|
103
100
|
const svelteConfig = await traceStep('load-svelte-config', loadSvelteConfig);
|
|
104
101
|
|
package/src/telemetry.ts
CHANGED
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
makeNodeTransport,
|
|
7
7
|
NodeClient,
|
|
8
8
|
runWithAsyncContext,
|
|
9
|
-
|
|
9
|
+
setTag,
|
|
10
|
+
startSpan,
|
|
10
11
|
} from '@sentry/node';
|
|
11
12
|
import packageJson from '../package.json';
|
|
12
13
|
|
|
@@ -24,24 +25,29 @@ export async function withTelemetry<F>(
|
|
|
24
25
|
|
|
25
26
|
makeMain(sentryHub);
|
|
26
27
|
|
|
27
|
-
const transaction = sentryHub.startTransaction({
|
|
28
|
-
name: 'sentry-wizard-execution',
|
|
29
|
-
status: 'ok',
|
|
30
|
-
op: 'wizard.flow',
|
|
31
|
-
});
|
|
32
|
-
sentryHub.getScope().setSpan(transaction);
|
|
33
28
|
const sentrySession = sentryHub.startSession();
|
|
34
29
|
sentryHub.captureSession();
|
|
35
30
|
|
|
36
31
|
try {
|
|
37
|
-
return await
|
|
32
|
+
return await startSpan(
|
|
33
|
+
{
|
|
34
|
+
name: 'sentry-wizard-execution',
|
|
35
|
+
status: 'ok',
|
|
36
|
+
op: 'wizard.flow',
|
|
37
|
+
},
|
|
38
|
+
async () => {
|
|
39
|
+
updateProgress('start');
|
|
40
|
+
const res = await runWithAsyncContext(callback);
|
|
41
|
+
updateProgress('finished');
|
|
42
|
+
|
|
43
|
+
return res;
|
|
44
|
+
},
|
|
45
|
+
);
|
|
38
46
|
} catch (e) {
|
|
39
47
|
sentryHub.captureException('Error during wizard execution.');
|
|
40
|
-
transaction.setStatus('internal_error');
|
|
41
48
|
sentrySession.status = 'crashed';
|
|
42
49
|
throw e;
|
|
43
50
|
} finally {
|
|
44
|
-
transaction.finish();
|
|
45
51
|
sentryHub.endSession();
|
|
46
52
|
await sentryClient.flush(3000);
|
|
47
53
|
}
|
|
@@ -92,5 +98,10 @@ function createSentryInstance(enabled: boolean, integration: string) {
|
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
export function traceStep<T>(step: string, callback: () => T): T {
|
|
95
|
-
|
|
101
|
+
updateProgress(step);
|
|
102
|
+
return startSpan({ name: step, op: 'wizard.step' }, () => callback());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function updateProgress(step: string) {
|
|
106
|
+
setTag('progress', step);
|
|
96
107
|
}
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -5,6 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import * as childProcess from 'child_process';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
+
import * as os from 'os';
|
|
8
9
|
import { setInterval } from 'timers';
|
|
9
10
|
import { URL } from 'url';
|
|
10
11
|
import * as Sentry from '@sentry/node';
|
|
@@ -147,24 +148,73 @@ You can turn this off at any time by running ${chalk.cyanBright(
|
|
|
147
148
|
clack.note(welcomeText);
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
export async function
|
|
151
|
+
export async function confirmContinueIfNoOrDirtyGitRepo(): Promise<void> {
|
|
152
|
+
return traceStep('check-git-status', async () => {
|
|
153
|
+
if (!isInGitRepo()) {
|
|
154
|
+
const continueWithoutGit = await abortIfCancelled(
|
|
155
|
+
clack.confirm({
|
|
156
|
+
message:
|
|
157
|
+
'You are not inside a git repository. The wizard will create and update files. Do you want to continue anyway?',
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
Sentry.setTag('continue-without-git', continueWithoutGit);
|
|
162
|
+
|
|
163
|
+
if (!continueWithoutGit) {
|
|
164
|
+
await abort(undefined, 0);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const uncommittedOrUntrackedFiles = getUncommittedOrUntrackedFiles();
|
|
169
|
+
if (uncommittedOrUntrackedFiles.length) {
|
|
170
|
+
clack.log.warn(
|
|
171
|
+
`You have uncommitted or untracked files in your repo:
|
|
172
|
+
|
|
173
|
+
${uncommittedOrUntrackedFiles.join('\n')}
|
|
174
|
+
|
|
175
|
+
The wizard will create and update files.`,
|
|
176
|
+
);
|
|
177
|
+
const continueWithDirtyRepo = await abortIfCancelled(
|
|
178
|
+
clack.confirm({
|
|
179
|
+
message: 'Do you want to continue anyway?',
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
Sentry.setTag('continue-with-dirty-repo', continueWithDirtyRepo);
|
|
184
|
+
|
|
185
|
+
if (!continueWithDirtyRepo) {
|
|
186
|
+
await abort(undefined, 0);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function isInGitRepo() {
|
|
151
193
|
try {
|
|
152
194
|
childProcess.execSync('git rev-parse --is-inside-work-tree', {
|
|
153
195
|
stdio: 'ignore',
|
|
154
196
|
});
|
|
197
|
+
return true;
|
|
155
198
|
} catch {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
'You are not inside a git repository. The wizard will create and update files. Do you still want to continue?',
|
|
160
|
-
}),
|
|
161
|
-
);
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
162
202
|
|
|
163
|
-
|
|
203
|
+
function getUncommittedOrUntrackedFiles(): string[] {
|
|
204
|
+
try {
|
|
205
|
+
const gitStatus = childProcess
|
|
206
|
+
.execSync('git status --porcelain=v1')
|
|
207
|
+
.toString();
|
|
164
208
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
209
|
+
const files = gitStatus
|
|
210
|
+
.split(os.EOL)
|
|
211
|
+
.map((line) => line.trim())
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.map((f) => `- ${f.split(/\s+/)[1]}`);
|
|
214
|
+
|
|
215
|
+
return files;
|
|
216
|
+
} catch {
|
|
217
|
+
return [];
|
|
168
218
|
}
|
|
169
219
|
}
|
|
170
220
|
|
|
@@ -207,123 +257,127 @@ export async function installPackage({
|
|
|
207
257
|
alreadyInstalled: boolean;
|
|
208
258
|
askBeforeUpdating?: boolean;
|
|
209
259
|
}): Promise<void> {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
260
|
+
return traceStep('install-package', async () => {
|
|
261
|
+
if (alreadyInstalled && askBeforeUpdating) {
|
|
262
|
+
const shouldUpdatePackage = await abortIfCancelled(
|
|
263
|
+
clack.confirm({
|
|
264
|
+
message: `The ${chalk.bold.cyan(
|
|
265
|
+
packageName,
|
|
266
|
+
)} package is already installed. Do you want to update it to the latest version?`,
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
218
269
|
|
|
219
|
-
|
|
220
|
-
|
|
270
|
+
if (!shouldUpdatePackage) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
221
273
|
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const sdkInstallSpinner = clack.spinner();
|
|
225
274
|
|
|
226
|
-
|
|
275
|
+
const sdkInstallSpinner = clack.spinner();
|
|
227
276
|
|
|
228
|
-
|
|
229
|
-
`${alreadyInstalled ? 'Updating' : 'Installing'} ${chalk.bold.cyan(
|
|
230
|
-
packageName,
|
|
231
|
-
)} with ${chalk.bold(packageManager.label)}.`,
|
|
232
|
-
);
|
|
277
|
+
const packageManager = await getPackageManager();
|
|
233
278
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
clack.log.error(
|
|
239
|
-
`${chalk.red(
|
|
240
|
-
'Encountered the following error during installation:',
|
|
241
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
242
|
-
)}\n\n${e}\n\n${chalk.dim(
|
|
243
|
-
'If you think this issue is caused by the Sentry wizard, let us know here:\nhttps://github.com/getsentry/sentry-wizard/issues',
|
|
244
|
-
)}`,
|
|
279
|
+
sdkInstallSpinner.start(
|
|
280
|
+
`${alreadyInstalled ? 'Updating' : 'Installing'} ${chalk.bold.cyan(
|
|
281
|
+
packageName,
|
|
282
|
+
)} with ${chalk.bold(packageManager.label)}.`,
|
|
245
283
|
);
|
|
246
|
-
await abort();
|
|
247
|
-
}
|
|
248
284
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
285
|
+
try {
|
|
286
|
+
await installPackageWithPackageManager(packageManager, packageName);
|
|
287
|
+
} catch (e) {
|
|
288
|
+
sdkInstallSpinner.stop('Installation failed.');
|
|
289
|
+
clack.log.error(
|
|
290
|
+
`${chalk.red(
|
|
291
|
+
'Encountered the following error during installation:',
|
|
292
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
293
|
+
)}\n\n${e}\n\n${chalk.dim(
|
|
294
|
+
'If you think this issue is caused by the Sentry wizard, let us know here:\nhttps://github.com/getsentry/sentry-wizard/issues',
|
|
295
|
+
)}`,
|
|
296
|
+
);
|
|
297
|
+
await abort();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
sdkInstallSpinner.stop(
|
|
301
|
+
`${alreadyInstalled ? 'Updated' : 'Installed'} ${chalk.bold.cyan(
|
|
302
|
+
packageName,
|
|
303
|
+
)} with ${chalk.bold(packageManager.label)}.`,
|
|
304
|
+
);
|
|
305
|
+
});
|
|
254
306
|
}
|
|
255
307
|
|
|
256
308
|
export async function addSentryCliConfig(
|
|
257
309
|
authToken: string,
|
|
258
310
|
setupConfig: CliSetupConfig = sourceMapsCliSetupConfig,
|
|
259
311
|
): Promise<void> {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
);
|
|
263
|
-
if (configExists) {
|
|
264
|
-
const configContents = fs.readFileSync(
|
|
312
|
+
return traceStep('add-sentry-cli-config', async () => {
|
|
313
|
+
const configExists = fs.existsSync(
|
|
265
314
|
path.join(process.cwd(), setupConfig.filename),
|
|
266
|
-
'utf8',
|
|
267
315
|
);
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
setupConfig.filename,
|
|
273
|
-
)} already has auth token. Will not add one.`,
|
|
316
|
+
if (configExists) {
|
|
317
|
+
const configContents = fs.readFileSync(
|
|
318
|
+
path.join(process.cwd(), setupConfig.filename),
|
|
319
|
+
'utf8',
|
|
274
320
|
);
|
|
321
|
+
|
|
322
|
+
if (setupConfig.likelyAlreadyHasAuthToken(configContents)) {
|
|
323
|
+
clack.log.warn(
|
|
324
|
+
`${chalk.bold(
|
|
325
|
+
setupConfig.filename,
|
|
326
|
+
)} already has auth token. Will not add one.`,
|
|
327
|
+
);
|
|
328
|
+
} else {
|
|
329
|
+
try {
|
|
330
|
+
await fs.promises.writeFile(
|
|
331
|
+
path.join(process.cwd(), setupConfig.filename),
|
|
332
|
+
`${configContents}\n${setupConfig.tokenContent(authToken)}\n`,
|
|
333
|
+
{ encoding: 'utf8', flag: 'w' },
|
|
334
|
+
);
|
|
335
|
+
clack.log.success(
|
|
336
|
+
chalk.greenBright(
|
|
337
|
+
`Added auth token to ${chalk.bold(
|
|
338
|
+
setupConfig.filename,
|
|
339
|
+
)} for you to test uploading ${setupConfig.name} locally.`,
|
|
340
|
+
),
|
|
341
|
+
);
|
|
342
|
+
} catch {
|
|
343
|
+
clack.log.warning(
|
|
344
|
+
`Failed to add auth token to ${chalk.bold(
|
|
345
|
+
setupConfig.filename,
|
|
346
|
+
)}. Uploading ${
|
|
347
|
+
setupConfig.name
|
|
348
|
+
} during build will likely not work locally.`,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
275
352
|
} else {
|
|
276
353
|
try {
|
|
277
354
|
await fs.promises.writeFile(
|
|
278
355
|
path.join(process.cwd(), setupConfig.filename),
|
|
279
|
-
`${
|
|
356
|
+
`${setupConfig.tokenContent(authToken)}\n`,
|
|
280
357
|
{ encoding: 'utf8', flag: 'w' },
|
|
281
358
|
);
|
|
282
359
|
clack.log.success(
|
|
283
360
|
chalk.greenBright(
|
|
284
|
-
`
|
|
361
|
+
`Created ${chalk.bold(
|
|
285
362
|
setupConfig.filename,
|
|
286
|
-
)} for you to test uploading ${
|
|
363
|
+
)} with auth token for you to test uploading ${
|
|
364
|
+
setupConfig.name
|
|
365
|
+
} locally.`,
|
|
287
366
|
),
|
|
288
367
|
);
|
|
289
368
|
} catch {
|
|
290
369
|
clack.log.warning(
|
|
291
|
-
`Failed to
|
|
370
|
+
`Failed to create ${chalk.bold(
|
|
292
371
|
setupConfig.filename,
|
|
293
|
-
)}. Uploading ${
|
|
372
|
+
)} with auth token. Uploading ${
|
|
294
373
|
setupConfig.name
|
|
295
374
|
} during build will likely not work locally.`,
|
|
296
375
|
);
|
|
297
376
|
}
|
|
298
377
|
}
|
|
299
|
-
} else {
|
|
300
|
-
try {
|
|
301
|
-
await fs.promises.writeFile(
|
|
302
|
-
path.join(process.cwd(), setupConfig.filename),
|
|
303
|
-
`${setupConfig.tokenContent(authToken)}\n`,
|
|
304
|
-
{ encoding: 'utf8', flag: 'w' },
|
|
305
|
-
);
|
|
306
|
-
clack.log.success(
|
|
307
|
-
chalk.greenBright(
|
|
308
|
-
`Created ${chalk.bold(
|
|
309
|
-
setupConfig.filename,
|
|
310
|
-
)} with auth token for you to test uploading ${
|
|
311
|
-
setupConfig.name
|
|
312
|
-
} locally.`,
|
|
313
|
-
),
|
|
314
|
-
);
|
|
315
|
-
} catch {
|
|
316
|
-
clack.log.warning(
|
|
317
|
-
`Failed to create ${chalk.bold(
|
|
318
|
-
setupConfig.filename,
|
|
319
|
-
)} with auth token. Uploading ${
|
|
320
|
-
setupConfig.name
|
|
321
|
-
} during build will likely not work locally.`,
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
378
|
|
|
326
|
-
|
|
379
|
+
await addAuthTokenFileToGitIgnore(setupConfig.filename);
|
|
380
|
+
});
|
|
327
381
|
}
|
|
328
382
|
|
|
329
383
|
export async function addDotEnvSentryBuildPluginFile(
|
|
@@ -418,26 +472,40 @@ async function addAuthTokenFileToGitIgnore(filename: string): Promise<void> {
|
|
|
418
472
|
}
|
|
419
473
|
}
|
|
420
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Checks if @param packageId is listed as a dependency in @param packageJson.
|
|
477
|
+
* If not, it will ask users if they want to continue without the package.
|
|
478
|
+
*
|
|
479
|
+
* Use this function to check if e.g. a the framework of the SDK is installed
|
|
480
|
+
*
|
|
481
|
+
* @param packageJson the package.json object
|
|
482
|
+
* @param packageId the npm name of the package
|
|
483
|
+
* @param packageName a human readable name of the package
|
|
484
|
+
*/
|
|
421
485
|
export async function ensurePackageIsInstalled(
|
|
422
486
|
packageJson: PackageDotJson,
|
|
423
487
|
packageId: string,
|
|
424
488
|
packageName: string,
|
|
425
|
-
) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
})
|
|
433
|
-
|
|
489
|
+
): Promise<void> {
|
|
490
|
+
return traceStep('ensure-package-installed', async () => {
|
|
491
|
+
const installed = hasPackageInstalled(packageId, packageJson);
|
|
492
|
+
|
|
493
|
+
Sentry.setTag(`${packageName.toLowerCase()}-installed`, installed);
|
|
494
|
+
|
|
495
|
+
if (!installed) {
|
|
496
|
+
Sentry.setTag(`${packageName.toLowerCase()}-installed`, false);
|
|
497
|
+
const continueWithoutPackage = await abortIfCancelled(
|
|
498
|
+
clack.confirm({
|
|
499
|
+
message: `${packageName} does not seem to be installed. Do you still want to continue?`,
|
|
500
|
+
initialValue: false,
|
|
501
|
+
}),
|
|
502
|
+
);
|
|
434
503
|
|
|
435
|
-
|
|
436
|
-
|
|
504
|
+
if (!continueWithoutPackage) {
|
|
505
|
+
await abort(undefined, 0);
|
|
506
|
+
}
|
|
437
507
|
}
|
|
438
|
-
}
|
|
439
|
-
Sentry.setTag('package-installed', true);
|
|
440
|
-
}
|
|
508
|
+
});
|
|
441
509
|
}
|
|
442
510
|
|
|
443
511
|
export async function getPackageDotJson(): Promise<PackageDotJson> {
|
|
@@ -457,7 +525,9 @@ export async function getPackageDotJson(): Promise<PackageDotJson> {
|
|
|
457
525
|
packageJson = JSON.parse(packageJsonFileContents);
|
|
458
526
|
} catch {
|
|
459
527
|
clack.log.error(
|
|
460
|
-
|
|
528
|
+
`Unable to parse your ${chalk.cyan(
|
|
529
|
+
'package.json',
|
|
530
|
+
)}. Make sure it has a valid format!`,
|
|
461
531
|
);
|
|
462
532
|
|
|
463
533
|
await abort();
|
|
@@ -4,6 +4,9 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { promisify } from 'util';
|
|
6
6
|
|
|
7
|
+
import * as Sentry from '@sentry/node';
|
|
8
|
+
import { traceStep } from '../telemetry';
|
|
9
|
+
|
|
7
10
|
export interface PackageManager {
|
|
8
11
|
name: string;
|
|
9
12
|
label: string;
|
|
@@ -50,13 +53,16 @@ export const NPM: PackageManager = {
|
|
|
50
53
|
export const packageManagers = [BUN, YARN, PNPM, NPM];
|
|
51
54
|
|
|
52
55
|
export function detectPackageManger(): PackageManager | null {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
return traceStep('detect-package-manager', () => {
|
|
57
|
+
for (const packageManager of packageManagers) {
|
|
58
|
+
if (fs.existsSync(path.join(process.cwd(), packageManager.lockFile))) {
|
|
59
|
+
Sentry.setTag('package-manager', packageManager.name);
|
|
60
|
+
return packageManager;
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
Sentry.setTag('package-manager', 'not-detected');
|
|
64
|
+
return null;
|
|
65
|
+
});
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
export async function installPackageWithPackageManager(
|