UNPKG

pushscript

Version:

AI-powered Git workflow automation with conventional commits, vulnerability scanning, and multi-provider LLM support

177 lines (153 loc) 5.12 kB
/** * JSON Size Limiter for PushScript * Detects and prevents committing large JSON files */ import fs from 'fs'; import path from 'path'; import { execSync } from 'child_process'; import { logWarning, logError, logInfo } from '../utils/formatting.js'; // Default size limit: 250KB (in bytes) const DEFAULT_SIZE_LIMIT = 250 * 1024; // Patterns that should always be caught regardless of size const ALWAYS_IGNORE_PATTERNS = [ 'debug-', '-debug-', '.debug.' ]; /** * Get the configured JSON size limit * @returns {number} Size limit in bytes */ export function getJsonSizeLimit() { // Allow override via environment variable const envLimit = process.env.PUSHSCRIPT_JSON_SIZE_LIMIT; if (envLimit && !isNaN(parseInt(envLimit))) { return parseInt(envLimit); } return DEFAULT_SIZE_LIMIT; } /** * Check if a file should be ignored based on size or patterns * @param {string} filePath Path to the file * @returns {boolean} True if file exceeds size limit or matches ignore patterns */ function exceedsJsonSizeLimit(filePath) { if (!filePath.toLowerCase().endsWith('.json')) { return false; } // Always ignore files matching specific patterns const fileName = path.basename(filePath); if (ALWAYS_IGNORE_PATTERNS.some(pattern => fileName.includes(pattern))) { logInfo(`File ${fileName} matches debug pattern and will be ignored`); return true; } try { const stats = fs.statSync(filePath); const sizeLimit = getJsonSizeLimit(); return stats.size > sizeLimit; } catch (error) { // If we can't check the file, assume it's fine return false; } } /** * Get list of staged JSON files that exceed size limit * @returns {Array} List of large JSON files */ export function checkLargeJsonFiles() { try { // Get all staged files const stagedFiles = execSync('git diff --cached --name-only') .toString() .trim() .split('\n') .filter(file => file); // Filter for JSON files that exceed size limit const largeJsonFiles = stagedFiles .filter(file => file.toLowerCase().endsWith('.json')) .filter(file => { try { return exceedsJsonSizeLimit(file); } catch (error) { return false; } }); return largeJsonFiles; } catch (error) { logWarning(`Error checking for large JSON files: ${error.message}`); return []; } } /** * Add files to .gitignore * @param {Array} files List of files to add to .gitignore */ export function addToGitignore(files) { if (!files || files.length === 0) { return; } try { const gitignorePath = '.gitignore'; let gitignoreContent = ''; // Read existing .gitignore if it exists if (fs.existsSync(gitignorePath)) { gitignoreContent = fs.readFileSync(gitignorePath, 'utf8'); } // Prepare entries to add const entries = files.map(file => { // Use relative path and escape special characters return file.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }); // Check if entries already exist in .gitignore const newEntries = entries.filter(entry => { const regex = new RegExp(`^${entry}$`, 'm'); return !regex.test(gitignoreContent); }); if (newEntries.length === 0) { return; } // Add new entries to .gitignore const updatedContent = gitignoreContent.endsWith('\n') || gitignoreContent === '' ? gitignoreContent + newEntries.join('\n') + '\n' : gitignoreContent + '\n' + newEntries.join('\n') + '\n'; fs.writeFileSync(gitignorePath, updatedContent); logInfo(`Added ${newEntries.length} large JSON files to .gitignore`); // Unstage the files if (newEntries.length > 0) { execSync(`git reset -- ${files.join(' ')}`); } } catch (error) { logWarning(`Error updating .gitignore: ${error.message}`); } } /** * Handle large JSON files in the commit process * @param {boolean} autoAddToGitignore Whether to automatically add large files to .gitignore * @returns {boolean} True if process should continue, false if it should abort */ export function handleLargeJsonFiles(autoAddToGitignore = false) { const largeFiles = checkLargeJsonFiles(); if (largeFiles.length === 0) { return true; } const sizeLimit = getJsonSizeLimit(); const sizeLimitMB = (sizeLimit / 1024 / 1024).toFixed(2); logWarning(`Found ${largeFiles.length} large JSON files exceeding the ${sizeLimitMB}MB limit:`); largeFiles.forEach(file => { const stats = fs.statSync(file); const sizeMB = (stats.size / 1024 / 1024).toFixed(2); logWarning(`- ${file} (${sizeMB}MB)`); }); if (autoAddToGitignore) { logInfo('Adding large JSON files to .gitignore and unstaging them...'); addToGitignore(largeFiles); return true; } else { logError('Please remove these files from your commit:'); logInfo('Options:'); logInfo('1. Run: git reset -- <file> to unstage these files'); logInfo('2. Add them to .gitignore'); logInfo('3. Set PUSHSCRIPT_JSON_SIZE_LIMIT environment variable to increase the limit'); return false; } }