mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-07 21:44:51 +00:00
* Add devenv subcommands for test / format * Rename dev-env-config to devenvconfig for consitency sake
597 lines
18 KiB
Bash
Executable File
597 lines
18 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# InvoiceShelf Development Environment Startup Script
|
|
# Supports Linux and macOS
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Function to print colored output
|
|
print_info() {
|
|
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"
|
|
}
|
|
|
|
# Function to show usage
|
|
show_usage() {
|
|
echo "Usage: $0 [COMMAND]"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " (no command) Start the development environment (interactive setup)"
|
|
echo " start Start the development environment with existing configuration"
|
|
echo " stop Stop the development environment"
|
|
echo " destroy Stop and remove containers, networks, and images"
|
|
echo " logs Show logs from all services"
|
|
echo " rebuild Rebuild and restart the development environment"
|
|
echo " shell Enter the PHP container's shell"
|
|
echo " run [CMD] Run a command inside the PHP container (e.g., ./artisan)"
|
|
echo " test Run the test suite (Pest)"
|
|
echo " format Format the code (Pint)"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 # Interactive setup and start"
|
|
echo " $0 start # Start with last used configuration"
|
|
echo " $0 stop # Stop all services"
|
|
echo " $0 logs # View logs"
|
|
echo " $0 shell # Get a shell inside the PHP container"
|
|
echo " $0 run ./artisan --help"
|
|
}
|
|
|
|
# Function to detect OS
|
|
detect_os() {
|
|
case "$(uname -s)" in
|
|
Linux*) echo "linux";;
|
|
Darwin*) echo "mac";;
|
|
*) echo "unsupported";;
|
|
esac
|
|
}
|
|
|
|
# Function to get docker compose command
|
|
get_docker_compose_cmd() {
|
|
if command -v docker-compose &> /dev/null; then
|
|
echo "docker-compose"
|
|
else
|
|
echo "docker compose"
|
|
fi
|
|
}
|
|
|
|
# Function to find the most recent compose file used
|
|
find_compose_file() {
|
|
local config_file=".devenvconfig"
|
|
|
|
if [ -f "$config_file" ]; then
|
|
cat "$config_file"
|
|
else
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
# Function to save compose file configuration
|
|
save_config() {
|
|
local compose_file=$1
|
|
echo "$compose_file" > .devenvconfig
|
|
}
|
|
|
|
# Function to check if host entry exists
|
|
check_host_entry() {
|
|
if grep -q "invoiceshelf.test" /etc/hosts; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to add host entry
|
|
add_host_entry() {
|
|
local os_type=$1
|
|
|
|
print_info "Adding invoiceshelf.test to /etc/hosts..."
|
|
|
|
if [ "$os_type" = "linux" ] || [ "$os_type" = "mac" ]; then
|
|
# Check if we can write to /etc/hosts
|
|
if [ ! -w /etc/hosts ]; then
|
|
print_warning "Root permissions required to modify /etc/hosts"
|
|
if sudo sh -c 'echo "127.0.0.1 invoiceshelf.test" >> /etc/hosts'; then
|
|
print_success "Host entry added successfully"
|
|
else
|
|
print_error "Failed to add host entry"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "127.0.0.1 invoiceshelf.test" >> /etc/hosts
|
|
print_success "Host entry added successfully"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to select database type
|
|
select_database() {
|
|
echo "" >&2
|
|
print_info "Select database type:" >&2
|
|
echo "1) MySQL/MariaDB" >&2
|
|
echo "2) PostgreSQL" >&2
|
|
echo "3) SQLite" >&2
|
|
|
|
while true; do
|
|
read -p "Enter your choice (1-3): " db_choice
|
|
case $db_choice in
|
|
1) echo "mysql"; break;;
|
|
2) echo "pgsql"; break;;
|
|
3) echo "sqlite"; break;;
|
|
*) print_error "Invalid choice. Please enter 1, 2, or 3." >&2;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Function to ask about gotenberg
|
|
ask_gotenberg() {
|
|
echo "" >&2
|
|
print_info "Do you want to use Gotenberg for PDF generation?" >&2
|
|
print_info "Gotenberg provides better PDF generation capabilities but requires more resources." >&2
|
|
|
|
while true; do
|
|
read -p "Use Gotenberg? (y/n): " gotenberg_choice
|
|
case $gotenberg_choice in
|
|
[Yy]* ) echo "yes"; break;;
|
|
[Nn]* ) echo "no"; break;;
|
|
* ) print_error "Please answer yes (y) or no (n)." >&2;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Function to validate environment
|
|
validate_environment() {
|
|
# Detect OS
|
|
local os_type=$(detect_os)
|
|
|
|
if [ "$os_type" = "unsupported" ]; then
|
|
print_error "Unsupported operating system. This script only supports Linux and macOS."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if Docker is installed
|
|
if ! command -v docker &> /dev/null; then
|
|
print_error "Docker is not installed. Please install Docker first."
|
|
echo ""
|
|
print_info "Installation instructions:"
|
|
if [ "$os_type" = "linux" ]; then
|
|
echo " • Ubuntu/Debian: https://docs.docker.com/engine/install/ubuntu/"
|
|
echo " • CentOS/RHEL: https://docs.docker.com/engine/install/centos/"
|
|
echo " • Fedora: https://docs.docker.com/engine/install/fedora/"
|
|
else
|
|
echo " • macOS: https://docs.docker.com/desktop/mac/install/"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Check if Docker daemon is running
|
|
print_info "Checking Docker daemon status..."
|
|
if ! docker info &> /dev/null; then
|
|
print_error "Docker daemon is not running."
|
|
echo ""
|
|
print_info "To start Docker:"
|
|
if [ "$os_type" = "linux" ]; then
|
|
echo " • systemctl start docker"
|
|
echo " • sudo systemctl start docker (if not in docker group)"
|
|
echo " • Or start Docker Desktop if using it"
|
|
else
|
|
echo " • Start Docker Desktop application"
|
|
echo " • Or run: open -a Docker"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Check Docker daemon connectivity and permissions
|
|
if ! docker ps &> /dev/null; then
|
|
print_error "Cannot connect to Docker daemon. Permission denied."
|
|
echo ""
|
|
print_info "This might be a permissions issue. Try:"
|
|
if [ "$os_type" = "linux" ]; then
|
|
echo " • sudo usermod -aG docker \$USER"
|
|
echo " • Log out and log back in"
|
|
echo " • Or run the script with sudo (not recommended)"
|
|
else
|
|
echo " • Restart Docker Desktop"
|
|
echo " • Check Docker Desktop settings"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Check if Docker Compose is available
|
|
local compose_available=false
|
|
local compose_cmd=""
|
|
|
|
if command -v docker-compose &> /dev/null; then
|
|
if docker-compose version &> /dev/null; then
|
|
compose_available=true
|
|
compose_cmd="docker-compose"
|
|
fi
|
|
fi
|
|
|
|
if ! $compose_available && docker compose version &> /dev/null 2>&1; then
|
|
compose_available=true
|
|
compose_cmd="docker compose"
|
|
fi
|
|
|
|
if ! $compose_available; then
|
|
print_error "Docker Compose is not available or not working properly."
|
|
echo ""
|
|
print_info "Installation instructions:"
|
|
if [ "$os_type" = "linux" ]; then
|
|
echo " • Install docker-compose: sudo apt-get install docker-compose"
|
|
echo " • Or use Docker Compose V2: https://docs.docker.com/compose/install/"
|
|
else
|
|
echo " • Docker Compose should be included with Docker Desktop"
|
|
echo " • Try restarting Docker Desktop"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Check available system resources
|
|
print_info "Checking system resources..."
|
|
|
|
# Check available disk space (require at least 2GB free)
|
|
local available_space
|
|
if [ "$os_type" = "linux" ]; then
|
|
available_space=$(df / | awk 'NR==2 {print $4}')
|
|
else
|
|
available_space=$(df / | awk 'NR==2 {print $4}')
|
|
fi
|
|
|
|
# Convert KB to GB (approximate)
|
|
local available_gb=$((available_space / 1024 / 1024))
|
|
|
|
if [ $available_gb -lt 2 ]; then
|
|
print_warning "Low disk space detected: ${available_gb}GB available"
|
|
print_warning "Docker images and containers require significant disk space"
|
|
read -p "Continue anyway? (y/N): " continue_choice
|
|
case $continue_choice in
|
|
[Yy]* ) ;;
|
|
* ) print_info "Operation cancelled."; exit 1;;
|
|
esac
|
|
fi
|
|
|
|
# Check if Docker has enough resources allocated (for Docker Desktop)
|
|
if [ "$os_type" = "mac" ] || ([ "$os_type" = "linux" ] && command -v docker-desktop &> /dev/null); then
|
|
print_info "Detected Docker Desktop - ensure adequate resources are allocated"
|
|
print_info "Recommended: 4GB RAM, 2 CPU cores, 20GB disk space"
|
|
fi
|
|
|
|
print_success "Docker environment validation completed"
|
|
}
|
|
|
|
# Function to get compose file for subcommands
|
|
get_compose_file_for_cmd() {
|
|
local compose_file=$(find_compose_file)
|
|
|
|
if [ -z "$compose_file" ] || [ ! -f "$compose_file" ]; then
|
|
print_error "No previous configuration found. Please run the script without arguments first to set up the environment."
|
|
exit 1
|
|
fi
|
|
|
|
echo "$compose_file"
|
|
}
|
|
|
|
# Subcommand functions
|
|
cmd_start() {
|
|
print_info "Starting development environment..."
|
|
|
|
local compose_file=$(get_compose_file_for_cmd)
|
|
local docker_compose=$(get_docker_compose_cmd)
|
|
|
|
print_info "Using compose file: $compose_file"
|
|
|
|
if $docker_compose -f "$compose_file" up -d; then
|
|
print_success "Development environment started successfully!"
|
|
show_service_info
|
|
else
|
|
print_error "Failed to start development environment"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
cmd_stop() {
|
|
print_info "Stopping development environment..."
|
|
|
|
local compose_file=$(get_compose_file_for_cmd)
|
|
local docker_compose=$(get_docker_compose_cmd)
|
|
|
|
if $docker_compose -f "$compose_file" down --remove-orphans; then
|
|
print_success "Development environment stopped successfully!"
|
|
else
|
|
print_error "Failed to stop development environment"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
cmd_destroy() {
|
|
print_info "Destroying development environment (removing containers, networks, and images)..."
|
|
|
|
local compose_file=$(get_compose_file_for_cmd)
|
|
local docker_compose=$(get_docker_compose_cmd)
|
|
|
|
print_warning "This will remove all containers, networks, and images for this project."
|
|
read -p "Are you sure? (y/N): " confirm
|
|
|
|
case $confirm in
|
|
[Yy]* )
|
|
if $docker_compose -f "$compose_file" down --rmi all --volumes --remove-orphans; then
|
|
print_success "Development environment destroyed successfully!"
|
|
# Remove the config file since everything is destroyed
|
|
rm -f .devenvconfig
|
|
else
|
|
print_error "Failed to destroy development environment"
|
|
exit 1
|
|
fi
|
|
;;
|
|
* )
|
|
print_info "Operation cancelled."
|
|
;;
|
|
esac
|
|
}
|
|
|
|
cmd_logs() {
|
|
print_info "Showing logs from development environment..."
|
|
|
|
local compose_file=$(get_compose_file_for_cmd)
|
|
local docker_compose=$(get_docker_compose_cmd)
|
|
|
|
# Check if any additional arguments were passed for specific services
|
|
shift # Remove 'logs' from arguments
|
|
|
|
if [ $# -gt 0 ]; then
|
|
print_info "Showing logs for services: $*"
|
|
$docker_compose -f "$compose_file" logs -f "$@"
|
|
else
|
|
print_info "Showing logs for all services (Press Ctrl+C to exit)"
|
|
$docker_compose -f "$compose_file" logs -f
|
|
fi
|
|
}
|
|
|
|
cmd_rebuild() {
|
|
print_info "Rebuilding development environment..."
|
|
|
|
local compose_file=$(get_compose_file_for_cmd)
|
|
local docker_compose=$(get_docker_compose_cmd)
|
|
|
|
print_info "Stopping services..."
|
|
$docker_compose -f "$compose_file" down
|
|
|
|
print_info "Rebuilding images..."
|
|
if $docker_compose -f "$compose_file" build --no-cache; then
|
|
print_info "Starting services..."
|
|
if $docker_compose -f "$compose_file" up -d; then
|
|
print_success "Development environment rebuilt and started successfully!"
|
|
show_service_info
|
|
else
|
|
print_error "Failed to start development environment after rebuild"
|
|
exit 1
|
|
fi
|
|
else
|
|
print_error "Failed to rebuild development environment"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
cmd_shell() {
|
|
print_info "Entering PHP container shell..."
|
|
|
|
# Check if the container is running first
|
|
if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
|
|
print_error "PHP container 'invoiceshelf-dev-php' is not running."
|
|
print_info "Start the development environment first with: $0 start"
|
|
exit 1
|
|
fi
|
|
|
|
print_info "Connecting to invoiceshelf-dev-php container... Type 'exit' to leave."
|
|
|
|
# Try /bin/bash first, fall back to /bin/sh if bash is not available
|
|
if ! docker exec -it invoiceshelf-dev-php /bin/bash; then
|
|
docker exec -it invoiceshelf-dev-php /bin/sh
|
|
fi
|
|
print_success "Exited from container shell."
|
|
}
|
|
|
|
cmd_run() {
|
|
shift # Remove 'run' from arguments
|
|
if [ $# -eq 0 ]; then
|
|
print_error "No command provided to 'run'."
|
|
show_usage
|
|
exit 1
|
|
fi
|
|
|
|
print_info "Running command inside PHP container: $@"
|
|
|
|
# Check if the container is running first
|
|
if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
|
|
print_error "PHP container 'invoiceshelf-dev-php' is not running."
|
|
print_info "Start the development environment first with: $0 start"
|
|
exit 1
|
|
fi
|
|
|
|
docker exec -it -w /var/www/html invoiceshelf-dev-php "$@"
|
|
}
|
|
|
|
# Function to run tests
|
|
cmd_test() {
|
|
print_info "Running tests (Pest)..."
|
|
|
|
# Check if the container is running first
|
|
if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
|
|
print_error "PHP container 'invoiceshelf-dev-php' is not running."
|
|
print_info "Start the development environment first with: $0 start"
|
|
exit 1
|
|
fi
|
|
|
|
shift # Remove 'test' from arguments
|
|
docker exec -it -w /var/www/html invoiceshelf-dev-php /var/www/html/vendor/bin/pest "$@"
|
|
}
|
|
|
|
# Function to format code
|
|
cmd_format() {
|
|
print_info "Formatting code (Pint)..."
|
|
|
|
# Check if the container is running first
|
|
if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
|
|
print_error "PHP container 'invoiceshelf-dev-php' is not running."
|
|
print_info "Start the development environment first with: $0 start"
|
|
exit 1
|
|
fi
|
|
|
|
shift # Remove 'format' from arguments
|
|
docker exec -it -w /var/www/html invoiceshelf-dev-php /var/www/html/vendor/bin/pint "$@"
|
|
}
|
|
|
|
# Function to show service information
|
|
show_service_info() {
|
|
echo ""
|
|
print_info "Available services:"
|
|
echo " • Application: http://invoiceshelf.test"
|
|
echo " • Adminer (DB): http://localhost:8080"
|
|
echo " • Mailpit: http://localhost:8025"
|
|
echo ""
|
|
print_info "Useful commands:"
|
|
echo " • Stop: $0 stop"
|
|
echo " • View logs: $0 logs"
|
|
echo " • Rebuild: $0 rebuild"
|
|
echo " • Shell: $0 shell"
|
|
echo " • Run command: $0 run php artisan help"
|
|
}
|
|
|
|
# Main setup function (original functionality)
|
|
setup_environment() {
|
|
print_info "InvoiceShelf Development Environment Setup"
|
|
echo "=========================================="
|
|
|
|
local os_type=$(detect_os)
|
|
print_success "Detected OS: $os_type"
|
|
|
|
validate_environment
|
|
|
|
local docker_compose=$(get_docker_compose_cmd)
|
|
print_success "Docker and Docker Compose are available"
|
|
|
|
# Check host entry
|
|
if check_host_entry; then
|
|
print_success "invoiceshelf.test host entry already exists"
|
|
else
|
|
print_warning "invoiceshelf.test host entry not found"
|
|
add_host_entry "$os_type"
|
|
fi
|
|
|
|
# Select database type
|
|
local db_type=$(select_database)
|
|
print_success "Selected database: $db_type"
|
|
|
|
# Ask about Gotenberg
|
|
local use_gotenberg=$(ask_gotenberg)
|
|
|
|
# Build compose file name
|
|
local compose_file
|
|
if [ "$use_gotenberg" = "yes" ]; then
|
|
compose_file="docker/development/docker-compose.${db_type}.gotenberg.yml"
|
|
print_success "Using Gotenberg-enabled compose file"
|
|
else
|
|
compose_file="docker/development/docker-compose.${db_type}.yml"
|
|
print_success "Using standard compose file"
|
|
fi
|
|
|
|
# Check if compose file exists
|
|
if [ ! -f "$compose_file" ]; then
|
|
print_error "Compose file not found: $compose_file"
|
|
exit 1
|
|
fi
|
|
|
|
# Save configuration for future use
|
|
save_config "$compose_file"
|
|
|
|
print_info "Starting development environment..."
|
|
print_info "Compose file: $compose_file"
|
|
|
|
# Start the development environment
|
|
if $docker_compose -f "$compose_file" up -d; then
|
|
echo ""
|
|
print_success "Development environment started successfully!"
|
|
show_service_info
|
|
else
|
|
print_error "Failed to start development environment"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Main script execution
|
|
main() {
|
|
local command=${1:-""}
|
|
|
|
case "$command" in
|
|
"start")
|
|
validate_environment > /dev/null
|
|
cmd_start
|
|
;;
|
|
"stop")
|
|
validate_environment > /dev/null
|
|
cmd_stop
|
|
;;
|
|
"destroy")
|
|
validate_environment > /dev/null
|
|
cmd_destroy
|
|
;;
|
|
"logs")
|
|
validate_environment > /dev/null
|
|
cmd_logs "$@"
|
|
;;
|
|
"rebuild")
|
|
validate_environment > /dev/null
|
|
cmd_rebuild
|
|
;;
|
|
"shell")
|
|
validate_environment > /dev/null
|
|
cmd_shell
|
|
;;
|
|
"run")
|
|
validate_environment > /dev/null
|
|
cmd_run "$@"
|
|
;;
|
|
"test")
|
|
validate_environment > /dev/null
|
|
cmd_test "$@"
|
|
;;
|
|
"format")
|
|
validate_environment > /dev/null
|
|
cmd_format "$@"
|
|
;;
|
|
"help"|"-h"|"--help")
|
|
show_usage
|
|
;;
|
|
"")
|
|
setup_environment
|
|
;;
|
|
*)
|
|
print_error "Unknown command: $command"
|
|
echo ""
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|