@sentry/wizard 3.10.0 → 3.11.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +47 -7
  2. package/dist/lib/Constants.d.ts +1 -0
  3. package/dist/lib/Constants.js +5 -0
  4. package/dist/lib/Constants.js.map +1 -1
  5. package/dist/lib/Steps/ChooseIntegration.js +8 -4
  6. package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
  7. package/dist/lib/Steps/Integrations/Android.d.ts +9 -0
  8. package/dist/lib/Steps/Integrations/Android.js +86 -0
  9. package/dist/lib/Steps/Integrations/Android.js.map +1 -0
  10. package/dist/lib/Steps/Integrations/ReactNative.js +3 -3
  11. package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
  12. package/dist/lib/Steps/PromptForParameters.js +36 -3
  13. package/dist/lib/Steps/PromptForParameters.js.map +1 -1
  14. package/dist/lib/Steps/SentryProjectSelector.js +1 -1
  15. package/dist/lib/Steps/SentryProjectSelector.js.map +1 -1
  16. package/dist/package.json +4 -3
  17. package/dist/src/android/android-wizard.d.ts +2 -0
  18. package/dist/src/android/android-wizard.js +217 -0
  19. package/dist/src/android/android-wizard.js.map +1 -0
  20. package/dist/src/android/code-tools.d.ts +39 -0
  21. package/dist/src/android/code-tools.js +161 -0
  22. package/dist/src/android/code-tools.js.map +1 -0
  23. package/dist/src/android/gradle.d.ts +62 -0
  24. package/dist/src/android/gradle.js +281 -0
  25. package/dist/src/android/gradle.js.map +1 -0
  26. package/dist/src/android/manifest.d.ts +57 -0
  27. package/dist/src/android/manifest.js +183 -0
  28. package/dist/src/android/manifest.js.map +1 -0
  29. package/dist/src/android/templates.d.ts +11 -0
  30. package/dist/src/android/templates.js +34 -0
  31. package/dist/src/android/templates.js.map +1 -0
  32. package/dist/src/apple/apple-wizard.js +123 -64
  33. package/dist/src/apple/apple-wizard.js.map +1 -1
  34. package/dist/src/apple/cocoapod.js +4 -3
  35. package/dist/src/apple/cocoapod.js.map +1 -1
  36. package/dist/src/apple/code-tools.d.ts +1 -1
  37. package/dist/src/apple/code-tools.js +43 -19
  38. package/dist/src/apple/code-tools.js.map +1 -1
  39. package/dist/src/apple/fastlane.d.ts +1 -1
  40. package/dist/src/apple/fastlane.js +12 -6
  41. package/dist/src/apple/fastlane.js.map +1 -1
  42. package/dist/src/apple/templates.d.ts +2 -2
  43. package/dist/src/apple/templates.js +4 -4
  44. package/dist/src/apple/templates.js.map +1 -1
  45. package/dist/src/apple/xcode-manager.d.ts +19 -3
  46. package/dist/src/apple/xcode-manager.js +126 -24
  47. package/dist/src/apple/xcode-manager.js.map +1 -1
  48. package/dist/src/nextjs/nextjs-wizard.js +49 -11
  49. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  50. package/dist/src/nextjs/templates.d.ts +2 -0
  51. package/dist/src/nextjs/templates.js +6 -2
  52. package/dist/src/nextjs/templates.js.map +1 -1
  53. package/dist/src/remix/remix-wizard.js +10 -20
  54. package/dist/src/remix/remix-wizard.js.map +1 -1
  55. package/dist/src/sourcemaps/sourcemaps-wizard.js +26 -13
  56. package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
  57. package/dist/src/sourcemaps/tools/nextjs.js +1 -1
  58. package/dist/src/sourcemaps/tools/nextjs.js.map +1 -1
  59. package/dist/src/sourcemaps/tools/sentry-cli.js +19 -16
  60. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  61. package/dist/src/sourcemaps/tools/vite.d.ts +2 -1
  62. package/dist/src/sourcemaps/tools/vite.js +99 -12
  63. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  64. package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
  65. package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
  66. package/dist/src/sveltekit/sdk-setup.js +3 -3
  67. package/dist/src/sveltekit/sdk-setup.js.map +1 -1
  68. package/dist/src/sveltekit/sveltekit-wizard.js +34 -44
  69. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  70. package/dist/src/telemetry.js +1 -0
  71. package/dist/src/telemetry.js.map +1 -1
  72. package/dist/src/utils/ast-utils.d.ts +2 -2
  73. package/dist/src/utils/ast-utils.js +7 -7
  74. package/dist/src/utils/ast-utils.js.map +1 -1
  75. package/dist/src/utils/clack-utils.d.ts +22 -28
  76. package/dist/src/utils/clack-utils.js +270 -264
  77. package/dist/src/utils/clack-utils.js.map +1 -1
  78. package/dist/src/utils/package-manager.d.ts +10 -0
  79. package/dist/{lib/Helper/PackageManager.js → src/utils/package-manager.js} +42 -74
  80. package/dist/src/utils/package-manager.js.map +1 -0
  81. package/dist/src/utils/release-registry.d.ts +1 -0
  82. package/dist/src/utils/release-registry.js +68 -0
  83. package/dist/src/utils/release-registry.js.map +1 -0
  84. package/dist/src/utils/sentrycli-utils.d.ts +4 -0
  85. package/dist/src/utils/sentrycli-utils.js +41 -0
  86. package/dist/src/utils/sentrycli-utils.js.map +1 -0
  87. package/dist/test/sourcemaps/tools/vite.test.d.ts +1 -0
  88. package/dist/test/sourcemaps/tools/vite.test.js +132 -0
  89. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -0
  90. package/lib/Constants.ts +5 -0
  91. package/lib/Steps/ChooseIntegration.ts +7 -3
  92. package/lib/Steps/Integrations/Android.ts +23 -0
  93. package/lib/Steps/Integrations/ReactNative.ts +9 -3
  94. package/lib/Steps/PromptForParameters.ts +48 -3
  95. package/lib/Steps/SentryProjectSelector.ts +3 -1
  96. package/package.json +4 -3
  97. package/src/android/android-wizard.ts +196 -0
  98. package/src/android/code-tools.ts +156 -0
  99. package/src/android/gradle.ts +245 -0
  100. package/src/android/manifest.ts +180 -0
  101. package/src/android/templates.ts +88 -0
  102. package/src/apple/apple-wizard.ts +113 -35
  103. package/src/apple/cocoapod.ts +6 -3
  104. package/src/apple/code-tools.ts +46 -18
  105. package/src/apple/fastlane.ts +6 -12
  106. package/src/apple/templates.ts +2 -8
  107. package/src/apple/xcode-manager.ts +167 -25
  108. package/src/nextjs/nextjs-wizard.ts +72 -8
  109. package/src/nextjs/templates.ts +16 -2
  110. package/src/remix/remix-wizard.ts +10 -15
  111. package/src/sourcemaps/sourcemaps-wizard.ts +19 -5
  112. package/src/sourcemaps/tools/nextjs.ts +2 -2
  113. package/src/sourcemaps/tools/sentry-cli.ts +8 -7
  114. package/src/sourcemaps/tools/vite.ts +136 -6
  115. package/src/sourcemaps/utils/detect-tool.ts +2 -1
  116. package/src/sveltekit/sdk-setup.ts +4 -4
  117. package/src/sveltekit/sveltekit-wizard.ts +5 -14
  118. package/src/telemetry.ts +2 -0
  119. package/src/utils/ast-utils.ts +7 -5
  120. package/src/utils/clack-utils.ts +337 -283
  121. package/src/utils/package-manager.ts +61 -0
  122. package/src/utils/release-registry.ts +19 -0
  123. package/src/utils/sentrycli-utils.ts +22 -0
  124. package/test/sourcemaps/tools/vite.test.ts +149 -0
  125. package/dist/lib/Helper/PackageManager.d.ts +0 -22
  126. package/dist/lib/Helper/PackageManager.js.map +0 -1
  127. package/dist/src/utils/vendor/clack-custom-select.d.ts +0 -21
  128. package/dist/src/utils/vendor/clack-custom-select.js +0 -137
  129. package/dist/src/utils/vendor/clack-custom-select.js.map +0 -1
  130. package/lib/Helper/PackageManager.ts +0 -59
  131. package/src/utils/vendor/clack-custom-select.ts +0 -160
