#!/usr/bin/env bash # ============================================================================= # Changemaker Lite V2 — Build & Push to Gitea Registry # Builds production Docker images, tags with commit SHA + latest, and pushes # to the Gitea container registry at gitea.bnkops.com/admin. # # Usage: # ./scripts/build-and-push.sh [OPTIONS] # # Options: # --services a,b,c Comma-separated list of services to build # (default: api admin media-api nginx) # --no-push Build only, skip push (verify builds work) # --tag TAG Override commit SHA tag (default: git rev-parse --short HEAD) # --registry URL Override registry (default: gitea.bnkops.com/admin) # --dry-run Print commands without executing # --help Show this help # # Prerequisites: # docker login gitea.bnkops.com # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # --- Defaults --- REGISTRY="${GITEA_REGISTRY:-gitea.bnkops.com/admin}" COMMIT_SHA="$(git -C "$PROJECT_DIR" rev-parse --short HEAD 2>/dev/null || echo "local")" TAG="${COMMIT_SHA}" SERVICES="api admin media-api nginx" NO_PUSH=false DRY_RUN=false # --- Colors --- if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' else RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC='' fi info() { echo -e "${BLUE}[INFO]${NC} $*"; } success() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } run() { if [[ "$DRY_RUN" == "true" ]]; then echo -e "${CYAN}[DRY-RUN]${NC} $*"; else eval "$@"; fi; } # --- Arg parser --- while [[ $# -gt 0 ]]; do case "$1" in --services) SERVICES="${2//,/ }"; shift 2 ;; --no-push) NO_PUSH=true; shift ;; --tag) TAG="$2"; shift 2 ;; --registry) REGISTRY="$2"; shift 2 ;; --dry-run) DRY_RUN=true; shift ;; --help|-h) sed -n '2,30p' "$0" | grep '^#' | sed 's/^# \?//' exit 0 ;; *) error "Unknown option: $1"; exit 1 ;; esac done echo -e "${BOLD}Changemaker Lite — Build & Push${NC}" echo " Registry: $REGISTRY" echo " Tag: $TAG" echo " Services: $SERVICES" echo " Push: $([[ "$NO_PUSH" == "true" ]] && echo "no" || echo "yes")" echo "" # --- Build mapping: service → dockerfile + context --- build_service() { local svc="$1" local image="$REGISTRY/changemaker-${svc}:${TAG}" local image_latest="$REGISTRY/changemaker-${svc}:latest" case "$svc" in api) info "Building api (Express + Prisma)..." run docker buildx build \ --target production \ --tag "${image}" \ --tag "${image_latest}" \ --load \ "${PROJECT_DIR}/api" ;; admin) info "Building admin (React + Vite)..." run docker buildx build \ --target production \ --tag "${image}" \ --tag "${image_latest}" \ --load \ "${PROJECT_DIR}/admin" ;; media-api) info "Building media-api (Fastify + FFmpeg)..." run docker buildx build \ --target production \ --file "${PROJECT_DIR}/api/Dockerfile.media" \ --tag "${image}" \ --tag "${image_latest}" \ --load \ "${PROJECT_DIR}/api" ;; nginx) info "Building nginx (reverse proxy)..." run docker buildx build \ --tag "${image}" \ --tag "${image_latest}" \ --load \ "${PROJECT_DIR}/nginx" ;; *) error "Unknown service: $svc" return 1 ;; esac success "Built ${svc} → ${image}" if [[ "$NO_PUSH" == "false" ]]; then info "Pushing ${svc}:${TAG}..." run docker push "${image}" run docker push "${image_latest}" success "Pushed ${svc}:${TAG} + :latest" fi } # --- Main --- FAILED=() for svc in $SERVICES; do if ! build_service "$svc"; then FAILED+=("$svc") fi done echo "" if [[ ${#FAILED[@]} -eq 0 ]]; then if [[ "$NO_PUSH" == "true" ]]; then success "All services built (not pushed)." else success "All services built and pushed." fi echo "" if [[ "$NO_PUSH" == "false" ]]; then info "Images available in registry:" for svc in $SERVICES; do echo " ${REGISTRY}/changemaker-${svc}:${TAG}" done echo "" info "To use these images: IMAGE_TAG=${TAG} docker compose pull ${SERVICES}" info "Or set IMAGE_TAG=${TAG} in .env" fi else error "Failed services: ${FAILED[*]}" exit 1 fi