@sentry/wizard 3.11.0 → 3.13.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/ChooseIntegration.js +1 -0
- package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/src/android/android-wizard.js +14 -4
- package/dist/src/android/android-wizard.js.map +1 -1
- package/dist/src/android/code-tools.d.ts +8 -0
- package/dist/src/android/code-tools.js +20 -8
- package/dist/src/android/code-tools.js.map +1 -1
- package/dist/src/android/gradle.js +6 -1
- package/dist/src/android/gradle.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +5 -2
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.d.ts +1 -1
- package/dist/src/nextjs/templates.js +2 -2
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/remix/remix-wizard.js +8 -4
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/remix/sdk-setup.d.ts +5 -1
- package/dist/src/remix/sdk-setup.js +3 -2
- package/dist/src/remix/sdk-setup.js.map +1 -1
- package/dist/src/sourcemaps/tools/sentry-cli.d.ts +9 -0
- package/dist/src/sourcemaps/tools/sentry-cli.js +26 -22
- package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
- package/dist/src/sourcemaps/tools/tsc.d.ts +6 -0
- package/dist/src/sourcemaps/tools/tsc.js +98 -17
- package/dist/src/sourcemaps/tools/tsc.js.map +1 -1
- package/dist/src/sourcemaps/tools/vite.js +39 -124
- package/dist/src/sourcemaps/tools/vite.js.map +1 -1
- package/dist/src/sourcemaps/tools/webpack.d.ts +6 -1
- package/dist/src/sourcemaps/tools/webpack.js +280 -25
- package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
- package/dist/src/sveltekit/sdk-setup.js +123 -49
- package/dist/src/sveltekit/sdk-setup.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.d.ts +1 -0
- package/dist/src/sveltekit/sveltekit-wizard.js +119 -44
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/sveltekit/utils.d.ts +2 -0
- package/dist/src/sveltekit/utils.js +48 -0
- package/dist/src/sveltekit/utils.js.map +1 -0
- package/dist/src/utils/ast-utils.d.ts +77 -3
- package/dist/src/utils/ast-utils.js +172 -6
- package/dist/src/utils/ast-utils.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +85 -1
- package/dist/src/utils/clack-utils.js +214 -51
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +5 -0
- package/dist/src/utils/package-manager.js +11 -7
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/test/android/code-tools.test.d.ts +1 -0
- package/dist/test/android/code-tools.test.js +34 -0
- package/dist/test/android/code-tools.test.js.map +1 -0
- package/dist/test/sourcemaps/tools/sentry-cli.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/sentry-cli.test.js +112 -0
- package/dist/test/sourcemaps/tools/sentry-cli.test.js.map +1 -0
- package/dist/test/sourcemaps/tools/tsc.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/tsc.test.js +121 -0
- package/dist/test/sourcemaps/tools/tsc.test.js.map +1 -0
- package/dist/test/sourcemaps/tools/webpack.test.d.ts +1 -0
- package/dist/test/sourcemaps/tools/webpack.test.js +179 -0
- package/dist/test/sourcemaps/tools/webpack.test.js.map +1 -0
- package/dist/test/utils/ast-utils.test.js +181 -15
- package/dist/test/utils/ast-utils.test.js.map +1 -1
- package/dist/test/utils/clack-utils.test.d.ts +1 -0
- package/dist/test/utils/clack-utils.test.js +200 -0
- package/dist/test/utils/clack-utils.test.js.map +1 -0
- package/lib/Steps/ChooseIntegration.ts +1 -0
- package/package.json +1 -1
- package/src/android/android-wizard.ts +16 -5
- package/src/android/code-tools.ts +21 -7
- package/src/android/gradle.ts +6 -1
- package/src/nextjs/nextjs-wizard.ts +15 -3
- package/src/nextjs/templates.ts +3 -2
- package/src/remix/remix-wizard.ts +8 -11
- package/src/remix/sdk-setup.ts +8 -2
- package/src/sourcemaps/tools/sentry-cli.ts +16 -9
- package/src/sourcemaps/tools/tsc.ts +133 -28
- package/src/sourcemaps/tools/vite.ts +37 -127
- package/src/sourcemaps/tools/webpack.ts +343 -27
- package/src/sveltekit/sdk-setup.ts +115 -39
- package/src/sveltekit/sveltekit-wizard.ts +93 -25
- package/src/sveltekit/utils.ts +50 -0
- package/src/utils/ast-utils.ts +203 -7
- package/src/utils/clack-utils.ts +211 -44
- package/src/utils/package-manager.ts +12 -6
- package/test/android/code-tools.test.ts +49 -0
- package/test/sourcemaps/tools/sentry-cli.test.ts +51 -0
- package/test/sourcemaps/tools/tsc.test.ts +181 -0
- package/test/sourcemaps/tools/webpack.test.ts +303 -0
- package/test/utils/ast-utils.test.ts +240 -20
- package/test/utils/clack-utils.test.ts +142 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-utils.js","sourceRoot":"","sources":["../../../src/utils/ast-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ast-utils.js","sourceRoot":"","sources":["../../../src/utils/ast-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\n\nimport * as recast from 'recast';\nimport x = recast.types;\nimport t = x.namedTypes;\n\nconst b = recast.types.builders;\n\n/**\n * Checks if a file where we don't know its concrete file type yet exists\n * and returns the full path to the file with the correct file type.\n */\nexport function findFile(\n filePath: string,\n fileTypes: string[] = ['.js', '.ts', '.mjs', '.cjs'],\n): string | undefined {\n return fileTypes\n .map((type) => `${filePath}${type}`)\n .find((file) => fs.existsSync(file));\n}\n\n/**\n * checks for require('@sentry/*') syntax\n */\nexport function hasSentryContent(program: t.Program): boolean {\n let foundSentry: boolean | undefined = false;\n recast.visit(program, {\n visitStringLiteral(path) {\n foundSentry = foundSentry || path.node.value.startsWith('@sentry/');\n this.traverse(path);\n },\n visitLiteral(path) {\n foundSentry =\n foundSentry || path.node.value?.toString().startsWith('@sentry/');\n this.traverse(path);\n },\n });\n\n return !!foundSentry;\n}\n\n/**\n * Searches for a property of an ObjectExpression by name\n *\n * @param object the ObjectExpression to search in\n * @param name the name of the property to search for\n *\n * @returns the property if it exists\n */\nexport function getObjectProperty(\n object: t.ObjectExpression,\n name: string,\n): t.Property | undefined {\n return object.properties.find((p): p is t.Property => {\n const isObjectProp = p.type === 'Property' || p.type === 'ObjectProperty';\n\n if (!isObjectProp) {\n return false;\n }\n\n const hasMatchingLiteralKey =\n isObjectProp &&\n (p.key.type === 'Literal' || p.key.type === 'StringLiteral') &&\n p.key.value === name;\n\n if (hasMatchingLiteralKey) {\n return true;\n }\n\n // has matching identifier key\n return isObjectProp && p.key.type === 'Identifier' && p.key.name === name;\n });\n}\n\n/**\n * Attempts to find a property of an ObjectExpression by name. If it doesn't exist,\n * the property will be added to the ObjectExpression with the provided default value.\n *\n * @param object the parent object expression to search in\n * @param name the name of the property to search for\n * @param defaultValue the default value to set if the property doesn't exist\n *\n * @returns the\n */\nexport function getOrSetObjectProperty(\n object: t.ObjectExpression,\n name: string,\n defaultValue:\n | t.Literal\n | t.BooleanLiteral\n | t.StringLiteral\n | t.ObjectExpression,\n): t.Property {\n const existingProperty = getObjectProperty(object, name);\n\n if (existingProperty) {\n return existingProperty;\n }\n\n const newProperty = b.property.from({\n kind: 'init',\n key: b.stringLiteral(name),\n value: defaultValue,\n });\n\n object.properties.push(newProperty);\n\n return newProperty;\n}\n\n/**\n * Sets a property of an ObjectExpression if it exists, otherwise adds it\n * to the ObjectExpression. Optionally, a comment can be added to the\n * property.\n *\n * @param object the ObjectExpression to set the property on\n * @param name the name of the property to set\n * @param value the value of the property to set\n * @param comment (optional) a comment to add to the property\n */\nexport function setOrUpdateObjectProperty(\n object: t.ObjectExpression,\n name: string,\n value: t.Literal | t.BooleanLiteral | t.StringLiteral | t.ObjectExpression,\n comment?: string,\n) {\n const newComments =\n comment &&\n comment.split('\\n').map((c) => b.commentLine(` ${c}`, true, false));\n\n const existingProperty = getObjectProperty(object, name);\n\n if (existingProperty) {\n existingProperty.value = value;\n if (newComments) {\n existingProperty.comments = [\n ...(existingProperty?.comments || []),\n ...newComments,\n ];\n }\n } else {\n object.properties.push(\n b.objectProperty.from({\n key: b.stringLiteral(name),\n value,\n ...(newComments && {\n comments: newComments,\n }),\n }),\n );\n }\n}\n\ntype JsonCParseResult =\n | {\n jsonObject: t.ObjectExpression;\n ast: t.Program;\n }\n | {\n jsonObject: undefined;\n ast: undefined;\n };\n\n/**\n * Parses a JSON string with (potential) comments (JSON-C) and returns the JS AST\n * that can be walked and modified with recast like a normal JS AST.\n *\n * This is done by wrapping the JSON-C string in parentheses, thereby making it\n * a JS `Program` with an `ExpressionStatement` as its body. The expression is then\n * extracted from the AST and returned alongside the AST.\n *\n * To preserve as much original formatting as possible, the returned `ast`\n * property should be passed to {@link `printJsonC`} to get the JSON-C string back.\n *\n * If the input is not valid JSON-C, the result will be undefined.\n *\n * @see {@link JsonCParseResult}\n *\n * @param jsonString a JSON-C string\n *\n * @returns a {@link JsonCParseResult}, containing either the JSON-C object and the AST or undefined in both cases\n */\nexport function parseJsonC(jsonString: string): JsonCParseResult {\n try {\n const jsTsConfig = `(${jsonString})`;\n // no idea why recast returns any here, this is dumb :/\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const ast = recast.parse(jsTsConfig.toString()).program as t.Program;\n\n const jsonObject =\n (ast.body[0].type === 'ExpressionStatement' &&\n ast.body[0].expression.type === 'ObjectExpression' &&\n ast.body[0].expression) ||\n undefined;\n\n if (jsonObject) {\n return { jsonObject, ast };\n }\n } catch {\n /* empty */\n }\n return { jsonObject: undefined, ast: undefined };\n}\n\n/**\n * Takes the AST of a parsed JSON-C \"program\" and returns the JSON-C string without\n * any of the temporary JS wrapper code that was previously applied.\n *\n * Only use this in conjunction with {@link `parseJsonC`}\n *\n * @param ast the `ast` returned from {@link `parseJsonC`}\n *\n * @returns the JSON-C string\n */\nexport function printJsonC(ast: t.Program): string {\n const js = recast.print(ast).code;\n return js.substring(1, js.length - 1);\n}\n"]}
|
|
@@ -31,7 +31,7 @@ export declare function installPackage({ packageName, alreadyInstalled, askBefor
|
|
|
31
31
|
alreadyInstalled: boolean;
|
|
32
32
|
askBeforeUpdating?: boolean;
|
|
33
33
|
}): Promise<void>;
|
|
34
|
-
export declare function addSentryCliConfig(authToken: string, setupConfig?: CliSetupConfig
|
|
34
|
+
export declare function addSentryCliConfig(authToken: string, setupConfig?: CliSetupConfig): Promise<void>;
|
|
35
35
|
export declare function addDotEnvSentryBuildPluginFile(authToken: string): Promise<void>;
|
|
36
36
|
export declare function ensurePackageIsInstalled(packageJson: PackageDotJson, packageId: string, packageName: string): Promise<void>;
|
|
37
37
|
export declare function getPackageDotJson(): Promise<PackageDotJson>;
|
|
@@ -53,3 +53,87 @@ export declare function getOrAskForProjectData(options: WizardOptions, platform?
|
|
|
53
53
|
selectedProject: SentryProjectData;
|
|
54
54
|
authToken: string;
|
|
55
55
|
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Asks users if they have a config file for @param tool (e.g. Vite).
|
|
58
|
+
* If yes, asks users to specify the path to their config file.
|
|
59
|
+
*
|
|
60
|
+
* Use this helper function as a fallback mechanism if the lookup for
|
|
61
|
+
* a config file with its most usual location/name fails.
|
|
62
|
+
*
|
|
63
|
+
* @param toolName Name of the tool for which we're looking for the config file
|
|
64
|
+
* @param configFileName Name of the most common config file name (e.g. vite.config.js)
|
|
65
|
+
*
|
|
66
|
+
* @returns a user path to the config file or undefined if the user doesn't have a config file
|
|
67
|
+
*/
|
|
68
|
+
export declare function askForToolConfigPath(toolName: string, configFileName: string): Promise<string | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Prints copy/paste-able instructions to the console.
|
|
71
|
+
* Afterwards asks the user if they added the code snippet to their file.
|
|
72
|
+
*
|
|
73
|
+
* While there's no point in providing a "no" answer here, it gives users time to fulfill the
|
|
74
|
+
* task before the wizard continues with additional steps.
|
|
75
|
+
*
|
|
76
|
+
* Use this function if you want to show users instructions on how to add/modify
|
|
77
|
+
* code in their file. This is helpful if automatic insertion failed or is not possible/feasible.
|
|
78
|
+
*
|
|
79
|
+
* @param filename the name of the file to which the code snippet should be applied.
|
|
80
|
+
* If a path is provided, only the filename will be used.
|
|
81
|
+
*
|
|
82
|
+
* @param codeSnippet the snippet to be printed. Use {@link makeCodeSnippet} to create the
|
|
83
|
+
* diff-like format for visually highlighting unchanged or modified lines of code.
|
|
84
|
+
*
|
|
85
|
+
* @param hint (optional) a hint to be printed after the main instruction to add
|
|
86
|
+
* the code from @param codeSnippet to their @param filename.
|
|
87
|
+
*
|
|
88
|
+
* More guidelines on copy/paste instructions:
|
|
89
|
+
* @see {@link https://develop.sentry.dev/sdk/setup-wizards/#copy--paste-snippets}
|
|
90
|
+
*
|
|
91
|
+
* TODO: refactor copy paste instructions across different wizards to use this function.
|
|
92
|
+
* this might require adding a custom message parameter to the function
|
|
93
|
+
*/
|
|
94
|
+
export declare function showCopyPasteInstructions(filename: string, codeSnippet: string, hint?: string): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Callback that exposes formatting helpers for a code snippet.
|
|
97
|
+
* @param unchanged - Formats text as old code.
|
|
98
|
+
* @param plus - Formats text as new code.
|
|
99
|
+
* @param minus - Formats text as removed code.
|
|
100
|
+
*/
|
|
101
|
+
type CodeSnippetFormatter = (unchanged: (txt: string) => string, plus: (txt: string) => string, minus: (txt: string) => string) => string;
|
|
102
|
+
/**
|
|
103
|
+
* Crafts a code snippet that can be used to e.g.
|
|
104
|
+
* - print copy/paste instructions to the console
|
|
105
|
+
* - create a new config file.
|
|
106
|
+
*
|
|
107
|
+
* @param colors set this to true if you want the final snippet to be colored.
|
|
108
|
+
* This is useful for printing the snippet to the console as part of copy/paste instructions.
|
|
109
|
+
*
|
|
110
|
+
* @param callback the callback that returns the formatted code snippet.
|
|
111
|
+
* It exposes takes the helper functions for marking code as unchaned, new or removed.
|
|
112
|
+
* These functions no-op if no special formatting should be applied
|
|
113
|
+
* and otherwise apply the appropriate formatting/coloring.
|
|
114
|
+
* (@see {@link CodeSnippetFormatter})
|
|
115
|
+
*
|
|
116
|
+
* @see {@link showCopyPasteInstructions} for the helper with which to display the snippet in the console.
|
|
117
|
+
*
|
|
118
|
+
* @returns a string containing the final, formatted code snippet.
|
|
119
|
+
*/
|
|
120
|
+
export declare function makeCodeSnippet(colors: boolean, callback: CodeSnippetFormatter): string;
|
|
121
|
+
/**
|
|
122
|
+
* Creates a new config file with the given @param filepath and @param codeSnippet.
|
|
123
|
+
*
|
|
124
|
+
* Use this function to create a new config file for users. This is useful
|
|
125
|
+
* when users answered that they don't yet have a config file for a tool.
|
|
126
|
+
*
|
|
127
|
+
* (This doesn't mean that they don't yet have some other way of configuring
|
|
128
|
+
* their tool but we can leave it up to them to figure out how to merge configs
|
|
129
|
+
* here.)
|
|
130
|
+
*
|
|
131
|
+
* @param filepath absolute path to the new config file
|
|
132
|
+
* @param codeSnippet the snippet to be inserted into the file
|
|
133
|
+
* @param moreInformation (optional) the message to be printed after the file was created
|
|
134
|
+
* For example, this can be a link to more information about configuring the tool.
|
|
135
|
+
*
|
|
136
|
+
* @returns true on sucess, false otherwise
|
|
137
|
+
*/
|
|
138
|
+
export declare function createNewConfigFile(filepath: string, codeSnippet: string, moreInformation?: string): Promise<boolean>;
|
|
139
|
+
export {};
|
|
@@ -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.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;
|
|
74
|
+
exports.createNewConfigFile = exports.makeCodeSnippet = 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"));
|
|
@@ -76,6 +85,7 @@ var Sentry = __importStar(require("@sentry/node"));
|
|
|
76
85
|
var package_json_1 = require("./package-json");
|
|
77
86
|
var telemetry_1 = require("../telemetry");
|
|
78
87
|
var package_manager_1 = require("./package-manager");
|
|
88
|
+
var debug_1 = require("./debug");
|
|
79
89
|
var opn = require('opn');
|
|
80
90
|
exports.SENTRY_DOT_ENV_FILE = '.env.sentry-build-plugin';
|
|
81
91
|
exports.SENTRY_CLI_RC_FILE = '.sentryclirc';
|
|
@@ -165,15 +175,15 @@ function printWelcome(options) {
|
|
|
165
175
|
console.log('');
|
|
166
176
|
clack.intro(chalk_1.default.inverse(" ".concat(options.wizardName, " ")));
|
|
167
177
|
var welcomeText = options.message ||
|
|
168
|
-
|
|
178
|
+
"The ".concat(options.wizardName, " will help you set up Sentry for your application.\nThank you for using Sentry :)");
|
|
169
179
|
if (options.promoCode) {
|
|
170
|
-
welcomeText
|
|
180
|
+
welcomeText = "".concat(welcomeText, "\n\nUsing promo-code: ").concat(options.promoCode);
|
|
171
181
|
}
|
|
172
182
|
if (wizardPackage.version) {
|
|
173
|
-
welcomeText
|
|
183
|
+
welcomeText = "".concat(welcomeText, "\n\nVersion: ").concat(wizardPackage.version);
|
|
174
184
|
}
|
|
175
185
|
if (options.telemetryEnabled) {
|
|
176
|
-
welcomeText
|
|
186
|
+
welcomeText = "".concat(welcomeText, "\n\nThis wizard sends telemetry data and crash reports to Sentry. This helps us improve the Wizard.\nYou can turn this off at any time by running ").concat(chalk_1.default.cyanBright('sentry-wizard --disable-telemetry'), ".");
|
|
177
187
|
}
|
|
178
188
|
clack.note(welcomeText);
|
|
179
189
|
}
|
|
@@ -291,32 +301,7 @@ function installPackage(_a) {
|
|
|
291
301
|
});
|
|
292
302
|
}
|
|
293
303
|
exports.installPackage = installPackage;
|
|
294
|
-
function
|
|
295
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
296
|
-
var configContents, e_2;
|
|
297
|
-
return __generator(this, function (_a) {
|
|
298
|
-
switch (_a.label) {
|
|
299
|
-
case 0:
|
|
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."));
|
|
303
|
-
return [3 /*break*/, 4];
|
|
304
|
-
case 1:
|
|
305
|
-
_a.trys.push([1, 3, , 4]);
|
|
306
|
-
return [4 /*yield*/, fs.promises.appendFile(path.join(process.cwd(), setupConfig.filename), "\n".concat(setupConfig.orgAndProjContent(org, project), "\n"))];
|
|
307
|
-
case 2:
|
|
308
|
-
_a.sent();
|
|
309
|
-
return [3 /*break*/, 4];
|
|
310
|
-
case 3:
|
|
311
|
-
e_2 = _a.sent();
|
|
312
|
-
clack.log.warn("".concat(chalk_1.default.bold(setupConfig.filename), " could not be updated with org and project."));
|
|
313
|
-
return [3 /*break*/, 4];
|
|
314
|
-
case 4: return [2 /*return*/];
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
function addSentryCliConfig(authToken, setupConfig, orgSlug, projectSlug) {
|
|
304
|
+
function addSentryCliConfig(authToken, setupConfig) {
|
|
320
305
|
if (setupConfig === void 0) { setupConfig = exports.sourceMapsCliSetupConfig; }
|
|
321
306
|
return __awaiter(this, void 0, void 0, function () {
|
|
322
307
|
var configExists, configContents, _a, _b;
|
|
@@ -352,14 +337,8 @@ function addSentryCliConfig(authToken, setupConfig, orgSlug, projectSlug) {
|
|
|
352
337
|
_b = _c.sent();
|
|
353
338
|
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."));
|
|
354
339
|
return [3 /*break*/, 8];
|
|
355
|
-
case 8:
|
|
356
|
-
if (!(orgSlug && projectSlug)) return [3 /*break*/, 10];
|
|
357
|
-
return [4 /*yield*/, addOrgAndProjectToSentryCliRc(orgSlug, projectSlug, setupConfig)];
|
|
340
|
+
case 8: return [4 /*yield*/, addAuthTokenFileToGitIgnore(setupConfig.filename)];
|
|
358
341
|
case 9:
|
|
359
|
-
_c.sent();
|
|
360
|
-
_c.label = 10;
|
|
361
|
-
case 10: return [4 /*yield*/, addAuthTokenFileToGitIgnore(setupConfig.filename)];
|
|
362
|
-
case 11:
|
|
363
342
|
_c.sent();
|
|
364
343
|
return [2 /*return*/];
|
|
365
344
|
}
|
|
@@ -447,7 +426,8 @@ function ensurePackageIsInstalled(packageJson, packageId, packageName) {
|
|
|
447
426
|
return __generator(this, function (_a) {
|
|
448
427
|
switch (_a.label) {
|
|
449
428
|
case 0:
|
|
450
|
-
if (!!(0, package_json_1.hasPackageInstalled)(packageId, packageJson)) return [3 /*break*/,
|
|
429
|
+
if (!!(0, package_json_1.hasPackageInstalled)(packageId, packageJson)) return [3 /*break*/, 4];
|
|
430
|
+
Sentry.setTag('package-installed', false);
|
|
451
431
|
return [4 /*yield*/, abortIfCancelled(clack.confirm({
|
|
452
432
|
message: "".concat(packageName, " does not seem to be installed. Do you still want to continue?"),
|
|
453
433
|
initialValue: false,
|
|
@@ -459,7 +439,11 @@ function ensurePackageIsInstalled(packageJson, packageId, packageName) {
|
|
|
459
439
|
case 2:
|
|
460
440
|
_a.sent();
|
|
461
441
|
_a.label = 3;
|
|
462
|
-
case 3: return [
|
|
442
|
+
case 3: return [3 /*break*/, 5];
|
|
443
|
+
case 4:
|
|
444
|
+
Sentry.setTag('package-installed', true);
|
|
445
|
+
_a.label = 5;
|
|
446
|
+
case 5: return [2 /*return*/];
|
|
463
447
|
}
|
|
464
448
|
});
|
|
465
449
|
});
|
|
@@ -756,19 +740,27 @@ function askForWizardLogin(options) {
|
|
|
756
740
|
}
|
|
757
741
|
function askForProjectSelection(projects) {
|
|
758
742
|
return __awaiter(this, void 0, void 0, function () {
|
|
759
|
-
var selection;
|
|
743
|
+
var label, sortedProjects, selection;
|
|
760
744
|
return __generator(this, function (_a) {
|
|
761
745
|
switch (_a.label) {
|
|
762
|
-
case 0:
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
746
|
+
case 0:
|
|
747
|
+
label = function (project) {
|
|
748
|
+
return "".concat(project.organization.slug, "/").concat(project.slug);
|
|
749
|
+
};
|
|
750
|
+
sortedProjects = __spreadArray([], projects, true);
|
|
751
|
+
sortedProjects.sort(function (a, b) {
|
|
752
|
+
return label(a).localeCompare(label(b));
|
|
753
|
+
});
|
|
754
|
+
return [4 /*yield*/, abortIfCancelled(clack.select({
|
|
755
|
+
maxItems: 12,
|
|
756
|
+
message: 'Select your Sentry project.',
|
|
757
|
+
options: sortedProjects.map(function (project) {
|
|
758
|
+
return {
|
|
759
|
+
value: project,
|
|
760
|
+
label: label(project),
|
|
761
|
+
};
|
|
762
|
+
}),
|
|
763
|
+
}))];
|
|
772
764
|
case 1:
|
|
773
765
|
selection = _a.sent();
|
|
774
766
|
Sentry.setTag('project', selection.slug);
|
|
@@ -779,4 +771,175 @@ function askForProjectSelection(projects) {
|
|
|
779
771
|
});
|
|
780
772
|
});
|
|
781
773
|
}
|
|
774
|
+
/**
|
|
775
|
+
* Asks users if they have a config file for @param tool (e.g. Vite).
|
|
776
|
+
* If yes, asks users to specify the path to their config file.
|
|
777
|
+
*
|
|
778
|
+
* Use this helper function as a fallback mechanism if the lookup for
|
|
779
|
+
* a config file with its most usual location/name fails.
|
|
780
|
+
*
|
|
781
|
+
* @param toolName Name of the tool for which we're looking for the config file
|
|
782
|
+
* @param configFileName Name of the most common config file name (e.g. vite.config.js)
|
|
783
|
+
*
|
|
784
|
+
* @returns a user path to the config file or undefined if the user doesn't have a config file
|
|
785
|
+
*/
|
|
786
|
+
function askForToolConfigPath(toolName, configFileName) {
|
|
787
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
788
|
+
var hasConfig;
|
|
789
|
+
return __generator(this, function (_a) {
|
|
790
|
+
switch (_a.label) {
|
|
791
|
+
case 0: return [4 /*yield*/, abortIfCancelled(clack.confirm({
|
|
792
|
+
message: "Do you have a ".concat(toolName, " config file (e.g. ").concat(chalk_1.default.cyan(configFileName), ")?"),
|
|
793
|
+
initialValue: true,
|
|
794
|
+
}))];
|
|
795
|
+
case 1:
|
|
796
|
+
hasConfig = _a.sent();
|
|
797
|
+
if (!hasConfig) {
|
|
798
|
+
return [2 /*return*/, undefined];
|
|
799
|
+
}
|
|
800
|
+
return [4 /*yield*/, abortIfCancelled(clack.text({
|
|
801
|
+
message: "Please enter the path to your ".concat(toolName, " config file:"),
|
|
802
|
+
placeholder: path.join('.', configFileName),
|
|
803
|
+
validate: function (value) {
|
|
804
|
+
if (!value) {
|
|
805
|
+
return 'Please enter a path.';
|
|
806
|
+
}
|
|
807
|
+
try {
|
|
808
|
+
fs.accessSync(value);
|
|
809
|
+
}
|
|
810
|
+
catch (_a) {
|
|
811
|
+
return 'Could not access the file at this path.';
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
}))];
|
|
815
|
+
case 2: return [2 /*return*/, _a.sent()];
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
exports.askForToolConfigPath = askForToolConfigPath;
|
|
821
|
+
/**
|
|
822
|
+
* Prints copy/paste-able instructions to the console.
|
|
823
|
+
* Afterwards asks the user if they added the code snippet to their file.
|
|
824
|
+
*
|
|
825
|
+
* While there's no point in providing a "no" answer here, it gives users time to fulfill the
|
|
826
|
+
* task before the wizard continues with additional steps.
|
|
827
|
+
*
|
|
828
|
+
* Use this function if you want to show users instructions on how to add/modify
|
|
829
|
+
* code in their file. This is helpful if automatic insertion failed or is not possible/feasible.
|
|
830
|
+
*
|
|
831
|
+
* @param filename the name of the file to which the code snippet should be applied.
|
|
832
|
+
* If a path is provided, only the filename will be used.
|
|
833
|
+
*
|
|
834
|
+
* @param codeSnippet the snippet to be printed. Use {@link makeCodeSnippet} to create the
|
|
835
|
+
* diff-like format for visually highlighting unchanged or modified lines of code.
|
|
836
|
+
*
|
|
837
|
+
* @param hint (optional) a hint to be printed after the main instruction to add
|
|
838
|
+
* the code from @param codeSnippet to their @param filename.
|
|
839
|
+
*
|
|
840
|
+
* More guidelines on copy/paste instructions:
|
|
841
|
+
* @see {@link https://develop.sentry.dev/sdk/setup-wizards/#copy--paste-snippets}
|
|
842
|
+
*
|
|
843
|
+
* TODO: refactor copy paste instructions across different wizards to use this function.
|
|
844
|
+
* this might require adding a custom message parameter to the function
|
|
845
|
+
*/
|
|
846
|
+
function showCopyPasteInstructions(filename, codeSnippet, hint) {
|
|
847
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
848
|
+
return __generator(this, function (_a) {
|
|
849
|
+
switch (_a.label) {
|
|
850
|
+
case 0:
|
|
851
|
+
clack.log.step("Add the following code to your ".concat(chalk_1.default.cyan(path.basename(filename)), " file:").concat(hint ? chalk_1.default.dim(" (".concat(chalk_1.default.dim(hint), ")")) : ''));
|
|
852
|
+
// Padding the code snippet to be printed with a \n at the beginning and end
|
|
853
|
+
// This makes it easier to distinguish the snippet from the rest of the output
|
|
854
|
+
// Intentionally logging directly to console here so that the code can be copied/pasted directly
|
|
855
|
+
// eslint-disable-next-line no-console
|
|
856
|
+
console.log("\n".concat(codeSnippet, "\n"));
|
|
857
|
+
return [4 /*yield*/, abortIfCancelled(clack.select({
|
|
858
|
+
message: 'Did you apply the snippet above?',
|
|
859
|
+
options: [{ label: 'Yes, continue!', value: true }],
|
|
860
|
+
initialValue: true,
|
|
861
|
+
}))];
|
|
862
|
+
case 1:
|
|
863
|
+
_a.sent();
|
|
864
|
+
return [2 /*return*/];
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
exports.showCopyPasteInstructions = showCopyPasteInstructions;
|
|
870
|
+
/**
|
|
871
|
+
* Crafts a code snippet that can be used to e.g.
|
|
872
|
+
* - print copy/paste instructions to the console
|
|
873
|
+
* - create a new config file.
|
|
874
|
+
*
|
|
875
|
+
* @param colors set this to true if you want the final snippet to be colored.
|
|
876
|
+
* This is useful for printing the snippet to the console as part of copy/paste instructions.
|
|
877
|
+
*
|
|
878
|
+
* @param callback the callback that returns the formatted code snippet.
|
|
879
|
+
* It exposes takes the helper functions for marking code as unchaned, new or removed.
|
|
880
|
+
* These functions no-op if no special formatting should be applied
|
|
881
|
+
* and otherwise apply the appropriate formatting/coloring.
|
|
882
|
+
* (@see {@link CodeSnippetFormatter})
|
|
883
|
+
*
|
|
884
|
+
* @see {@link showCopyPasteInstructions} for the helper with which to display the snippet in the console.
|
|
885
|
+
*
|
|
886
|
+
* @returns a string containing the final, formatted code snippet.
|
|
887
|
+
*/
|
|
888
|
+
function makeCodeSnippet(colors, callback) {
|
|
889
|
+
var unchanged = function (txt) { return (colors ? chalk_1.default.grey(txt) : txt); };
|
|
890
|
+
var plus = function (txt) { return (colors ? chalk_1.default.greenBright(txt) : txt); };
|
|
891
|
+
var minus = function (txt) { return (colors ? chalk_1.default.redBright(txt) : txt); };
|
|
892
|
+
return callback(unchanged, plus, minus);
|
|
893
|
+
}
|
|
894
|
+
exports.makeCodeSnippet = makeCodeSnippet;
|
|
895
|
+
/**
|
|
896
|
+
* Creates a new config file with the given @param filepath and @param codeSnippet.
|
|
897
|
+
*
|
|
898
|
+
* Use this function to create a new config file for users. This is useful
|
|
899
|
+
* when users answered that they don't yet have a config file for a tool.
|
|
900
|
+
*
|
|
901
|
+
* (This doesn't mean that they don't yet have some other way of configuring
|
|
902
|
+
* their tool but we can leave it up to them to figure out how to merge configs
|
|
903
|
+
* here.)
|
|
904
|
+
*
|
|
905
|
+
* @param filepath absolute path to the new config file
|
|
906
|
+
* @param codeSnippet the snippet to be inserted into the file
|
|
907
|
+
* @param moreInformation (optional) the message to be printed after the file was created
|
|
908
|
+
* For example, this can be a link to more information about configuring the tool.
|
|
909
|
+
*
|
|
910
|
+
* @returns true on sucess, false otherwise
|
|
911
|
+
*/
|
|
912
|
+
function createNewConfigFile(filepath, codeSnippet, moreInformation) {
|
|
913
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
914
|
+
var prettyFilename, e_2;
|
|
915
|
+
return __generator(this, function (_a) {
|
|
916
|
+
switch (_a.label) {
|
|
917
|
+
case 0:
|
|
918
|
+
if (!path.isAbsolute(filepath)) {
|
|
919
|
+
(0, debug_1.debug)("createNewConfigFile: filepath is not absolute: ".concat(filepath));
|
|
920
|
+
return [2 /*return*/, false];
|
|
921
|
+
}
|
|
922
|
+
prettyFilename = chalk_1.default.cyan(path.relative(process.cwd(), filepath));
|
|
923
|
+
_a.label = 1;
|
|
924
|
+
case 1:
|
|
925
|
+
_a.trys.push([1, 3, , 4]);
|
|
926
|
+
return [4 /*yield*/, fs.promises.writeFile(filepath, codeSnippet)];
|
|
927
|
+
case 2:
|
|
928
|
+
_a.sent();
|
|
929
|
+
clack.log.success("Added new ".concat(prettyFilename, " file."));
|
|
930
|
+
if (moreInformation) {
|
|
931
|
+
clack.log.info(chalk_1.default.gray(moreInformation));
|
|
932
|
+
}
|
|
933
|
+
return [2 /*return*/, true];
|
|
934
|
+
case 3:
|
|
935
|
+
e_2 = _a.sent();
|
|
936
|
+
(0, debug_1.debug)(e_2);
|
|
937
|
+
clack.log.warn("Could not create a new ".concat(prettyFilename, " file. Please create one manually and follow the instructions below."));
|
|
938
|
+
return [3 /*break*/, 4];
|
|
939
|
+
case 4: return [2 /*return*/, false];
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
exports.createNewConfigFile = createNewConfigFile;
|
|
782
945
|
//# sourceMappingURL=clack-utils.js.map
|