Uecko_ERP/scripts/build-factuges.sh
2025-12-15 19:21:09 +01:00

267 lines
8.7 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_VERSION="1.2.4"
# =====================================================
# FACTUGES Build Script
# -----------------------------------------------------
# Build + Export de la API y/o WEB (por compañía)
# =====================================================
# Uso:
# ./build_factuges.sh <company> [--api|web|all] [--load]
#
# Ejemplos:
# ./build_factuges.sh acme --api --load # solo API + carga en Docker local
# ./build_factuges.sh acme --web # solo web
# ./build_factuges.sh acme # API + web (por defecto)
#
# Funcionalidades:
# - Detecta automáticamente el nombre, versión y puerto de la API
# - Compila la web React (Vite)
# - Copia los estáticos a out/<company>/web/dist
# - Genera imagen Docker etiquetada por compañía + versión + latest
# - Guarda la imagen .tar en out/<company>/api/
# - Carga la imagen en Docker (opcional)
# =====================================================
# --- Configuración base ---
COMPANY=""
MODE="all" # api | web | all
LOAD=false
# --- Validar que el primer argumento existe y no es un flag ---
if [[ $# -eq 0 || "$1" == --* ]]; then
echo "❌ ERROR: Falta el parámetro <company>"
echo "Uso: ./build_factuges.sh <company> [--api|--web|--all] [--load]"
echo "Ejemplos:"
echo " ./build_factuges.sh acme --api"
echo " ./build_factuges.sh acme --web"
exit 1
fi
COMPANY="$1"
SSH_USER="rodax"
SSH_HOST="vps-2.rodax-software.com"
SSH_PORT="49152"
# Override por compañía específica
if [[ "$COMPANY" == "rodax" ]]; then
SSH_USER="rodax"
SSH_HOST="factuges.rodax-software.local"
SSH_PORT="22"
fi
# --- Parseo de flags ---
shift # quitamos el <company>, ahora solo quedan flags
for arg in "$@"; do
case "$arg" in
--api) MODE="api" ;;
--web) MODE="web" ;;
--all) MODE="all" ;;
--load) LOAD=true ;;
*) echo "⚠️ Argumento desconocido: $arg" ;;
esac
done
# --- Paths base ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(realpath "${SCRIPT_DIR}/..")"
SERVER_DIR="${PROJECT_DIR}/apps/server"
WEB_DIR="${PROJECT_DIR}/apps/web"
OUT_API_DIR="${PROJECT_DIR}/out/${COMPANY}/api"
OUT_WEB_DIR="${PROJECT_DIR}/out/${COMPANY}/web"
if [[ -z "$COMPANY" ]]; then
echo "❌ Error: debes indicar la compañía. Ejemplo: ./build_factuges.sh acme [--api|--web|--all] [--load]"
exit 1
fi
if [[ $COMPANY =~ --.* ]]; then
echo "❌ Error: debes indicar la compañía. Ejemplo: ./build_factuges.sh acme [--api|--web|--all] [--load]"
exit 1
fi
# --- Verificaciones mínimas ---
[[ -d "$SERVER_DIR" ]] || { echo "❌ Falta ${SERVER_DIR}"; exit 1; }
[[ -d "$WEB_DIR" ]] || { echo "❌ Falta ${WEB_DIR}"; exit 1; }
# --- Detectar nombre y versión de la API ---
IMAGE_NAME=$(node -p "require('${SERVER_DIR}/package.json').name.replace(/^@.*\\//, '')" 2>/dev/null || echo "api")
API_VERSION=$(node -p "require('${SERVER_DIR}/package.json').version" 2>/dev/null || echo "0.0.0")
# --- Detectar versión de la web ---
WEB_VERSION=$(node -p "require('${WEB_DIR}/package.json').version" 2>/dev/null || echo "0.0.0")
# --- Detectar puerto ---
PORT=""
if [[ -f "${SERVER_DIR}/.env" ]]; then
PORT=$(grep -E '^PORT=' "${SERVER_DIR}/.env" | cut -d'=' -f2 | tr -d '"')
fi
if [[ -z "$PORT" && -f "${PROJECT_DIR}/Dockerfile" ]]; then
PORT=$(grep -E '^EXPOSE ' "${PROJECT_DIR}/Dockerfile" | awk '{print $2}' | head -n1)
fi
PORT="${PORT:-3002}" # valor por defecto
# --- 3. Etiquetas e información ---
DATE=$(date +'%Y%m%d-%H%M%S')
ISO_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
USER_NAME=$(whoami)
GIT_HASH=$(git -C "$PROJECT_DIR" rev-parse --short HEAD 2>/dev/null || echo "unknown")
GIT_BRANCH=$(git -C "$PROJECT_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
IMAGE_TAG_V="${IMAGE_NAME}:${COMPANY}-v${API_VERSION}"
IMAGE_TAG_LATEST="${IMAGE_NAME}:${COMPANY}-latest"
mkdir -p "$OUT_API_DIR" "$OUT_WEB_DIR"
rm -rf "${OUT_API_DIR:?}/"*
rm -rf "${OUT_WEB_DIR:?}/"*
echo ""
echo "-------------------------------------------------------"
echo " FACTUGES Build Script v${SCRIPT_VERSION}"
echo " Construyendo entorno para compañía '${COMPANY}'"
echo " Proyecto: ${IMAGE_NAME}"
echo " Versión API: ${API_VERSION}"
echo " Versión Web: ${WEB_VERSION}"
echo " Puerto API: ${PORT}"
echo " Etiquetas: ${IMAGE_TAG_V}, ${IMAGE_TAG_LATEST}"
echo " API out: ${OUT_API_DIR}"
echo " WEB out: ${OUT_WEB_DIR}"
echo " Modo: ${MODE}"
echo " Cargar: ${LOAD}"
echo "-------------------------------------------------------"
# =====================================================
# 1⃣ WEB
# =====================================================
if [[ "$MODE" == "web" || "$MODE" == "all" ]]; then
echo "🌐 Compilando web con Vite..."
cd "${WEB_DIR}"
# Puedes pasar variables específicas por compañía
# Ejemplo: VITE_COMPANY=acme VITE_API_BASE=https://acme.localhost/api
VITE_COMPANY="${COMPANY}" pnpm build:${COMPANY}
# Carpeta versionada
VERSION_DIR="${OUT_WEB_DIR}/versions/v${WEB_VERSION}-${DATE}"
mkdir -p "${VERSION_DIR}/dist"
rm -rf "${VERSION_DIR}/dist"/*
cp -r "${WEB_DIR}/dist/"* "${VERSION_DIR}/dist/"
# Enlace simbólico 'latest' → versión recién compilada
ln -sfn "${VERSION_DIR}" "${OUT_WEB_DIR}/latest"
# Manifest JSON de la web
cat > "${VERSION_DIR}/manifest.json" <<EOF
{
"type": "web",
"company": "${COMPANY}",
"version": "${WEB_VERSION}",
"buildTime": "${ISO_DATE}",
"user": "${USER_NAME}",
"git": {
"branch": "${GIT_BRANCH}",
"commit": "${GIT_HASH}"
},
"source": "${PROJECT_DIR}/apps/web",
"dist": "${VERSION_DIR}/dist"
}
EOF
echo "✅ Web v${WEB_VERSION} compilada y copiada a ${VERSION_DIR}"
echo " 🔗 Enlace 'latest' actualizado a ${OUT_WEB_DIR}/latest"
fi
# =====================================================
# 2⃣ API
# =====================================================
if [[ "$MODE" == "api" || "$MODE" == "all" ]]; then
# Recopilar plantillas
${SCRIPT_DIR}/build-templates.sh ${COMPANY}
TEMPLATES_DIR="${PROJECT_DIR}/out/${COMPANY}/templates"
cd "${PROJECT_DIR}"
echo "🐳 Construyendo imagen Docker..."
#docker build --no-cache --debug -t "${IMAGE_TAG_V}" -t "${IMAGE_TAG_LATEST}" \
docker build \
-t "${IMAGE_TAG_V}" -t "${IMAGE_TAG_LATEST}" \
--build-arg PORT="${PORT}" --build-arg COMPANY="${COMPANY}" \
-f "${PROJECT_DIR}/Dockerfile" "${PROJECT_DIR}"
echo "✅ Imagen Docker construida correctamente"
TAR_FILE_V="${OUT_API_DIR}/${IMAGE_NAME}-${COMPANY}-v${API_VERSION}-${DATE}.tar"
TAR_FILE_LATEST="${OUT_API_DIR}/${IMAGE_NAME}-${COMPANY}-latest.tar"
docker save "${IMAGE_TAG_V}" "${IMAGE_TAG_LATEST}" -o "${TAR_FILE_V}"
cp -f "${TAR_FILE_V}" "${TAR_FILE_LATEST}"
echo "📦 Imagen guardada:"
echo " ${TAR_FILE_V}"
echo " ${TAR_FILE_LATEST}"
# Manifest JSON de la API
cat > "${OUT_API_DIR}/${IMAGE_NAME}-${COMPANY}-v${API_VERSION}-${DATE}-manifest.json" <<EOF
{
"type": "api",
"company": "${COMPANY}",
"image": "${IMAGE_TAG_V}",
"version": "${API_VERSION}",
"buildTime": "${ISO_DATE}",
"user": "${USER_NAME}",
"git": {
"branch": "${GIT_BRANCH}",
"commit": "${GIT_HASH}"
},
"port": "${PORT}",
"files": {
"versioned": "$(basename ${TAR_FILE_V})",
"latest": "$(basename ${TAR_FILE_LATEST})"
}
}
EOF
echo "📦 API manifest generado en ${OUT_API_DIR}/manifest-v${API_VERSION}-${DATE}.json"
fi
if [[ "$LOAD" == true ]]; then
echo "📥 Cargando imagen en producción ${SSH_HOST}..."
[[ "$MODE" == "web" || "$MODE" == "all" ]] && scp -r -P "${SSH_PORT}" "${OUT_WEB_DIR}" "${SSH_USER}@${SSH_HOST}:/opt/factuges/${COMPANY}/"
[[ "$MODE" == "api" || "$MODE" == "all" ]] && scp -r -P "${SSH_PORT}" "${OUT_API_DIR}" "${SSH_USER}@${SSH_HOST}:/opt/factuges/${COMPANY}/"
[[ "$MODE" == "api" || "$MODE" == "all" ]] && scp -r -P "${SSH_PORT}" "${TEMPLATES_DIR}" "${SSH_USER}@${SSH_HOST}:/opt/factuges/${COMPANY}/"
if [[ "$MODE" == "api" || "$MODE" == "all" ]]; then
RESULT=$(ssh -p "${SSH_PORT}" "${SSH_USER}@${SSH_HOST}" \
"docker load -i /opt/factuges/${COMPANY}/api/$(basename "${TAR_FILE_LATEST}")")
echo "${RESULT}"
fi
echo "✅ Imagen cargada en producción"
fi
# =====================================================
# 3⃣ Resumen
# =====================================================
echo "-------------------------------------------------------"
echo "🎯 Resultado final para '${COMPANY}'"
[[ "$MODE" == "web" || "$MODE" == "all" ]] && echo " 🌐 Web: v${WEB_VERSION}${OUT_WEB_DIR}/versions/v${WEB_VERSION}-${DATE}"
[[ "$MODE" == "api" || "$MODE" == "all" ]] && echo " 🐳 API: v${API_VERSION}${OUT_API_DIR}"
echo "🧩 Script version: ${SCRIPT_VERSION} - FIN"
echo "-------------------------------------------------------"
echo ""
echo ""
echo ""