Files
TimeTracker/scripts/validate-setup.py
Dries Peeters 0752332ed6 feat: Implement comprehensive CI/CD pipeline with GitHub Actions
Implement a complete, production-ready CI/CD pipeline that runs 100% on
GitHub Actions with zero external dependencies. This replaces and consolidates
existing workflows with an optimized, streamlined pipeline.

## Major Changes
- Add 3 new workflows (ci-comprehensive, cd-development, cd-release)
- Remove 2 redundant workflows (backed up)
- Add 130+ tests across 4 new test files
- Add 8 documentation guides (60+ KB)
- Add developer tools and scripts
2025-10-09 13:02:39 +02:00

269 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
TimeTracker CI/CD Setup Validation Script
Validates that all CI/CD components are properly configured
"""
import os
import sys
import subprocess
from pathlib import Path
class Colors:
"""ANSI color codes for terminal output"""
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
ENDC = '\033[0m'
BOLD = '\033[1m'
def print_header(text):
"""Print a formatted header"""
print(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.ENDC}")
print(f"{Colors.BOLD}{Colors.BLUE}{text:^60}{Colors.ENDC}")
print(f"{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.ENDC}\n")
def print_success(text):
"""Print success message"""
print(f"{Colors.GREEN}{Colors.ENDC} {text}")
def print_error(text):
"""Print error message"""
print(f"{Colors.RED}{Colors.ENDC} {text}")
def print_warning(text):
"""Print warning message"""
print(f"{Colors.YELLOW}{Colors.ENDC} {text}")
def print_info(text):
"""Print info message"""
print(f"{Colors.BLUE}{Colors.ENDC} {text}")
def check_file_exists(filepath, required=True):
"""Check if a file exists"""
path = Path(filepath)
if path.exists():
print_success(f"Found: {filepath}")
return True
else:
if required:
print_error(f"Missing required file: {filepath}")
else:
print_warning(f"Optional file not found: {filepath}")
return False
def check_python_package(package_name):
"""Check if a Python package is installed"""
try:
__import__(package_name)
print_success(f"Python package '{package_name}' is installed")
return True
except ImportError:
print_error(f"Python package '{package_name}' is NOT installed")
return False
def run_command(command, description):
"""Run a command and check if it succeeds"""
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
print_success(f"{description}: OK")
return True
else:
print_error(f"{description}: FAILED")
if result.stderr:
print(f" Error: {result.stderr[:200]}")
return False
except subprocess.TimeoutExpired:
print_error(f"{description}: TIMEOUT")
return False
except Exception as e:
print_error(f"{description}: ERROR ({str(e)})")
return False
def main():
"""Main validation function"""
print_header("TimeTracker CI/CD Setup Validation")
# Track results
checks = {
'workflows': [],
'tests': [],
'config': [],
'docs': [],
'python': []
}
# 1. Check GitHub Actions workflows
print_header("1. GitHub Actions Workflows")
workflows = [
'.github/workflows/ci-comprehensive.yml',
'.github/workflows/cd-development.yml',
'.github/workflows/cd-release.yml',
'.github/workflows/docker-publish.yml',
'.github/workflows/migration-check.yml',
]
for workflow in workflows:
checks['workflows'].append(check_file_exists(workflow))
# 2. Check test files
print_header("2. Test Files")
test_files = [
'tests/conftest.py',
'tests/test_basic.py',
'tests/test_routes.py',
'tests/test_models_comprehensive.py',
'tests/test_security.py',
'tests/test_analytics.py',
'tests/test_invoices.py',
]
for test_file in test_files:
checks['tests'].append(check_file_exists(test_file))
# 3. Check configuration files
print_header("3. Configuration Files")
config_files = [
('pytest.ini', True),
('requirements-test.txt', True),
('.pre-commit-config.yaml', False),
('Makefile', False),
('.gitignore', True),
]
for config_file, required in config_files:
checks['config'].append(check_file_exists(config_file, required))
# 4. Check documentation
print_header("4. Documentation")
docs = [
'CI_CD_DOCUMENTATION.md',
'CI_CD_QUICK_START.md',
'CI_CD_IMPLEMENTATION_SUMMARY.md',
]
for doc in docs:
checks['docs'].append(check_file_exists(doc))
# 5. Check Python dependencies
print_header("5. Python Dependencies")
packages = [
'pytest',
'flask',
'sqlalchemy',
]
for package in packages:
checks['python'].append(check_python_package(package))
# 6. Check Python test dependencies
print_header("6. Test Dependencies")
test_packages = [
'pytest',
'pytest_cov',
'pytest_flask',
'black',
'flake8',
'bandit',
]
test_deps_ok = True
for package in test_packages:
if not check_python_package(package.replace('_', '-')):
test_deps_ok = False
if not test_deps_ok:
print_info("Install test dependencies: pip install -r requirements-test.txt")
# 7. Run quick tests
print_header("7. Quick Test Validation")
# Check if pytest can discover tests
if run_command('pytest --collect-only -q', 'Test discovery'):
print_info("Tests can be discovered successfully")
# Try to run smoke tests (if they exist)
if run_command('pytest -m smoke --co -q', 'Smoke test discovery'):
print_info("Smoke tests are properly marked")
# 8. Check Docker setup
print_header("8. Docker Configuration")
docker_files = [
('Dockerfile', True),
('docker-compose.yml', True),
('.dockerignore', False),
]
for docker_file, required in docker_files:
check_file_exists(docker_file, required)
# 9. Check helper scripts
print_header("9. Helper Scripts")
scripts = [
'scripts/run-tests.sh',
'scripts/run-tests.bat',
]
for script in scripts:
check_file_exists(script, required=False)
# 10. Summary
print_header("Validation Summary")
total_checks = sum(len(v) for v in checks.values())
passed_checks = sum(sum(v) for v in checks.values())
print(f"\n{Colors.BOLD}Results:{Colors.ENDC}")
print(f" Workflows: {sum(checks['workflows'])}/{len(checks['workflows'])}")
print(f" Tests: {sum(checks['tests'])}/{len(checks['tests'])}")
print(f" Configuration: {sum(checks['config'])}/{len(checks['config'])}")
print(f" Documentation: {sum(checks['docs'])}/{len(checks['docs'])}")
print(f" Python deps: {sum(checks['python'])}/{len(checks['python'])}")
print(f"\n{Colors.BOLD}Total: {passed_checks}/{total_checks}{Colors.ENDC}")
if passed_checks == total_checks:
print(f"\n{Colors.GREEN}{Colors.BOLD}✓ All checks passed! CI/CD setup is complete.{Colors.ENDC}")
print(f"\n{Colors.BOLD}Next steps:{Colors.ENDC}")
print(" 1. Run smoke tests: pytest -m smoke")
print(" 2. Create a test PR to verify CI works")
print(" 3. Review documentation: CI_CD_QUICK_START.md")
return 0
else:
failed = total_checks - passed_checks
print(f"\n{Colors.YELLOW}{Colors.BOLD}⚠ Setup incomplete: {failed} checks failed{Colors.ENDC}")
print(f"\n{Colors.BOLD}Action required:{Colors.ENDC}")
print(" 1. Review errors above")
print(" 2. Install missing dependencies: pip install -r requirements-test.txt")
print(" 3. Check documentation: CI_CD_DOCUMENTATION.md")
return 1
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
print(f"\n\n{Colors.YELLOW}Validation interrupted by user{Colors.ENDC}")
sys.exit(130)
except Exception as e:
print(f"\n{Colors.RED}Validation failed with error: {e}{Colors.ENDC}")
sys.exit(1)