#!/bin/bash set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TEMP_DIR=$(mktemp -d) DEPLOY_FLAG=false RUN_FRONTEND=true RUN_BACKEND=true BUILDX_CACHE_BASE="/Volumes/Lenovo SSD/.buildx-cache" cleanup() { rm -rf "$TEMP_DIR" } trap cleanup EXIT log_info() { echo -e "${BLUE}ℹ ${NC}$1" } log_success() { echo -e "${GREEN}✓${NC} $1" } log_error() { echo -e "${RED}✗${NC} $1" } log_warning() { echo -e "${YELLOW}⚠${NC} $1" } prefix_output() { local prefix=$1 local color=$2 while IFS= read -r line; do echo -e "${color}[${prefix}]${NC} $line" done } show_help() { cat << EOF Usage: $(basename "$0") [OPTIONS] CI/CD Pipeline Script - Runs frontend and backend builds in parallel with optional deployment OPTIONS: --deploy Deploy to server after successful build --frontend-only Run only the frontend job --backend-only Run only the backend job --no-frontend Skip the frontend job --no-backend Skip the backend job --help Show this help message EXAMPLES: $(basename "$0") # Run all jobs in parallel $(basename "$0") --deploy # Run all jobs and deploy $(basename "$0") --frontend-only # Run only frontend job $(basename "$0") --backend-only # Run only backend job $(basename "$0") --frontend-only --deploy # Run frontend and deploy ENVIRONMENT: GIT_SHA Git commit SHA (default: current HEAD) NOTE: On macOS, the script will automatically launch in a new iTerm window. EOF exit 0 } check_command() { if ! command -v "$1" &> /dev/null; then log_error "Required command '$1' not found. Please install it first." exit 1 fi } check_version() { local cmd=$1 local expected=$2 local version_arg=$3 local version_output=$($cmd $version_arg 2>&1 || true) log_info "Checking $cmd version (expected: $expected)" echo " Found: $version_output" } validate_environment() { log_info "Validating environment..." check_command "node" check_command "pnpm" check_command "java" check_command "docker" if [ "$DEPLOY_FLAG" = true ]; then check_command "ssh" fi check_version "node" "22.16.0" "--version" check_version "java" "21" "--version" if [ -z "$GIT_SHA" ]; then GIT_SHA=$(git rev-parse HEAD 2>/dev/null || echo "unknown") export GIT_SHA log_info "GIT_SHA set to: $GIT_SHA" fi log_success "Environment validation completed" } frontend_job() { local log_file="$TEMP_DIR/frontend.log" local use_prefix=$1 ( set +e echo "==================== FRONTEND JOB ====================" log_info "Starting frontend build..." cd "$SCRIPT_DIR/legalconsenthub" || exit 1 log_info "Installing dependencies..." pnpm install --frozen-lockfile if [ $? -ne 0 ]; then log_error "Dependencies installation failed" exit 1 fi log_success "Dependencies installed" log_info "Running linting..." pnpm lint if [ $? -ne 0 ]; then log_error "Linting failed" exit 1 fi log_success "Linting passed" log_info "Running type checking..." pnpm type-check if [ $? -ne 0 ]; then log_error "Type checking failed" exit 1 fi log_success "Type checking passed" log_info "Building Docker image..." mkdir -p "$BUILDX_CACHE_BASE/frontend" docker buildx build \ --platform linux/amd64 \ --tag "gitea.lugnas.de/denis/legalconsenthub:latest" \ --tag "gitea.lugnas.de/denis/legalconsenthub:$GIT_SHA" \ --file ./Dockerfile \ --cache-from type=local,src="$BUILDX_CACHE_BASE/frontend" \ --cache-to type=local,dest="$BUILDX_CACHE_BASE/frontend",mode=max \ --push \ .. if [ $? -ne 0 ]; then log_error "Docker build failed" exit 1 fi log_success "Docker image built and pushed successfully" log_info "Image: gitea.lugnas.de/denis/legalconsenthub:latest" log_info "Image: gitea.lugnas.de/denis/legalconsenthub:$GIT_SHA" exit 0 ) 2>&1 | if [ "$use_prefix" = true ]; then prefix_output "FRONTEND" "$BLUE"; else cat; fi | tee "$log_file" return ${PIPESTATUS[0]} } backend_job() { local log_file="$TEMP_DIR/backend.log" local use_prefix=$1 ( set +e echo "==================== BACKEND JOB ====================" log_info "Starting backend build..." cd "$SCRIPT_DIR/legalconsenthub-backend" || exit 1 log_info "Building application..." ./gradlew build -x test if [ $? -ne 0 ]; then log_error "Build failed" exit 1 fi log_success "Build completed" log_info "Running ktlint check..." ./gradlew ktlintCheck if [ $? -ne 0 ]; then log_error "ktlint check failed" exit 1 fi log_success "ktlint check passed" log_info "Running tests..." ./gradlew test if [ $? -ne 0 ]; then log_error "Tests failed" exit 1 fi log_success "Tests passed" log_info "Building Docker image..." mkdir -p "$BUILDX_CACHE_BASE/backend" docker buildx build \ --platform linux/amd64 \ --tag "gitea.lugnas.de/denis/legalconsenthub-backend:latest" \ --tag "gitea.lugnas.de/denis/legalconsenthub-backend:$GIT_SHA" \ --file ./Dockerfile \ --cache-from type=local,src="$BUILDX_CACHE_BASE/backend" \ --cache-to type=local,dest="$BUILDX_CACHE_BASE/backend",mode=max \ --push \ .. if [ $? -ne 0 ]; then log_error "Docker build failed" exit 1 fi log_success "Docker image built and pushed successfully" log_info "Image: gitea.lugnas.de/denis/legalconsenthub-backend:latest" log_info "Image: gitea.lugnas.de/denis/legalconsenthub-backend:$GIT_SHA" exit 0 ) 2>&1 | if [ "$use_prefix" = true ]; then prefix_output "BACKEND" "$GREEN"; else cat; fi | tee "$log_file" return ${PIPESTATUS[0]} } run_jobs() { local job_count=0 [ "$RUN_FRONTEND" = true ] && ((job_count++)) [ "$RUN_BACKEND" = true ] && ((job_count++)) local run_parallel=false if [ "$job_count" -gt 1 ]; then run_parallel=true log_info "Starting $job_count parallel jobs..." else log_info "Starting job..." fi echo "" local frontend_exit=0 local backend_exit=0 if [ "$run_parallel" = true ]; then local frontend_pid="" local backend_pid="" if [ "$RUN_FRONTEND" = true ]; then frontend_job true & frontend_pid=$! log_info "Frontend PID: $frontend_pid" fi if [ "$RUN_BACKEND" = true ]; then backend_job true & backend_pid=$! log_info "Backend PID: $backend_pid" fi log_info "Waiting for jobs to complete..." echo "" set +e if [ -n "$frontend_pid" ]; then wait $frontend_pid frontend_exit=$? fi if [ -n "$backend_pid" ]; then wait $backend_pid backend_exit=$? fi set -e else if [ "$RUN_FRONTEND" = true ]; then set +e frontend_job false frontend_exit=$? set -e fi if [ "$RUN_BACKEND" = true ]; then set +e backend_job false backend_exit=$? set -e fi fi echo "" echo "==================== JOB SUMMARY ====================" local has_failure=false if [ "$RUN_FRONTEND" = true ]; then if [ "$frontend_exit" -eq 0 ]; then log_success "Frontend job completed successfully" else log_error "Frontend job failed with exit code $frontend_exit" has_failure=true fi fi if [ "$RUN_BACKEND" = true ]; then if [ "$backend_exit" -eq 0 ]; then log_success "Backend job completed successfully" else log_error "Backend job failed with exit code $backend_exit" has_failure=true fi fi if [ "$has_failure" = true ]; then log_error "One or more jobs failed. Aborting pipeline." exit 1 fi log_success "All jobs completed successfully" } launch_in_iterm() { log_info "Launching pipeline in new iTerm window..." local script_path="$0" local args="" for arg in "$@"; do args="$args $arg" done osascript <