@sentry/wizard 3.10.0 → 3.12.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 (150) hide show
  1. package/CHANGELOG.md +54 -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 +225 -0
  19. package/dist/src/android/android-wizard.js.map +1 -0
  20. package/dist/src/android/code-tools.d.ts +47 -0
  21. package/dist/src/android/code-tools.js +173 -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 +286 -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 +123 -111
  63. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  64. package/dist/src/sourcemaps/tools/webpack.d.ts +6 -1
  65. package/dist/src/sourcemaps/tools/webpack.js +290 -25
  66. package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
  67. package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
  68. package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
  69. package/dist/src/sveltekit/sdk-setup.js +5 -5
  70. package/dist/src/sveltekit/sdk-setup.js.map +1 -1
  71. package/dist/src/sveltekit/sveltekit-wizard.js +34 -44
  72. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  73. package/dist/src/telemetry.js +1 -0
  74. package/dist/src/telemetry.js.map +1 -1
  75. package/dist/src/utils/ast-utils.d.ts +9 -5
  76. package/dist/src/utils/ast-utils.js +26 -11
  77. package/dist/src/utils/ast-utils.js.map +1 -1
  78. package/dist/src/utils/clack-utils.d.ts +74 -28
  79. package/dist/src/utils/clack-utils.js +427 -264
  80. package/dist/src/utils/clack-utils.js.map +1 -1
  81. package/dist/src/utils/package-manager.d.ts +10 -0
  82. package/dist/{lib/Helper/PackageManager.js → src/utils/package-manager.js} +42 -74
  83. package/dist/src/utils/package-manager.js.map +1 -0
  84. package/dist/src/utils/release-registry.d.ts +1 -0
  85. package/dist/src/utils/release-registry.js +68 -0
  86. package/dist/src/utils/release-registry.js.map +1 -0
  87. package/dist/src/utils/sentrycli-utils.d.ts +4 -0
  88. package/dist/src/utils/sentrycli-utils.js +41 -0
  89. package/dist/src/utils/sentrycli-utils.js.map +1 -0
  90. package/dist/test/android/code-tools.test.d.ts +1 -0
  91. package/dist/test/android/code-tools.test.js +34 -0
  92. package/dist/test/android/code-tools.test.js.map +1 -0
  93. package/dist/test/sourcemaps/tools/vite.test.d.ts +1 -0
  94. package/dist/test/sourcemaps/tools/vite.test.js +132 -0
  95. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -0
  96. package/dist/test/sourcemaps/tools/webpack.test.d.ts +1 -0
  97. package/dist/test/sourcemaps/tools/webpack.test.js +179 -0
  98. package/dist/test/sourcemaps/tools/webpack.test.js.map +1 -0
  99. package/dist/test/utils/ast-utils.test.js +42 -7
  100. package/dist/test/utils/ast-utils.test.js.map +1 -1
  101. package/dist/test/utils/clack-utils.test.d.ts +1 -0
  102. package/dist/test/utils/clack-utils.test.js +200 -0
  103. package/dist/test/utils/clack-utils.test.js.map +1 -0
  104. package/lib/Constants.ts +5 -0
  105. package/lib/Steps/ChooseIntegration.ts +7 -3
  106. package/lib/Steps/Integrations/Android.ts +23 -0
  107. package/lib/Steps/Integrations/ReactNative.ts +9 -3
  108. package/lib/Steps/PromptForParameters.ts +48 -3
  109. package/lib/Steps/SentryProjectSelector.ts +3 -1
  110. package/package.json +4 -3
  111. package/src/android/android-wizard.ts +204 -0
  112. package/src/android/code-tools.ts +170 -0
  113. package/src/android/gradle.ts +250 -0
  114. package/src/android/manifest.ts +180 -0
  115. package/src/android/templates.ts +88 -0
  116. package/src/apple/apple-wizard.ts +113 -35
  117. package/src/apple/cocoapod.ts +6 -3
  118. package/src/apple/code-tools.ts +46 -18
  119. package/src/apple/fastlane.ts +6 -12
  120. package/src/apple/templates.ts +2 -8
  121. package/src/apple/xcode-manager.ts +167 -25
  122. package/src/nextjs/nextjs-wizard.ts +72 -8
  123. package/src/nextjs/templates.ts +16 -2
  124. package/src/remix/remix-wizard.ts +10 -15
  125. package/src/sourcemaps/sourcemaps-wizard.ts +19 -5
  126. package/src/sourcemaps/tools/nextjs.ts +2 -2
  127. package/src/sourcemaps/tools/sentry-cli.ts +8 -7
  128. package/src/sourcemaps/tools/vite.ts +143 -79
  129. package/src/sourcemaps/tools/webpack.ts +369 -30
  130. package/src/sourcemaps/utils/detect-tool.ts +2 -1
  131. package/src/sveltekit/sdk-setup.ts +10 -6
  132. package/src/sveltekit/sveltekit-wizard.ts +5 -14
  133. package/src/telemetry.ts +2 -0
  134. package/src/utils/ast-utils.ts +29 -11
  135. package/src/utils/clack-utils.ts +485 -283
  136. package/src/utils/package-manager.ts +61 -0
  137. package/src/utils/release-registry.ts +19 -0
  138. package/src/utils/sentrycli-utils.ts +22 -0
  139. package/test/android/code-tools.test.ts +49 -0
  140. package/test/sourcemaps/tools/vite.test.ts +149 -0
  141. package/test/sourcemaps/tools/webpack.test.ts +303 -0
  142. package/test/utils/ast-utils.test.ts +28 -9
  143. package/test/utils/clack-utils.test.ts +142 -0
  144. package/dist/lib/Helper/PackageManager.d.ts +0 -22
  145. package/dist/lib/Helper/PackageManager.js.map +0 -1
  146. package/dist/src/utils/vendor/clack-custom-select.d.ts +0 -21
  147. package/dist/src/utils/vendor/clack-custom-select.js +0 -137
  148. package/dist/src/utils/vendor/clack-custom-select.js.map +0 -1
  149. package/lib/Helper/PackageManager.ts +0 -59
  150. package/src/utils/vendor/clack-custom-select.ts +0 -160
