Files
5why-analyzer/app.py
donald ea4108b905 fix: Use npm.cmd on Windows for npm version check
Fixed npm detection on Windows by using npm.cmd instead of npm.
This resolves the 'npm is not installed or not in PATH' error on Windows systems.

Changes:
- Updated check_npm_installed() to use npm.cmd on Windows
- Uses self.is_windows flag to determine correct command
- Maintains cross-platform compatibility

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 00:02:35 +08:00

311 lines
11 KiB
Python

#!/usr/bin/env python3
"""
5 Why Root Cause Analyzer - Application Launcher
Version: 1.0.0
Description: Python script to start both backend and frontend services
"""
import os
import sys
import time
import signal
import subprocess
import platform
from pathlib import Path
class Color:
"""ANSI color codes for terminal output"""
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
class AppLauncher:
"""Main application launcher class"""
def __init__(self):
self.project_root = Path(__file__).parent
self.backend_process = None
self.frontend_process = None
self.is_windows = platform.system() == 'Windows'
def print_banner(self):
"""Print application banner"""
print(f"\n{Color.HEADER}{Color.BOLD}{'='*70}{Color.ENDC}")
print(f"{Color.HEADER}{Color.BOLD} 5 Why Root Cause Analyzer - v1.0.0{Color.ENDC}")
print(f"{Color.HEADER}{Color.BOLD} Enterprise-grade Root Cause Analysis Tool{Color.ENDC}")
print(f"{Color.HEADER}{Color.BOLD}{'='*70}{Color.ENDC}\n")
def print_info(self, message):
"""Print info message"""
print(f"{Color.OKBLUE}[INFO]{Color.ENDC} {message}")
def print_success(self, message):
"""Print success message"""
print(f"{Color.OKGREEN}[SUCCESS]{Color.ENDC} {message}")
def print_warning(self, message):
"""Print warning message"""
print(f"{Color.WARNING}[WARNING]{Color.ENDC} {message}")
def print_error(self, message):
"""Print error message"""
print(f"{Color.FAIL}[ERROR]{Color.ENDC} {message}")
def check_node_installed(self):
"""Check if Node.js is installed"""
try:
result = subprocess.run(
['node', '--version'],
capture_output=True,
text=True,
check=True
)
version = result.stdout.strip()
self.print_success(f"Node.js detected: {version}")
return True
except (subprocess.CalledProcessError, FileNotFoundError):
self.print_error("Node.js is not installed or not in PATH")
self.print_info("Please install Node.js 18+ from https://nodejs.org/")
return False
def check_npm_installed(self):
"""Check if npm is installed"""
try:
# Use npm.cmd on Windows, npm on Unix
npm_cmd = 'npm.cmd' if self.is_windows else 'npm'
result = subprocess.run(
[npm_cmd, '--version'],
capture_output=True,
text=True,
check=True
)
version = result.stdout.strip()
self.print_success(f"npm detected: {version}")
return True
except (subprocess.CalledProcessError, FileNotFoundError):
self.print_error("npm is not installed or not in PATH")
return False
def check_dependencies_installed(self):
"""Check if node_modules exists"""
node_modules = self.project_root / 'node_modules'
if node_modules.exists():
self.print_success("Dependencies installed (node_modules found)")
return True
else:
self.print_warning("Dependencies not installed (node_modules not found)")
self.print_info("Run 'npm install' to install dependencies")
return False
def check_env_file(self):
"""Check if .env file exists"""
env_file = self.project_root / '.env'
if env_file.exists():
self.print_success("Environment file (.env) found")
return True
else:
self.print_warning(".env file not found")
self.print_info("Copy .env.example to .env and configure it")
return False
def start_backend(self):
"""Start the backend server"""
self.print_info("Starting backend server...")
try:
# Use 'npm.cmd' on Windows, 'npm' on Unix
npm_cmd = 'npm.cmd' if self.is_windows else 'npm'
self.backend_process = subprocess.Popen(
[npm_cmd, 'run', 'server'],
cwd=str(self.project_root),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if self.is_windows else 0
)
# Wait a bit and check if process started successfully
time.sleep(2)
if self.backend_process.poll() is None:
self.print_success("Backend server started successfully")
self.print_info("Backend running at: http://localhost:3001")
return True
else:
self.print_error("Backend server failed to start")
return False
except Exception as e:
self.print_error(f"Failed to start backend: {str(e)}")
return False
def start_frontend(self):
"""Start the frontend development server"""
self.print_info("Starting frontend development server...")
try:
# Use 'npm.cmd' on Windows, 'npm' on Unix
npm_cmd = 'npm.cmd' if self.is_windows else 'npm'
self.frontend_process = subprocess.Popen(
[npm_cmd, 'run', 'client'],
cwd=str(self.project_root),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if self.is_windows else 0
)
# Wait a bit and check if process started successfully
time.sleep(3)
if self.frontend_process.poll() is None:
self.print_success("Frontend server started successfully")
self.print_info("Frontend running at: http://localhost:5173")
return True
else:
self.print_error("Frontend server failed to start")
return False
except Exception as e:
self.print_error(f"Failed to start frontend: {str(e)}")
return False
def monitor_processes(self):
"""Monitor both processes and print their output"""
self.print_info("\n" + "="*70)
self.print_success("Both services are running!")
self.print_info("="*70)
print(f"\n{Color.OKGREEN}{Color.BOLD}Access the application:{Color.ENDC}")
print(f" {Color.OKCYAN}Frontend:{Color.ENDC} http://localhost:5173")
print(f" {Color.OKCYAN}Backend API:{Color.ENDC} http://localhost:3001")
print(f" {Color.OKCYAN}API Health:{Color.ENDC} http://localhost:3001/health")
print(f"\n{Color.OKGREEN}{Color.BOLD}Test Accounts:{Color.ENDC}")
print(f" {Color.OKCYAN}Admin:{Color.ENDC} admin@example.com / Admin@123456")
print(f" {Color.OKCYAN}User1:{Color.ENDC} user001@example.com / User@123456")
print(f" {Color.OKCYAN}User2:{Color.ENDC} user002@example.com / User@123456")
print(f"\n{Color.WARNING}Press Ctrl+C to stop all services{Color.ENDC}\n")
try:
# Keep the script running and monitor processes
while True:
# Check if backend is still running
if self.backend_process.poll() is not None:
self.print_error("Backend process terminated unexpectedly")
break
# Check if frontend is still running
if self.frontend_process.poll() is not None:
self.print_error("Frontend process terminated unexpectedly")
break
time.sleep(1)
except KeyboardInterrupt:
self.print_info("\nReceived shutdown signal...")
def cleanup(self):
"""Clean up and terminate all processes"""
self.print_info("Shutting down services...")
# Terminate frontend
if self.frontend_process and self.frontend_process.poll() is None:
try:
if self.is_windows:
# On Windows, use taskkill to terminate process tree
subprocess.run(
['taskkill', '/F', '/T', '/PID', str(self.frontend_process.pid)],
capture_output=True
)
else:
self.frontend_process.terminate()
self.frontend_process.wait(timeout=5)
self.print_success("Frontend server stopped")
except Exception as e:
self.print_warning(f"Error stopping frontend: {str(e)}")
# Terminate backend
if self.backend_process and self.backend_process.poll() is None:
try:
if self.is_windows:
# On Windows, use taskkill to terminate process tree
subprocess.run(
['taskkill', '/F', '/T', '/PID', str(self.backend_process.pid)],
capture_output=True
)
else:
self.backend_process.terminate()
self.backend_process.wait(timeout=5)
self.print_success("Backend server stopped")
except Exception as e:
self.print_warning(f"Error stopping backend: {str(e)}")
self.print_success("All services stopped successfully")
def run(self):
"""Main run method"""
self.print_banner()
# Pre-flight checks
self.print_info("Running pre-flight checks...")
if not self.check_node_installed():
return 1
if not self.check_npm_installed():
return 1
if not self.check_dependencies_installed():
self.print_warning("Please run 'npm install' first")
return 1
if not self.check_env_file():
self.print_warning("Please configure .env file first")
return 1
self.print_success("All pre-flight checks passed!\n")
# Start services
if not self.start_backend():
self.cleanup()
return 1
time.sleep(2) # Give backend time to start
if not self.start_frontend():
self.cleanup()
return 1
# Monitor processes
try:
self.monitor_processes()
finally:
self.cleanup()
return 0
def main():
"""Main entry point"""
launcher = AppLauncher()
try:
sys.exit(launcher.run())
except Exception as e:
print(f"\n{Color.FAIL}[FATAL ERROR]{Color.ENDC} {str(e)}")
launcher.cleanup()
sys.exit(1)
if __name__ == '__main__':
main()