@@ -62,7 +62,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
62
62
  return (mod && mod.__esModule) ? mod : { "default": mod };
63
63
  };
64
64
  Object.defineProperty(exports, "__esModule", { value: true });
65
- exports.getOrAskForProjectData = exports.isUsingTypeScript = exports.detectPackageManager = exports.getPackageDotJson = exports.ensurePackageIsInstalled = exports.addDotEnvSentryBuildPluginFile = exports.addSentryCliRc = exports.askForSelfHosted = exports.installPackage = exports.askForProjectSelection = exports.askForItemSelection = exports.askForWizardLogin = exports.askToInstallSentryCLI = exports.confirmContinueEvenThoughNoGitRepo = exports.printWelcome = exports.abortIfCancelled = exports.abort = exports.SENTRY_CLI_RC_FILE = exports.SENTRY_DOT_ENV_FILE = void 0;
65
+ exports.getOrAskForProjectData = exports.isUsingTypeScript = exports.getPackageDotJson = exports.ensurePackageIsInstalled = exports.addDotEnvSentryBuildPluginFile = exports.addSentryCliConfig = exports.installPackage = exports.askForItemSelection = exports.askToInstallSentryCLI = exports.confirmContinueEvenThoughNoGitRepo = exports.printWelcome = exports.abortIfCancelled = exports.abort = exports.sourceMapsCliSetupConfig = exports.SENTRY_PROPERTIES_FILE = exports.SENTRY_CLI_RC_FILE = exports.SENTRY_DOT_ENV_FILE = void 0;
66
66
  // @ts-ignore - clack is ESM and TS complains about that. It works though
67
67
  var clack = __importStar(require("@clack/prompts"));
68
68
  var axios_1 = __importDefault(require("axios"));
@@ -72,15 +72,33 @@ var fs = __importStar(require("fs"));
72
72
  var path = __importStar(require("path"));
73
73
  var timers_1 = require("timers");
74
74
  var url_1 = require("url");
75
- var util_1 = require("util");
76
75
  var Sentry = __importStar(require("@sentry/node"));
77
- var clack_custom_select_1 = require("./vendor/clack-custom-select");
78
76
  var package_json_1 = require("./package-json");
79
77
  var telemetry_1 = require("../telemetry");
78
+ var package_manager_1 = require("./package-manager");
80
79
  var opn = require('opn');
81
80
  exports.SENTRY_DOT_ENV_FILE = '.env.sentry-build-plugin';
82
81
  exports.SENTRY_CLI_RC_FILE = '.sentryclirc';
82
+ exports.SENTRY_PROPERTIES_FILE = 'sentry.properties';
83
83
  var SAAS_URL = 'https://sentry.io/';