@@ -58,11 +58,20 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
58
58
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
59
  }
60
60
  };
61
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
62
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
63
+ if (ar || !(i in from)) {
64
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
65
+ ar[i] = from[i];
66
+ }
67
+ }
68
+ return to.concat(ar || Array.prototype.slice.call(from));
69
+ };
61
70
  var __importDefault = (this && this.__importDefault) || function (mod) {
62
71
  return (mod && mod.__esModule) ? mod : { "default": mod };
63
72
  };
64
73
  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;
74
+ exports.createNewConfigFile = exports.showCopyPasteInstructions = exports.askForToolConfigPath = 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
75
  // @ts-ignore - clack is ESM and TS complains about that. It works though
67
76
  var clack = __importStar(require("@clack/prompts"));
68
77
  var axios_1 = __importDefault(require("axios"));
@@ -72,15 +81,34 @@ var fs = __importStar(require("fs"));
72
81
  var path = __importStar(require("path"));
73
82
  var timers_1 = require("timers");
74
83
  var url_1 = require("url");
75
- var util_1 = require("util");
76
84
  var Sentry = __importStar(require("@sentry/node"));
77
- var clack_custom_select_1 = require("./vendor/clack-custom-select");
78
85
  var package_json_1 = require("./package-json");
79
86
  var telemetry_1 = require("../telemetry");
87
+ var package_manager_1 = require("./package-manager");
88
+ var debug_1 = require("./debug");
80
89
  var opn = require('opn');
81
90
  exports.SENTRY_DOT_ENV_FILE = '.env.sentry-build-plugin';
82
91
  exports.SENTRY_CLI_RC_FILE = '.sentryclirc';
92
+ exports.SENTRY_PROPERTIES_FILE = 'sentry.properties';
83
93
  var SAAS_URL = 'https://sentry.io/';
