@sentry/wizard
Version:
Sentry wizard helping you to configure your project
159 lines (157 loc) • 8.82 kB
JavaScript
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
;