@sentry/wizard 3.25.2 → 3.27.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/dist/lib/Steps/OpenSentry.js +1 -1
- package/dist/lib/Steps/OpenSentry.js.map +1 -1
- package/dist/package.json +2 -1
- package/dist/src/nextjs/nextjs-wizard.d.ts +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +194 -99
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +7 -3
- package/dist/src/nextjs/templates.js +27 -14
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/run.js +1 -1
- package/dist/src/run.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/telemetry.js +10 -3
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +4 -1
- package/dist/src/utils/clack-utils.js +81 -11
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +5 -2
- package/dist/src/utils/package-manager.js +44 -56
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/src/utils/types.d.ts +6 -0
- package/dist/src/utils/types.js.map +1 -1
- package/dist/src/utils/url.js +7 -2
- package/dist/src/utils/url.js.map +1 -1
- package/dist/test/nextjs/templates.test.js +79 -1
- package/dist/test/nextjs/templates.test.js.map +1 -1
- package/dist/test/sourcemaps/tools/sentry-cli.test.js +2 -1
- package/dist/test/sourcemaps/tools/sentry-cli.test.js.map +1 -1
- package/lib/Steps/OpenSentry.ts +1 -1
- package/package.json +2 -1
- package/src/nextjs/nextjs-wizard.ts +209 -101
- package/src/nextjs/templates.ts +54 -26
- package/src/run.ts +1 -1
- package/src/sourcemaps/sourcemaps-wizard.ts +1 -1
- package/src/telemetry.ts +7 -1
- package/src/utils/clack-utils.ts +77 -7
- package/src/utils/package-manager.ts +43 -13
- package/src/utils/types.ts +7 -0
- package/src/utils/url.ts +6 -2
- package/test/nextjs/templates.test.ts +296 -2
- package/test/sourcemaps/tools/sentry-cli.test.ts +2 -1
package/src/nextjs/templates.ts
CHANGED
|
@@ -7,6 +7,7 @@ type WithSentryConfigOptions = {
|
|
|
7
7
|
selfHosted: boolean;
|
|
8
8
|
sentryUrl: string;
|
|
9
9
|
tunnelRoute: boolean;
|
|
10
|
+
reactComponentAnnotation: boolean;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
export function getWithSentryConfigOptionsTemplate({
|
|
@@ -14,6 +15,7 @@ export function getWithSentryConfigOptionsTemplate({
|
|
|
14
15
|
projectSlug,
|
|
15
16
|
selfHosted,
|
|
16
17
|
tunnelRoute,
|
|
18
|
+
reactComponentAnnotation,
|
|
17
19
|
sentryUrl,
|
|
18
20
|
}: WithSentryConfigOptions): string {
|
|
19
21
|
return `{
|
|
@@ -32,7 +34,15 @@ export function getWithSentryConfigOptionsTemplate({
|
|
|
32
34
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
|
33
35
|
|
|
34
36
|
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
|
35
|
-
widenClientFileUpload: true
|
|
37
|
+
widenClientFileUpload: true,${
|
|
38
|
+
reactComponentAnnotation
|
|
39
|
+
? `\n
|
|
40
|
+
// Automatically annotate React components to show their full name in breadcrumbs and session replay
|
|
41
|
+
reactComponentAnnotation: {
|
|
42
|
+
enabled: true,
|
|
43
|
+
},`
|
|
44
|
+
: ''
|
|
45
|
+
}
|
|
36
46
|
|
|
37
47
|
// ${
|
|
38
48
|
tunnelRoute ? 'Route' : 'Uncomment to route'
|
|
@@ -102,9 +112,26 @@ export default withSentryConfig(
|
|
|
102
112
|
`;
|
|
103
113
|
}
|
|
104
114
|
|
|
115
|
+
function getClientIntegrationsSnippet(features: { replay: boolean }) {
|
|
116
|
+
if (features.replay) {
|
|
117
|
+
return `
|
|
118
|
+
|
|
119
|
+
// Add optional integrations for additional features
|
|
120
|
+
integrations: [
|
|
121
|
+
Sentry.replayIntegration(),
|
|
122
|
+
],`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
|
|
105
128
|
export function getSentryConfigContents(
|
|
106
129
|
dsn: string,
|
|
107
130
|
config: 'server' | 'client' | 'edge',
|
|
131
|
+
selectedFeaturesMap: {
|
|
132
|
+
replay: boolean;
|
|
133
|
+
performance: boolean;
|
|
134
|
+
},
|
|
108
135
|
): string {
|
|
109
136
|
let primer;
|
|
110
137
|
if (config === 'server') {
|
|
@@ -122,33 +149,31 @@ export function getSentryConfigContents(
|
|
|
122
149
|
// https://docs.sentry.io/platforms/javascript/guides/nextjs/`;
|
|
123
150
|
}
|
|
124
151
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
152
|
+
const integrationsOptions = getClientIntegrationsSnippet({
|
|
153
|
+
replay: config === 'client' && selectedFeaturesMap.replay,
|
|
154
|
+
});
|
|
128
155
|
|
|
129
|
-
|
|
156
|
+
let replayOptions = '';
|
|
157
|
+
if (config === 'client') {
|
|
158
|
+
if (selectedFeaturesMap.replay) {
|
|
159
|
+
replayOptions += `
|
|
130
160
|
|
|
161
|
+
// Define how likely Replay events are sampled.
|
|
131
162
|
// This sets the sample rate to be 10%. You may want this to be 100% while
|
|
132
163
|
// in development and sample at a lower rate in production
|
|
133
164
|
replaysSessionSampleRate: 0.1,
|
|
134
165
|
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
// Additional Replay configuration goes in here, for example:
|
|
139
|
-
maskAllText: true,
|
|
140
|
-
blockAllMedia: true,
|
|
141
|
-
}),
|
|
142
|
-
],`;
|
|
166
|
+
// Define how likely Replay events are sampled when an error occurs.
|
|
167
|
+
replaysOnErrorSampleRate: 1.0,`;
|
|
168
|
+
}
|
|
143
169
|
}
|
|
144
170
|
|
|
145
|
-
let
|
|
146
|
-
if (
|
|
147
|
-
|
|
171
|
+
let performanceOptions = '';
|
|
172
|
+
if (selectedFeaturesMap.performance) {
|
|
173
|
+
performanceOptions += `
|
|
148
174
|
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
`;
|
|
175
|
+
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
|
|
176
|
+
tracesSampleRate: 1,`;
|
|
152
177
|
}
|
|
153
178
|
|
|
154
179
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
@@ -157,13 +182,10 @@ export function getSentryConfigContents(
|
|
|
157
182
|
import * as Sentry from "@sentry/nextjs";
|
|
158
183
|
|
|
159
184
|
Sentry.init({
|
|
160
|
-
dsn: "${dsn}"
|
|
161
|
-
|
|
162
|
-
// Adjust this value in production, or use tracesSampler for greater control
|
|
163
|
-
tracesSampleRate: 1,
|
|
185
|
+
dsn: "${dsn}",${integrationsOptions}${performanceOptions}${replayOptions}
|
|
164
186
|
|
|
165
187
|
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
|
166
|
-
debug: false
|
|
188
|
+
debug: false,
|
|
167
189
|
});
|
|
168
190
|
`;
|
|
169
191
|
}
|
|
@@ -261,7 +283,7 @@ export default function Page() {
|
|
|
261
283
|
`;
|
|
262
284
|
}
|
|
263
285
|
|
|
264
|
-
export function
|
|
286
|
+
export function getSentryExamplePagesDirApiRoute() {
|
|
265
287
|
return `// A faulty API route to test Sentry's error monitoring
|
|
266
288
|
export default function handler(_req, res) {
|
|
267
289
|
throw new Error("Sentry Example API Route Error");
|
|
@@ -307,16 +329,19 @@ export default CustomErrorComponent;
|
|
|
307
329
|
export function getSimpleUnderscoreErrorCopyPasteSnippet() {
|
|
308
330
|
return `
|
|
309
331
|
${chalk.green(`import * as Sentry from '@sentry/nextjs';`)}
|
|
332
|
+
${chalk.green(`import Error from "next/error";`)}
|
|
310
333
|
|
|
311
334
|
${chalk.dim(
|
|
312
335
|
'// Replace "YourCustomErrorComponent" with your custom error component!',
|
|
313
336
|
)}
|
|
314
337
|
YourCustomErrorComponent.getInitialProps = async (${chalk.green(
|
|
315
|
-
|
|
338
|
+
'contextData',
|
|
316
339
|
)}) => {
|
|
317
340
|
${chalk.green('await Sentry.captureUnderscoreErrorException(contextData);')}
|
|
318
341
|
|
|
319
342
|
${chalk.dim('// ...other getInitialProps code')}
|
|
343
|
+
|
|
344
|
+
return Error.getInitialProps(contextData);
|
|
320
345
|
};
|
|
321
346
|
`;
|
|
322
347
|
}
|
|
@@ -326,6 +351,7 @@ export function getFullUnderscoreErrorCopyPasteSnippet(isTs: boolean) {
|
|
|
326
351
|
import * as Sentry from '@sentry/nextjs';${
|
|
327
352
|
isTs ? '\nimport type { NextPageContext } from "next";' : ''
|
|
328
353
|
}
|
|
354
|
+
import Error from "next/error";
|
|
329
355
|
|
|
330
356
|
${chalk.dim(
|
|
331
357
|
'// Replace "YourCustomErrorComponent" with your custom error component!',
|
|
@@ -334,6 +360,8 @@ YourCustomErrorComponent.getInitialProps = async (contextData${
|
|
|
334
360
|
isTs ? ': NextPageContext' : ''
|
|
335
361
|
}) => {
|
|
336
362
|
await Sentry.captureUnderscoreErrorException(contextData);
|
|
363
|
+
|
|
364
|
+
return Error.getInitialProps(contextData);
|
|
337
365
|
};
|
|
338
366
|
`;
|
|
339
367
|
}
|
package/src/run.ts
CHANGED
|
@@ -60,7 +60,7 @@ export async function run(argv: Args) {
|
|
|
60
60
|
{ value: 'android', label: 'Android' },
|
|
61
61
|
{ value: 'cordova', label: 'Cordova' },
|
|
62
62
|
{ value: 'electron', label: 'Electron' },
|
|
63
|
-
{ value: 'nextjs', label: '
|
|
63
|
+
{ value: 'nextjs', label: 'Next.js' },
|
|
64
64
|
{ value: 'remix', label: 'Remix' },
|
|
65
65
|
{ value: 'sveltekit', label: 'SvelteKit' },
|
|
66
66
|
{ value: 'sourcemaps', label: 'Configure Source Maps Upload' },
|
|
@@ -141,7 +141,7 @@ async function askForUsedBundlerTool(): Promise<SupportedTools> {
|
|
|
141
141
|
{
|
|
142
142
|
label: 'Next.js',
|
|
143
143
|
value: 'nextjs',
|
|
144
|
-
hint: 'Select this option if you want to set up source maps in a
|
|
144
|
+
hint: 'Select this option if you want to set up source maps in a Next.js project.',
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
label: 'Remix',
|
package/src/telemetry.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
runWithAsyncContext,
|
|
9
9
|
setTag,
|
|
10
10
|
startSpan,
|
|
11
|
+
flush,
|
|
11
12
|
} from '@sentry/node';
|
|
12
13
|
import packageJson from '../package.json';
|
|
13
14
|
|
|
@@ -49,7 +50,12 @@ export async function withTelemetry<F>(
|
|
|
49
50
|
throw e;
|
|
50
51
|
} finally {
|
|
51
52
|
sentryHub.endSession();
|
|
52
|
-
await sentryClient.flush(3000)
|
|
53
|
+
await sentryClient.flush(3000).then(null, () => {
|
|
54
|
+
// If telemetry flushing fails we generally don't care
|
|
55
|
+
});
|
|
56
|
+
await flush(3000).then(null, () => {
|
|
57
|
+
// If telemetry flushing fails we generally don't care
|
|
58
|
+
});
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
61
|
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -10,12 +10,11 @@ import { setInterval } from 'timers';
|
|
|
10
10
|
import { URL } from 'url';
|
|
11
11
|
import * as Sentry from '@sentry/node';
|
|
12
12
|
import { hasPackageInstalled, PackageDotJson } from './package-json';
|
|
13
|
-
import { SentryProjectData, WizardOptions } from './types';
|
|
13
|
+
import { Feature, SentryProjectData, WizardOptions } from './types';
|
|
14
14
|
import { traceStep } from '../telemetry';
|
|
15
15
|
import {
|
|
16
16
|
detectPackageManger,
|
|
17
17
|
PackageManager,
|
|
18
|
-
installPackageWithPackageManager,
|
|
19
18
|
packageManagers,
|
|
20
19
|
} from './package-manager';
|
|
21
20
|
import { debug } from './debug';
|
|
@@ -23,6 +22,9 @@ import { fulfillsVersionRange } from './semver';
|
|
|
23
22
|
|
|
24
23
|
const opn = require('opn') as (
|
|
25
24
|
url: string,
|
|
25
|
+
options?: {
|
|
26
|
+
wait?: boolean;
|
|
27
|
+
},
|
|
26
28
|
) => Promise<childProcess.ChildProcess>;
|
|
27
29
|
|
|
28
30
|
export const SENTRY_DOT_ENV_FILE = '.env.sentry-build-plugin';
|
|
@@ -383,7 +385,31 @@ export async function installPackage({
|
|
|
383
385
|
);
|
|
384
386
|
|
|
385
387
|
try {
|
|
386
|
-
await
|
|
388
|
+
await new Promise<void>((resolve, reject) => {
|
|
389
|
+
childProcess.exec(
|
|
390
|
+
`${packageManager.installCommand} ${packageName} ${packageManager.flags}`,
|
|
391
|
+
(err, stdout, stderr) => {
|
|
392
|
+
if (err) {
|
|
393
|
+
// Write a log file so we can better troubleshoot issues
|
|
394
|
+
fs.writeFileSync(
|
|
395
|
+
path.join(
|
|
396
|
+
process.cwd(),
|
|
397
|
+
`sentry-wizard-installation-error-${Date.now()}.log`,
|
|
398
|
+
),
|
|
399
|
+
JSON.stringify({
|
|
400
|
+
stdout,
|
|
401
|
+
stderr,
|
|
402
|
+
}),
|
|
403
|
+
{ encoding: 'utf8' },
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
reject(err);
|
|
407
|
+
} else {
|
|
408
|
+
resolve();
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
);
|
|
412
|
+
});
|
|
387
413
|
} catch (e) {
|
|
388
414
|
sdkInstallSpinner.stop('Installation failed.');
|
|
389
415
|
clack.log.error(
|
|
@@ -391,7 +417,7 @@ export async function installPackage({
|
|
|
391
417
|
'Encountered the following error during installation:',
|
|
392
418
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
393
419
|
)}\n\n${e}\n\n${chalk.dim(
|
|
394
|
-
|
|
420
|
+
"The wizard has created a `sentry-wizard-installation-error-*.log` file. If you think this issue is caused by the Sentry wizard, create an issue on GitHub and include the log file's content:\nhttps://github.com/getsentry/sentry-wizard/issues",
|
|
395
421
|
)}`,
|
|
396
422
|
);
|
|
397
423
|
await abort();
|
|
@@ -614,10 +640,21 @@ SENTRY_AUTH_TOKEN=${authToken}
|
|
|
614
640
|
}
|
|
615
641
|
|
|
616
642
|
async function addCliConfigFileToGitIgnore(filename: string): Promise<void> {
|
|
617
|
-
|
|
643
|
+
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
644
|
+
|
|
618
645
|
try {
|
|
646
|
+
const gitignoreContent = await fs.promises.readFile(gitignorePath, 'utf8');
|
|
647
|
+
if (gitignoreContent.split(/\r?\n/).includes(filename)) {
|
|
648
|
+
clack.log.info(
|
|
649
|
+
`${chalk.bold('.gitignore')} already has ${chalk.bold(
|
|
650
|
+
filename,
|
|
651
|
+
)}. Will not add it again.`,
|
|
652
|
+
);
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
|
|
619
656
|
await fs.promises.appendFile(
|
|
620
|
-
|
|
657
|
+
gitignorePath,
|
|
621
658
|
`\n# Sentry Config File\n${filename}\n`,
|
|
622
659
|
{ encoding: 'utf8' },
|
|
623
660
|
);
|
|
@@ -958,7 +995,7 @@ async function askForWizardLogin(options: {
|
|
|
958
995
|
)}\n\n${chalk.cyan(urlToOpen)}`,
|
|
959
996
|
);
|
|
960
997
|
|
|
961
|
-
opn(urlToOpen).catch(() => {
|
|
998
|
+
opn(urlToOpen, { wait: false }).catch(() => {
|
|
962
999
|
// opn throws in environments that don't have a browser (e.g. remote shells) so we just noop here
|
|
963
1000
|
});
|
|
964
1001
|
|
|
@@ -1240,3 +1277,36 @@ export async function askShouldCreateExamplePage(
|
|
|
1240
1277
|
),
|
|
1241
1278
|
);
|
|
1242
1279
|
}
|
|
1280
|
+
|
|
1281
|
+
export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
|
|
1282
|
+
features: F,
|
|
1283
|
+
): Promise<{ [key in F[number]['id']]: boolean }> {
|
|
1284
|
+
return traceStep('feature-selection', async () => {
|
|
1285
|
+
const selectedFeatures: Record<string, boolean> = {};
|
|
1286
|
+
|
|
1287
|
+
for (const feature of features) {
|
|
1288
|
+
const selected = await abortIfCancelled(
|
|
1289
|
+
clack.select({
|
|
1290
|
+
message: feature.prompt,
|
|
1291
|
+
initialValue: true,
|
|
1292
|
+
options: [
|
|
1293
|
+
{
|
|
1294
|
+
value: true,
|
|
1295
|
+
label: 'Yes',
|
|
1296
|
+
hint: feature.enabledHint,
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
value: false,
|
|
1300
|
+
label: 'No',
|
|
1301
|
+
hint: feature.disabledHint,
|
|
1302
|
+
},
|
|
1303
|
+
],
|
|
1304
|
+
}),
|
|
1305
|
+
);
|
|
1306
|
+
|
|
1307
|
+
selectedFeatures[feature.id] = selected;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
return selectedFeatures as { [key in F[number]['id']]: boolean };
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/typedef */
|
|
2
|
-
import { exec } from 'child_process';
|
|
3
2
|
import * as fs from 'fs';
|
|
4
3
|
import * as path from 'path';
|
|
5
|
-
import { promisify } from 'util';
|
|
6
4
|
|
|
7
5
|
import * as Sentry from '@sentry/node';
|
|
8
6
|
import { traceStep } from '../telemetry';
|
|
@@ -15,6 +13,8 @@ export interface PackageManager {
|
|
|
15
13
|
buildCommand: string;
|
|
16
14
|
/* The command that the package manager uses to run a script from package.json */
|
|
17
15
|
runScriptCommand: string;
|
|
16
|
+
flags: string;
|
|
17
|
+
detect: () => boolean;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export const BUN: PackageManager = {
|
|
@@ -24,14 +24,47 @@ export const BUN: PackageManager = {
|
|
|
24
24
|
installCommand: 'bun add',
|
|
25
25
|
buildCommand: 'bun run build',
|
|
26
26
|
runScriptCommand: 'bun run',
|
|
27
|
+
flags: '',
|
|
28
|
+
detect: () => fs.existsSync(path.join(process.cwd(), BUN.lockFile)),
|
|
27
29
|
};
|
|
28
|
-
export const
|
|
30
|
+
export const YARN_V1: PackageManager = {
|
|
29
31
|
name: 'yarn',
|
|
30
|
-
label: 'Yarn',
|
|
32
|
+
label: 'Yarn V1',
|
|
31
33
|
lockFile: 'yarn.lock',
|
|
32
34
|
installCommand: 'yarn add',
|
|
33
35
|
buildCommand: 'yarn build',
|
|
34
36
|
runScriptCommand: 'yarn',
|
|
37
|
+
flags: '--ignore-workspace-root-check',
|
|
38
|
+
detect: () => {
|
|
39
|
+
try {
|
|
40
|
+
return fs
|
|
41
|
+
.readFileSync(path.join(process.cwd(), YARN_V1.lockFile), 'utf-8')
|
|
42
|
+
.slice(0, 500)
|
|
43
|
+
.includes('yarn lockfile v1');
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
/** YARN V2/3/4 */
|
|
50
|
+
export const YARN_V2: PackageManager = {
|
|
51
|
+
name: 'yarn',
|
|
52
|
+
label: 'Yarn V2/3/4',
|
|
53
|
+
lockFile: 'yarn.lock',
|
|
54
|
+
installCommand: 'yarn add',
|
|
55
|
+
buildCommand: 'yarn build',
|
|
56
|
+
runScriptCommand: 'yarn',
|
|
57
|
+
flags: '',
|
|
58
|
+
detect: () => {
|
|
59
|
+
try {
|
|
60
|
+
return fs
|
|
61
|
+
.readFileSync(path.join(process.cwd(), YARN_V2.lockFile), 'utf-8')
|
|
62
|
+
.slice(0, 500)
|
|
63
|
+
.includes('__metadata');
|
|
64
|
+
} catch (e) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
},
|
|
35
68
|
};
|
|
36
69
|
export const PNPM: PackageManager = {
|
|
37
70
|
name: 'pnpm',
|
|
@@ -40,6 +73,8 @@ export const PNPM: PackageManager = {
|
|
|
40
73
|
installCommand: 'pnpm add',
|
|
41
74
|
buildCommand: 'pnpm build',
|
|
42
75
|
runScriptCommand: 'pnpm',
|
|
76
|
+
flags: '--ignore-workspace-root-check',
|
|
77
|
+
detect: () => fs.existsSync(path.join(process.cwd(), PNPM.lockFile)),
|
|
43
78
|
};
|
|
44
79
|
export const NPM: PackageManager = {
|
|
45
80
|
name: 'npm',
|
|
@@ -48,14 +83,16 @@ export const NPM: PackageManager = {
|
|
|
48
83
|
installCommand: 'npm add',
|
|
49
84
|
buildCommand: 'npm run build',
|
|
50
85
|
runScriptCommand: 'npm run',
|
|
86
|
+
flags: '',
|
|
87
|
+
detect: () => fs.existsSync(path.join(process.cwd(), NPM.lockFile)),
|
|
51
88
|
};
|
|
52
89
|
|
|
53
|
-
export const packageManagers = [BUN,
|
|
90
|
+
export const packageManagers = [BUN, YARN_V1, YARN_V2, PNPM, NPM];
|
|
54
91
|
|
|
55
92
|
export function detectPackageManger(): PackageManager | null {
|
|
56
93
|
return traceStep('detect-package-manager', () => {
|
|
57
94
|
for (const packageManager of packageManagers) {
|
|
58
|
-
if (
|
|
95
|
+
if (packageManager.detect()) {
|
|
59
96
|
Sentry.setTag('package-manager', packageManager.name);
|
|
60
97
|
return packageManager;
|
|
61
98
|
}
|
|
@@ -64,10 +101,3 @@ export function detectPackageManger(): PackageManager | null {
|
|
|
64
101
|
return null;
|
|
65
102
|
});
|
|
66
103
|
}
|
|
67
|
-
|
|
68
|
-
export async function installPackageWithPackageManager(
|
|
69
|
-
packageManager: PackageManager,
|
|
70
|
-
packageName: string,
|
|
71
|
-
): Promise<void> {
|
|
72
|
-
await promisify(exec)(`${packageManager.installCommand} ${packageName}`);
|
|
73
|
-
}
|
package/src/utils/types.ts
CHANGED
package/src/utils/url.ts
CHANGED
|
@@ -15,8 +15,12 @@ export function getIssueStreamUrl({
|
|
|
15
15
|
projectId: string;
|
|
16
16
|
}): string {
|
|
17
17
|
const urlObject = new URL(url);
|
|
18
|
-
urlObject.host
|
|
19
|
-
|
|
18
|
+
if (urlObject.host === 'sentry.io') {
|
|
19
|
+
urlObject.host = `${orgSlug}.${urlObject.host}`;
|
|
20
|
+
urlObject.pathname = '/issues/';
|
|
21
|
+
} else {
|
|
22
|
+
urlObject.pathname = `/organizations/${orgSlug}/issues/`;
|
|
23
|
+
}
|
|
20
24
|
urlObject.searchParams.set('project', projectId);
|
|
21
25
|
|
|
22
26
|
return urlObject.toString();
|