run-quality-checks.sh•13.8 kB
#!/bin/bash
/**
* EuConquisto Composer MCP Server - Quality Checks Script
*
* @version 0.1.0
* @created 2025-06-08
* @updated 2025-06-08
* @author EuConquisto Development Team
*
* @description Automated quality assurance script running linting, testing,
* coverage analysis, and code quality metrics validation.
*
* @testStatus PENDING
* @coverage N/A
*
* @dependencies
* - npm
* - ESLint
* - Jest
* - TypeScript
*
* @supersedes N/A
* @supersededBy N/A
*/
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
# Quality thresholds
MIN_COVERAGE=80
MAX_COMPLEXITY=10
MAX_LINES_PER_FILE=500
MAX_FUNCTIONS_PER_FILE=20
# Function to print colored output
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
print_metric() {
echo -e "${PURPLE}[METRIC]${NC} $1"
}
# Function to run TypeScript compilation
run_typescript_check() {
print_status "Running TypeScript compilation check..."
if npm run build > /tmp/tsc-output.log 2>&1; then
print_success "TypeScript compilation passed"
return 0
else
print_error "TypeScript compilation failed"
cat /tmp/tsc-output.log
return 1
fi
}
# Function to run ESLint
run_eslint() {
print_status "Running ESLint analysis..."
# Run ESLint and capture output
if npm run lint > /tmp/eslint-output.log 2>&1; then
print_success "ESLint analysis passed"
# Count warnings if any
WARNINGS=$(grep -c "warning" /tmp/eslint-output.log || echo "0")
if [ "$WARNINGS" -gt 0 ]; then
print_warning "Found $WARNINGS ESLint warnings"
fi
return 0
else
print_error "ESLint analysis failed"
cat /tmp/eslint-output.log
return 1
fi
}
# Function to run tests with coverage
run_tests_with_coverage() {
print_status "Running test suite with coverage..."
if npm run test:coverage > /tmp/test-output.log 2>&1; then
print_success "Test suite passed"
# Extract coverage information
COVERAGE=$(grep -o "All files.*[0-9]\+\.[0-9]\+" /tmp/test-output.log | tail -1 | grep -o "[0-9]\+\.[0-9]\+" || echo "0")
if [ -n "$COVERAGE" ]; then
print_metric "Test coverage: $COVERAGE%"
# Check if coverage meets minimum requirement
if (( $(echo "$COVERAGE >= $MIN_COVERAGE" | bc -l) )); then
print_success "Coverage meets minimum requirement ($MIN_COVERAGE%)"
else
print_warning "Coverage below minimum requirement ($MIN_COVERAGE%). Current: $COVERAGE%"
fi
fi
return 0
else
print_error "Test suite failed"
cat /tmp/test-output.log
return 1
fi
}
# Function to analyze code complexity
analyze_code_complexity() {
print_status "Analyzing code complexity..."
# Count files and functions
TS_FILES=$(find src -name "*.ts" | wc -l)
TOTAL_LINES=$(find src -name "*.ts" -exec wc -l {} + | tail -1 | awk '{print $1}')
print_metric "TypeScript files: $TS_FILES"
print_metric "Total lines of code: $TOTAL_LINES"
# Check for large files
LARGE_FILES=$(find src -name "*.ts" -exec wc -l {} + | awk -v max="$MAX_LINES_PER_FILE" '$1 > max {print $2 " (" $1 " lines)"}')
if [ -n "$LARGE_FILES" ]; then
print_warning "Large files detected (>$MAX_LINES_PER_FILE lines):"
echo "$LARGE_FILES"
else
print_success "No overly large files detected"
fi
# Average lines per file
if [ "$TS_FILES" -gt 0 ]; then
AVG_LINES=$((TOTAL_LINES / TS_FILES))
print_metric "Average lines per file: $AVG_LINES"
fi
}
# Function to check version consistency
check_version_consistency() {
print_status "Checking version consistency..."
# Get versions from different files
PROJECT_VERSION=$(grep '"version"' package.json | cut -d'"' -f4)
VERSION_FILE_VERSION=$(grep "Version.*:" VERSION | head -1 | sed 's/.*: *//' | sed 's/ .*//')
README_VERSION=$(grep "Version.*:" README.md | head -1 | sed 's/.*: *//' | sed 's/ .*//')
print_metric "package.json version: $PROJECT_VERSION"
print_metric "VERSION file version: $VERSION_FILE_VERSION"
print_metric "README.md version: $README_VERSION"
if [ "$PROJECT_VERSION" = "$VERSION_FILE_VERSION" ] && [ "$PROJECT_VERSION" = "$README_VERSION" ]; then
print_success "Version consistency validated"
VERSION_CONSISTENT="true"
else
print_error "Version inconsistency detected"
VERSION_CONSISTENT="false"
return 1
fi
}
# Function to check file version headers
check_file_headers() {
print_status "Checking file version headers..."
# Check TypeScript files
TS_FILES_TOTAL=$(find src -name "*.ts" | wc -l)
TS_FILES_WITH_HEADERS=$(find src -name "*.ts" -exec grep -l "@version" {} + | wc -l)
print_metric "TypeScript files: $TS_FILES_TOTAL"
print_metric "Files with version headers: $TS_FILES_WITH_HEADERS"
if [ "$TS_FILES_TOTAL" -eq "$TS_FILES_WITH_HEADERS" ]; then
print_success "All TypeScript files have version headers"
HEADERS_COMPLETE="true"
else
MISSING_HEADERS=$((TS_FILES_TOTAL - TS_FILES_WITH_HEADERS))
print_warning "$MISSING_HEADERS TypeScript files missing version headers"
HEADERS_COMPLETE="false"
fi
}
# Function to validate project metadata
validate_project_metadata() {
print_status "Validating project metadata..."
if [ -f "project.json" ]; then
# Check if project.json is valid JSON
if jq empty project.json 2>/dev/null; then
PROJECT_VERSION_JSON=$(jq -r '.project.version' project.json)
COMPLETED_TASKS=$(jq -r '.development.completedTasks' project.json)
print_metric "project.json version: $PROJECT_VERSION_JSON"
print_metric "Completed tasks: $COMPLETED_TASKS/15"
if [ "$PROJECT_VERSION" = "$PROJECT_VERSION_JSON" ]; then
print_success "project.json metadata synchronized"
METADATA_VALID="true"
else
print_warning "project.json version mismatch"
METADATA_VALID="false"
fi
else
print_error "project.json is not valid JSON"
METADATA_VALID="false"
fi
else
print_warning "project.json not found"
METADATA_VALID="false"
fi
}
# Function to check documentation coverage
check_documentation_coverage() {
print_status "Checking documentation coverage..."
# Count files with JSDoc comments
FILES_WITH_DOCS=$(find src -name "*.ts" -exec grep -l "/\*\*" {} + | wc -l)
TOTAL_TS_FILES=$(find src -name "*.ts" | wc -l)
if [ "$TOTAL_TS_FILES" -gt 0 ]; then
DOC_COVERAGE=$((FILES_WITH_DOCS * 100 / TOTAL_TS_FILES))
print_metric "Documentation coverage: $DOC_COVERAGE% ($FILES_WITH_DOCS/$TOTAL_TS_FILES files)"
if [ "$DOC_COVERAGE" -ge 80 ]; then
print_success "Documentation coverage is good"
else
print_warning "Documentation coverage could be improved"
fi
fi
# Check for README files
README_FILES=$(find . -name "README.md" | wc -l)
print_metric "README files: $README_FILES"
}
# Function to check security vulnerabilities
check_security() {
print_status "Checking for security vulnerabilities..."
if command -v npm >/dev/null 2>&1; then
if npm audit --audit-level=moderate > /tmp/audit-output.log 2>&1; then
print_success "No moderate or high security vulnerabilities found"
else
VULNERABILITIES=$(grep -c "vulnerabilities" /tmp/audit-output.log || echo "0")
if [ "$VULNERABILITIES" -gt 0 ]; then
print_warning "Security vulnerabilities detected - run 'npm audit' for details"
else
print_success "Security audit completed"
fi
fi
else
print_warning "npm not available for security audit"
fi
}
# Function to check Git status
check_git_status() {
print_status "Checking Git status..."
if [ -d ".git" ]; then
# Check for uncommitted changes
if [ -n "$(git status --porcelain)" ]; then
print_warning "Uncommitted changes detected"
git status --short
else
print_success "Working directory is clean"
fi
# Check current branch
CURRENT_BRANCH=$(git branch --show-current)
print_metric "Current branch: $CURRENT_BRANCH"
# Check for unpushed commits
UNPUSHED=$(git log @{u}.. --oneline 2>/dev/null | wc -l || echo "0")
if [ "$UNPUSHED" -gt 0 ]; then
print_warning "$UNPUSHED unpushed commits"
else
print_success "All commits are pushed"
fi
else
print_warning "Not a Git repository"
fi
}
# Function to generate quality report
generate_quality_report() {
print_status "Generating quality report..."
REPORT_DIR="validation/quality-metrics"
REPORT_FILE="$REPORT_DIR/quality-report-$(date +%Y%m%d-%H%M%S).json"
mkdir -p "$REPORT_DIR"
# Create JSON report
cat > "$REPORT_FILE" << EOF
{
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"version": "0.1.0",
"metrics": {
"coverage": ${COVERAGE:-0},
"files": {
"total": $TS_FILES,
"totalLines": $TOTAL_LINES,
"averageLines": ${AVG_LINES:-0},
"withDocumentation": $FILES_WITH_DOCS
},
"documentation": {
"coverage": ${DOC_COVERAGE:-0},
"readmeFiles": $README_FILES
},
"quality": {
"minimumCoverage": $MIN_COVERAGE,
"maxLinesPerFile": $MAX_LINES_PER_FILE,
"coverageMet": $([ "${COVERAGE:-0}" -ge "$MIN_COVERAGE" ] && echo "true" || echo "false")
},
"versioning": {
"consistent": $([ "${VERSION_CONSISTENT:-false}" = "true" ] && echo "true" || echo "false"),
"headersComplete": $([ "${HEADERS_COMPLETE:-false}" = "true" ] && echo "true" || echo "false"),
"metadataValid": $([ "${METADATA_VALID:-false}" = "true" ] && echo "true" || echo "false")
}
},
"checks": {
"typescript": $([ "$TYPESCRIPT_PASSED" = "true" ] && echo "true" || echo "false"),
"eslint": $([ "$ESLINT_PASSED" = "true" ] && echo "true" || echo "false"),
"tests": $([ "$TESTS_PASSED" = "true" ] && echo "true" || echo "false"),
"security": $([ "$SECURITY_PASSED" = "true" ] && echo "true" || echo "false")
}
}
EOF
print_success "Quality report generated: $REPORT_FILE"
}
# Function to display summary
display_summary() {
echo ""
echo "=============================================="
echo "📊 Quality Check Summary"
echo "=============================================="
echo ""
# Calculate overall score
PASSED_CHECKS=0
TOTAL_CHECKS=4
[ "$TYPESCRIPT_PASSED" = "true" ] && PASSED_CHECKS=$((PASSED_CHECKS + 1))
[ "$ESLINT_PASSED" = "true" ] && PASSED_CHECKS=$((PASSED_CHECKS + 1))
[ "$TESTS_PASSED" = "true" ] && PASSED_CHECKS=$((PASSED_CHECKS + 1))
[ "$SECURITY_PASSED" = "true" ] && PASSED_CHECKS=$((PASSED_CHECKS + 1))
SCORE=$((PASSED_CHECKS * 100 / TOTAL_CHECKS))
echo "Overall Score: $SCORE% ($PASSED_CHECKS/$TOTAL_CHECKS checks passed)"
echo ""
echo "Check Results:"
echo " TypeScript Compilation: $([ "$TYPESCRIPT_PASSED" = "true" ] && echo "✅ PASSED" || echo "❌ FAILED")"
echo " ESLint Analysis: $([ "$ESLINT_PASSED" = "true" ] && echo "✅ PASSED" || echo "❌ FAILED")"
echo " Test Suite: $([ "$TESTS_PASSED" = "true" ] && echo "✅ PASSED" || echo "❌ FAILED")"
echo " Security Audit: $([ "$SECURITY_PASSED" = "true" ] && echo "✅ PASSED" || echo "❌ FAILED")"
echo ""
echo "Metrics:"
echo " Test Coverage: ${COVERAGE:-0}% (minimum: $MIN_COVERAGE%)"
echo " Documentation Coverage: ${DOC_COVERAGE:-0}%"
echo " Total Files: $TS_FILES"
echo " Total Lines: $TOTAL_LINES"
echo ""
if [ "$SCORE" -ge 75 ]; then
print_success "Quality checks passed! 🎉"
return 0
else
print_warning "Quality checks need attention 🔧"
return 1
fi
}
# Main execution
main() {
echo "=============================================="
echo "🔍 EuConquisto Composer MCP Server - Quality Checks"
echo "=============================================="
echo ""
# Initialize status variables
TYPESCRIPT_PASSED="false"
ESLINT_PASSED="false"
TESTS_PASSED="false"
SECURITY_PASSED="false"
# Run checks
if run_typescript_check; then
TYPESCRIPT_PASSED="true"
fi
if run_eslint; then
ESLINT_PASSED="true"
fi
if run_tests_with_coverage; then
TESTS_PASSED="true"
fi
if check_security; then
SECURITY_PASSED="true"
fi
# Additional analysis
analyze_code_complexity
check_documentation_coverage
check_git_status
# Version validation
check_version_consistency
check_file_headers
validate_project_metadata
# Generate report
generate_quality_report
# Display summary
display_summary
}
# Execute main function
main "$@"