UNPKG

devibe

Version:

Intelligent repository cleanup with auto mode, AI learning, markdown consolidation, auto-consolidate workflow, context-aware classification, and cost optimization

270 lines 8.97 kB
import * as fs from 'fs/promises'; import * as path from 'path'; import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); export class BuildDetector { async detect(projectPath) { const technologies = []; // Check for Node.js if (await this.fileExists(path.join(projectPath, 'package.json'))) { technologies.push('nodejs'); } // Check for Docker if (await this.fileExists(path.join(projectPath, 'Dockerfile'))) { technologies.push('docker'); } // Check for Python if ((await this.fileExists(path.join(projectPath, 'setup.py'))) || (await this.fileExists(path.join(projectPath, 'pyproject.toml')))) { technologies.push('python'); } // Check for Go if (await this.fileExists(path.join(projectPath, 'go.mod'))) { technologies.push('go'); } return technologies; } async fileExists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } } export class NodeJSBuildValidator { technology = 'nodejs'; async canValidate(projectPath) { try { await fs.access(path.join(projectPath, 'package.json')); return true; } catch { return false; } } async runBuild(projectPath) { const startTime = Date.now(); try { // Check if build script exists const packageJsonPath = path.join(projectPath, 'package.json'); const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8')); if (!packageJson.scripts?.build) { return { success: true, exitCode: 0, duration: Date.now() - startTime, stdout: '', stderr: '', recommendation: '⚠️ No build script found in package.json\n' + ' Skipping build validation (not blocking)\n' + ' To enable: Add "build": "tsc" or your build command to package.json scripts', }; } const { stdout, stderr } = await execAsync('npm run build', { cwd: projectPath, timeout: 60000, // 60 second timeout }); return { success: true, exitCode: 0, duration: Date.now() - startTime, stdout, stderr, }; } catch (error) { // Check if it's a missing script error if (error.message?.includes('missing script')) { return { success: true, exitCode: 0, duration: Date.now() - startTime, stdout: '', stderr: '', recommendation: '⚠️ Build script not configured\n' + ' This project may not require a build step\n' + ' To add one: Add "build": "your-command" to package.json scripts', }; } return { success: false, exitCode: error.code || 1, duration: Date.now() - startTime, stdout: error.stdout || '', stderr: error.stderr || error.message, recommendation: '💡 Build failed. Possible fixes:\n' + ' • Run "npm install" to ensure dependencies are installed\n' + ' • Check for TypeScript errors if using tsc\n' + ' • Review build script in package.json\n' + ' • Run "npm run build" manually to see full error', }; } } } export class DockerBuildValidator { technology = 'docker'; async canValidate(projectPath) { try { await fs.access(path.join(projectPath, 'Dockerfile')); return true; } catch { return false; } } async runBuild(projectPath) { const startTime = Date.now(); try { // For safety, we only validate Dockerfile syntax, not actually build const dockerfilePath = path.join(projectPath, 'Dockerfile'); const content = await fs.readFile(dockerfilePath, 'utf-8'); // Basic validation: check for FROM instruction if (!content.match(/^FROM\s+/m)) { throw new Error('Invalid Dockerfile: missing FROM instruction'); } return { success: true, exitCode: 0, duration: Date.now() - startTime, stdout: 'Dockerfile syntax valid', stderr: '', }; } catch (error) { return { success: false, exitCode: 1, duration: Date.now() - startTime, stdout: '', stderr: error.message, }; } } } export class PythonBuildValidator { technology = 'python'; async canValidate(projectPath) { try { await fs.access(path.join(projectPath, 'setup.py')); return true; } catch { try { await fs.access(path.join(projectPath, 'pyproject.toml')); return true; } catch { return false; } } } async runBuild(projectPath) { const startTime = Date.now(); try { const { stdout, stderr } = await execAsync('python -m py_compile *.py', { cwd: projectPath, timeout: 30000, }); return { success: true, exitCode: 0, duration: Date.now() - startTime, stdout, stderr, }; } catch (error) { return { success: false, exitCode: error.code || 1, duration: Date.now() - startTime, stdout: error.stdout || '', stderr: error.stderr || error.message, }; } } } export class GoBuildValidator { technology = 'go'; async canValidate(projectPath) { try { await fs.access(path.join(projectPath, 'go.mod')); return true; } catch { return false; } } async runBuild(projectPath) { const startTime = Date.now(); try { const { stdout, stderr } = await execAsync('go build ./...', { cwd: projectPath, timeout: 60000, }); return { success: true, exitCode: 0, duration: Date.now() - startTime, stdout, stderr, }; } catch (error) { return { success: false, exitCode: error.code || 1, duration: Date.now() - startTime, stdout: error.stdout || '', stderr: error.stderr || error.message, }; } } } export class BuildValidationService { validators; constructor() { this.validators = new Map([ ['nodejs', new NodeJSBuildValidator()], ['docker', new DockerBuildValidator()], ['python', new PythonBuildValidator()], ['go', new GoBuildValidator()], ]); } async validateBuild(projectPath, technology) { const validator = this.validators.get(technology); if (!validator) { throw new Error(`No validator for technology: ${technology}`); } if (!(await validator.canValidate(projectPath))) { throw new Error(`Cannot validate ${technology} build at ${projectPath}`); } return validator.runBuild(projectPath); } async validateAllBuilds(projectPath) { const detector = new BuildDetector(); const technologies = await detector.detect(projectPath); const results = new Map(); for (const tech of technologies) { try { const result = await this.validateBuild(projectPath, tech); results.set(tech, result); } catch (error) { results.set(tech, { success: false, exitCode: 1, duration: 0, stdout: '', stderr: error.message, }); } } return results; } } //# sourceMappingURL=build-validator.js.map