94
+ exports.sourceMapsCliSetupConfig = {
95
+ filename: exports.SENTRY_CLI_RC_FILE,
96
+ name: 'source maps',
97
+ likelyAlreadyHasAuthToken: function (contents) {
98
+ return !!(contents.includes('[auth]') && contents.match(/token=./g));
99
+ },
100
+ tokenContent: function (authToken) {
101
+ return "[auth]\ntoken=".concat(authToken);
102
+ },
103
+ likelyAlreadyHasOrgAndProject: function (contents) {
104
+ return !!(contents.includes('[defaults]') &&
105
+ contents.match(/org=./g) &&
106
+ contents.match(/project=./g));
107
+ },
108
+ orgAndProjContent: function (org, project) {
109
+ return "[defaults]\norg=".concat(org, "\nproject=").concat(project);
110
+ },
111
+ };
84
112
  function abort(message, status) {
85
113
  return __awaiter(this, void 0, void 0, function () {
86
114
  var sentryHub, sentryTransaction, sentrySession;
@@ -204,99 +232,12 @@ function askToInstallSentryCLI() {
204
232
  });
205
233
  }
206
234
  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
235
  function askForItemSelection(items, message) {
295
236
  return __awaiter(this, void 0, void 0, function () {
296
237
  var selection;
297
238
  return __generator(this, function (_a) {
298
239
  switch (_a.label) {
299
- case 0: return [4 /*yield*/, abortIfCancelled((0, clack_custom_select_1.windowedSelect)({
240
+ case 0: return [4 /*yield*/, abortIfCancelled(clack.select({
300
241
  maxItems: 12,
301
242
  message: message,
302
243
  options: items.map(function (item, index) {
@@ -314,32 +255,6 @@ function askForItemSelection(items, message) {
314
255
  });
315
256
  }
316
257
  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
258
  function installPackage(_a) {
344
259
  var packageName = _a.packageName, alreadyInstalled = _a.alreadyInstalled, _b = _a.askBeforeUpdating, askBeforeUpdating = _b === void 0 ? true : _b;
345
260
  return __awaiter(this, void 0, void 0, function () {
@@ -362,187 +277,98 @@ function installPackage(_a) {
362
277
  return [4 /*yield*/, getPackageManager()];
363
278
  case 3:
364
279
  packageManager = _c.sent();
365
- sdkInstallSpinner.start("".concat(alreadyInstalled ? 'Updating' : 'Installing', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager), "."));
280
+ sdkInstallSpinner.start("".concat(alreadyInstalled ? 'Updating' : 'Installing', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager.label), "."));
366
281
  _c.label = 4;
367
282
  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"))];
283
+ _c.trys.push([4, 6, , 8]);
284
+ return [4 /*yield*/, (0, package_manager_1.installPackageWithPackageManager)(packageManager, packageName)];
371
285
  case 5:
372
286
  _c.sent();
373
- return [3 /*break*/, 10];
287
+ return [3 /*break*/, 8];
374
288
  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
289
  e_1 = _c.sent();
389
290
  sdkInstallSpinner.stop('Installation failed.');
390
291
  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
292
  return [4 /*yield*/, abort()];
392
- case 12:
293
+ case 7:
393
294
  _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), "."));
295
+ return [3 /*break*/, 8];
296
+ case 8:
297
+ sdkInstallSpinner.stop("".concat(alreadyInstalled ? 'Updated' : 'Installed', " ").concat(chalk_1.default.bold.cyan(packageName), " with ").concat(chalk_1.default.bold(packageManager.label), "."));
397
298
  return [2 /*return*/];
398
299
  }
399
300
  });
400
301
  });
401
302
  }
402
303
  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) {
413
- 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) {
304
+ function addOrgAndProjectToSentryCliRc(org, project, setupConfig) {
476
305
  return __awaiter(this, void 0, void 0, function () {
477
- var clircContents, likelyAlreadyHasOrgAndProject, e_2;
306
+ var configContents, e_2;
478
307
  return __generator(this, function (_a) {
479
308
  switch (_a.label) {
480
309
  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."));
310
+ configContents = fs.readFileSync(path.join(process.cwd(), setupConfig.filename), 'utf8');
311
+ if (!setupConfig.likelyAlreadyHasOrgAndProject(configContents)) return [3 /*break*/, 1];
312
+ clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " already has org and project. Will not add them."));
487
313
  return [3 /*break*/, 4];
488
314
  case 1:
489
315
  _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"))];
316
+ return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), setupConfig.filename), "\n".concat(setupConfig.orgAndProjContent(org, project), "\n"))];
491
317
  case 2:
492
318
  _a.sent();
493
319
  return [3 /*break*/, 4];
494
320
  case 3:
495
321
  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."));
322
+ clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " could not be updated with org and project."));
497
323
  return [3 /*break*/, 4];
498
324
  case 4: return [2 /*return*/];
499
325
  }
500
326
  });
501
327
  });
502
328
  }