84
+ exports.sourceMapsCliSetupConfig = {
85
+ filename: exports.SENTRY_CLI_RC_FILE,
86
+ name: 'source maps',
87
+ likelyAlreadyHasAuthToken: function (contents) {
88
+ return !!(contents.includes('[auth]') && contents.match(/token=./g));
89
+ },
90
+ tokenContent: function (authToken) {
91
+ return "[auth]\ntoken=".concat(authToken);
92
+ },
93
+ likelyAlreadyHasOrgAndProject: function (contents) {
94
+ return !!(contents.includes('[defaults]') &&
95
+ contents.match(/org=./g) &&
96
+ contents.match(/project=./g));
97
+ },
98
+ orgAndProjContent: function (org, project) {
99
+ return "[defaults]\norg=".concat(org, "\nproject=").concat(project);
100
+ },
101
+ };
84
102
  function abort(message, status) {
85
103
  return __awaiter(this, void 0, void 0, function () {
86
104
  var sentryHub, sentryTransaction, sentrySession;
@@ -204,99 +222,12 @@ function askToInstallSentryCLI() {
204
222
  });
205
223
  }
206
224
  exports.askToInstallSentryCLI = askToInstallSentryCLI;
207
- function askForWizardLogin(options) {
208
- return __awaiter(this, void 0, void 0, function () {
209
- var hasSentryAccount, wizardHash, _a, loginUrl, urlToOpen, loginSpinner, data;
210
- return __generator(this, function (_b) {
211
- switch (_b.label) {
212
- case 0:
213
- Sentry.setTag('has-promo-code', !!options.promoCode);
214
- return [4 /*yield*/, clack.confirm({
215
- message: 'Do you already have a Sentry account?',
216
- })];
217
- case 1:
218
- hasSentryAccount = _b.sent();
219
- return [4 /*yield*/, abortIfCancelled(hasSentryAccount)];
220
- case 2:
221
- hasSentryAccount = _b.sent();
222
- Sentry.setTag('already-has-sentry-account', hasSentryAccount);
223
- _b.label = 3;
224
- case 3:
225
- _b.trys.push([3, 5, , 10]);
226
- return [4 /*yield*/, axios_1.default.get("".concat(options.url, "api/0/wizard/"))];
227
- case 4:
228
- wizardHash = (_b.sent()).data.hash;
229
- return [3 /*break*/, 10];
230
- case 5:
231
- _a = _b.sent();
232
- if (!(options.url !== SAAS_URL)) return [3 /*break*/, 7];
233
- clack.log.error('Loading Wizard failed. Did you provide the right URL?');
234
- return [4 /*yield*/, abort(chalk_1.default.red('Please check your configuration and try again.\n\n Let us know if you think this is an issue with the wizard or Sentry: https://github.com/getsentry/sentry-wizard/issues'))];
235
- case 6:
236
- _b.sent();
237
- return [3 /*break*/, 9];
238
- case 7:
239
- clack.log.error('Loading Wizard failed.');
240
- return [4 /*yield*/, abort(chalk_1.default.red('Please try again in a few minutes and let us know if this issue persists: https://github.com/getsentry/sentry-wizard/issues'))];
241
- case 8:
242
- _b.sent();
243
- _b.label = 9;
244
- case 9: return [3 /*break*/, 10];
245
- case 10:
246
- loginUrl = new url_1.URL("".concat(options.url, "account/settings/wizard/").concat(wizardHash, "/"));
247
- if (!hasSentryAccount) {
248
- loginUrl.searchParams.set('signup', '1');
249
- if (options.platform) {
250
- loginUrl.searchParams.set('project_platform', options.platform);
251
- }
252
- }
253
- if (options.promoCode) {
254
- loginUrl.searchParams.set('code', options.promoCode);
255
- }
256
- urlToOpen = loginUrl.toString();
257
- clack.log.info("".concat(chalk_1.default.bold("If the browser window didn't open automatically, please open the following link to ".concat(hasSentryAccount ? 'log' : 'sign', " into Sentry:")), "\n\n").concat(chalk_1.default.cyan(urlToOpen)));
258
- opn(urlToOpen).catch(function () {
259
- // opn throws in environments that don't have a browser (e.g. remote shells) so we just noop here
260
- });
261
- loginSpinner = clack.spinner();
262
- loginSpinner.start('Waiting for you to log in using the link above');
263
- return [4 /*yield*/, new Promise(function (resolve) {
264
- var pollingInterval = (0, timers_1.setInterval)(function () {
265
- axios_1.default
266
- .get("".concat(options.url, "api/0/wizard/").concat(wizardHash, "/"))
267
- .then(function (result) {
268
- resolve(result.data);
269
- clearTimeout(timeout);
270
- clearInterval(pollingInterval);
271
- void axios_1.default.delete("".concat(options.url, "api/0/wizard/").concat(wizardHash, "/"));
272
- })
273
- .catch(function () {
274
- // noop - just try again
275
- });
276
- }, 500);
277
- var timeout = setTimeout(function () {
278
- clearInterval(pollingInterval);
279
- loginSpinner.stop('Login timed out. No worries - it happens to the best of us.');
280
- Sentry.setTag('opened-wizard-link', false);
281
- void abort('Please restart the Wizard and log in to complete the setup.');
282
- }, 180000);
283
- })];
284
- case 11:
285
- data = _b.sent();
286
- loginSpinner.stop('Login complete.');
287
- Sentry.setTag('opened-wizard-link', true);
288
- return [2 /*return*/, data];
289
- }
290
- });
291
- });
292
- }
293
- exports.askForWizardLogin = askForWizardLogin;
294
225
  function askForItemSelection(items, message) {
295
226
  return __awaiter(this, void 0, void 0, function () {
296
227
  var selection;
297
228
  return __generator(this, function (_a) {
298
229
  switch (_a.label) {
299
- case 0: return [4 /*yield*/, abortIfCancelled((0, clack_custom_select_1.windowedSelect)({
230
+ case 0: return [4 /*yield*/, abortIfCancelled(clack.select({
300
231
  maxItems: 12,
301
232
  message: message,
302
233
  options: items.map(function (item, index) {
@@ -314,32 +245,6 @@ function askForItemSelection(items, message) {
314
245
  });
315
246
  }
316
247
  exports.askForItemSelection = askForItemSelection;
317
- function askForProjectSelection(projects) {
318
- return __awaiter(this, void 0, void 0, function () {
319
- var selection;
320
- return __generator(this, function (_a) {
321
- switch (_a.label) {
322
- case 0: return [4 /*yield*/, abortIfCancelled((0, clack_custom_select_1.windowedSelect)({
323
- maxItems: 12,
324
- message: 'Select your Sentry project.',
325
- options: projects.map(function (project) {
326
- return {
327
- value: project,
328
- label: "".concat(project.organization.slug, "/").concat(project.slug),
329
- };
330
- }),
331
- }))];
332
- case 1:
333
- selection = _a.sent();
334
- Sentry.setTag('project', selection.slug);
335
- Sentry.setTag('project-platform', selection.platform);
336
- Sentry.setUser({ id: selection.organization.slug });
337
- return [2 /*return*/, selection];
338
- }
339
- });
340
- });
341
- }
342
- exports.askForProjectSelection = askForProjectSelection;
343
248
  function installPackage(_a) {
344
249
  var packageName = _a.packageName, alreadyInstalled = _a.alreadyInstalled, _b = _a.askBeforeUpdating, askBeforeUpdating = _b === void 0 ? true : _b;
345
250
  return __awaiter(this, void 0, void 0, function () {
@@ -362,187 +267,98 @@ function installPackage(_a) {
362
267
  return [4 /*yield*/, getPackageManager()];
363
268
  case 3:
364
269
  packageManager = _c.sent();
365
- sdkInstallSpinner.start("".concat(alreadyInstalled ? 'Updating' : 'Installing', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager), "."));
270
+ sdkInstallSpinner.start("".concat(alreadyInstalled ? 'Updating' : 'Installing', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager.label), "."));
366
271
  _c.label = 4;
367
272
  case 4:
368
- _c.trys.push([4, 11, , 13]);
369
- if (!(packageManager === 'yarn')) return [3 /*break*/, 6];
370
- return [4 /*yield*/, (0, util_1.promisify)(childProcess.exec)("yarn add ".concat(packageName, "@latest"))];
273
+ _c.trys.push([4, 6, , 8]);
274
+ return [4 /*yield*/, (0, package_manager_1.installPackageWithPackageManager)(packageManager, packageName)];
371
275
  case 5:
372
276
  _c.sent();
373
- return [3 /*break*/, 10];
277
+ return [3 /*break*/, 8];
374
278
  case 6:
375
- if (!(packageManager === 'pnpm')) return [3 /*break*/, 8];
376
- return [4 /*yield*/, (0, util_1.promisify)(childProcess.exec)("pnpm add ".concat(packageName, "@latest"))];
377
- case 7:
378
- _c.sent();
379
- return [3 /*break*/, 10];
380
- case 8:
381
- if (!(packageManager === 'npm')) return [3 /*break*/, 10];
382
- return [4 /*yield*/, (0, util_1.promisify)(childProcess.exec)("npm install ".concat(packageName, "@latest"))];
383
- case 9:
384
- _c.sent();
385
- _c.label = 10;
386
- case 10: return [3 /*break*/, 13];
387
- case 11:
388
279
  e_1 = _c.sent();
389
280
  sdkInstallSpinner.stop('Installation failed.');
390
281
  clack.log.error("".concat(chalk_1.default.red('Encountered the following error during installation:'), "\n\n").concat(e_1, "\n\n").concat(chalk_1.default.dim('If you think this issue is caused by the Sentry wizard, let us know here:\nhttps://github.com/getsentry/sentry-wizard/issues')));
391
282
  return [4 /*yield*/, abort()];
392
- case 12:
283
+ case 7:
393
284
  _c.sent();
394
- return [3 /*break*/, 13];
395
- case 13:
396
- sdkInstallSpinner.stop("".concat(alreadyInstalled ? 'Updated' : 'Installed', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager), "."));
285
+ return [3 /*break*/, 8];
286
+ case 8:
287
+ sdkInstallSpinner.stop("".concat(alreadyInstalled ? 'Updated' : 'Installed', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager.label), "."));
397
288
  return [2 /*return*/];
398
289
  }
399
290
  });
400
291
  });
401
292
  }
402
293
  exports.installPackage = installPackage;
403
- /**
404
- * Asks users if they are using SaaS or self-hosted Sentry and returns the validated URL.
405
- *
406
- * If users started the wizard with a --url arg, that URL is used as the default and we skip
407
- * the self-hosted question. However, the passed url is still validated and in case it's
408
- * invalid, users are asked to enter a new one until it is valid.
409
- *
410
- * @param urlFromArgs the url passed via the --url arg
411
- */
412
- function askForSelfHosted(urlFromArgs) {
294
+ function addOrgAndProjectToSentryCliRc(org, project, setupConfig) {
413
295
  return __awaiter(this, void 0, void 0, function () {
414
- var choice, validUrl, tmpUrlFromArgs, url, _a, isSelfHostedUrl;
415
- return __generator(this, function (_b) {
416
- switch (_b.label) {
417
- case 0:
418
- if (!!urlFromArgs) return [3 /*break*/, 2];
419
- return [4 /*yield*/, abortIfCancelled(clack.select({
420
- message: 'Are you using Sentry SaaS or self-hosted Sentry?',
421
- options: [
422
- { value: 'saas', label: 'Sentry SaaS (sentry.io)' },
423
- {
424
- value: 'self-hosted',
425
- label: 'Self-hosted/on-premise/single-tenant',
426
- },
427
- ],
428
- }))];
429
- case 1:
430
- choice = _b.sent();
431
- if (choice === 'saas') {
432
- Sentry.setTag('url', SAAS_URL);
433
- Sentry.setTag('self-hosted', false);
434
- return [2 /*return*/, { url: SAAS_URL, selfHosted: false }];
435
- }
436
- _b.label = 2;
437
- case 2:
438
- tmpUrlFromArgs = urlFromArgs;
439
- _b.label = 3;
440
- case 3:
441
- if (!(validUrl === undefined)) return [3 /*break*/, 6];
442
- _a = tmpUrlFromArgs;
443
- if (_a) return [3 /*break*/, 5];
444
- return [4 /*yield*/, abortIfCancelled(clack.text({
445
- message: "Please enter the URL of your ".concat(urlFromArgs ? '' : 'self-hosted ', "Sentry instance."),
446
- placeholder: 'https://sentry.io/',
447
- }))];
448
- case 4:
449
- _a = (_b.sent());
450
- _b.label = 5;
451
- case 5:
452
- url = _a;
453
- tmpUrlFromArgs = undefined;
454
- try {
455
- validUrl = new url_1.URL(url).toString();
456
- // We assume everywhere else that the URL ends in a slash
457
- if (!validUrl.endsWith('/')) {
458
- validUrl += '/';
459
- }
460
- }
461
- catch (_c) {
462
- clack.log.error('Please enter a valid URL. (It should look something like "https://sentry.mydomain.com/")');
463
- }
464
- return [3 /*break*/, 3];
465
- case 6:
466
- isSelfHostedUrl = new url_1.URL(validUrl).host !== new url_1.URL(SAAS_URL).host;
467
- Sentry.setTag('url', validUrl);
468
- Sentry.setTag('self-hosted', isSelfHostedUrl);
469
- return [2 /*return*/, { url: validUrl, selfHosted: true }];
470
- }
471
- });
472
- });
473
- }
474
- exports.askForSelfHosted = askForSelfHosted;
475
- function addOrgAndProjectToSentryCliRc(org, project) {
476
- return __awaiter(this, void 0, void 0, function () {
477
- var clircContents, likelyAlreadyHasOrgAndProject, e_2;
296
+ var configContents, e_2;
478
297
  return __generator(this, function (_a) {
479
298
  switch (_a.label) {
480
299
  case 0:
481
- clircContents = fs.readFileSync(path.join(process.cwd(), exports.SENTRY_CLI_RC_FILE), 'utf8');
482
- likelyAlreadyHasOrgAndProject = !!(clircContents.includes('[defaults]') &&
483
- clircContents.match(/org=./g) &&
484
- clircContents.match(/project=./g));
485
- if (!likelyAlreadyHasOrgAndProject) return [3 /*break*/, 1];
486
- clack.log.warn("".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), " already has org and project. Will not add them."));
300
+ configContents = fs.readFileSync(path.join(process.cwd(), setupConfig.filename), 'utf8');
301
+ if (!setupConfig.likelyAlreadyHasOrgAndProject(configContents)) return [3 /*break*/, 1];
302
+ clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " already has org and project. Will not add them."));
487
303
  return [3 /*break*/, 4];
488
304
  case 1:
489
305
  _a.trys.push([1, 3, , 4]);
490
- return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), exports.SENTRY_CLI_RC_FILE), "\n[defaults]\norg=".concat(org, "\nproject=").concat(project, "\n"))];
306
+ return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), setupConfig.filename), "\n".concat(setupConfig.orgAndProjContent(org, project), "\n"))];
491
307
  case 2:
492
308
  _a.sent();
493
309
  return [3 /*break*/, 4];
494
310
  case 3:
495
311
  e_2 = _a.sent();
496
- clack.log.warn("".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), " could not be updated with org and project."));
312
+ clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " could not be updated with org and project."));
497
313
  return [3 /*break*/, 4];
