UNPKG

agentic-qe

Version:

Agentic Quality Engineering Fleet System - AI-driven quality management platform

203 lines 9.27 kB
"use strict"; /** * Quality Gate Command * Execute quality gates with configurable thresholds */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createQualityGateCommand = exports.QualityGateExecutor = void 0; const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const child_process_1 = require("child_process"); const util_1 = require("util"); const execAsync = (0, util_1.promisify)(child_process_1.exec); class QualityGateExecutor { constructor(config = {}) { this.config = { coverage: config.coverage ?? 80, complexity: config.complexity ?? 10, maintainability: config.maintainability ?? 65, duplications: config.duplications ?? 3, securityHotspots: config.securityHotspots ?? 0, bugs: config.bugs ?? 0, vulnerabilities: config.vulnerabilities ?? 0, }; } async execute() { const metrics = await this.collectMetrics(); const violations = this.checkThresholds(metrics); const passed = violations.length === 0; const result = { passed, metrics, violations, timestamp: new Date().toISOString(), }; // Store result in shared memory await this.storeInMemory(result); return result; } async collectMetrics() { // Simulate metrics collection - in real implementation, integrate with SonarQube, Codecov, etc. return { coverage: await this.getCoverage(), complexity: await this.getComplexity(), maintainability: await this.getMaintainability(), duplications: await this.getDuplications(), securityHotspots: await this.getSecurityHotspots(), bugs: await this.getBugs(), vulnerabilities: await this.getVulnerabilities(), }; } async getCoverage() { try { // Try to read coverage from jest/nyc const { stdout } = await execAsync('npx nyc report --reporter=json-summary 2>/dev/null || echo "{}"'); const coverage = JSON.parse(stdout); return coverage?.total?.lines?.pct ?? 0; } catch { return 0; } } async getComplexity() { // Placeholder - integrate with complexity analysis tools return Math.random() * 15; } async getMaintainability() { // Placeholder - integrate with maintainability index tools return 60 + Math.random() * 30; } async getDuplications() { // Placeholder - integrate with duplication detection return Math.random() * 5; } async getSecurityHotspots() { // Placeholder - integrate with security scanners return Math.floor(Math.random() * 3); } async getBugs() { // Placeholder - integrate with static analysis return Math.floor(Math.random() * 2); } async getVulnerabilities() { // Placeholder - integrate with vulnerability scanners return Math.floor(Math.random() * 2); } checkThresholds(metrics) { const violations = []; if (metrics.coverage < this.config.coverage) { violations.push(`Coverage ${metrics.coverage.toFixed(1)}% < ${this.config.coverage}%`); } if (metrics.complexity > this.config.complexity) { violations.push(`Complexity ${metrics.complexity.toFixed(1)} > ${this.config.complexity}`); } if (metrics.maintainability < this.config.maintainability) { violations.push(`Maintainability ${metrics.maintainability.toFixed(1)} < ${this.config.maintainability}`); } if (metrics.duplications > this.config.duplications) { violations.push(`Duplications ${metrics.duplications.toFixed(1)}% > ${this.config.duplications}%`); } if (metrics.securityHotspots > this.config.securityHotspots) { violations.push(`Security Hotspots ${metrics.securityHotspots} > ${this.config.securityHotspots}`); } if (metrics.bugs > this.config.bugs) { violations.push(`Bugs ${metrics.bugs} > ${this.config.bugs}`); } if (metrics.vulnerabilities > this.config.vulnerabilities) { violations.push(`Vulnerabilities ${metrics.vulnerabilities} > ${this.config.vulnerabilities}`); } return violations; } async storeInMemory(result) { try { await execAsync(`npx claude-flow@alpha hooks post-edit --file "quality-gate" --memory-key "aqe/swarm/quality-cli-commands/gate-result" --metadata '${JSON.stringify(result)}'`); } catch (error) { // Memory storage is optional console.warn('Failed to store in memory:', error); } } displayResults(result) { console.log('\n' + chalk_1.default.bold('Quality Gate Results')); console.log(chalk_1.default.gray('─'.repeat(60))); // Display metrics console.log(chalk_1.default.bold('\nMetrics:')); this.displayMetric('Coverage', result.metrics.coverage, '%', this.config.coverage); this.displayMetric('Complexity', result.metrics.complexity, '', this.config.complexity, true); this.displayMetric('Maintainability', result.metrics.maintainability, '', this.config.maintainability); this.displayMetric('Duplications', result.metrics.duplications, '%', this.config.duplications, true); this.displayMetric('Security Hotspots', result.metrics.securityHotspots, '', this.config.securityHotspots, true); this.displayMetric('Bugs', result.metrics.bugs, '', this.config.bugs, true); this.displayMetric('Vulnerabilities', result.metrics.vulnerabilities, '', this.config.vulnerabilities, true); // Display violations if (result.violations.length > 0) { console.log('\n' + chalk_1.default.red.bold('❌ Violations:')); result.violations.forEach((v) => console.log(chalk_1.default.red(` • ${v}`))); } // Display final result console.log('\n' + chalk_1.default.gray('─'.repeat(60))); if (result.passed) { console.log(chalk_1.default.green.bold('✓ Quality Gate PASSED')); } else { console.log(chalk_1.default.red.bold('✗ Quality Gate FAILED')); } console.log(chalk_1.default.gray(`Timestamp: ${result.timestamp}\n`)); } displayMetric(name, value, unit, threshold, inverse = false) { const passes = inverse ? value <= threshold : value >= threshold; const color = passes ? chalk_1.default.green : chalk_1.default.red; const icon = passes ? '✓' : '✗'; const comparison = inverse ? '<=' : '>='; console.log(` ${color(icon)} ${name.padEnd(20)} ${color(value.toFixed(1) + unit)} (${comparison} ${threshold}${unit})`); } } exports.QualityGateExecutor = QualityGateExecutor; function createQualityGateCommand() { const command = new commander_1.Command('gate') .description('Execute quality gates with configurable thresholds') .option('--coverage <number>', 'Minimum code coverage percentage', '80') .option('--complexity <number>', 'Maximum cyclomatic complexity', '10') .option('--maintainability <number>', 'Minimum maintainability index', '65') .option('--duplications <number>', 'Maximum duplication percentage', '3') .option('--security-hotspots <number>', 'Maximum security hotspots', '0') .option('--bugs <number>', 'Maximum bugs', '0') .option('--vulnerabilities <number>', 'Maximum vulnerabilities', '0') .option('--json', 'Output results as JSON') .action(async (options) => { const spinner = (0, ora_1.default)('Executing quality gate...').start(); try { const config = { coverage: parseFloat(options.coverage), complexity: parseFloat(options.complexity), maintainability: parseFloat(options.maintainability), duplications: parseFloat(options.duplications), securityHotspots: parseInt(options.securityHotspots), bugs: parseInt(options.bugs), vulnerabilities: parseInt(options.vulnerabilities), }; const executor = new QualityGateExecutor(config); const result = await executor.execute(); spinner.stop(); if (options.json) { console.log(JSON.stringify(result, null, 2)); } else { executor.displayResults(result); } process.exit(result.passed ? 0 : 1); } catch (error) { spinner.fail('Quality gate execution failed'); console.error(chalk_1.default.red('Error:'), error); process.exit(1); } }); return command; } exports.createQualityGateCommand = createQualityGateCommand; //# sourceMappingURL=gate.js.map