503
- function addSentryCliRc(authToken, orgSlug, projectSlug) {
329
+ function addSentryCliConfig(authToken, setupConfig, orgSlug, projectSlug) {
330
+ if (setupConfig === void 0) { setupConfig = exports.sourceMapsCliSetupConfig; }
504
331
  return __awaiter(this, void 0, void 0, function () {
505
- var clircExists, clircContents, likelyAlreadyHasAuthToken, _a, _b;
332
+ var configExists, configContents, _a, _b;
506
333
  return __generator(this, function (_c) {
507
334
  switch (_c.label) {
508
335
  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."));
336
+ configExists = fs.existsSync(path.join(process.cwd(), setupConfig.filename));
337
+ if (!configExists) return [3 /*break*/, 5];
338
+ configContents = fs.readFileSync(path.join(process.cwd(), setupConfig.filename), 'utf8');
339
+ if (!setupConfig.likelyAlreadyHasAuthToken(configContents)) return [3 /*break*/, 1];
340
+ clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " already has auth token. Will not add one."));
515
341
  return [3 /*break*/, 4];
516
342
  case 1:
517
343
  _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' })];
344
+ 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
345
  case 2:
520
346
  _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."));
347
+ 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
348
  return [3 /*break*/, 4];
523
349
  case 3:
524
350
  _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."));
351
+ 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
352
  return [3 /*break*/, 4];
527
353
  case 4: return [3 /*break*/, 8];
528
354
  case 5:
529
355
  _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' })];
356
+ return [4 /*yield*/, fs.promises.writeFile(path.join(process.cwd(), setupConfig.filename), "".concat(setupConfig.tokenContent(authToken), "\n"), { encoding: 'utf8', flag: 'w' })];
531
357
  case 6:
532
358
  _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."));
359
+ 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
360
  return [3 /*break*/, 8];
535
361
  case 7:
536
362
  _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."));
363
+ 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
364
  return [3 /*break*/, 8];
539
365
  case 8:
540
366
  if (!(orgSlug && projectSlug)) return [3 /*break*/, 10];
541
- return [4 /*yield*/, addOrgAndProjectToSentryCliRc(orgSlug, projectSlug)];
367
+ return [4 /*yield*/, addOrgAndProjectToSentryCliRc(orgSlug, projectSlug, setupConfig)];
542
368
  case 9:
543
369
  _c.sent();
544
370
  _c.label = 10;
545
- case 10: return [4 /*yield*/, addAuthTokenFileToGitIgnore(exports.SENTRY_CLI_RC_FILE)];
371
+ case 10: return [4 /*yield*/, addAuthTokenFileToGitIgnore(setupConfig.filename)];
546
372
  case 11:
547
373
  _c.sent();
548
374
  return [2 /*return*/];
@@ -550,7 +376,7 @@ function addSentryCliRc(authToken, orgSlug, projectSlug) {
550
376
  });
551
377
  });
552
378
  }
553
- exports.addSentryCliRc = addSentryCliRc;
379
+ exports.addSentryCliConfig = addSentryCliConfig;
554
380
  function addDotEnvSentryBuildPluginFile(authToken) {
555
381
  return __awaiter(this, void 0, void 0, function () {
556
382
  var envVarContent, dotEnvFilePath, dotEnvFileExists, dotEnvFileContent, hasAuthToken, _a, _b;
@@ -614,7 +440,7 @@ function addAuthTokenFileToGitIgnore(filename) {
614
440
  return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), '.gitignore'), "\n# Sentry Auth Token\n".concat(filename, "\n"), { encoding: 'utf8' })];
615
441
  case 1:
616
442
  _b.sent();
617
- clack.log.success("Added ".concat(chalk_1.default.bold(filename), " to ").concat(chalk_1.default.bold('.gitignore'), "."));
443
+ clack.log.success(chalk_1.default.greenBright("Added ".concat(chalk_1.default.bold(filename), " to ").concat(chalk_1.default.bold('.gitignore'), ".")));
618
444
  return [3 /*break*/, 3];
619
445
  case 2:
620
446
  _a = _b.sent();
@@ -688,39 +514,25 @@ function getPackageManager() {
688
514
  return __generator(this, function (_a) {
689
515
  switch (_a.label) {
690
516
  case 0:
691
- detectedPackageManager = detectPackageManager();
517
+ detectedPackageManager = (0, package_manager_1.detectPackageManger)();
692
518
  if (detectedPackageManager) {
693
519
  return [2 /*return*/, detectedPackageManager];
694
520
  }
695
521
  return [4 /*yield*/, abortIfCancelled(clack.select({
696
522
  message: 'Please select your package manager.',
697
- options: [
698
- { value: 'npm', label: 'Npm' },
699
- { value: 'yarn', label: 'Yarn' },
700
- { value: 'pnpm', label: 'Pnpm' },
701
- ],
523
+ options: package_manager_1.packageManagers.map(function (packageManager) { return ({
524
+ value: packageManager,
525
+ label: packageManager.label,
526
+ }); }),
702
527
  }))];
703
528
  case 1:
704
529
  selectedPackageManager = _a.sent();
705
- Sentry.setTag('package-manager', selectedPackageManager);
530
+ Sentry.setTag('package-manager', selectedPackageManager.name);
706
531
  return [2 /*return*/, selectedPackageManager];
707
532
  }
708
533
  });
709
534
  });
