- Fix JS-008: Replace raw fetch() with apiClient in letzshop-vendor-directory.js - Fix JS-005: Add init guard to letzshop-vendor-directory.js - Fix JS-004: Increase search region in validator (800→2000 chars) to detect currentPage in files with setup code before return statement - Fix JS-001: Use centralized logger in media-picker.js - Fix API-002: Move database query from onboarding.py to order_service.py - Fix FE-001: Add noqa comment to search.html (shop uses custom themed pagination) - Add audit validator to validate_all.py script - Update frontend.yaml with vendor exclusion pattern Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
248 lines
8.9 KiB
Python
Executable File
248 lines
8.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Unified Code Validator
|
|
======================
|
|
Runs all validation scripts (architecture, security, performance, audit) in sequence.
|
|
|
|
This provides a single entry point for comprehensive code validation,
|
|
useful for CI/CD pipelines and pre-commit hooks.
|
|
|
|
Usage:
|
|
python scripts/validate_all.py # Run all validators
|
|
python scripts/validate_all.py --security # Run only security validator
|
|
python scripts/validate_all.py --performance # Run only performance validator
|
|
python scripts/validate_all.py --architecture # Run only architecture validator
|
|
python scripts/validate_all.py --audit # Run only audit validator
|
|
python scripts/validate_all.py -v # Verbose output
|
|
python scripts/validate_all.py --fail-fast # Stop on first failure
|
|
python scripts/validate_all.py --json # JSON output
|
|
|
|
Options:
|
|
--architecture Run architecture validator
|
|
--security Run security validator
|
|
--performance Run performance validator
|
|
--audit Run audit validator
|
|
--fail-fast Stop on first validator failure
|
|
-v, --verbose Show detailed output
|
|
--errors-only Only show errors
|
|
--json Output results as JSON
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add parent directory to path for imports
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
|
|
def run_architecture_validator(verbose: bool = False) -> tuple[int, dict]:
|
|
"""Run the architecture validator"""
|
|
try:
|
|
# Import dynamically to avoid circular imports
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
from scripts.validate_architecture import ArchitectureValidator
|
|
|
|
config_path = Path.cwd() / ".architecture-rules.yaml"
|
|
validator = ArchitectureValidator(config_path=config_path, verbose=verbose)
|
|
result = validator.validate_all()
|
|
|
|
return (
|
|
1 if result.has_errors() else 0,
|
|
{
|
|
"name": "Architecture",
|
|
"files_checked": result.files_checked,
|
|
"errors": sum(1 for v in result.violations if v.severity.value == "error"),
|
|
"warnings": sum(1 for v in result.violations if v.severity.value == "warning"),
|
|
"info": sum(1 for v in result.violations if v.severity.value == "info"),
|
|
}
|
|
)
|
|
except ImportError as e:
|
|
print(f"⚠️ Architecture validator not available: {e}")
|
|
return 0, {"name": "Architecture", "skipped": True}
|
|
except Exception as e:
|
|
print(f"❌ Architecture validator failed: {e}")
|
|
return 1, {"name": "Architecture", "error": str(e)}
|
|
|
|
|
|
def run_security_validator(verbose: bool = False) -> tuple[int, dict]:
|
|
"""Run the security validator"""
|
|
try:
|
|
from validate_security import SecurityValidator
|
|
|
|
validator = SecurityValidator(verbose=verbose)
|
|
result = validator.validate_all()
|
|
|
|
return (
|
|
1 if result.has_errors() else 0,
|
|
{
|
|
"name": "Security",
|
|
"files_checked": result.files_checked,
|
|
"errors": result.error_count(),
|
|
"warnings": result.warning_count(),
|
|
"info": result.info_count(),
|
|
}
|
|
)
|
|
except ImportError as e:
|
|
print(f"⚠️ Security validator not available: {e}")
|
|
return 0, {"name": "Security", "skipped": True}
|
|
except Exception as e:
|
|
print(f"❌ Security validator failed: {e}")
|
|
return 1, {"name": "Security", "error": str(e)}
|
|
|
|
|
|
def run_performance_validator(verbose: bool = False) -> tuple[int, dict]:
|
|
"""Run the performance validator"""
|
|
try:
|
|
from validate_performance import PerformanceValidator
|
|
|
|
validator = PerformanceValidator(verbose=verbose)
|
|
result = validator.validate_all()
|
|
|
|
return (
|
|
1 if result.has_errors() else 0,
|
|
{
|
|
"name": "Performance",
|
|
"files_checked": result.files_checked,
|
|
"errors": result.error_count(),
|
|
"warnings": result.warning_count(),
|
|
"info": result.info_count(),
|
|
}
|
|
)
|
|
except ImportError as e:
|
|
print(f"⚠️ Performance validator not available: {e}")
|
|
return 0, {"name": "Performance", "skipped": True}
|
|
except Exception as e:
|
|
print(f"❌ Performance validator failed: {e}")
|
|
return 1, {"name": "Performance", "error": str(e)}
|
|
|
|
|
|
def run_audit_validator(verbose: bool = False) -> tuple[int, dict]:
|
|
"""Run the audit validator"""
|
|
try:
|
|
from validate_audit import AuditValidator
|
|
|
|
validator = AuditValidator()
|
|
has_errors = not validator.validate()
|
|
|
|
return (
|
|
1 if has_errors else 0,
|
|
{
|
|
"name": "Audit",
|
|
"files_checked": len(validator.files_checked) if hasattr(validator, 'files_checked') else 0,
|
|
"errors": len(validator.errors),
|
|
"warnings": len(validator.warnings),
|
|
"info": len(validator.info) if hasattr(validator, 'info') else 0,
|
|
}
|
|
)
|
|
except ImportError as e:
|
|
print(f"⚠️ Audit validator not available: {e}")
|
|
return 0, {"name": "Audit", "skipped": True}
|
|
except Exception as e:
|
|
print(f"❌ Audit validator failed: {e}")
|
|
return 1, {"name": "Audit", "error": str(e)}
|
|
|
|
|
|
def print_summary(results: list[dict], json_output: bool = False):
|
|
"""Print validation summary"""
|
|
if json_output:
|
|
print(json.dumps({"validators": results}, indent=2))
|
|
return
|
|
|
|
print("\n" + "=" * 80)
|
|
print("📊 UNIFIED VALIDATION SUMMARY")
|
|
print("=" * 80)
|
|
|
|
total_errors = 0
|
|
total_warnings = 0
|
|
total_info = 0
|
|
|
|
for result in results:
|
|
if result.get("skipped"):
|
|
print(f"\n⏭️ {result['name']}: Skipped")
|
|
elif result.get("error"):
|
|
print(f"\n❌ {result['name']}: Error - {result['error']}")
|
|
else:
|
|
errors = result.get("errors", 0)
|
|
warnings = result.get("warnings", 0)
|
|
info = result.get("info", 0)
|
|
total_errors += errors
|
|
total_warnings += warnings
|
|
total_info += info
|
|
|
|
status = "✅" if errors == 0 else "❌"
|
|
print(f"\n{status} {result['name']}:")
|
|
print(f" Files: {result.get('files_checked', 0)}")
|
|
print(f" Errors: {errors}, Warnings: {warnings}, Info: {info}")
|
|
|
|
print("\n" + "-" * 80)
|
|
print(f"TOTAL: {total_errors} errors, {total_warnings} warnings, {total_info} info")
|
|
print("=" * 80)
|
|
|
|
if total_errors > 0:
|
|
print("❌ VALIDATION FAILED")
|
|
elif total_warnings > 0:
|
|
print(f"⚠️ VALIDATION PASSED WITH {total_warnings} WARNING(S)")
|
|
else:
|
|
print("✅ VALIDATION PASSED")
|
|
print("=" * 80)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Unified code validator - runs architecture, security, performance, and audit checks",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
)
|
|
parser.add_argument("--architecture", action="store_true", help="Run architecture validator")
|
|
parser.add_argument("--security", action="store_true", help="Run security validator")
|
|
parser.add_argument("--performance", action="store_true", help="Run performance validator")
|
|
parser.add_argument("--audit", action="store_true", help="Run audit validator")
|
|
parser.add_argument("--fail-fast", action="store_true", help="Stop on first failure")
|
|
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
|
|
parser.add_argument("--errors-only", action="store_true", help="Only show errors")
|
|
parser.add_argument("--json", action="store_true", help="JSON output")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# If no specific validators selected, run all
|
|
run_all = not (args.architecture or args.security or args.performance or args.audit)
|
|
|
|
print("\n🔍 UNIFIED CODE VALIDATION")
|
|
print("=" * 80)
|
|
|
|
validators = []
|
|
if run_all or args.architecture:
|
|
validators.append(("Architecture", run_architecture_validator))
|
|
if run_all or args.security:
|
|
validators.append(("Security", run_security_validator))
|
|
if run_all or args.performance:
|
|
validators.append(("Performance", run_performance_validator))
|
|
if run_all or args.audit:
|
|
validators.append(("Audit", run_audit_validator))
|
|
|
|
results = []
|
|
exit_code = 0
|
|
|
|
for name, validator_func in validators:
|
|
print(f"\n{'=' * 40}")
|
|
print(f"🔍 Running {name} Validator...")
|
|
print("=" * 40)
|
|
|
|
code, result = validator_func(verbose=args.verbose)
|
|
|
|
results.append(result)
|
|
|
|
if code != 0:
|
|
exit_code = 1
|
|
if args.fail_fast:
|
|
print(f"\n❌ {name} validator failed. Stopping (--fail-fast)")
|
|
break
|
|
|
|
print_summary(results, json_output=args.json)
|
|
sys.exit(exit_code)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|