agentic-qe
Version:
Agentic Quality Engineering Fleet System - AI-driven quality management platform
203 lines • 9.27 kB
JavaScript
;
/**
* 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