UNPKG

@sentry/wizard

Version:

Sentry wizard helping you to configure your project

155 lines (138 loc) 4.17 kB
import * as fs from 'fs'; import * as path from 'path'; import * as templates from './templates'; import { askForItemSelection } from '../utils/clack-utils'; // @ts-ignore - clack is ESM and TS complains about that. It works though import clack from '@clack/prompts'; export function fastFile(projectPath: string): string | null { const fastlanePath = path.join(projectPath, 'fastlane', 'Fastfile'); return fs.existsSync(fastlanePath) ? fastlanePath : null; } function findIOSPlatform( content: string, ): { index: number; length: number } | null { const platformRegex = /^ *platform\s+:([^ ]+)[^\n]*\n/gim; let match = platformRegex.exec(content); if (!match) { // No platform found, treat whole file as one platform. return { index: 0, length: content.length }; } let index = -1; while (match) { if (match[1] === 'ios') { index = match.index + match[0].length; break; } match = platformRegex.exec(content); } if (index === -1) { return null; } //After finding the platform, we need to find the end of the platform block. //This solution has the assumption that the file is well formed, //which is not a perfect solution, but it's good enough assumption. const platformEndRegex = /^end[^\n]*/gim; match = platformEndRegex.exec(content.slice(index)); if (!match) { return null; } return { index, length: match.index }; } function findLanes( content: string, ): { index: number; length: number; name: string }[] | null { const laneRegex = /^ {2}lane\s+:([^ ]+)[^\n]*\n/gim; let match = laneRegex.exec(content); if (!match) { return null; } const lanes: { index: number; length: number; name: string }[] = []; while (match) { const laneEnd = /^ {2}end/m.exec( content.slice(match.index + match[0].length), ); if (laneEnd === null) { return null; } lanes.push({ index: match.index + match[0].length, length: laneEnd.index, name: match[1], }); match = laneRegex.exec(content); } return lanes; } function addSentryToLane( content: string, lane: { index: number; length: number; name: string }, org: string, project: string, ): string { const laneContent = content.slice(lane.index, lane.index + lane.length); const sentryCLIMatch = /sentry_cli\s*\([^)]+\)/gim.exec(laneContent); if (sentryCLIMatch) { // Sentry already added to lane. Update it. return ( content.slice(0, sentryCLIMatch.index + lane.index) + templates.getFastlaneSnippet(org, project).trim() + content.slice( sentryCLIMatch.index + sentryCLIMatch[0].length + lane.index, ) ); } // Sentry not added to lane. Add it. return ( content.slice(0, lane.index + lane.length) + '\n' + templates.getFastlaneSnippet(org, project) + '\n' + content.slice(lane.index + lane.length) ); } export async function addSentryToFastlane( projectPath: string, org: string, project: string, ): Promise<boolean> { const fastFilePath = fastFile(projectPath); if (!fastFilePath) { return false; } const fileContent = fs.readFileSync(fastFilePath, 'utf8'); const platform = findIOSPlatform(fileContent); if (!platform) { return false; } const platformContent = fileContent.slice( platform.index, platform.index + platform.length, ); const lanes = findLanes(platformContent); lanes?.forEach((l) => (l.index += platform.index)); if (!lanes || lanes.length === 0) { clack.log.warn('No suitable lanes in your Fastfile.'); return false; } let newFileContent: string | undefined; if (lanes.length === 1) { newFileContent = addSentryToLane(fileContent, lanes[0], org, project); } else { const laneNames = lanes.map((l) => l.name); const selectedLane = await askForItemSelection( laneNames, 'Select lane to add Sentry to:', ); if (selectedLane === undefined) { return false; } newFileContent = addSentryToLane( fileContent, lanes[selectedLane.index], org, project, ); } fs.writeFileSync(fastFilePath, newFileContent, 'utf8'); return true; }