498
314
  case 4: return [2 /*return*/];
499
315
  }
500
316
  });
501
317
  });
502
318
  }
503
- function addSentryCliRc(authToken, orgSlug, projectSlug) {
319
+ function addSentryCliConfig(authToken, setupConfig, orgSlug, projectSlug) {
320
+ if (setupConfig === void 0) { setupConfig = exports.sourceMapsCliSetupConfig; }
504
321
  return __awaiter(this, void 0, void 0, function () {
505
- var clircExists, clircContents, likelyAlreadyHasAuthToken, _a, _b;
322
+ var configExists, configContents, _a, _b;
506
323
  return __generator(this, function (_c) {
507
324
  switch (_c.label) {
508
325
  case 0:
509
- clircExists = fs.existsSync(path.join(process.cwd(), exports.SENTRY_CLI_RC_FILE));
510
- if (!clircExists) return [3 /*break*/, 5];
511
- clircContents = fs.readFileSync(path.join(process.cwd(), exports.SENTRY_CLI_RC_FILE), 'utf8');
512
- likelyAlreadyHasAuthToken = !!(clircContents.includes('[auth]') && clircContents.match(/token=./g));
513
- if (!likelyAlreadyHasAuthToken) return [3 /*break*/, 1];
514
- clack.log.warn("".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), " already has auth token. Will not add one."));
326
+ configExists = fs.existsSync(path.join(process.cwd(), setupConfig.filename));
327
+ if (!configExists) return [3 /*break*/, 5];
328
+ configContents = fs.readFileSync(path.join(process.cwd(), setupConfig.filename), 'utf8');
329
+ if (!setupConfig.likelyAlreadyHasAuthToken(configContents)) return [3 /*break*/, 1];
330
+ clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " already has auth token. Will not add one."));
515
331
  return [3 /*break*/, 4];
516
332
  case 1:
517
333
  _c.trys.push([1, 3, , 4]);
518
- return [4 /*yield*/, fs.promises.writeFile(path.join(process.cwd(), exports.SENTRY_CLI_RC_FILE), "".concat(clircContents, "\n[auth]\ntoken=").concat(authToken, "\n"), { encoding: 'utf8', flag: 'w' })];
334
+ return [4 /*yield*/, fs.promises.writeFile(path.join(process.cwd(), setupConfig.filename), "".concat(configContents, "\n").concat(setupConfig.tokenContent(authToken), "\n"), { encoding: 'utf8', flag: 'w' })];
519
335
  case 2:
520
336
  _c.sent();
521
- clack.log.success("Added auth token to ".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), " for you to test uploading source maps locally."));
337
+ clack.log.success(chalk_1.default.greenBright("Added auth token to ".concat(chalk_1.default.bold(setupConfig.filename), " for you to test uploading ").concat(setupConfig.name, " locally.")));
522
338
  return [3 /*break*/, 4];
523
339
  case 3:
524
340
  _a = _c.sent();
525
- clack.log.warning("Failed to add auth token to ".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), ". Uploading source maps during build will likely not work locally."));
341
+ clack.log.warning("Failed to add auth token to ".concat(chalk_1.default.bold(setupConfig.filename), ". Uploading ").concat(setupConfig.name, " during build will likely not work locally."));
526
342
  return [3 /*break*/, 4];