710
535
  }
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
536
  function isUsingTypeScript() {
725
537
  try {
726
538
  return fs.existsSync(path.join(process.cwd(), 'tsconfig.json'));
@@ -730,7 +542,18 @@ function isUsingTypeScript() {
730
542
  }
731
543
  }
732
544
  exports.isUsingTypeScript = isUsingTypeScript;
733
- function getOrAskForProjectData(options) {
545
+ /**
546
+ * Checks if we already got project data from a previous wizard invocation.
547
+ * If yes, this data is returned.
548
+ * Otherwise, we start the login flow and ask the user to select a project.
549
+ *
550
+ * Use this function to get project data for the wizard.
551
+ *
552
+ * @param options wizard options
553
+ * @param platform the platform of the wizard
554
+ * @returns project data (org, project, token, url)
555
+ */
556
+ function getOrAskForProjectData(options, platform) {
734
557
  var _a;
735
558
  return __awaiter(this, void 0, void 0, function () {
736
559
  var _b, sentryUrl, selfHosted, _c, projects, apiKeys, selectedProject;
@@ -752,15 +575,22 @@ function getOrAskForProjectData(options) {
752
575
  return askForWizardLogin({
753
576
  promoCode: options.promoCode,
754
577
  url: sentryUrl,
755
- platform: 'javascript-nextjs',
578
+ platform: platform,
756
579
  });
757
580
  })];
758
581
  case 2:
759
582
  _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
- })];
583
+ if (!(!projects || !projects.length)) return [3 /*break*/, 4];
584
+ clack.log.error('No projects found. Please create a project in Sentry and try again.');
585
+ Sentry.setTag('no-projects-found', true);
586
+ return [4 /*yield*/, abort()];
763
587
  case 3:
588
+ _d.sent();
589
+ _d.label = 4;
590
+ case 4: return [4 /*yield*/, (0, telemetry_1.traceStep)('select-project', function () {
591
+ return askForProjectSelection(projects);
592
+ })];
593
+ case 5:
764
594
  selectedProject = _d.sent();
765
595
  return [2 /*return*/, {
766
596
  sentryUrl: sentryUrl,
@@ -773,4 +603,337 @@ function getOrAskForProjectData(options) {
773
603
  });
774
604
  }
775
605
  exports.getOrAskForProjectData = getOrAskForProjectData;
