2025-11-03 19:45:03 +00:00
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
2025-11-28 15:00:18 +00:00
|
|
|
|
SCRIPT_VERSION="1.2.1"
|
2025-11-03 19:45:03 +00:00
|
|
|
|
|
|
|
|
|
|
# =====================================================
|
|
|
|
|
|
# FACTUGES Build Script
|
|
|
|
|
|
# -----------------------------------------------------
|
2025-11-27 19:07:30 +00:00
|
|
|
|
# Build + Export de la API y/o WEB (por compañía)
|
2025-11-03 19:45:03 +00:00
|
|
|
|
# =====================================================
|
|
|
|
|
|
# Uso:
|
2025-11-27 19:07:30 +00:00
|
|
|
|
# ./build_factuges.sh <company> [--api|web|all] [--load]
|
2025-11-03 19:45:03 +00:00
|
|
|
|
#
|
|
|
|
|
|
# Ejemplos:
|
2025-11-27 19:07:30 +00:00
|
|
|
|
# ./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)
|
2025-11-03 19:45:03 +00:00
|
|
|
|
#
|
|
|
|
|
|
# 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 ---
|
2025-11-27 19:07:30 +00:00
|
|
|
|
COMPANY=""
|
2025-11-03 19:45:03 +00:00
|
|
|
|
MODE="all" # api | web | all
|
|
|
|
|
|
LOAD=false
|
|
|
|
|
|
|
2025-11-27 19:07:30 +00:00
|
|
|
|
# --- 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"
|
|
|
|
|
|
|
2025-11-03 19:45:03 +00:00
|
|
|
|
# --- Parseo de flags ---
|
2025-11-27 19:07:30 +00:00
|
|
|
|
shift # quitamos el <company>, ahora solo quedan flags
|
|
|
|
|
|
|
|
|
|
|
|
for arg in "$@"; do
|
2025-11-03 19:45:03 +00:00
|
|
|
|
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
|
2025-11-27 19:07:30 +00:00
|
|
|
|
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]"
|
2025-11-03 19:45:03 +00:00
|
|
|
|
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
|
2025-11-27 19:07:30 +00:00
|
|
|
|
VITE_COMPANY="${COMPANY}" pnpm build:${COMPANY}
|
2025-11-03 19:45:03 +00:00
|
|
|
|
|
|
|
|
|
|
# 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
|
2025-11-27 19:07:30 +00:00
|
|
|
|
# Recopilar plantillas
|
|
|
|
|
|
${SCRIPT_DIR}/build-templates.sh
|
|
|
|
|
|
|
2025-11-03 19:45:03 +00:00
|
|
|
|
cd "${PROJECT_DIR}"
|
|
|
|
|
|
echo "🐳 Construyendo imagen Docker..."
|
|
|
|
|
|
|
|
|
|
|
|
docker build --no-cache --debug -t "${IMAGE_TAG_V}" -t "${IMAGE_TAG_LATEST}" \
|
2025-11-27 19:07:30 +00:00
|
|
|
|
--build-arg PORT="${PORT}" --build-arg COMPANY="${COMPANY}" \
|
2025-11-03 19:45:03 +00:00
|
|
|
|
-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": "${TAR_FILE_V}",
|
|
|
|
|
|
"latest": "${TAR_FILE_LATEST}"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
EOF
|
|
|
|
|
|
|
|
|
|
|
|
echo "📦 API manifest generado en ${OUT_API_DIR}/manifest-v${API_VERSION}-${DATE}.json"
|
2025-11-28 15:00:18 +00:00
|
|
|
|
fi
|
2025-11-03 19:45:03 +00:00
|
|
|
|
|
2025-11-28 15:00:18 +00:00
|
|
|
|
if [[ "$LOAD" == true ]]; then
|
|
|
|
|
|
echo "📥 Cargando imagen en producción vps-2.rodax-software.com..."
|
|
|
|
|
|
[[ "$MODE" == "web" || "$MODE" == "all" ]] && scp -r -P 49152 ${OUT_WEB_DIR} rodax@vps-2.rodax-software.com:/opt/factuges/${COMPANY}/
|
|
|
|
|
|
[[ "$MODE" == "api" || "$MODE" == "all" ]] && scp -r -P 49152 ${OUT_API_DIR} rodax@vps-2.rodax-software.com:/opt/factuges/${COMPANY}/
|
2025-11-27 19:07:30 +00:00
|
|
|
|
|
2025-11-28 15:00:18 +00:00
|
|
|
|
[[ "$MODE" == "api" || "$MODE" == "all" ]] && RESULT=$(ssh -p 49152 rodax@vps-2.rodax-software.com "docker load -i ${TAR_FILE_LATEST}")
|
|
|
|
|
|
[[ "$MODE" == "api" || "$MODE" == "all" ]] && echo $RESULT
|
|
|
|
|
|
#docker load -i "${TAR_FILE_V}"
|
|
|
|
|
|
echo "✅ Imagen cargada en producción"
|
2025-11-03 19:45:03 +00:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-28 15:00:18 +00:00
|
|
|
|
|
2025-11-03 19:45:03 +00:00
|
|
|
|
# =====================================================
|
|
|
|
|
|
# 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 ""
|