527
343
  case 4: return [3 /*break*/, 8];
528
344
  case 5:
529
345
  _c.trys.push([5, 7, , 8]);
530
- return [4 /*yield*/, fs.promises.writeFile(path.join(process.cwd(), exports.SENTRY_CLI_RC_FILE), "[auth]\ntoken=".concat(authToken, "\n"), { encoding: 'utf8', flag: 'w' })];
346
+ return [4 /*yield*/, fs.promises.writeFile(path.join(process.cwd(), setupConfig.filename), "".concat(setupConfig.tokenContent(authToken), "\n"), { encoding: 'utf8', flag: 'w' })];
531
347
  case 6:
532
348
  _c.sent();
533
- clack.log.success("Created ".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), " with auth token for you to test uploading source maps locally."));
349
+ clack.log.success(chalk_1.default.greenBright("Created ".concat(chalk_1.default.bold(setupConfig.filename), " with auth token for you to test uploading ").concat(setupConfig.name, " locally.")));
534
350
  return [3 /*break*/, 8];
535
351
  case 7:
536
352
  _b = _c.sent();
537
- clack.log.warning("Failed to create ".concat(chalk_1.default.bold(exports.SENTRY_CLI_RC_FILE), " with auth token. Uploading source maps during build will likely not work locally."));
353
+ clack.log.warning("Failed to create ".concat(chalk_1.default.bold(setupConfig.filename), " with auth token. Uploading ").concat(setupConfig.name, " during build will likely not work locally."));
538
354
  return [3 /*break*/, 8];
