- Füge --no-sudo Option für Installation ohne Root-Rechte hinzu - Verbessere Node.js Installation mit NVM Fallback für Benutzer-Level - Implementiere mehrere Fallback-Mechanismen für pnpm-Installation - Füge automatische PATH-Konfiguration in .bashrc hinzu - Erstelle zusätzliches Start-Skript für einfache manuelle Ausführung - Verbessere Fehlerbehandlung und Diagnoseinformationen - Füge expliziten Abhängigkeitsinstallationsschritt hinzu 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1463 lines
50 KiB
Bash
Executable File
1463 lines
50 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# MYP Frontend Installation Script for Debian
|
|
# This script installs and configures the MYP frontend reservation platform
|
|
|
|
# We'll handle errors ourselves rather than exiting immediately
|
|
# set -e
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
LOG_FILE="$SCRIPT_DIR/frontend-install.log"
|
|
|
|
# Function for logging with timestamps and colors
|
|
log() {
|
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
local message="[$timestamp] $1"
|
|
echo -e "$message" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Function for logging errors with timestamps and colors
|
|
log_error() {
|
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
local message="[$timestamp] ERROR: $1"
|
|
echo -e "\033[0;31m$message\033[0m" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Function for logging warnings with timestamps and colors
|
|
log_warning() {
|
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
local message="[$timestamp] WARNING: $1"
|
|
echo -e "\033[0;33m$message\033[0m" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Function for logging success with timestamps and colors
|
|
log_success() {
|
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
local message="[$timestamp] SUCCESS: $1"
|
|
echo -e "\033[0;32m$message\033[0m" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Function to check if a command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Clear log file
|
|
> "$LOG_FILE"
|
|
|
|
# Add script usage info
|
|
usage() {
|
|
echo "Usage: $0 [OPTIONS]"
|
|
echo ""
|
|
echo "OPTIONS:"
|
|
echo " --auto-production Non-interactive installation in production mode"
|
|
echo " --auto-development Non-interactive installation in development mode"
|
|
echo " --auto-test Non-interactive installation in test environment mode"
|
|
echo " --no-sudo Run without sudo privileges (limited functionality)"
|
|
echo " --help Show this help message"
|
|
echo ""
|
|
echo "Example:"
|
|
echo " $0 --auto-production"
|
|
exit 1
|
|
}
|
|
|
|
# Check for help flag
|
|
if [ "$1" == "--help" ]; then
|
|
usage
|
|
fi
|
|
|
|
# Check if we're running with no-sudo option
|
|
if [[ "$*" == *"--no-sudo"* ]]; then
|
|
NO_SUDO=true
|
|
log "Running in non-sudo mode with limited functionality"
|
|
else
|
|
NO_SUDO=false
|
|
fi
|
|
|
|
log "===== Starting MYP Frontend Installation ====="
|
|
log "Installation directory: $SCRIPT_DIR"
|
|
|
|
# Display system information
|
|
log "System information:"
|
|
uname -a >> "$LOG_FILE" 2>&1
|
|
lsb_release -a >> "$LOG_FILE" 2>&1 || cat /etc/os-release >> "$LOG_FILE" 2>&1
|
|
log "CPU: $(grep "model name" /proc/cpuinfo | head -n1 | cut -d':' -f2 | sed 's/^ *//')"
|
|
log "Memory: $(free -h | grep "Mem:" | awk '{print $2}')"
|
|
log "Disk space: $(df -h / | awk 'NR==2 {print $4}') free on /"
|
|
|
|
# Check for root privileges unless --no-sudo was specified
|
|
if [ "$EUID" -ne 0 ] && [ "$NO_SUDO" = "false" ]; then
|
|
log_error "This script must be run as root"
|
|
log_warning "Use --no-sudo option for limited functionality installation"
|
|
log_warning "Example: $0 --auto-development --no-sudo"
|
|
exit 1
|
|
fi
|
|
|
|
# System update (only if running as root)
|
|
if [ "$NO_SUDO" = "false" ]; then
|
|
log "Updating system packages..."
|
|
apt update -y >> "$LOG_FILE" 2>&1 || log_error "Failed to update apt repositories"
|
|
apt upgrade -y >> "$LOG_FILE" 2>&1 || log_warning "Failed to upgrade packages, continuing anyway"
|
|
|
|
# Install required packages
|
|
log "Installing essential system packages and network tools..."
|
|
apt install -y curl git wget htop net-tools iptables iputils-ping traceroute nmap tcpdump nftables \
|
|
netcat-openbsd dnsutils whois vim nano rsync zip unzip xz-utils sqlite3 \
|
|
apt-transport-https ca-certificates gnupg lsb-release bash-completion \
|
|
make build-essential libssl-dev zlib1g-dev >> "$LOG_FILE" 2>&1 || log_warning "Some packages failed to install"
|
|
else
|
|
log "Skipping system package installation (non-sudo mode)..."
|
|
# Check if critical tools are available
|
|
for cmd in curl git wget node npm; do
|
|
if ! command_exists "$cmd"; then
|
|
log_warning "$cmd is not installed. This might cause problems."
|
|
log_warning "Install with: sudo apt install $cmd"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Install Docker using the official Docker repository (skip in non-sudo mode)
|
|
if [ "$NO_SUDO" = "false" ]; then
|
|
log "Installing Docker from official repository..."
|
|
if ! command_exists docker; then
|
|
# Remove any old Docker versions
|
|
apt remove -y docker docker-engine docker.io containerd runc >> "$LOG_FILE" 2>&1 || true
|
|
|
|
# Add Docker's official GPG key
|
|
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg >> "$LOG_FILE" 2>&1
|
|
|
|
# Set up the stable repository
|
|
echo \
|
|
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
|
|
https://download.docker.com/linux/debian \
|
|
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
|
|
# Update apt and install Docker
|
|
apt update -y >> "$LOG_FILE" 2>&1
|
|
apt install -y docker-ce docker-ce-cli containerd.io >> "$LOG_FILE" 2>&1
|
|
|
|
# Install Docker Compose
|
|
log "Installing Docker Compose..."
|
|
curl -L "https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose >> "$LOG_FILE" 2>&1
|
|
chmod +x /usr/local/bin/docker-compose >> "$LOG_FILE" 2>&1
|
|
ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose >> "$LOG_FILE" 2>&1
|
|
else
|
|
log "Docker already installed: $(docker --version)"
|
|
log "Docker Compose already installed: $(docker-compose --version)"
|
|
fi
|
|
else
|
|
log "Skipping Docker installation (non-sudo mode)..."
|
|
# Check if Docker is available
|
|
if command_exists docker; then
|
|
log "Docker already installed: $(docker --version)"
|
|
if command_exists docker-compose; then
|
|
log "Docker Compose already installed: $(docker-compose --version)"
|
|
else
|
|
log_warning "Docker Compose not installed. Some features may not work."
|
|
fi
|
|
else
|
|
log_warning "Docker not installed. Container features will not be available."
|
|
log_warning "Install Docker with: curl -fsSL https://get.docker.com | sudo sh"
|
|
fi
|
|
fi
|
|
|
|
# Install Node.js 20.x
|
|
if ! command_exists node || [ "$(node -v 2>/dev/null | cut -d. -f1 | tr -d 'v')" -lt 20 2>/dev/null ]; then
|
|
log "Installing Node.js 20.x..."
|
|
if [ "$NO_SUDO" = "false" ]; then
|
|
# System-wide installation
|
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - >> "$LOG_FILE" 2>&1
|
|
apt install -y nodejs >> "$LOG_FILE" 2>&1
|
|
else
|
|
# User-level installation using nvm (Node Version Manager)
|
|
log "Installing Node.js using NVM (user-level)..."
|
|
# Install NVM if not already installed
|
|
if [ ! -d "$HOME/.nvm" ]; then
|
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash >> "$LOG_FILE" 2>&1
|
|
export NVM_DIR="$HOME/.nvm"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
|
else
|
|
export NVM_DIR="$HOME/.nvm"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
|
fi
|
|
|
|
# Install Node.js 20 using NVM
|
|
nvm install 20 >> "$LOG_FILE" 2>&1
|
|
nvm use 20 >> "$LOG_FILE" 2>&1
|
|
fi
|
|
|
|
# Verify installation
|
|
if command_exists node; then
|
|
log_success "Node.js $(node -v) installed"
|
|
else
|
|
log_error "Node.js installation failed"
|
|
exit 1
|
|
fi
|
|
else
|
|
log "Node.js $(node -v) already installed"
|
|
fi
|
|
|
|
# Install pnpm - with more robust installation approaches
|
|
if ! command_exists pnpm; then
|
|
log "Installing pnpm package manager..."
|
|
|
|
# First, try npm installation
|
|
if command_exists npm; then
|
|
npm install -g pnpm >> "$LOG_FILE" 2>&1
|
|
fi
|
|
|
|
# Check if npm method succeeded
|
|
if ! command_exists pnpm; then
|
|
log "Trying alternative pnpm installation method..."
|
|
curl -fsSL https://get.pnpm.io/install.sh | bash - >> "$LOG_FILE" 2>&1
|
|
|
|
# Update PATH to include pnpm
|
|
export PNPM_HOME="${PNPM_HOME:-$HOME/.local/share/pnpm}"
|
|
export PATH="$PNPM_HOME:$PATH"
|
|
|
|
# Add to ~/.bashrc for future use if it's not already there
|
|
if ! grep -q "PNPM_HOME" "$HOME/.bashrc" 2>/dev/null; then
|
|
echo 'export PNPM_HOME="$HOME/.local/share/pnpm"' >> "$HOME/.bashrc"
|
|
echo 'export PATH="$PNPM_HOME:$PATH"' >> "$HOME/.bashrc"
|
|
log "Added pnpm to PATH in .bashrc for future terminal sessions"
|
|
fi
|
|
|
|
# Try standalone installation if previous methods failed
|
|
if ! command_exists pnpm; then
|
|
log "Trying standalone installation of pnpm..."
|
|
# Create bin directory if it doesn't exist
|
|
mkdir -p "$HOME/.local/bin"
|
|
|
|
# Download standalone PNPM
|
|
curl -fsSL https://github.com/pnpm/pnpm/releases/download/v9.12.1/pnpm-linuxstatic-x64 -o "$HOME/.local/bin/pnpm" >> "$LOG_FILE" 2>&1
|
|
chmod +x "$HOME/.local/bin/pnpm"
|
|
|
|
# Add to PATH
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
|
|
# Add to ~/.bashrc if not already there
|
|
if ! grep -q "/.local/bin" "$HOME/.bashrc" 2>/dev/null; then
|
|
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Verify installation
|
|
if command_exists pnpm; then
|
|
log_success "pnpm $(pnpm --version) installed"
|
|
else
|
|
log_error "pnpm installation failed"
|
|
log_error "Please try to install manually with: npm install -g pnpm"
|
|
exit 1
|
|
fi
|
|
else
|
|
log "pnpm $(pnpm --version) already installed"
|
|
fi
|
|
|
|
# Make sure pnpm is in PATH for this script session
|
|
export PNPM_HOME="${PNPM_HOME:-$HOME/.local/share/pnpm}"
|
|
export PATH="$PNPM_HOME:$HOME/.local/bin:$PATH"
|
|
|
|
# Create a .pnpmrc file to ensure proper configuration
|
|
echo "standalone=true" > "$HOME/.pnpmrc" 2>/dev/null || log_warning "Could not create .pnpmrc file"
|
|
|
|
# Enable and start Docker (skip in non-sudo mode)
|
|
if [ "$NO_SUDO" = "false" ]; then
|
|
log "Ensuring Docker is running..."
|
|
systemctl enable docker >> "$LOG_FILE" 2>&1 || log_warning "Failed to enable Docker service"
|
|
systemctl start docker >> "$LOG_FILE" 2>&1 || log_warning "Failed to start Docker service"
|
|
|
|
# Configure Docker for multi-architecture builds
|
|
log "Setting up Docker for multi-architecture builds..."
|
|
if command_exists docker; then
|
|
if ! docker buildx ls 2>/dev/null | grep -q "default"; then
|
|
docker buildx create --name mybuilder --use >> "$LOG_FILE" 2>&1 || log_warning "Failed to configure Docker buildx"
|
|
log "Docker buildx configured"
|
|
else
|
|
log "Docker buildx already configured"
|
|
fi
|
|
else
|
|
log_warning "Docker not available, skipping buildx configuration"
|
|
fi
|
|
else
|
|
log "Skipping Docker service configuration (non-sudo mode)..."
|
|
fi
|
|
|
|
# Make sure we have the docker directory for configuration
|
|
mkdir -p "$SCRIPT_DIR/docker/caddy"
|
|
|
|
# Check if Caddyfile exists
|
|
if [ ! -f "$SCRIPT_DIR/docker/caddy/Caddyfile" ]; then
|
|
log "Creating Caddyfile template..."
|
|
cat > "$SCRIPT_DIR/docker/caddy/Caddyfile" << EOF
|
|
# Caddyfile for MYP Frontend
|
|
# Replace example.com with your actual domain
|
|
|
|
:80 {
|
|
# Automatic HTTPS will be enabled if you use a domain name
|
|
# For local development or internal network, HTTP is fine
|
|
|
|
# Reverse proxy to frontend app
|
|
reverse_proxy frontend:3000
|
|
|
|
# Basic headers for security
|
|
header {
|
|
# Enable HSTS
|
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
|
# Enable XSS protection
|
|
X-XSS-Protection "1; mode=block"
|
|
# Prevent content type sniffing
|
|
X-Content-Type-Options "nosniff"
|
|
# Clickjacking protection
|
|
X-Frame-Options "SAMEORIGIN"
|
|
# Allow backend API access (CORS)
|
|
Access-Control-Allow-Origin "http://192.168.0.105:5000"
|
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
|
Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"
|
|
Access-Control-Allow-Credentials "true"
|
|
}
|
|
|
|
# Log access
|
|
log {
|
|
output file /var/log/caddy/access.log
|
|
}
|
|
}
|
|
EOF
|
|
log "Caddyfile created. Edit it to configure your domain if needed."
|
|
fi
|
|
|
|
# Create GitHub OAuth credentials file
|
|
if [ ! -d "/srv/myp-env" ]; then
|
|
log "Creating directory for environment variables..."
|
|
mkdir -p /srv/myp-env
|
|
fi
|
|
|
|
if [ ! -f "/srv/myp-env/github.env" ]; then
|
|
log "Creating GitHub OAuth credentials file with static backend URL..."
|
|
cat > /srv/myp-env/github.env << EOF
|
|
# GitHub OAuth Credentials
|
|
# Replace these with your actual GitHub OAuth app credentials
|
|
|
|
AUTH_GITHUB_ID=your_github_client_id
|
|
AUTH_GITHUB_SECRET=your_github_client_secret
|
|
AUTH_SECRET=$(openssl rand -hex 32)
|
|
AUTH_TRUST_HOST=true
|
|
NEXT_PUBLIC_BACKEND_URL=http://192.168.0.105:5000
|
|
|
|
# Add additional environment variables as needed
|
|
EOF
|
|
log "ATTENTION: GitHub OAuth credentials file created with generated AUTH_SECRET"
|
|
log " Backend URL set to http://192.168.0.105:5000"
|
|
log " Please edit /srv/myp-env/github.env with your actual GitHub OAuth app credentials"
|
|
fi
|
|
|
|
# Create a copy of the environment file in the git repository
|
|
log "Creating a copy of the environment file for version control..."
|
|
if [ ! -f "$SCRIPT_DIR/.env.example" ]; then
|
|
cat > "$SCRIPT_DIR/.env.example" << EOF
|
|
# GitHub OAuth Credentials Example
|
|
# This is a template for the required environment variables
|
|
|
|
AUTH_GITHUB_ID=your_github_client_id
|
|
AUTH_GITHUB_SECRET=your_github_client_secret
|
|
AUTH_SECRET=random_string_generated_during_installation
|
|
AUTH_TRUST_HOST=true
|
|
NEXT_PUBLIC_BACKEND_URL=http://192.168.0.105:5000
|
|
|
|
# Add additional environment variables as needed
|
|
EOF
|
|
log "Environment example file created at $SCRIPT_DIR/.env.example"
|
|
fi
|
|
|
|
# Create database directory if it doesn't exist
|
|
log "Setting up database directory..."
|
|
mkdir -p /srv/MYP-DB
|
|
|
|
# Determine if we should run in non-interactive mode
|
|
if [ -n "$1" ] && [ "$1" == "--auto-production" ]; then
|
|
log "Running in automatic production mode (non-interactive)..."
|
|
production_mode="y"
|
|
test_environment="n"
|
|
elif [ -n "$1" ] && [ "$1" == "--auto-development" ]; then
|
|
log "Running in automatic development mode (non-interactive)..."
|
|
production_mode="n"
|
|
test_environment="n"
|
|
elif [ -n "$1" ] && [ "$1" == "--auto-test" ]; then
|
|
log "Running in automatic test environment mode (non-interactive)..."
|
|
production_mode="n"
|
|
test_environment="y"
|
|
else
|
|
# Interactive mode
|
|
log "Running in interactive mode..."
|
|
# Check if we need to run in development or production mode
|
|
echo "Choose installation type:"
|
|
echo "1) Production mode (Docker container)"
|
|
echo "2) Development mode (local dev server)"
|
|
echo "3) Test environment (integrates with real backend)"
|
|
read -p "Enter your choice (1-3): " install_choice
|
|
|
|
case $install_choice in
|
|
1)
|
|
production_mode="y"
|
|
test_environment="n"
|
|
;;
|
|
2)
|
|
production_mode="n"
|
|
test_environment="n"
|
|
;;
|
|
3)
|
|
production_mode="n"
|
|
test_environment="y"
|
|
;;
|
|
*)
|
|
log "Invalid choice. Defaulting to development mode."
|
|
production_mode="n"
|
|
test_environment="n"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
if [ "$test_environment" = "y" ] || [ "$test_environment" = "Y" ]; then
|
|
# Test environment mode - using Docker for integration testing
|
|
log "Setting up test environment for integration testing..."
|
|
|
|
# Ensure test directory exists
|
|
mkdir -p "$SCRIPT_DIR/docker"
|
|
|
|
# Create test environment compose file if it doesn't exist
|
|
if [ ! -f "$SCRIPT_DIR/docker/test-env.yml" ]; then
|
|
log "Creating test environment docker-compose file..."
|
|
cat > "$SCRIPT_DIR/docker/test-env.yml" << EOF
|
|
version: '3.8'
|
|
|
|
services:
|
|
# Backend for testing
|
|
backend:
|
|
build:
|
|
context: ../../backend
|
|
dockerfile: Dockerfile
|
|
container_name: myp-backend-test
|
|
ports:
|
|
- "5000:5000"
|
|
environment:
|
|
- SECRET_KEY=testsecretkey123456789
|
|
- DATABASE_URL=sqlite:///myp.db
|
|
- FLASK_ENV=development
|
|
- TESTING=true
|
|
volumes:
|
|
- backend-test-data:/app/instance
|
|
networks:
|
|
- test-network
|
|
|
|
# Frontend for testing - bound to loopback address
|
|
frontend-test:
|
|
build:
|
|
context: ..
|
|
dockerfile: Dockerfile
|
|
container_name: myp-frontend-test
|
|
environment:
|
|
- NODE_ENV=development
|
|
- AUTH_TRUST_HOST=true
|
|
- AUTH_SECRET=test-secret-key-for-testing-only-do-not-use-in-production
|
|
- NEXT_PUBLIC_BACKEND_URL=http://backend:5000
|
|
ports:
|
|
- "127.0.0.1:3000:3000"
|
|
depends_on:
|
|
- backend
|
|
networks:
|
|
- test-network
|
|
|
|
networks:
|
|
test-network:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
backend-test-data:
|
|
EOF
|
|
log "Test environment docker-compose file created"
|
|
fi
|
|
|
|
# Create test integration script if it doesn't exist
|
|
if [ ! -f "$SCRIPT_DIR/docker/test-integration.sh" ]; then
|
|
log "Creating test integration script..."
|
|
cat > "$SCRIPT_DIR/docker/test-integration.sh" << 'EOF'
|
|
#!/bin/bash
|
|
|
|
# Test integration script - validates if the frontend and backend work together
|
|
# Specifically designed to test if the production environment setup will work
|
|
|
|
# Get the directory containing this script
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
TEST_LOG="$SCRIPT_DIR/test-integration.log"
|
|
|
|
# Colors for output
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Create or clear log file
|
|
> "$TEST_LOG"
|
|
|
|
echo -e "${YELLOW}Starting MYP integration test environment...${NC}" | tee -a "$TEST_LOG"
|
|
echo "Test directory: $SCRIPT_DIR" | tee -a "$TEST_LOG"
|
|
echo "Parent directory: $PARENT_DIR" | tee -a "$TEST_LOG"
|
|
echo "Log file: $TEST_LOG" | tee -a "$TEST_LOG"
|
|
|
|
# Check if Docker is available
|
|
if ! command -v docker &> /dev/null; then
|
|
echo -e "${RED}Error: Docker is not installed or not in PATH${NC}" | tee -a "$TEST_LOG"
|
|
exit 1
|
|
fi
|
|
|
|
# Function to run docker compose (handles both docker-compose and docker compose syntax)
|
|
run_docker_compose() {
|
|
if command -v docker-compose &> /dev/null; then
|
|
docker-compose "$@"
|
|
else
|
|
docker compose "$@"
|
|
fi
|
|
}
|
|
|
|
# Stop any existing test environment (cleanup)
|
|
echo -e "${YELLOW}Cleaning up any existing test environment...${NC}" | tee -a "$TEST_LOG"
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1
|
|
|
|
# Start the test environment
|
|
echo -e "${YELLOW}Starting test environment with docker-compose...${NC}" | tee -a "$TEST_LOG"
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" up -d >> "$TEST_LOG" 2>&1
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo -e "${RED}Failed to start test environment.${NC}" | tee -a "$TEST_LOG"
|
|
echo "Check the log file for details: $TEST_LOG" | tee -a "$TEST_LOG"
|
|
exit 1
|
|
fi
|
|
|
|
# Wait for backend to be ready
|
|
echo -e "${YELLOW}Waiting for backend to be ready...${NC}" | tee -a "$TEST_LOG"
|
|
max_attempts=30
|
|
attempt=1
|
|
backend_ready=false
|
|
|
|
while [ $attempt -le $max_attempts ] && [ "$backend_ready" = "false" ]; do
|
|
echo "Checking backend readiness (attempt $attempt/$max_attempts)..." | tee -a "$TEST_LOG"
|
|
|
|
if curl -s http://localhost:5000/api/health &> /dev/null; then
|
|
backend_ready=true
|
|
echo -e "${GREEN}Backend is ready!${NC}" | tee -a "$TEST_LOG"
|
|
else
|
|
echo "Backend not ready yet, waiting..." | tee -a "$TEST_LOG"
|
|
sleep 2
|
|
attempt=$((attempt+1))
|
|
fi
|
|
done
|
|
|
|
if [ "$backend_ready" = "false" ]; then
|
|
echo -e "${RED}Backend failed to start properly after $max_attempts attempts${NC}" | tee -a "$TEST_LOG"
|
|
echo "Logs from backend container:" | tee -a "$TEST_LOG"
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" logs backend >> "$TEST_LOG" 2>&1
|
|
|
|
# Cleanup
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1
|
|
exit 1
|
|
fi
|
|
|
|
# Wait for frontend to be ready
|
|
echo -e "${YELLOW}Waiting for frontend to be ready...${NC}" | tee -a "$TEST_LOG"
|
|
max_attempts=30
|
|
attempt=1
|
|
frontend_ready=false
|
|
|
|
while [ $attempt -le $max_attempts ] && [ "$frontend_ready" = "false" ]; do
|
|
echo "Checking frontend readiness (attempt $attempt/$max_attempts)..." | tee -a "$TEST_LOG"
|
|
|
|
if curl -s http://127.0.0.1:3000 &> /dev/null; then
|
|
frontend_ready=true
|
|
echo -e "${GREEN}Frontend is ready!${NC}" | tee -a "$TEST_LOG"
|
|
else
|
|
echo "Frontend not ready yet, waiting..." | tee -a "$TEST_LOG"
|
|
sleep 2
|
|
attempt=$((attempt+1))
|
|
fi
|
|
done
|
|
|
|
if [ "$frontend_ready" = "false" ]; then
|
|
echo -e "${RED}Frontend failed to start properly after $max_attempts attempts${NC}" | tee -a "$TEST_LOG"
|
|
echo "Logs from frontend container:" | tee -a "$TEST_LOG"
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" logs frontend-test >> "$TEST_LOG" 2>&1
|
|
|
|
# Cleanup
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1
|
|
exit 1
|
|
fi
|
|
|
|
# Perform basic integration tests
|
|
echo -e "${YELLOW}Performing basic integration tests...${NC}" | tee -a "$TEST_LOG"
|
|
|
|
# Test 1: Frontend can fetch API data (printers endpoint)
|
|
echo "Test 1: Frontend can fetch data from backend API..." | tee -a "$TEST_LOG"
|
|
frontend_container_id=$(docker ps -qf "name=myp-frontend-test")
|
|
if [ -z "$frontend_container_id" ]; then
|
|
echo -e "${RED}Failed to find frontend container${NC}" | tee -a "$TEST_LOG"
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1
|
|
exit 1
|
|
fi
|
|
|
|
# Run a simple test inside the frontend container to check API connectivity
|
|
api_test_result=$(docker exec $frontend_container_id curl -s http://backend:5000/api/health)
|
|
if [[ "$api_test_result" == *"healthy"* ]]; then
|
|
echo -e "${GREEN}Test 1 PASSED: Frontend can connect to backend API${NC}" | tee -a "$TEST_LOG"
|
|
else
|
|
echo -e "${RED}Test 1 FAILED: Frontend cannot connect to backend API${NC}" | tee -a "$TEST_LOG"
|
|
echo "API response: $api_test_result" | tee -a "$TEST_LOG"
|
|
# Don't exit, continue with other tests
|
|
fi
|
|
|
|
# Test 2: Frontend serves HTML content
|
|
echo "Test 2: Frontend serves valid HTML content..." | tee -a "$TEST_LOG"
|
|
frontend_html=$(curl -s http://127.0.0.1:3000)
|
|
if [[ "$frontend_html" == *"<!DOCTYPE html>"* ]]; then
|
|
echo -e "${GREEN}Test 2 PASSED: Frontend serves valid HTML${NC}" | tee -a "$TEST_LOG"
|
|
else
|
|
echo -e "${RED}Test 2 FAILED: Frontend does not serve valid HTML${NC}" | tee -a "$TEST_LOG"
|
|
# Don't exit, continue with other tests
|
|
fi
|
|
|
|
# All tests completed
|
|
echo -e "${GREEN}Integration tests completed${NC}" | tee -a "$TEST_LOG"
|
|
|
|
# Ask if the environment should be kept running or shutdown
|
|
echo -e "${YELLOW}Test environment is running at:${NC}" | tee -a "$TEST_LOG"
|
|
echo "Frontend: http://127.0.0.1:3000" | tee -a "$TEST_LOG"
|
|
echo "Backend: http://localhost:5000" | tee -a "$TEST_LOG"
|
|
echo "" | tee -a "$TEST_LOG"
|
|
|
|
read -p "Do you want to keep the test environment running? (y/n): " keep_running
|
|
|
|
if [[ "$keep_running" != "y" && "$keep_running" != "Y" ]]; then
|
|
echo -e "${YELLOW}Shutting down test environment...${NC}" | tee -a "$TEST_LOG"
|
|
run_docker_compose -f "$SCRIPT_DIR/test-env.yml" down >> "$TEST_LOG" 2>&1
|
|
echo -e "${GREEN}Test environment has been shut down${NC}" | tee -a "$TEST_LOG"
|
|
else
|
|
echo -e "${GREEN}Test environment is still running${NC}" | tee -a "$TEST_LOG"
|
|
echo "To stop it later, run: docker-compose -f $SCRIPT_DIR/test-env.yml down" | tee -a "$TEST_LOG"
|
|
fi
|
|
|
|
echo -e "${GREEN}Integration testing completed. See log for details: $TEST_LOG${NC}"
|
|
EOF
|
|
chmod +x "$SCRIPT_DIR/docker/test-integration.sh"
|
|
log "Test integration script created and made executable"
|
|
fi
|
|
|
|
# Run the integration test
|
|
log "Running integration test to verify the environment..."
|
|
"$SCRIPT_DIR/docker/test-integration.sh"
|
|
|
|
# Add entries to package.json for running tests
|
|
if ! grep -q "test:integration" "$SCRIPT_DIR/package.json"; then
|
|
log "Adding test integration commands to package.json..."
|
|
# This approach requires jq, which might not be installed. Using a temporary approach.
|
|
# Would be better to use jq for proper JSON manipulation
|
|
sed -i 's/"scripts": {/"scripts": {\n "test:integration": "bash docker\/test-integration.sh",/g' "$SCRIPT_DIR/package.json"
|
|
fi
|
|
|
|
log "Test environment setup complete!"
|
|
log "To run integration tests again: cd $SCRIPT_DIR && pnpm test:integration"
|
|
log "Or directly: $SCRIPT_DIR/docker/test-integration.sh"
|
|
|
|
elif [ "$production_mode" = "y" ] || [ "$production_mode" = "Y" ]; then
|
|
# Production mode - using Docker
|
|
log "Setting up in production mode using Docker..."
|
|
|
|
# Create docker-compose file if it doesn't exist
|
|
if [ ! -f "$SCRIPT_DIR/docker/compose.yml" ]; then
|
|
log "Creating docker-compose.yml file with network configuration..."
|
|
cat > "$SCRIPT_DIR/docker/compose.yml" << EOF
|
|
version: '3.8'
|
|
|
|
services:
|
|
frontend:
|
|
image: myp-rp:latest
|
|
restart: unless-stopped
|
|
environment:
|
|
- NODE_ENV=production
|
|
env_file:
|
|
- /srv/myp-env/github.env
|
|
volumes:
|
|
- /srv/MYP-DB:/app/.next/cache/drizzle
|
|
networks:
|
|
- myp-network
|
|
- backend-network # Network for communicating with backend
|
|
|
|
caddy:
|
|
image: caddy:2.8
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
|
|
- caddy_data:/data
|
|
- caddy_config:/config
|
|
networks:
|
|
- myp-network
|
|
depends_on:
|
|
- frontend
|
|
|
|
networks:
|
|
myp-network:
|
|
driver: bridge
|
|
backend-network: # Network for connecting to the backend at 192.168.0.105
|
|
driver: bridge
|
|
ipam:
|
|
config:
|
|
- subnet: 192.168.0.0/24
|
|
gateway: 192.168.0.1
|
|
|
|
volumes:
|
|
caddy_data:
|
|
caddy_config:
|
|
EOF
|
|
log "docker-compose.yml created with backend network configuration"
|
|
fi
|
|
|
|
# Create Docker Compose for testing environment if it doesn't exist
|
|
if [ ! -d "$SCRIPT_DIR/cypress" ]; then
|
|
log "Creating Cypress directory for testing..."
|
|
mkdir -p "$SCRIPT_DIR/cypress"
|
|
fi
|
|
|
|
if [ ! -f "$SCRIPT_DIR/cypress/docker-compose.test.yml" ]; then
|
|
log "Creating docker-compose.test.yml for testing environment..."
|
|
cat > "$SCRIPT_DIR/cypress/docker-compose.test.yml" << EOF
|
|
version: '3.8'
|
|
|
|
services:
|
|
# Backend service
|
|
backend:
|
|
build:
|
|
context: ../../../backend
|
|
dockerfile: Dockerfile
|
|
container_name: myp-backend-test
|
|
ports:
|
|
- "5000:5000"
|
|
environment:
|
|
- SECRET_KEY=testsecretkey123456789
|
|
- DATABASE_URL=sqlite:///myp.db
|
|
- FLASK_ENV=development
|
|
- TESTING=true
|
|
volumes:
|
|
- backend-test-data:/app/instance
|
|
restart: unless-stopped
|
|
networks:
|
|
- test-network
|
|
|
|
# Optional: Frontend test service if needed
|
|
frontend-test:
|
|
image: cypress/included:13.6.1
|
|
container_name: myp-frontend-test
|
|
depends_on:
|
|
- backend
|
|
environment:
|
|
- CYPRESS_baseUrl=http://host.docker.internal:3000
|
|
- CYPRESS_backendUrl=http://backend:5000
|
|
volumes:
|
|
- ..:/app
|
|
- ./cypress.config.ts:/app/cypress.config.ts
|
|
working_dir: /app
|
|
command: npx cypress run
|
|
networks:
|
|
- test-network
|
|
|
|
networks:
|
|
test-network:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
backend-test-data:
|
|
EOF
|
|
log "Test environment docker-compose.yml created"
|
|
fi
|
|
|
|
if [ ! -f "$SCRIPT_DIR/cypress/start-test-environment.sh" ]; then
|
|
log "Creating test environment startup script..."
|
|
cat > "$SCRIPT_DIR/cypress/start-test-environment.sh" << 'EOF'
|
|
#!/bin/bash
|
|
|
|
# Script to start a test environment with backend and optional test runner
|
|
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
BACKEND_DIR="$(dirname "$(dirname "$PARENT_DIR")")/backend"
|
|
|
|
# Colors for output
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${GREEN}Starting MYP test environment...${NC}"
|
|
echo "Script directory: $SCRIPT_DIR"
|
|
echo "Frontend directory: $PARENT_DIR"
|
|
echo "Backend directory: $BACKEND_DIR"
|
|
|
|
# Check if Docker is available
|
|
if ! command -v docker &> /dev/null; then
|
|
echo -e "${RED}Error: Docker is not installed or not in PATH${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if docker-compose is available
|
|
if ! command -v docker-compose &> /dev/null && ! command -v docker compose &> /dev/null; then
|
|
echo -e "${RED}Error: Neither docker-compose nor docker compose is available${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Function to run docker compose (handles both docker-compose and docker compose syntax)
|
|
run_docker_compose() {
|
|
if command -v docker-compose &> /dev/null; then
|
|
docker-compose "$@"
|
|
else
|
|
docker compose "$@"
|
|
fi
|
|
}
|
|
|
|
# Check if backend Docker image exists
|
|
echo -e "${YELLOW}Checking for backend Docker image...${NC}"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Start the backend container
|
|
echo -e "${GREEN}Starting backend container...${NC}"
|
|
run_docker_compose -f docker-compose.test.yml up -d backend
|
|
|
|
# Wait for backend to be ready
|
|
echo -e "${YELLOW}Waiting for backend to be ready...${NC}"
|
|
max_attempts=30
|
|
attempt=1
|
|
backend_ready=false
|
|
|
|
while [ $attempt -le $max_attempts ] && [ "$backend_ready" = "false" ]; do
|
|
echo "Checking backend readiness (attempt $attempt/$max_attempts)..."
|
|
|
|
if curl -s http://localhost:5000/api/health 2>&1 | grep -q "healthy"; then
|
|
backend_ready=true
|
|
echo -e "${GREEN}Backend is ready!${NC}"
|
|
else
|
|
echo "Backend not ready yet, waiting..."
|
|
sleep 2
|
|
attempt=$((attempt+1))
|
|
fi
|
|
done
|
|
|
|
if [ "$backend_ready" = "false" ]; then
|
|
echo -e "${RED}Backend failed to start properly after $max_attempts attempts${NC}"
|
|
echo "Logs from backend container:"
|
|
run_docker_compose -f docker-compose.test.yml logs backend
|
|
exit 1
|
|
fi
|
|
|
|
# Start frontend development server if it's not already running
|
|
if ! curl -s http://localhost:3000 > /dev/null; then
|
|
echo -e "${YELLOW}Starting frontend development server...${NC}"
|
|
cd "$PARENT_DIR"
|
|
|
|
# Run in background
|
|
echo "Starting Next.js development server in the background..."
|
|
nohup pnpm dev > "$SCRIPT_DIR/frontend.log" 2>&1 &
|
|
|
|
# Store the PID for later cleanup
|
|
FRONTEND_PID=$!
|
|
echo $FRONTEND_PID > "$SCRIPT_DIR/frontend.pid"
|
|
|
|
echo -e "${GREEN}Frontend development server started with PID $FRONTEND_PID${NC}"
|
|
echo "Frontend logs available at: $SCRIPT_DIR/frontend.log"
|
|
|
|
# Wait for frontend to be ready
|
|
echo -e "${YELLOW}Waiting for frontend to be ready...${NC}"
|
|
max_attempts=30
|
|
attempt=1
|
|
frontend_ready=false
|
|
|
|
while [ $attempt -le $max_attempts ] && [ "$frontend_ready" = "false" ]; do
|
|
echo "Checking frontend readiness (attempt $attempt/$max_attempts)..."
|
|
|
|
if curl -s http://localhost:3000 > /dev/null; then
|
|
frontend_ready=true
|
|
echo -e "${GREEN}Frontend is ready!${NC}"
|
|
else
|
|
echo "Frontend not ready yet, waiting..."
|
|
sleep 2
|
|
attempt=$((attempt+1))
|
|
fi
|
|
done
|
|
|
|
if [ "$frontend_ready" = "false" ]; then
|
|
echo -e "${RED}Frontend failed to start properly${NC}"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo -e "${GREEN}Frontend already running at http://localhost:3000${NC}"
|
|
fi
|
|
|
|
echo -e "${GREEN}Test environment is ready!${NC}"
|
|
echo "Backend is available at: http://localhost:5000"
|
|
echo "Frontend is available at: http://localhost:3000"
|
|
echo ""
|
|
echo "To run Cypress tests:"
|
|
echo " cd $PARENT_DIR && pnpm cypress"
|
|
echo ""
|
|
echo "To stop the test environment:"
|
|
echo " $SCRIPT_DIR/stop-test-environment.sh"
|
|
EOF
|
|
chmod +x "$SCRIPT_DIR/cypress/start-test-environment.sh"
|
|
log "Test environment startup script created and made executable"
|
|
fi
|
|
|
|
if [ ! -f "$SCRIPT_DIR/cypress/stop-test-environment.sh" ]; then
|
|
log "Creating test environment shutdown script..."
|
|
cat > "$SCRIPT_DIR/cypress/stop-test-environment.sh" << 'EOF'
|
|
#!/bin/bash
|
|
|
|
# Script to stop the test environment
|
|
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# Colors for output
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${YELLOW}Stopping MYP test environment...${NC}"
|
|
|
|
# Function to run docker compose (handles both docker-compose and docker compose syntax)
|
|
run_docker_compose() {
|
|
if command -v docker-compose &> /dev/null; then
|
|
docker-compose "$@"
|
|
else
|
|
docker compose "$@"
|
|
fi
|
|
}
|
|
|
|
# Stop the backend container
|
|
echo "Stopping backend containers..."
|
|
cd "$SCRIPT_DIR"
|
|
run_docker_compose -f docker-compose.test.yml down
|
|
|
|
# Stop the frontend development server if we started it
|
|
if [ -f "$SCRIPT_DIR/frontend.pid" ]; then
|
|
FRONTEND_PID=$(cat "$SCRIPT_DIR/frontend.pid")
|
|
echo "Stopping frontend development server (PID: $FRONTEND_PID)..."
|
|
|
|
if kill -0 $FRONTEND_PID 2>/dev/null; then
|
|
kill $FRONTEND_PID
|
|
echo "Frontend development server stopped"
|
|
else
|
|
echo "Frontend development server is not running with PID $FRONTEND_PID"
|
|
fi
|
|
|
|
rm -f "$SCRIPT_DIR/frontend.pid"
|
|
rm -f "$SCRIPT_DIR/frontend.log"
|
|
else
|
|
echo "No frontend PID file found, assuming it was started externally"
|
|
fi
|
|
|
|
echo -e "${GREEN}Test environment has been stopped${NC}"
|
|
EOF
|
|
chmod +x "$SCRIPT_DIR/cypress/stop-test-environment.sh"
|
|
log "Test environment shutdown script created and made executable"
|
|
fi
|
|
|
|
# Build Docker image with error handling
|
|
log "Building Docker image (this may take a while)..."
|
|
|
|
# Check available disk space before starting build
|
|
available_space=$(df -m / | awk 'NR==2 {print $4}')
|
|
if [ "$available_space" -lt 2000 ]; then
|
|
log "WARNING: Low disk space (${available_space}MB). Docker build may fail."
|
|
log "Consider freeing up at least 2GB of space before continuing."
|
|
read -p "Continue anyway? (y/n): " continue_build
|
|
if [ "$continue_build" != "y" ] && [ "$continue_build" != "Y" ]; then
|
|
log "Docker build aborted due to low disk space."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Test Docker is working properly
|
|
if ! docker info >> "$LOG_FILE" 2>&1; then
|
|
log "ERROR: Docker is not running or the current user doesn't have permission to use Docker."
|
|
log "Try running 'sudo systemctl restart docker' or add your user to the docker group with:"
|
|
log "'sudo usermod -aG docker $USER' and then log out and back in."
|
|
exit 1
|
|
fi
|
|
|
|
# Try to use existing build script if available
|
|
if [ -f "$SCRIPT_DIR/docker/build.sh" ]; then
|
|
log "Using existing build script..."
|
|
cd "$SCRIPT_DIR/docker"
|
|
if bash build.sh >> "$LOG_FILE" 2>&1; then
|
|
log "Docker image built successfully using build.sh"
|
|
else
|
|
log "ERROR: Docker build failed using build.sh script"
|
|
log "Attempting direct build as fallback..."
|
|
cd "$SCRIPT_DIR"
|
|
if docker build -t myp-rp:latest . >> "$LOG_FILE" 2>&1; then
|
|
log "Docker image built successfully using direct method"
|
|
else
|
|
log "ERROR: Docker build failed. Check the log at $LOG_FILE for details."
|
|
exit 1
|
|
fi
|
|
fi
|
|
else
|
|
# Direct build method
|
|
log "Building Docker image manually..."
|
|
cd "$SCRIPT_DIR"
|
|
if docker build -t myp-rp:latest . >> "$LOG_FILE" 2>&1; then
|
|
log "Docker image built successfully"
|
|
else
|
|
log "ERROR: Docker build failed. Check the log at $LOG_FILE for details."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Verify the image was created
|
|
if docker image inspect myp-rp:latest >> /dev/null 2>&1; then
|
|
log "Verified: Docker image myp-rp:latest exists"
|
|
else
|
|
log "ERROR: Docker image myp-rp:latest does not exist after build"
|
|
exit 1
|
|
fi
|
|
|
|
# Start the application with error handling
|
|
log "Starting the application using Docker Compose..."
|
|
cd "$SCRIPT_DIR/docker"
|
|
|
|
# Ensure we have the compose file
|
|
if [ ! -f "compose.yml" ]; then
|
|
log "ERROR: compose.yml not found in $(pwd)"
|
|
log "Looking for compose file in alternative locations..."
|
|
find "$SCRIPT_DIR" -name "compose.yml" -o -name "docker-compose.yml" 2>/dev/null | while read compose_file; do
|
|
log "Found compose file at: $compose_file"
|
|
done
|
|
exit 1
|
|
fi
|
|
|
|
# Test docker-compose to make sure it's working
|
|
if ! docker-compose version >> "$LOG_FILE" 2>&1; then
|
|
log "WARNING: docker-compose command failed. Trying with docker compose (with space)..."
|
|
if ! docker compose version >> "$LOG_FILE" 2>&1; then
|
|
log "ERROR: Both docker-compose and docker compose commands failed."
|
|
log "Please check Docker and Docker Compose installation."
|
|
exit 1
|
|
else
|
|
# Use docker compose instead
|
|
log "Using docker compose (with space) command..."
|
|
if docker compose -f compose.yml up -d >> "$LOG_FILE" 2>&1; then
|
|
log "Application started successfully with docker compose!"
|
|
else
|
|
log "ERROR: Failed to start application with docker compose."
|
|
log "Check logs with: docker compose -f compose.yml logs"
|
|
exit 1
|
|
fi
|
|
fi
|
|
else
|
|
# Use docker-compose
|
|
if docker-compose -f compose.yml up -d >> "$LOG_FILE" 2>&1; then
|
|
log "Application started successfully with docker-compose!"
|
|
else
|
|
log "ERROR: Failed to start application with docker-compose."
|
|
log "Check logs with: docker-compose -f compose.yml logs"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Verify containers are running
|
|
log "Verifying containers are running..."
|
|
sleep 5 # Give containers a moment to start
|
|
|
|
running_containers=$(docker ps --format '{{.Names}}' | grep -c "myp\|frontend\|caddy" || echo "0")
|
|
if [ "$running_containers" -gt 0 ]; then
|
|
log "Detected $running_containers running containers related to MYP."
|
|
else
|
|
log "WARNING: No running containers detected for MYP frontend."
|
|
log "Check container status with: docker ps -a"
|
|
fi
|
|
|
|
log "Frontend installed and running in production mode!"
|
|
log "The application should be accessible at http://localhost"
|
|
log "Check logs with: docker-compose -f $SCRIPT_DIR/docker/compose.yml logs -f"
|
|
|
|
else
|
|
# Development mode
|
|
log "Setting up in development mode..."
|
|
|
|
# Install dependencies
|
|
log "Installing project dependencies with pnpm..."
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Make sure we're in the right directory and pnpm is available
|
|
log "Current directory: $(pwd)"
|
|
log "Checking pnpm path: $(which pnpm 2>/dev/null || echo 'pnpm not found in PATH')"
|
|
|
|
# Install dependencies with retry mechanism
|
|
max_attempts=3
|
|
attempt=1
|
|
success=false
|
|
|
|
while [ $attempt -le $max_attempts ] && [ "$success" = "false" ]; do
|
|
log "Attempt $attempt of $max_attempts to install dependencies..."
|
|
|
|
if command_exists pnpm; then
|
|
if pnpm install >> "$LOG_FILE" 2>&1; then
|
|
log "Dependencies installed successfully!"
|
|
success=true
|
|
else
|
|
log "WARNING: pnpm install failed on attempt $attempt"
|
|
fi
|
|
else
|
|
log "ERROR: pnpm not found in PATH. Trying to fix..."
|
|
export PATH="$PATH:$HOME/.local/share/pnpm:$HOME/.pnpm:$(npm global bin)"
|
|
if ! command_exists pnpm; then
|
|
log "Attempting to reinstall pnpm..."
|
|
npm install -g pnpm >> "$LOG_FILE" 2>&1
|
|
fi
|
|
fi
|
|
|
|
attempt=$((attempt+1))
|
|
|
|
# If we've failed but have more attempts to go, wait a bit before trying again
|
|
if [ "$success" = "false" ] && [ $attempt -le $max_attempts ]; then
|
|
log "Waiting 5 seconds before retry..."
|
|
sleep 5
|
|
fi
|
|
done
|
|
|
|
if [ "$success" = "false" ]; then
|
|
log "ERROR: Failed to install dependencies after $max_attempts attempts."
|
|
log "Please check the log file at $LOG_FILE for details."
|
|
log "You may need to run 'pnpm install' manually in $SCRIPT_DIR"
|
|
else
|
|
log "Dependencies successfully installed."
|
|
fi
|
|
|
|
# Create .env.local file for development
|
|
if [ ! -f "$SCRIPT_DIR/.env.local" ]; then
|
|
log "Creating development environment file with static backend URL..."
|
|
cat > "$SCRIPT_DIR/.env.local" << EOF
|
|
# Development Environment Variables
|
|
|
|
# GitHub OAuth
|
|
AUTH_GITHUB_ID=your_github_client_id
|
|
AUTH_GITHUB_SECRET=your_github_client_secret
|
|
AUTH_SECRET=$(openssl rand -hex 32)
|
|
AUTH_TRUST_HOST=true
|
|
|
|
# Backend URL - Static IP for backend
|
|
NEXT_PUBLIC_BACKEND_URL=http://192.168.0.105:5000
|
|
|
|
# Test environment
|
|
CYPRESS_TEST_USER=test-user
|
|
EOF
|
|
log "ATTENTION: Development environment file created with generated AUTH_SECRET"
|
|
log " Backend URL set to http://192.168.0.105:5000"
|
|
log " Added Cypress test user configuration"
|
|
log " Please edit $SCRIPT_DIR/.env.local with your actual GitHub OAuth credentials"
|
|
fi
|
|
|
|
# Set up Cypress testing if it doesn't exist
|
|
if [ ! -f "$SCRIPT_DIR/cypress.config.ts" ]; then
|
|
log "Setting up Cypress configuration..."
|
|
cat > "$SCRIPT_DIR/cypress.config.ts" << EOF
|
|
import { defineConfig } from 'cypress'
|
|
|
|
export default defineConfig({
|
|
e2e: {
|
|
baseUrl: 'http://localhost:3000',
|
|
supportFile: 'cypress/support/commands.ts',
|
|
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
|
|
},
|
|
component: {
|
|
devServer: {
|
|
framework: 'next',
|
|
bundler: 'webpack',
|
|
},
|
|
},
|
|
env: {
|
|
backendUrl: 'http://localhost:5000',
|
|
},
|
|
})
|
|
EOF
|
|
log "Cypress configuration created"
|
|
fi
|
|
|
|
# Create Cypress support directory if it doesn't exist
|
|
if [ ! -d "$SCRIPT_DIR/cypress/support" ]; then
|
|
log "Creating Cypress support directory..."
|
|
mkdir -p "$SCRIPT_DIR/cypress/support"
|
|
fi
|
|
|
|
# Add Cypress commands file if it doesn't exist
|
|
if [ ! -f "$SCRIPT_DIR/cypress/support/commands.ts" ]; then
|
|
log "Creating Cypress commands file..."
|
|
cat > "$SCRIPT_DIR/cypress/support/commands.ts" << EOF
|
|
// -- This is a parent command --
|
|
Cypress.Commands.add('login', () => {
|
|
// Simulate logged in user without OAuth
|
|
window.localStorage.setItem('myp:user', JSON.stringify({
|
|
id: 'test-user-id',
|
|
name: 'Test User',
|
|
email: 'test@example.com',
|
|
role: 'user'
|
|
}))
|
|
})
|
|
|
|
// -- This is a child command --
|
|
Cypress.Commands.add('createPrintJob', (printerId, duration) => {
|
|
cy.intercept('POST', \`/api/printers/\${printerId}/reserve\`, {
|
|
id: 'test-job-id',
|
|
printerId,
|
|
userId: 'test-user-id',
|
|
startTime: new Date().toISOString(),
|
|
endTime: new Date(Date.now() + duration * 60000).toISOString(),
|
|
status: 'active'
|
|
}).as('createJob')
|
|
|
|
return cy.wrap('test-job-id')
|
|
})
|
|
|
|
declare global {
|
|
namespace Cypress {
|
|
interface Chainable {
|
|
login(): Chainable<void>
|
|
createPrintJob(printerId: string, duration: number): Chainable<string>
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
log "Cypress commands file created"
|
|
fi
|
|
|
|
# Create Cypress e2e directory if it doesn't exist
|
|
if [ ! -d "$SCRIPT_DIR/cypress/e2e" ]; then
|
|
log "Creating Cypress e2e directory..."
|
|
mkdir -p "$SCRIPT_DIR/cypress/e2e"
|
|
fi
|
|
|
|
# Add Cypress example test file if it doesn't exist
|
|
if [ ! -f "$SCRIPT_DIR/cypress/e2e/home.cy.ts" ]; then
|
|
log "Creating Cypress example test file..."
|
|
cat > "$SCRIPT_DIR/cypress/e2e/home.cy.ts" << EOF
|
|
describe('Homepage', () => {
|
|
beforeEach(() => {
|
|
cy.visit('/')
|
|
})
|
|
|
|
it('loads the homepage successfully', () => {
|
|
cy.contains('Manage Your Printers')
|
|
cy.get('a[href="/printer"]').should('exist')
|
|
})
|
|
|
|
it('shows printer cards', () => {
|
|
cy.get('[class*="w-auto h-36"]').should('exist')
|
|
})
|
|
|
|
it('has working navigation', () => {
|
|
cy.get('header').should('exist')
|
|
cy.get('a[href="/"]').should('exist')
|
|
})
|
|
})
|
|
EOF
|
|
log "Cypress example test file created"
|
|
fi
|
|
|
|
# Create systemd service for development mode (if running as root)
|
|
if [ "$NO_SUDO" = "false" ]; then
|
|
log "Creating systemd service for development mode..."
|
|
cat > /etc/systemd/system/myp-frontend-dev.service << EOF
|
|
[Unit]
|
|
Description=MYP Frontend Development Service
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=${SUDO_USER:-$USER}
|
|
WorkingDirectory=$SCRIPT_DIR
|
|
ExecStart=$(which pnpm 2>/dev/null || echo "/usr/bin/pnpm") dev
|
|
Restart=always
|
|
RestartSec=10
|
|
Environment=PATH=/usr/bin:/usr/local/bin:${HOME}/.local/share/pnpm:${HOME}/.local/bin:${HOME}/.nvm/versions/node/$(node -v 2>/dev/null || echo "v20.0.0")/bin
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
# Reload systemd and enable the service
|
|
systemctl daemon-reload
|
|
systemctl enable myp-frontend-dev.service
|
|
else
|
|
# Create a user-level service file for systemd if possible
|
|
log "Creating user-level service file for development mode..."
|
|
mkdir -p "$HOME/.config/systemd/user"
|
|
cat > "$HOME/.config/systemd/user/myp-frontend-dev.service" << EOF
|
|
[Unit]
|
|
Description=MYP Frontend Development Service
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=$SCRIPT_DIR
|
|
ExecStart=$(which pnpm 2>/dev/null || echo "${HOME}/.local/bin/pnpm") dev
|
|
Restart=always
|
|
RestartSec=10
|
|
Environment=PATH=/usr/bin:/usr/local/bin:${HOME}/.local/share/pnpm:${HOME}/.local/bin:${HOME}/.nvm/versions/node/$(node -v 2>/dev/null || echo "v20.0.0")/bin
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
EOF
|
|
|
|
# Create a convenient start script
|
|
cat > "$SCRIPT_DIR/start-dev-server.sh" << 'EOF'
|
|
#!/bin/bash
|
|
|
|
# Script to start the development server
|
|
|
|
# Get the directory where this script is located
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
# Source environment setup
|
|
if [ -f "$HOME/.bashrc" ]; then
|
|
source "$HOME/.bashrc"
|
|
fi
|
|
|
|
# Ensure NVM is loaded if available
|
|
if [ -d "$HOME/.nvm" ]; then
|
|
export NVM_DIR="$HOME/.nvm"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
|
|
nvm use 20 &>/dev/null || true
|
|
fi
|
|
|
|
# Add pnpm to PATH if not already there
|
|
if [ -d "$HOME/.local/share/pnpm" ]; then
|
|
export PNPM_HOME="$HOME/.local/share/pnpm"
|
|
export PATH="$PNPM_HOME:$PATH"
|
|
fi
|
|
|
|
if [ -d "$HOME/.local/bin" ]; then
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
fi
|
|
|
|
# Change to the script directory
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Check for pnpm
|
|
if ! command -v pnpm &>/dev/null; then
|
|
echo "ERROR: pnpm not found in PATH"
|
|
echo "Try installing it with: npm install -g pnpm"
|
|
exit 1
|
|
fi
|
|
|
|
# Start the development server
|
|
echo "Starting MYP frontend development server..."
|
|
pnpm dev
|
|
EOF
|
|
chmod +x "$SCRIPT_DIR/start-dev-server.sh"
|
|
|
|
log_success "Created user-level service and start script"
|
|
log "To start the development server manually, run: $SCRIPT_DIR/start-dev-server.sh"
|
|
log "To use systemd user service: systemctl --user enable --now myp-frontend-dev.service"
|
|
fi
|
|
|
|
log "Installation complete!"
|
|
log ""
|
|
log "To start the frontend development service, run: systemctl start myp-frontend-dev"
|
|
log "To check service status, run: systemctl status myp-frontend-dev"
|
|
log "To view logs, run: journalctl -u myp-frontend-dev -f"
|
|
log ""
|
|
log "For manual development startup, run: cd $SCRIPT_DIR && pnpm dev"
|
|
log ""
|
|
log "The application should be accessible at http://localhost:3000 when running"
|
|
fi
|
|
|
|
# Perform one-time installation of dependencies using pnpm
|
|
log "Installing project dependencies with pnpm..."
|
|
# First check that pnpm is definitely in PATH
|
|
if ! command_exists pnpm; then
|
|
log_error "pnpm still not found in PATH despite installation attempts"
|
|
log_error "PATH: $PATH"
|
|
log_error "Checking for pnpm installation locations..."
|
|
|
|
for pnpm_location in "$HOME/.local/bin/pnpm" "$HOME/.local/share/pnpm/pnpm" "/usr/local/bin/pnpm" "/usr/bin/pnpm"; do
|
|
if [ -f "$pnpm_location" ]; then
|
|
log_warning "pnpm found at $pnpm_location but not in PATH"
|
|
log_warning "Using absolute path to install dependencies..."
|
|
|
|
# Use absolute path to pnpm
|
|
cd "$SCRIPT_DIR"
|
|
"$pnpm_location" install >> "$LOG_FILE" 2>&1
|
|
PNPM_STATUS=$?
|
|
|
|
if [ $PNPM_STATUS -eq 0 ]; then
|
|
log_success "Project dependencies installed using absolute pnpm path"
|
|
else
|
|
log_error "Failed to install dependencies using absolute pnpm path"
|
|
fi
|
|
|
|
break
|
|
fi
|
|
done
|
|
else
|
|
# pnpm is in PATH
|
|
cd "$SCRIPT_DIR"
|
|
pnpm install >> "$LOG_FILE" 2>&1
|
|
PNPM_STATUS=$?
|
|
|
|
if [ $PNPM_STATUS -eq 0 ]; then
|
|
log_success "Project dependencies installed"
|
|
else
|
|
log_error "Failed to install dependencies"
|
|
fi
|
|
fi
|
|
|
|
log "For issues, check the log file at: $LOG_FILE"
|
|
# Add helpful commands for post-installation management
|
|
log "===== Post-Installation Information ====="
|
|
log "Here are some helpful commands for managing your installation:"
|
|
log ""
|
|
log "System management:"
|
|
log " - Check system status: htop, free -h, df -h"
|
|
log " - Network status: ip a, netstat -tulpn, ss -tulpn"
|
|
log " - View logs: tail -f /var/log/syslog, journalctl -f"
|
|
log ""
|
|
log "Frontend development:"
|
|
log " - Start development server: $SCRIPT_DIR/start-dev-server.sh"
|
|
log " - Install missing dependencies: cd $SCRIPT_DIR && pnpm install"
|
|
log " - Lint code: cd $SCRIPT_DIR && pnpm lint"
|
|
log " - Format code: cd $SCRIPT_DIR && npx @biomejs/biome format --write ./src"
|
|
log ""
|
|
log "Docker management:"
|
|
log " - List containers: docker ps -a"
|
|
log " - Container logs: docker logs <container_id>"
|
|
log " - Stop containers: docker-compose -f $SCRIPT_DIR/docker/compose.yml down"
|
|
log " - Start containers: docker-compose -f $SCRIPT_DIR/docker/compose.yml up -d"
|
|
log " - Restart containers: docker-compose -f $SCRIPT_DIR/docker/compose.yml restart"
|
|
log ""
|
|
if [ "$test_environment" = "y" ] || [ "$test_environment" = "Y" ]; then
|
|
log "Test environment commands:"
|
|
log " - Run integration test: bash $SCRIPT_DIR/docker/test-integration.sh"
|
|
log " - View test logs: cat $SCRIPT_DIR/docker/test-integration.log"
|
|
log " - Stop test environment: docker-compose -f $SCRIPT_DIR/docker/test-env.yml down"
|
|
else
|
|
log "Testing environment:"
|
|
log " - Start test environment: cd $SCRIPT_DIR && pnpm test:start-environment"
|
|
log " - Run Cypress tests: cd $SCRIPT_DIR && pnpm cypress"
|
|
log " - Stop test environment: cd $SCRIPT_DIR && pnpm test:stop-environment"
|
|
log " - To install test environment: $0 --auto-test"
|
|
fi
|
|
log ""
|
|
log "Backend connection:"
|
|
log " - Test backend connection: curl -I http://192.168.0.105:5000/api/test"
|
|
log " - Check backend accessibility: ping 192.168.0.105"
|
|
log ""
|
|
log "Installation Complete! 🎉" |