name: Build Producción & Push a Harbor on: push: branches: - main - development workflow_dispatch: inputs: environment: description: 'Desplegar dev' required: true default: 'development' type: choice options: - development - main jobs: # Ejecuta la suite de tests del backend antes de construir imágenes. # Si falla, no se ejecuta build (ni push ni deploy). test: runs-on: self-hosted steps: - name: Checkout código uses: actions/checkout@v4 # No usamos actions/setup-python: en runners self-hosted (Debian) suele fallar # al descargar versiones desde el manifest. Se usa python3 del sistema + venv. # En Debian/Ubuntu hace falta el paquete python3-venv (ensurepip); si falla el venv, # se intenta instalar con apt (root en act/containers, sudo en servidor típico). - name: Instalar dependencias y ejecutar tests del backend env: TEST_DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }} run: | set -e if [ -z "$TEST_DATABASE_URL" ]; then echo "::error::Define el secret TEST_DATABASE_URL en el repo (Gitea → Ajustes → Secretos)." echo "Ejemplo: postgresql://usuario:clave@127.0.0.1:5432/nombre_bd (host real, no el texto \"host\")" exit 1 fi python3 --version VENV="$GITHUB_WORKSPACE/.pytest-venv" install_python3_venv() { export DEBIAN_FRONTEND=noninteractive if ! command -v apt-get >/dev/null 2>&1; then echo "::error::No hay apt-get. Instala manualmente el paquete equivalente a python3-venv." return 1 fi if [ "$(id -u)" -eq 0 ]; then apt-get update -qq apt-get install -y python3-venv else sudo apt-get update -qq sudo apt-get install -y python3-venv fi } if ! python3 -m venv "$VENV" 2>/dev/null; then echo "venv falló (ensurepip no disponible). Instalando python3-venv..." install_python3_venv python3 -m venv "$VENV" fi . "$VENV/bin/activate" python -m pip install --upgrade pip pip install -r "$GITHUB_WORKSPACE/backend/requirements.txt" cd "$GITHUB_WORKSPACE/backend" export TEST_DATABASE_URL="$TEST_DATABASE_URL" alembic upgrade head pytest -q tests -v -ra -s build: runs-on: self-hosted needs: test steps: - name: Checkout código uses: actions/checkout@v4 with: fetch-depth: 0 # Necesario para obtener el historial completo de git # ------------------------ # Generar versión automática # ------------------------ - name: Generar versión automática id: version run: | # Obtener año y mes actual YEAR=$(date +%y) MONTH=$(date +%m) # Detectar rama actual usando variables de Gitea BRANCH="${GITHUB_REF##*/}" if [ "$BRANCH" = "development" ]; then # Para development: YY.MM.1. SHORT_HASH=$(git rev-parse --short=8 HEAD) VERSION="${YEAR}.${MONTH}.${{ secrets.VERSION_MAYOR }}.${SHORT_HASH}" elif [ "$BRANCH" = "main" ]; then # Para main: YY.MM.0. # Intentar obtener el último tag LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") if [ -z "$LAST_TAG" ]; then # No hay tags, usar commit count total (primera ejecución) COMMIT_COUNT=$(git rev-list --count HEAD) echo "⚠️ No se encontraron tags. Usando commit count total: ${COMMIT_COUNT}" else # Hay tags, contar commits desde el último tag COMMIT_COUNT=$(git rev-list ${LAST_TAG}..HEAD --count) # Si es 0, significa que estamos en el mismo commit del tag, incrementar if [ "$COMMIT_COUNT" -eq 0 ]; then COMMIT_COUNT=1 fi echo "📌 Último tag: ${LAST_TAG}" echo "🔢 Commits desde el último tag: ${COMMIT_COUNT}" fi VERSION="${YEAR}.${MONTH}.${{ secrets.VERSION_MAYOR }}.${COMMIT_COUNT}" else # Fallback para otras ramas SHORT_HASH=$(git rev-parse --short=8 HEAD) VERSION="${YEAR}.${MONTH}.99.${SHORT_HASH}" fi # Guardar versión en output para usarla en steps posteriores echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT echo "BRANCH=${BRANCH}" >> $GITHUB_OUTPUT # Mostrar en logs echo "📦 Versión generada: ${VERSION}" echo "🌿 Rama: ${BRANCH}" - name: Login a Harbor run: | echo '${{ secrets.HARBOR_PASSWORD }}' | docker login \ dev.aduanasoft.com \ -u '${{ secrets.HARBOR_USERNAME }}' \ --password-stdin # ------------------------ # Backend # ------------------------ - name: Build backend run: | docker build \ --build-arg APP_VERSION=${{ steps.version.outputs.VERSION }} \ -t dev.aduanasoft.com/anexo76/backend:latest \ -f ./backend/Dockerfile \ ./backend # ------------------------ # Frontend # ------------------------ - name: Build frontend run: | docker build \ --build-arg VITE_API_URL=https://anexo76-dev.aduanasoft.com/api/ \ --build-arg VITE_KEYCLOAK_URL=https://anexo76-dev.aduanasoft.com/kcauth/ \ --build-arg INTERNAL_API_URL=http://backend:3467/api/ \ -t dev.aduanasoft.com/anexo76/frontend:latest \ -f ./frontend/Dockerfile.prod \ ./frontend # ------------------------ # Push imágenes # ------------------------ - name: Push backend run: | docker push dev.aduanasoft.com/anexo76/backend:latest - name: Push frontend run: | docker push dev.aduanasoft.com/anexo76/frontend:latest # ------------------------ # Crear tag de versión (solo para main) # ------------------------ - name: Crear tag de versión if: github.ref == 'refs/heads/main' run: | VERSION=${{ steps.version.outputs.VERSION }} git config user.name "Gitea Actions" git config user.email "actions@gitea.local" git tag -a "v${VERSION}" -m "Release version ${VERSION}" git push origin "v${VERSION}" echo "✅ Tag v${VERSION} creado y pusheado" # ------------------------ # Deploy a Development # ------------------------ - name: Deploy a servidor de desarrollo if: github.ref == 'refs/heads/development' run: | eval $(ssh-agent -s) ssh-add <(echo "${{ secrets.DEV_SERVER_SSH_KEY }}") ssh -o StrictHostKeyChecking=accept-new \ ${{ secrets.DEV_SERVER_USER }}@${{ secrets.DEV_SERVER_HOST }} \ 'cd ~/projects/anexo76 && \ echo '"'"'${{ secrets.HARBOR_PASSWORD }}'"'"' | docker login dev.aduanasoft.com -u '"'"'${{ secrets.HARBOR_USERNAME }}'"'"' --password-stdin && \ docker compose -f docker-compose.prod.yml pull && \ docker compose -f docker-compose.prod.yml up -d && \ docker image prune -f' ssh-agent -k