539
355
  case 8:
540
356
  if (!(orgSlug && projectSlug)) return [3 /*break*/, 10];
541
- return [4 /*yield*/, addOrgAndProjectToSentryCliRc(orgSlug, projectSlug)];
357
+ return [4 /*yield*/, addOrgAndProjectToSentryCliRc(orgSlug, projectSlug, setupConfig)];
542
358
  case 9:
543
359
  _c.sent();
544
360
  _c.label = 10;
545
- case 10: return [4 /*yield*/, addAuthTokenFileToGitIgnore(exports.SENTRY_CLI_RC_FILE)];
361
+ case 10: return [4 /*yield*/, addAuthTokenFileToGitIgnore(setupConfig.filename)];
546
362
  case 11:
547
363
  _c.sent();
548
364
  return [2 /*return*/];
@@ -550,7 +366,7 @@ function addSentryCliRc(authToken, orgSlug, projectSlug) {
550
366
  });
551
367
  });
552
368
  }
553
- exports.addSentryCliRc = addSentryCliRc;
369
+ exports.addSentryCliConfig = addSentryCliConfig;
554
370
  function addDotEnvSentryBuildPluginFile(authToken) {
555
371
  return __awaiter(this, void 0, void 0, function () {
556
372
  var envVarContent, dotEnvFilePath, dotEnvFileExists, dotEnvFileContent, hasAuthToken, _a, _b;
@@ -614,7 +430,7 @@ function addAuthTokenFileToGitIgnore(filename) {
614
430
  return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), '.gitignore'), "\n# Sentry Auth Token\n".concat(filename, "\n"), { encoding: 'utf8' })];
615
431
  case 1:
616
432
  _b.sent();
617
- clack.log.success("Added ".concat(chalk_1.default.bold(filename), " to ").concat(chalk_1.default.bold('.gitignore'), "."));
433
+ clack.log.success(chalk_1.default.greenBright("Added ".concat(chalk_1.default.bold(filename), " to ").concat(chalk_1.default.bold('.gitignore'), ".")));
618
434
  return [3 /*break*/, 3];
619
435
  case 2:
620
436
  _a = _b.sent();
@@ -688,39 +504,25 @@ function getPackageManager() {
688
504
  return __generator(this, function (_a) {
689
505
  switch (_a.label) {
690
506
  case 0:
691
- detectedPackageManager = detectPackageManager();
507
+ detectedPackageManager = (0, package_manager_1.detectPackageManger)();
692
508
  if (detectedPackageManager) {
693
509
  return [2 /*return*/, detectedPackageManager];
694
510
  }
695
511
  return [4 /*yield*/, abortIfCancelled(clack.select({
696
512
  message: 'Please select your package manager.',
697
- options: [
698
- { value: 'npm', label: 'Npm' },
699
- { value: 'yarn', label: 'Yarn' },
700
- { value: 'pnpm', label: 'Pnpm' },
701
- ],
513
+ options: package_manager_1.packageManagers.map(function (packageManager) { return ({
514
+ value: packageManager,
515
+ label: packageManager.label,
516
+ }); }),
702
517
  }))];
703
518
  case 1:
704
519
  selectedPackageManager = _a.sent();
705
- Sentry.setTag('package-manager', selectedPackageManager);
520
+ Sentry.setTag('package-manager', selectedPackageManager.name);
706
521
  return [2 /*return*/, selectedPackageManager];
707
522
  }
708
523
  });
709
524
  });
710
525
  }