606
+ /**
607
+ * Asks users if they are using SaaS or self-hosted Sentry and returns the validated URL.
608
+ *
609
+ * If users started the wizard with a --url arg, that URL is used as the default and we skip
610
+ * the self-hosted question. However, the passed url is still validated and in case it's
611
+ * invalid, users are asked to enter a new one until it is valid.
612
+ *
613
+ * @param urlFromArgs the url passed via the --url arg
614
+ */
615
+ function askForSelfHosted(urlFromArgs) {
616
+ return __awaiter(this, void 0, void 0, function () {
617
+ var choice, validUrl, tmpUrlFromArgs, url, _a, isSelfHostedUrl;
618
+ return __generator(this, function (_b) {
619
+ switch (_b.label) {
620
+ case 0:
621
+ if (!!urlFromArgs) return [3 /*break*/, 2];
622
+ return [4 /*yield*/, abortIfCancelled(clack.select({
623
+ message: 'Are you using Sentry SaaS or self-hosted Sentry?',
624
+ options: [
625
+ { value: 'saas', label: 'Sentry SaaS (sentry.io)' },
626
+ {
627
+ value: 'self-hosted',
628
+ label: 'Self-hosted/on-premise/single-tenant',
629
+ },
630
+ ],
631
+ }))];
632
+ case 1:
633
+ choice = _b.sent();
634
+ if (choice === 'saas') {
635
+ Sentry.setTag('url', SAAS_URL);
636
+ Sentry.setTag('self-hosted', false);
637
+ return [2 /*return*/, { url: SAAS_URL, selfHosted: false }];
638
+ }
639
+ _b.label = 2;
640
+ case 2:
641
+ tmpUrlFromArgs = urlFromArgs;
642
+ _b.label = 3;
643
+ case 3:
644
+ if (!(validUrl === undefined)) return [3 /*break*/, 6];
645
+ _a = tmpUrlFromArgs;
646
+ if (_a) return [3 /*break*/, 5];
647
+ return [4 /*yield*/, abortIfCancelled(clack.text({
648
+ message: "Please enter the URL of your ".concat(urlFromArgs ? '' : 'self-hosted ', "Sentry instance."),
649
+ placeholder: 'https://sentry.io/',
650
+ }))];
651
+ case 4:
652
+ _a = (_b.sent());
653
+ _b.label = 5;
654
+ case 5:
655
+ url = _a;
656
+ tmpUrlFromArgs = undefined;
657
+ try {
658
+ validUrl = new url_1.URL(url).toString();
659
+ // We assume everywhere else that the URL ends in a slash
660
+ if (!validUrl.endsWith('/')) {
661
+ validUrl += '/';
662
+ }
663
+ }
664
+ catch (_c) {
665
+ clack.log.error('Please enter a valid URL. (It should look something like "https://sentry.mydomain.com/")');
666
+ }
667
+ return [3 /*break*/, 3];
668
+ case 6:
669
+ isSelfHostedUrl = new url_1.URL(validUrl).host !== new url_1.URL(SAAS_URL).host;
670
+ Sentry.setTag('url', validUrl);
671
+ Sentry.setTag('self-hosted', isSelfHostedUrl);
672
+ return [2 /*return*/, { url: validUrl, selfHosted: true }];
673
+ }
674
+ });
675
+ });
676
+ }
677
+ function askForWizardLogin(options) {
678
+ return __awaiter(this, void 0, void 0, function () {
679
+ var hasSentryAccount, wizardHash, _a, loginUrl, urlToOpen, loginSpinner, data;
680
+ return __generator(this, function (_b) {
681
+ switch (_b.label) {
682
+ case 0:
683
+ Sentry.setTag('has-promo-code', !!options.promoCode);
684
+ return [4 /*yield*/, clack.confirm({
685
+ message: 'Do you already have a Sentry account?',
686
+ })];
687
+ case 1:
688
+ hasSentryAccount = _b.sent();
689
+ return [4 /*yield*/, abortIfCancelled(hasSentryAccount)];
690
+ case 2:
691
+ hasSentryAccount = _b.sent();
692
+ Sentry.setTag('already-has-sentry-account', hasSentryAccount);
693
+ _b.label = 3;
694
+ case 3:
695
+ _b.trys.push([3, 5, , 10]);
696
+ return [4 /*yield*/, axios_1.default.get("".concat(options.url, "api/0/wizard/"))];
697
+ case 4:
698
+ wizardHash = (_b.sent()).data.hash;
699
+ return [3 /*break*/, 10];
700
+ case 5:
701
+ _a = _b.sent();
702
+ if (!(options.url !== SAAS_URL)) return [3 /*break*/, 7];
703
+ clack.log.error('Loading Wizard failed. Did you provide the right URL?');
704
+ 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'))];
705
+ case 6:
706
+ _b.sent();
707
+ return [3 /*break*/, 9];
708
+ case 7:
709
+ clack.log.error('Loading Wizard failed.');
710
+ 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'))];
711
+ case 8:
712
+ _b.sent();
713
+ _b.label = 9;
714
+ case 9: return [3 /*break*/, 10];
715
+ case 10:
716
+ loginUrl = new url_1.URL("".concat(options.url, "account/settings/wizard/").concat(wizardHash, "/"));
717
+ if (!hasSentryAccount) {
718
+ loginUrl.searchParams.set('signup', '1');
719
+ if (options.platform) {
720
+ loginUrl.searchParams.set('project_platform', options.platform);
721
+ }
722
+ }
723
+ if (options.promoCode) {
724
+ loginUrl.searchParams.set('code', options.promoCode);
725
+ }
726
+ urlToOpen = loginUrl.toString();
727
+ 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)));
728
+ opn(urlToOpen).catch(function () {
729
+ // opn throws in environments that don't have a browser (e.g. remote shells) so we just noop here
730
+ });
731
+ loginSpinner = clack.spinner();
732
+ loginSpinner.start('Waiting for you to log in using the link above');
733
+ return [4 /*yield*/, new Promise(function (resolve) {
734
+ var pollingInterval = (0, timers_1.setInterval)(function () {
735
+ axios_1.default
736
+ .get("".concat(options.url, "api/0/wizard/").concat(wizardHash, "/"), {
737
+ headers: {
738
+ 'Accept-Encoding': 'deflate',
739
+ },
740
+ })
741
+ .then(function (result) {
742
+ resolve(result.data);
743
+ clearTimeout(timeout);
744
+ clearInterval(pollingInterval);
745
+ void axios_1.default.delete("".concat(options.url, "api/0/wizard/").concat(wizardHash, "/"));
746
+ })
747
+ .catch(function () {
748
+ // noop - just try again
749
+ });
750
+ }, 500);
751
+ var timeout = setTimeout(function () {
752
+ clearInterval(pollingInterval);
753
+ loginSpinner.stop('Login timed out. No worries - it happens to the best of us.');
754
+ Sentry.setTag('opened-wizard-link', false);
755
+ void abort('Please restart the Wizard and log in to complete the setup.');
756
+ }, 180000);
757
+ })];
758
+ case 11:
759
+ data = _b.sent();
760
+ loginSpinner.stop('Login complete.');
761
+ Sentry.setTag('opened-wizard-link', true);
762
+ return [2 /*return*/, data];
763
+ }
764
+ });
765
+ });
766
+ }
767
+ function askForProjectSelection(projects) {
768
+ return __awaiter(this, void 0, void 0, function () {
769
+ var label, sortedProjects, selection;
770
+ return __generator(this, function (_a) {
771
+ switch (_a.label) {
772
+ case 0:
773
+ label = function (project) {
774
+ return "".concat(project.organization.slug, "/").concat(project.slug);
775
+ };
776
+ sortedProjects = __spreadArray([], projects, true);
777
+ sortedProjects.sort(function (a, b) {
778
+ return label(a).localeCompare(label(b));
779
+ });
780
+ return [4 /*yield*/, abortIfCancelled(clack.select({
781
+ maxItems: 12,
782
+ message: 'Select your Sentry project.',
783
+ options: sortedProjects.map(function (project) {
784
+ return {
785
+ value: project,
786
+ label: label(project),
787
+ };
788
+ }),
789
+ }))];
790
+ case 1:
791
+ selection = _a.sent();
792
+ Sentry.setTag('project', selection.slug);
793
+ Sentry.setTag('project-platform', selection.platform);
794
+ Sentry.setUser({ id: selection.organization.slug });
795
+ return [2 /*return*/, selection];
796
+ }
797
+ });
798
+ });
799
+ }
800
+ /**
801
+ * Asks users if they have a config file for @param tool (e.g. Vite).
802
+ * If yes, asks users to specify the path to their config file.
803
+ *
804
+ * Use this helper function as a fallback mechanism if the lookup for
805
+ * a config file with its most usual location/name fails.
806
+ *
807
+ * @param toolName Name of the tool for which we're looking for the config file
808
+ * @param configFileName Name of the most common config file name (e.g. vite.config.js)
809
+ *
810
+ * @returns a user path to the config file or undefined if the user doesn't have a config file
811
+ */
812
+ function askForToolConfigPath(toolName, configFileName) {
813
+ return __awaiter(this, void 0, void 0, function () {
814
+ var hasConfig;
815
+ return __generator(this, function (_a) {
816
+ switch (_a.label) {
817
+ case 0: return [4 /*yield*/, abortIfCancelled(clack.confirm({
818
+ message: "Do you have a ".concat(toolName, " config file (e.g. ").concat(chalk_1.default.cyan(configFileName), "?"),
819
+ initialValue: true,
820
+ }))];
821
+ case 1:
822
+ hasConfig = _a.sent();
823
+ if (!hasConfig) {
824
+ return [2 /*return*/, undefined];
825
+ }
826
+ return [4 /*yield*/, abortIfCancelled(clack.text({
827
+ message: "Please enter the path to your ".concat(toolName, " config file:"),
828
+ placeholder: path.join('.', configFileName),
829
+ validate: function (value) {
830
+ if (!value) {
831
+ return 'Please enter a path.';
832
+ }
833
+ try {
834
+ fs.accessSync(value);
835
+ }
836
+ catch (_a) {
837
+ return 'Could not access the file at this path.';
838
+ }
839
+ },
840
+ }))];
841
+ case 2: return [2 /*return*/, _a.sent()];
842
+ }
843
+ });
844
+ });
845
+ }
846
+ exports.askForToolConfigPath = askForToolConfigPath;
847
+ /**
848
+ * Prints copy/paste-able instructions to the console.
849
+ * Afterwards asks the user if they added the code snippet to their file.
850
+ *
851
+ * While there's no point in providing a "no" answer here, it gives users time to fulfill the
852
+ * task before the wizard continues with additional steps.
853
+ *
854
+ * Use this function if you want to show users instructions on how to add/modify
855
+ * code in their file. This is helpful if automatic insertion failed or is not possible/feasible.
856
+ *
857
+ * @param filename the name of the file to which the code snippet should be applied.
858
+ * If a path is provided, only the filename will be used.
859
+ * @param codeSnippet the snippet to be printed.
860
+ * Make sure to follow the diff-like format of highlighting lines that require changes
861
+ * and showing unchanged lines in gray.
862
+ *
863
+ * TODO: Link to wizard spec (develop) once it is live
864
+ * TODO: refactor copy paste instructions across different wizards to use this function.
865
+ * this might require adding a custom message parameter to the function
866
+ */
867
+ function showCopyPasteInstructions(filename, codeSnippet) {
868
+ return __awaiter(this, void 0, void 0, function () {
869
+ return __generator(this, function (_a) {
870
+ switch (_a.label) {
871
+ case 0:
872
+ clack.log.step("Add the following code to your ".concat(chalk_1.default.cyan(path.basename(filename)), " file:"));
873
+ // Intentionally logging directly to console here so that the code can be copied/pasted directly
874
+ // eslint-disable-next-line no-console
875
+ console.log("\n".concat(codeSnippet));
876
+ return [4 /*yield*/, abortIfCancelled(clack.select({
877
+ message: 'Did you apply the snippet above?',
878
+ options: [{ label: 'Yes, continue!', value: true }],
879
+ initialValue: true,
880
+ }))];
881
+ case 1:
882
+ _a.sent();
883
+ return [2 /*return*/];
884
+ }
885
+ });
886
+ });
887
+ }
888
+ exports.showCopyPasteInstructions = showCopyPasteInstructions;
889
+ /**
890
+ * Creates a new config file with the given @param filepath and @param codeSnippet.
891
+ *
892
+ * Use this function to create a new config file for users. This is useful
893
+ * when users answered that they don't yet have a config file for a tool.
894
+ *
895
+ * (This doesn't mean that they don't yet have some other way of configuring
896
+ * their tool but we can leave it up to them to figure out how to merge configs
897
+ * here.)
898
+ *
899
+ * @param filepath absolute path to the new config file
900
+ * @param codeSnippet the snippet to be inserted into the file
901
+ * @param moreInformation (optional) the message to be printed after the file was created
902
+ * For example, this can be a link to more information about configuring the tool.
903
+ *
904
+ * @returns true on sucess, false otherwise
905
+ */
906
+ function createNewConfigFile(filepath, codeSnippet, moreInformation) {
907
+ return __awaiter(this, void 0, void 0, function () {
908
+ var prettyFilename, e_3;
909
+ return __generator(this, function (_a) {
910
+ switch (_a.label) {
911
+ case 0:
912
+ if (!path.isAbsolute(filepath)) {
913
+ (0, debug_1.debug)("createNewConfigFile: filepath is not absolute: ".concat(filepath));
914
+ return [2 /*return*/, false];
915
+ }
916
+ prettyFilename = chalk_1.default.cyan(path.relative(process.cwd(), filepath));
917
+ _a.label = 1;
918
+ case 1:
919
+ _a.trys.push([1, 3, , 4]);
920
+ return [4 /*yield*/, fs.promises.writeFile(filepath, codeSnippet)];
921
+ case 2:
922
+ _a.sent();
923
+ clack.log.success("Added new ".concat(prettyFilename, " file."));
924
+ if (moreInformation) {
925
+ clack.log.info(chalk_1.default.gray(moreInformation));
926
+ }
927
+ return [2 /*return*/, true];
928
+ case 3:
929
+ e_3 = _a.sent();
930
+ (0, debug_1.debug)(e_3);
931
+ clack.log.warn("Could not create a new ".concat(prettyFilename, " file. Please create one manually and follow the instructions below."));
932
+ return [3 /*break*/, 4];
933
+ case 4: return [2 /*return*/, false];
934
+ }
935
+ });
936
+ });
937
+ }
938
+ exports.createNewConfigFile = createNewConfigFile;
776
939
  //# sourceMappingURL=clack-utils.js.map