UNPKG

perf-audit-cli

Version:

CLI tool for continuous performance monitoring and analysis

160 lines 5.75 kB
import fs from 'fs'; import path from 'path'; import readline from 'readline'; import { CACHE_DIRECTORY, CACHE_RETENTION_DAYS, DEFAULT_RETENTION_DAYS, MILLISECONDS_PER_DAY, REPORT_EXTENSIONS, } from "../constants/index.js"; import { PerformanceDatabaseService } from "../core/database/index.js"; import { loadConfig } from "../utils/config.js"; import { Logger } from "../utils/logger.js"; export const cleanCommand = async (options) => { Logger.section('Cleaning performance data...'); try { const config = await loadConfig(); if (options.all) { await cleanAllData(config, options.force); } else { const retentionDays = options.days ?? DEFAULT_RETENTION_DAYS; await cleanOldData(config, retentionDays, options.force); } } catch (error) { handleCleanError(error); } }; const cleanAllData = async (config, force = false) => { if (!force) { const confirmed = await confirmAction('This will delete ALL performance data including database and reports. Are you sure?'); if (!confirmed) { Logger.warn('Clean cancelled.'); return; } } await cleanDatabase(); const deletedReportsCount = cleanAllReports(config); cleanCacheDirectory(); Logger.success(`${deletedReportsCount} report files deleted`); Logger.complete('All performance data has been cleaned!'); }; const cleanOldData = async (config, days, force = false) => { if (!force) { const confirmed = await confirmAction(`This will delete performance data older than ${days} days. Are you sure?`); if (!confirmed) { Logger.warn('Clean cancelled.'); return; } } const deletedBuilds = await cleanOldDatabaseRecords(days); const deletedReportsCount = cleanOldReports(config, days); cleanOldCacheFiles(); Logger.success(`${deletedBuilds} old builds deleted from database`); Logger.success(`${deletedReportsCount} old report files deleted`); Logger.success('Old cache files cleaned'); Logger.complete(`Performance data older than ${days} days has been cleaned!`); }; const cleanDatabase = async () => { const service = await PerformanceDatabaseService.instance(); await service.cleanDatabase(); }; const cleanAllReports = (config) => { const reportsDir = path.resolve(config.reports.outputDir); if (!fs.existsSync(reportsDir)) { return 0; } const files = fs.readdirSync(reportsDir); let deletedCount = 0; for (const file of files) { if (isReportFile(file)) { const filePath = path.join(reportsDir, file); fs.unlinkSync(filePath); deletedCount++; } } return deletedCount; }; const cleanCacheDirectory = () => { const cacheDir = path.resolve(CACHE_DIRECTORY); if (fs.existsSync(cacheDir)) { fs.rmSync(cacheDir, { recursive: true, force: true }); fs.mkdirSync(cacheDir, { recursive: true }); Logger.success('Cache directory cleaned'); } }; const cleanOldDatabaseRecords = async (days) => { const db = await PerformanceDatabaseService.instance(); const deletedBuilds = await db.cleanup(days); await db.close(); return deletedBuilds; }; const cleanOldReports = (config, days) => { const reportsDir = path.resolve(config.reports.outputDir); if (!fs.existsSync(reportsDir)) { return 0; } const cutoffTime = calculateCutoffTime(days); const files = fs.readdirSync(reportsDir); let deletedCount = 0; for (const file of files) { const filePath = path.join(reportsDir, file); const stats = fs.statSync(filePath); if (stats.mtimeMs < cutoffTime && isReportFile(file)) { fs.unlinkSync(filePath); deletedCount++; } } return deletedCount; }; const cleanOldCacheFiles = () => { const cacheDir = path.resolve(CACHE_DIRECTORY); if (fs.existsSync(cacheDir)) { const cutoffTime = calculateCutoffTime(CACHE_RETENTION_DAYS); cleanDirectoryRecursive(cacheDir, cutoffTime); } }; const calculateCutoffTime = (days) => { return Date.now() - (days * MILLISECONDS_PER_DAY); }; const isReportFile = (fileName) => { return REPORT_EXTENSIONS.some(ext => fileName.endsWith(ext)); }; const cleanDirectoryRecursive = (dir, cutoffTime) => { const items = fs.readdirSync(dir); for (const item of items) { const itemPath = path.join(dir, item); const stats = fs.statSync(itemPath); if (stats.isDirectory()) { cleanDirectoryRecursive(itemPath, cutoffTime); removeEmptyDirectory(itemPath); } else if (isOldFile(stats, cutoffTime)) { fs.unlinkSync(itemPath); } } }; const isOldFile = (stats, cutoffTime) => { return stats.mtimeMs < cutoffTime; }; const removeEmptyDirectory = (dirPath) => { const remainingItems = fs.readdirSync(dirPath); if (remainingItems.length === 0) { fs.rmdirSync(dirPath); } }; const confirmAction = async (message) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise(resolve => { rl.question(Logger.prompt(`${message} (y/N): `), answer => { rl.close(); const normalizedAnswer = answer.toLowerCase(); resolve(normalizedAnswer === 'y' || normalizedAnswer === 'yes'); }); }); }; const handleCleanError = (error) => { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; Logger.error('Clean failed', { error: errorMessage }); process.exit(1); }; //# sourceMappingURL=clean.js.map