711
- function detectPackageManager() {
712
- if (fs.existsSync(path.join(process.cwd(), 'yarn.lock'))) {
713
- return 'yarn';
714
- }
715
- if (fs.existsSync(path.join(process.cwd(), 'package-lock.json'))) {
716
- return 'npm';
717
- }
718
- if (fs.existsSync(path.join(process.cwd(), 'pnpm-lock.yaml'))) {
719
- return 'pnpm';
720
- }
721
- return undefined;
722
- }
723
- exports.detectPackageManager = detectPackageManager;
724
526
  function isUsingTypeScript() {
725
527
  try {
726
528
  return fs.existsSync(path.join(process.cwd(), 'tsconfig.json'));
@@ -730,7 +532,18 @@ function isUsingTypeScript() {
730
532
  }
731
533
  }
732
534
  exports.isUsingTypeScript = isUsingTypeScript;
733
- function getOrAskForProjectData(options) {
535
+ /**
536
+ * Checks if we already got project data from a previous wizard invocation.
537
+ * If yes, this data is returned.
538
+ * Otherwise, we start the login flow and ask the user to select a project.
539
+ *
540
+ * Use this function to get project data for the wizard.
541
+ *
542
+ * @param options wizard options
543
+ * @param platform the platform of the wizard
544
+ * @returns project data (org, project, token, url)
545
+ */
546
+ function getOrAskForProjectData(options, platform) {
734
547
  var _a;
735
548
  return __awaiter(this, void 0, void 0, function () {
736
549
  var _b, sentryUrl, selfHosted, _c, projects, apiKeys, selectedProject;
@@ -752,15 +565,22 @@ function getOrAskForProjectData(options) {
752
565
  return askForWizardLogin({
753
566
  promoCode: options.promoCode,
754
567
  url: sentryUrl,
755
- platform: 'javascript-nextjs',
568
+ platform: platform,
756
569
  });
757
570
  })];
758
571
  case 2:
759
572
  _c = _d.sent(), projects = _c.projects, apiKeys = _c.apiKeys;
760
- return [4 /*yield*/, (0, telemetry_1.traceStep)('select-project', function () {
761
- return askForProjectSelection(projects);
762
- })];
573
+ if (!(!projects || !projects.length)) return [3 /*break*/, 4];
574
+ clack.log.error('No projects found. Please create a project in Sentry and try again.');
575
+ Sentry.setTag('no-projects-found', true);
576
+ return [4 /*yield*/, abort()];
763
577
  case 3:
578
+ _d.sent();
579
+ _d.label = 4;
580
+ case 4: return [4 /*yield*/, (0, telemetry_1.traceStep)('select-project', function () {
581
+ return askForProjectSelection(projects);
582
+ })];
583
+ case 5:
764
584
  selectedProject = _d.sent();
765
585
  return [2 /*return*/, {
766
586
  sentryUrl: sentryUrl,
@@ -773,4 +593,190 @@ function getOrAskForProjectData(options) {
773
593
  });
774
594
  }
775
595
  exports.getOrAskForProjectData = getOrAskForProjectData;
596
+ /**
597
+ * Asks users if they are using SaaS or self-hosted Sentry and returns the validated URL.
598
+ *
599
+ * If users started the wizard with a --url arg, that URL is used as the default and we skip
600
+ * the self-hosted question. However, the passed url is still validated and in case it's
601
+ * invalid, users are asked to enter a new one until it is valid.
602
+ *
603
+ * @param urlFromArgs the url passed via the --url arg
604
+ */
605
+ function askForSelfHosted(urlFromArgs) {
606
+ return __awaiter(this, void 0, void 0, function () {
607
+ var choice, validUrl, tmpUrlFromArgs, url, _a, isSelfHostedUrl;
608
+ return __generator(this, function (_b) {
609
+ switch (_b.label) {
610
+ case 0:
611
+ if (!!urlFromArgs) return [3 /*break*/, 2];
612
+ return [4 /*yield*/, abortIfCancelled(clack.select({
613
+ message: 'Are you using Sentry SaaS or self-hosted Sentry?',
614
+ options: [
615
+ { value: 'saas', label: 'Sentry SaaS (sentry.io)' },
616
+ {
617
+ value: 'self-hosted',
618
+ label: 'Self-hosted/on-premise/single-tenant',
619
+ },
620
+ ],
621
+ }))];
622
+ case 1:
623
+ choice = _b.sent();
624
+ if (choice === 'saas') {
625
+ Sentry.setTag('url', SAAS_URL);
626
+ Sentry.setTag('self-hosted', false);
627
+ return [2 /*return*/, { url: SAAS_URL, selfHosted: false }];
628
+ }
629
+ _b.label = 2;
630
+ case 2:
631
+ tmpUrlFromArgs = urlFromArgs;
632
+ _b.label = 3;
633
+ case 3:
634
+ if (!(validUrl === undefined)) return [3 /*break*/, 6];
635
+ _a = tmpUrlFromArgs;
636
+ if (_a) return [3 /*break*/, 5];
637
+ return [4 /*yield*/, abortIfCancelled(clack.text({
638
+ message: "Please enter the URL of your ".concat(urlFromArgs ? '' : 'self-hosted ', "Sentry instance."),
639
+ placeholder: 'https://sentry.io/',
640
+ }))];
641
+ case 4:
642
+ _a = (_b.sent());
643
+ _b.label = 5;
644
+ case 5:
645
+ url = _a;
646
+ tmpUrlFromArgs = undefined;
647
+ try {
648
+ validUrl = new url_1.URL(url).toString();
649
+ // We assume everywhere else that the URL ends in a slash
650
+ if (!validUrl.endsWith('/')) {
651
+ validUrl += '/';
652
+ }
653
+ }
654
+ catch (_c) {
655
+ clack.log.error('Please enter a valid URL. (It should look something like "https://sentry.mydomain.com/")');
656
+ }
657
+ return [3 /*break*/, 3];
658
+ case 6:
659
+ isSelfHostedUrl = new url_1.URL(validUrl).host !== new url_1.URL(SAAS_URL).host;
660
+ Sentry.setTag('url', validUrl);
661
+ Sentry.setTag('self-hosted', isSelfHostedUrl);
662
+ return [2 /*return*/, { url: validUrl, selfHosted: true }];
663
+ }
664
+ });
665
+ });
666
+ }
667
+ function askForWizardLogin(options) {
668
+ return __awaiter(this, void 0, void 0, function () {
669
+ var hasSentryAccount, wizardHash, _a, loginUrl, urlToOpen, loginSpinner, data;
670
+ return __generator(this, function (_b) {
671
+ switch (_b.label) {
672
+ case 0:
673
+ Sentry.setTag('has-promo-code', !!options.promoCode);
674
+ return [4 /*yield*/, clack.confirm({
675
+ message: 'Do you already have a Sentry account?',
676
+ })];
677
+ case 1:
678
+ hasSentryAccount = _b.sent();
679
+ return [4 /*yield*/, abortIfCancelled(hasSentryAccount)];
680
+ case 2:
681
+ hasSentryAccount = _b.sent();
682
+ Sentry.setTag('already-has-sentry-account', hasSentryAccount);
683
+ _b.label = 3;
684
+ case 3:
685
+ _b.trys.push([3, 5, , 10]);
686
+ return [4 /*yield*/, axios_1.default.get("".concat(options.url, "api/0/wizard/"))];
687
+ case 4:
688
+ wizardHash = (_b.sent()).data.hash;
689
+ return [3 /*break*/, 10];
690
+ case 5:
691
+ _a = _b.sent();
692
+ if (!(options.url !== SAAS_URL)) return [3 /*break*/, 7];
693
+ clack.log.error('Loading Wizard failed. Did you provide the right URL?');
694
+ return [4 /*yield*/, abort(chalk_1.default.red('Please check your configuration and try again.\n\n Let us know if you think this is an issue with the wizard or Sentry: https://github.com/getsentry/sentry-wizard/issues'))];
695
+ case 6:
696
+ _b.sent();
697
+ return [3 /*break*/, 9];
698
+ case 7:
699
+ clack.log.error('Loading Wizard failed.');
700
+ return [4 /*yield*/, abort(chalk_1.default.red('Please try again in a few minutes and let us know if this issue persists: https://github.com/getsentry/sentry-wizard/issues'))];
701
+ case 8:
702
+ _b.sent();
703
+ _b.label = 9;
704
+ case 9: return [3 /*break*/, 10];
705
+ case 10:
706
+ loginUrl = new url_1.URL("".concat(options.url, "account/settings/wizard/").concat(wizardHash, "/"));
707
+ if (!hasSentryAccount) {
708
+ loginUrl.searchParams.set('signup', '1');
709
+ if (options.platform) {
710
+ loginUrl.searchParams.set('project_platform', options.platform);
711
+ }
712
+ }
713
+ if (options.promoCode) {
714
+ loginUrl.searchParams.set('code', options.promoCode);
715
+ }
716
+ urlToOpen = loginUrl.toString();
717
+ clack.log.info("".concat(chalk_1.default.bold("If the browser window didn't open automatically, please open the following link to ".concat(hasSentryAccount ? 'log' : 'sign', " into Sentry:")), "\n\n").concat(chalk_1.default.cyan(urlToOpen)));
718
+ opn(urlToOpen).catch(function () {
719
+ // opn throws in environments that don't have a browser (e.g. remote shells) so we just noop here
720
+ });
721
+ loginSpinner = clack.spinner();
722
+ loginSpinner.start('Waiting for you to log in using the link above');
723
+ return [4 /*yield*/, new Promise(function (resolve) {
724
+ var pollingInterval = (0, timers_1.setInterval)(function () {
725
+ axios_1.default
726
+ .get("".concat(options.url, "api/0/wizard/").concat(wizardHash, "/"), {
727
+ headers: {
728
+ 'Accept-Encoding': 'deflate',
729
+ },
730
+ })
731
+ .then(function (result) {
732
+ resolve(result.data);
733
+ clearTimeout(timeout);
734
+ clearInterval(pollingInterval);
735
+ void axios_1.default.delete("".concat(options.url, "api/0/wizard/").concat(wizardHash, "/"));
736
+ })
737
+ .catch(function () {
738
+ // noop - just try again
739
+ });
740
+ }, 500);
741
+ var timeout = setTimeout(function () {
742
+ clearInterval(pollingInterval);
743
+ loginSpinner.stop('Login timed out. No worries - it happens to the best of us.');
744
+ Sentry.setTag('opened-wizard-link', false);
745
+ void abort('Please restart the Wizard and log in to complete the setup.');
746
+ }, 180000);
747
+ })];
748
+ case 11:
749
+ data = _b.sent();
750
+ loginSpinner.stop('Login complete.');
751
+ Sentry.setTag('opened-wizard-link', true);
752
+ return [2 /*return*/, data];
753
+ }
754
+ });
755
+ });
756
+ }
757
+ function askForProjectSelection(projects) {
758
+ return __awaiter(this, void 0, void 0, function () {
759
+ var selection;
760
+ return __generator(this, function (_a) {
761
+ switch (_a.label) {
762
+ case 0: return [4 /*yield*/, abortIfCancelled(clack.select({
763
+ maxItems: 12,
764
+ message: 'Select your Sentry project.',
765
+ options: projects.map(function (project) {
766
+ return {
767
+ value: project,
768
+ label: "".concat(project.organization.slug, "/").concat(project.slug),
769
+ };
770
+ }),
771
+ }))];
772
+ case 1:
773
+ selection = _a.sent();
774
+ Sentry.setTag('project', selection.slug);
775
+ Sentry.setTag('project-platform', selection.platform);
776
+ Sentry.setUser({ id: selection.organization.slug });
777
+ return [2 /*return*/, selection];
778
+ }
779
+ });
780
+ });
781
+ }
776
782
  //# sourceMappingURL=clack-utils.js.map