UNPKG

@sentry/wizard

Version:

Sentry wizard helping you to configure your project

159 lines (157 loc) 8.82 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.runAndroidWizard = void 0; /* eslint-disable @typescript-eslint/no-unsafe-assignment */ const fs = __importStar(require("fs")); // @ts-expect-error - clack is ESM and TS complains about that. It works though const clack = __importStar(require("@clack/prompts")); const Sentry = __importStar(require("@sentry/node")); const chalk_1 = __importDefault(require("chalk")); const path = __importStar(require("path")); const telemetry_1 = require("../telemetry"); const clack_1 = require("../utils/clack"); const mcp_config_1 = require("../utils/clack/mcp-config"); const codetools = __importStar(require("./code-tools")); const gradle = __importStar(require("./gradle")); const manifest = __importStar(require("./manifest")); const proguardMappingCliSetupConfig = { ...clack_1.propertiesCliSetupConfig, name: 'proguard mappings', }; async function runAndroidWizard(options) { return (0, telemetry_1.withTelemetry)({ enabled: options.telemetryEnabled, integration: 'android', wizardOptions: options, }, () => runAndroidWizardWithTelemetry(options)); } exports.runAndroidWizard = runAndroidWizard; async function runAndroidWizardWithTelemetry(options) { (0, clack_1.printWelcome)({ wizardName: 'Sentry Android Wizard', promoCode: options.promoCode, }); await (0, clack_1.confirmContinueIfNoOrDirtyGitRepo)({ ignoreGitChanges: options.ignoreGitChanges, cwd: undefined, }); const projectDir = process.cwd(); const buildGradleFiles = findFilesWithExtensions(projectDir, [ '.gradle', 'gradle.kts', ]); if (!buildGradleFiles || buildGradleFiles.length === 0) { clack.log.error('No Gradle project found. Please run this command from the root of your project.'); Sentry.captureException('No Gradle project found'); await (0, clack_1.abort)(); return; } const appFile = await (0, telemetry_1.traceStep)('Select App File', () => gradle.selectAppFile(buildGradleFiles)); const { selectedProject, selfHosted, sentryUrl, authToken } = await (0, clack_1.getOrAskForProjectData)(options, 'android'); // Ask if user wants to enable Sentry Logs const enableLogs = await (0, clack_1.abortIfCancelled)(clack.confirm({ message: 'Do you want to enable Logs? (See https://docs.sentry.io/platforms/android/logs/)', })); Sentry.setTag('enable-logs', enableLogs); if (enableLogs) { clack.log.info('Logs will be enabled with default settings. You can send logs using the Sentry.logger() APIs or use one of the integrations: https://docs.sentry.io/platforms/android/logs/#integrations.'); } // ======== STEP 1. Add Sentry Gradle Plugin to build.gradle(.kts) ============ clack.log.step(`Adding ${chalk_1.default.bold('Sentry Gradle plugin')} to your app's ${chalk_1.default.cyan('build.gradle')} file.`); const pluginAdded = await (0, telemetry_1.traceStep)('Add Gradle Plugin', () => gradle.addGradlePlugin(appFile, selectedProject.organization.slug, selectedProject.slug)); if (!pluginAdded) { clack.log.warn("Could not add Sentry Gradle plugin to your app's build.gradle file. You'll have to add it manually.\nPlease follow the instructions at https://docs.sentry.io/platforms/android/#install"); } Sentry.setTag('gradle-plugin-added', pluginAdded); // ======== STEP 2. Configure Sentry SDK via AndroidManifest ============ clack.log.step(`Configuring Sentry SDK via ${chalk_1.default.cyan('AndroidManifest.xml')}`); const appDir = path.dirname(appFile); const manifestFile = path.join(appDir, 'src', 'main', 'AndroidManifest.xml'); const manifestUpdated = (0, telemetry_1.traceStep)('Update Android Manifest', () => manifest.addManifestSnippet(manifestFile, selectedProject.keys[0].dsn.public, enableLogs)); if (!manifestUpdated) { clack.log.warn("Could not configure the Sentry SDK. You'll have to do it manually.\nPlease follow the instructions at https://docs.sentry.io/platforms/android/#configure"); } Sentry.setTag('android-manifest-updated', manifestUpdated); // ======== STEP 3. Patch Main Activity with a test error snippet ============ clack.log.step(`Patching ${chalk_1.default.bold('Main Activity')} with a test error snippet.`); const mainActivity = (0, telemetry_1.traceStep)('Find Main Activity', () => manifest.getMainActivity(manifestFile)); let packageName = mainActivity.packageName; if (!packageName) { // if no package name in AndroidManifest, look into gradle script packageName = gradle.getNamespace(appFile); } const activityName = mainActivity.activityName; Sentry.setTag('has-activity-name', !!activityName); Sentry.setTag('has-package-name', !!packageName); if (!activityName || !packageName) { clack.log.warn("Could not find Activity with intent action MAIN. You'll have to manually verify the setup.\nPlease follow the instructions at https://docs.sentry.io/platforms/android/#verify"); Sentry.captureException('Could not find Main Activity'); } else { const packageNameStable = packageName; const activityFile = (0, telemetry_1.traceStep)('Find Main Activity Source File', () => codetools.findActivitySourceFile(appDir, packageNameStable, activityName)); const activityPatched = (0, telemetry_1.traceStep)('Patch Main Activity', () => codetools.patchMainActivity(activityFile)); if (!activityPatched) { clack.log.warn("Could not patch main activity. You'll have to manually verify the setup.\nPlease follow the instructions at https://docs.sentry.io/platforms/android/#verify"); } Sentry.setTag('main-activity-patched', activityPatched); } // ======== STEP 4. Add sentry-cli config file ============ clack.log.step(`Configuring ${chalk_1.default.bold('proguard mappings upload')} via the ${chalk_1.default.cyan('sentry.properties')} file.`); await (0, clack_1.addSentryCliConfig)({ authToken }, proguardMappingCliSetupConfig); // Offer optional project-scoped MCP config for Sentry with org and project scope await (0, mcp_config_1.offerProjectScopedMcpConfig)(selectedProject.organization.slug, selectedProject.slug); // ======== OUTRO ======== const issuesPageLink = selfHosted ? `${sentryUrl}organizations/${selectedProject.organization.slug}/issues/?project=${selectedProject.id}` : `https://${selectedProject.organization.slug}.sentry.io/issues/?project=${selectedProject.id}`; clack.outro(` ${chalk_1.default.greenBright('Successfully installed the Sentry Android SDK!')} ${chalk_1.default.cyan(`You can validate your setup by launching your application and checking Sentry issues page afterwards ${issuesPageLink}`)} Check out the SDK documentation for further configuration: https://docs.sentry.io/platforms/android/ `); } //find files with the given extension function findFilesWithExtensions(dir, extensions, filesWithExtensions = []) { const cwd = process.cwd(); const files = fs.readdirSync(dir, { withFileTypes: true }); for (const file of files) { if (file.isDirectory()) { const childDir = path.join(dir, file.name); findFilesWithExtensions(childDir, extensions, filesWithExtensions); } else if (extensions.some((ext) => file.name.endsWith(ext))) { filesWithExtensions.push(path.relative(cwd, path.join(dir, file.name))); } } return filesWithExtensions; } //# sourceMappingURL=android-wizard.js.map