Initial commit: Complete NodeJS-native setup

- Migrated from Python pre-commit to NodeJS-native solution
- Reorganized documentation structure
- Set up Husky + lint-staged for efficient pre-commit hooks
- Fixed Dockerfile healthcheck issue
- Added comprehensive documentation index
This commit is contained in:
William Valentin
2025-09-06 01:42:48 -07:00
commit e48adbcb00
159 changed files with 24405 additions and 0 deletions

518
scripts/gitea-helper.sh Executable file
View File

@@ -0,0 +1,518 @@
#!/bin/bash
# gitea-deploy.sh - Gitea-specific deployment script
# Usage: ./gitea-deploy.sh [environment] [image-tag]
set -e # Exit on any error
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
# Load environment variables from .env file if it exists
if [ -f "$PROJECT_DIR/.env" ]; then
export $(cat "$PROJECT_DIR/.env" | grep -v '^#' | grep -E '^[A-Z_]+=.*' | xargs)
fi
ENVIRONMENT=${1:-production}
IMAGE_TAG=${2:-latest}
REGISTRY=${GITEA_REGISTRY:-${CONTAINER_REGISTRY:-"ghcr.io"}}
IMAGE_NAME=${GITEA_REPOSITORY:-${CONTAINER_REPOSITORY:-"rxminder"}}
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_status() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
echo "🚀 Deploying RxMinder from Gitea to $ENVIRONMENT environment..."
# Check if running in Gitea Actions
if [ "$GITEA_ACTIONS" = "true" ]; then
print_status "Running in Gitea Actions environment"
# Load Gitea-specific environment variables
REGISTRY=${GITEA_SERVER_URL#https://}
IMAGE_NAME=${GITEA_REPOSITORY}
IMAGE_TAG=${GITEA_SHA:0:8}
print_status "Registry: $REGISTRY"
print_status "Image: $IMAGE_NAME:$IMAGE_TAG"
fi
# Check if .env file exists
if [ ! -f ".env" ]; then
print_warning ".env file not found, using defaults"
# Create minimal .env for Gitea deployment
cat > .env << EOF
COUCHDB_USER=admin
COUCHDB_PASSWORD=change-this-secure-password
VITE_COUCHDB_URL=http://couchdb:5984
VITE_COUCHDB_USER=admin
VITE_COUCHDB_PASSWORD=change-this-secure-password
APP_BASE_URL=http://localhost:8080
NODE_ENV=production
EOF
print_warning "Created default .env file - please update with your credentials"
fi
# Load environment variables
print_status "Loading environment variables from .env file..."
export $(cat .env | grep -v '^#' | xargs)
# Validate required environment variables
REQUIRED_VARS=("COUCHDB_USER" "COUCHDB_PASSWORD" "VITE_COUCHDB_URL")
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var}" ]; then
print_error "Required environment variable $var is not set"
exit 1
fi
done
print_success "Environment variables validated"
# Function to deploy via Docker Compose
deploy_compose() {
print_status "Deploying with Docker Compose..."
# Export image variables for compose
export IMAGE_TAG
export REGISTRY
export IMAGE_NAME
# Use the built image from registry if available
if [ "$GITEA_ACTIONS" = "true" ]; then
# Override the image in docker-compose
export FRONTEND_IMAGE="$REGISTRY/$IMAGE_NAME:$IMAGE_TAG"
print_status "Using Gitea Actions built image: $FRONTEND_IMAGE"
fi
# Pull the latest images
print_status "Pulling latest images..."
docker-compose -f docker/docker-compose.yaml pull || print_warning "Failed to pull some images"
# Start services
print_status "Starting services..."
docker-compose -f docker/docker-compose.yaml up -d
# Wait for services
print_status "Waiting for services to be ready..."
sleep 10
# Health check
print_status "Checking service health..."
if curl -f http://localhost:8080/health > /dev/null 2>&1; then
print_success "Frontend service is healthy"
else
print_warning "Frontend health check failed, checking logs..."
docker-compose -f docker/docker-compose.yaml logs frontend
fi
if curl -f http://localhost:5984/_up > /dev/null 2>&1; then
print_success "CouchDB service is healthy"
else
print_warning "CouchDB health check failed"
fi
}
# Function to deploy via Kubernetes
deploy_k8s() {
print_status "Deploying to Kubernetes..."
if ! command -v kubectl &> /dev/null; then
print_error "kubectl is not installed"
exit 1
fi
# Update image in k8s manifests
if [ "$GITEA_ACTIONS" = "true" ]; then
print_status "Updating Kubernetes manifests with new image..."
sed -i "s|image:.*rxminder.*|image: $REGISTRY/$IMAGE_NAME:$IMAGE_TAG|g" k8s/frontend-deployment.yaml
fi
# Apply manifests
print_status "Applying Kubernetes manifests..."
kubectl apply -f k8s/
# Wait for rollout
print_status "Waiting for deployment rollout..."
kubectl rollout status deployment/frontend-deployment
print_success "Kubernetes deployment completed"
}
# Main deployment logic
case "$ENVIRONMENT" in
"production"|"prod")
print_status "Deploying to production environment"
deploy_compose
;;
"kubernetes"|"k8s")
print_status "Deploying to Kubernetes environment"
deploy_k8s
;;
"staging")
print_status "Deploying to staging environment"
# Use staging-specific configurations
export APP_BASE_URL="http://staging.localhost:8080"
deploy_compose
;;
*)
print_error "Unknown environment: $ENVIRONMENT"
echo "Available environments: production, kubernetes, staging"
exit 1
;;
esac
print_success "Deployment to $ENVIRONMENT completed successfully! 🎉"
# Post-deployment tasks
print_status "Running post-deployment tasks..."
# Cleanup old images (optional)
if [ "$CLEANUP_OLD_IMAGES" = "true" ]; then
print_status "Cleaning up old Docker images..."
docker image prune -f --filter "until=72h" || print_warning "Image cleanup failed"
fi
# Send notification (if configured)
if [ -n "$DEPLOYMENT_WEBHOOK_URL" ]; then
print_status "Sending deployment notification..."
curl -X POST "$DEPLOYMENT_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\":\"✅ RxMinder deployed to $ENVIRONMENT\", \"environment\":\"$ENVIRONMENT\", \"image\":\"$REGISTRY/$IMAGE_NAME:$IMAGE_TAG\"}" \
|| print_warning "Failed to send notification"
fi
print_success "All tasks completed! 🚀"
print_error "Docker is not installed"
exit 1
fi
# Check Docker Buildx
if ! docker buildx version >/dev/null 2>&1; then
print_error "Docker Buildx is not available"
exit 1
fi
# Check if in Gitea Actions environment
if [ "$GITEA_ACTIONS" = "true" ]; then
print_status "Running in Gitea Actions environment"
GITEA_REGISTRY=${GITEA_SERVER_URL#https://}
GITEA_REPOSITORY=${GITEA_REPOSITORY}
fi
print_success "All requirements met"
}
setup_buildx() {
print_status "Setting up Docker Buildx for Gitea..."
# Create builder if it doesn't exist
if ! docker buildx ls | grep -q "gitea-builder"; then
print_status "Creating Gitea buildx builder..."
docker buildx create \
--name gitea-builder \
--driver docker-container \
--bootstrap \
--use
print_success "Gitea builder created"
else
docker buildx use gitea-builder
print_success "Using existing Gitea builder"
fi
}
login_registry() {
print_status "Logging into Gitea registry..."
if [ -z "$GITEA_TOKEN" ]; then
print_error "GITEA_TOKEN environment variable is required"
print_status "Set it with: export GITEA_TOKEN=your_token"
exit 1
fi
# Login to Gitea registry
echo "$GITEA_TOKEN" | docker login "$GITEA_REGISTRY" -u "$GITEA_ACTOR" --password-stdin
print_success "Logged into Gitea registry"
}
build_local() {
print_status "Building for local development..."
cd "$PROJECT_DIR"
# Load environment variables
if [ -f ".env" ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Build with Gitea bake file
docker buildx bake \
-f .gitea/gitea-bake.hcl \
--set="*.platform=linux/amd64" \
--load \
dev
print_success "Local build completed"
}
build_multiplatform() {
local tag=${1:-$DEFAULT_TAG}
print_status "Building multi-platform image with tag: $tag..."
cd "$PROJECT_DIR"
# Load environment variables
if [ -f ".env" ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Export variables for bake
export TAG="$tag"
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "dev")}
# Build with Gitea bake file
docker buildx bake \
-f .gitea/gitea-bake.hcl \
app-ci
print_success "Multi-platform build completed"
}
build_staging() {
print_status "Building staging image..."
cd "$PROJECT_DIR"
# Load environment variables
if [ -f ".env.staging" ]; then
export $(cat .env.staging | grep -v '^#' | xargs)
elif [ -f ".env" ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Export variables for bake
export TAG="staging-$(date +%Y%m%d-%H%M%S)"
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "staging")}
# Build staging target
docker buildx bake \
-f .gitea/gitea-bake.hcl \
staging
print_success "Staging build completed"
}
build_production() {
local tag=${1:-$DEFAULT_TAG}
print_status "Building production image with tag: $tag..."
cd "$PROJECT_DIR"
# Load production environment variables
if [ -f ".env.production" ]; then
export $(cat .env.production | grep -v '^#' | xargs)
elif [ -f ".env" ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Export variables for bake
export TAG="$tag"
export GITEA_SHA=${GITEA_SHA:-$(git rev-parse --short HEAD 2>/dev/null || echo "prod")}
# Build production target with full attestations
docker buildx bake \
-f .gitea/gitea-bake.hcl \
prod
print_success "Production build completed"
}
test_local() {
print_status "Running tests locally..."
cd "$PROJECT_DIR"
# Install dependencies if needed
if [ ! -d "node_modules" ]; then
print_status "Installing dependencies..."
bun install --frozen-lockfile
fi
# Run linting
print_status "Running linter..."
bun run lint
# Run type checking
print_status "Running type checker..."
bun run type-check
# Run tests
print_status "Running tests..."
bun run test
print_success "All tests passed"
}
deploy() {
local environment=${1:-production}
local tag=${2:-latest}
print_status "Deploying to $environment with tag $tag..."
# Use the gitea-deploy script
"$SCRIPT_DIR/gitea-deploy.sh" "$environment" "$tag"
}
cleanup() {
print_status "Cleaning up Gitea builder and images..."
# Remove builder
if docker buildx ls | grep -q "gitea-builder"; then
docker buildx rm gitea-builder
print_success "Gitea builder removed"
fi
# Clean up old images (keep last 3 tags)
print_status "Cleaning up old images..."
docker image prune -f --filter "until=72h" || print_warning "Image cleanup failed"
print_success "Cleanup completed"
}
show_status() {
print_status "Gitea CI/CD Status"
echo
# Check environment
if [ "$GITEA_ACTIONS" = "true" ]; then
echo "🏃 Running in Gitea Actions"
echo "📦 Registry: $GITEA_REGISTRY"
echo "📋 Repository: $GITEA_REPOSITORY"
echo "🏷️ SHA: ${GITEA_SHA:-unknown}"
echo "🌿 Branch: ${GITEA_REF_NAME:-unknown}"
else
echo "💻 Running locally"
echo "📦 Registry: $GITEA_REGISTRY"
echo "📋 Repository: $GITEA_REPOSITORY"
fi
echo
# Check Docker and buildx
echo "🐳 Docker version: $(docker --version)"
echo "🔧 Buildx version: $(docker buildx version)"
# Check builders
echo
echo "🏗️ Available builders:"
docker buildx ls
}
show_help() {
cat << EOF
Gitea CI/CD Helper for RxMinder
Usage: $0 [command] [options]
Commands:
setup - Setup buildx builder for Gitea
login - Login to Gitea registry
build-local - Build for local development
build-multi [tag] - Build multi-platform image
build-staging - Build staging image
build-prod [tag] - Build production image
test - Run tests locally
deploy [env] [tag] - Deploy to environment
cleanup - Cleanup builders and images
status - Show CI/CD status
help - Show this help
Examples:
$0 setup
$0 build-local
$0 build-multi v1.2.3
$0 build-staging
$0 build-prod v1.2.3
$0 test
$0 deploy production v1.2.3
$0 deploy staging
$0 status
Environment Variables:
GITEA_REGISTRY - Gitea registry URL (default: gitea.example.com)
GITEA_REPOSITORY - Repository name (default: user/rxminder)
GITEA_TOKEN - Gitea access token (required for registry)
GITEA_ACTOR - Gitea username (for registry login)
EOF
}
# Main command handling
case "${1:-help}" in
"setup")
check_requirements
setup_buildx
;;
"login")
check_requirements
login_registry
;;
"build-local")
check_requirements
setup_buildx
build_local
;;
"build-multi")
check_requirements
setup_buildx
login_registry
build_multiplatform "$2"
;;
"build-staging")
check_requirements
setup_buildx
login_registry
build_staging
;;
"build-prod")
check_requirements
setup_buildx
login_registry
build_production "$2"
;;
"test")
test_local
;;
"deploy")
deploy "$2" "$3"
;;
"cleanup")
cleanup
;;
"status")
show_status
;;
"help"|*)
show_help
;;
esac