Merge pull request 'ci-cd/migrations' (#253) from ci-cd/migrations into development

Reviewed-on: ADUANASOFT/anexo76#253
This commit is contained in:
2026-03-24 20:42:49 +00:00
3 changed files with 25 additions and 4 deletions

View File

@@ -36,7 +36,7 @@ jobs:
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@host:5432/nombre_bd"
echo "Ejemplo: postgresql://usuario:clave@127.0.0.1:5432/nombre_bd (host real, no el texto \"host\")"
exit 1
fi
python3 --version

View File

@@ -46,10 +46,27 @@ def _validate_sqlalchemy_url(url: str, env_key: str) -> None:
except Exception as e:
raise RuntimeError(
f"{env_key} no es una URL de SQLAlchemy válida. "
"Ejemplo: postgresql://usuario:clave@host:5432/nombre_bd"
"Ejemplo: postgresql://usuario:clave@127.0.0.1:5432/nombre_bd"
) from e
def _reject_documentation_placeholder_host(url: str, source: str) -> None:
"""
Evita el error críptico de DNS: muchos ejemplos usan @host:5432 como texto literal.
"""
try:
parsed = make_url(url)
except Exception:
return
h = (parsed.host or "").strip().lower()
if h == "host":
raise RuntimeError(
f"{source}: el hostname \"host\" es un placeholder de documentación, no un servidor real. "
"Usa el host alcanzable desde el runner (IP, nombre DNS, servicio en docker-compose, "
"o host.docker.internal si act corre en contenedor y Postgres en tu máquina)."
)
def get_database_url():
"""Obtiene la URL de la base de datos (PostgreSQL) desde variables de entorno o alembic.ini."""
# CI / pytest: misma URL que los tests (secret TEST_DATABASE_URL) o DATABASE_URL explícita.
@@ -60,6 +77,7 @@ def get_database_url():
if raw and raw.strip():
normalized = _normalize_alembic_sqlalchemy_url(raw)
_validate_sqlalchemy_url(normalized, env_key)
_reject_documentation_placeholder_host(normalized, env_key)
return normalized
# Construcción desde settings (CORE_DB_* en .env / entorno)
@@ -74,7 +92,9 @@ def get_database_url():
encoded_user = quote_plus(user)
encoded_password = quote_plus(password)
encoded_db = quote_plus(db)
return f"postgresql+psycopg2://{encoded_user}:{encoded_password}@{host}:{port}/{encoded_db}"
built = f"postgresql+psycopg2://{encoded_user}:{encoded_password}@{host}:{port}/{encoded_db}"
_reject_documentation_placeholder_host(built, "CORE_DB_HOST")
return built
except Exception as e:
logger.error(f"Error al construir URL: {e}")
@@ -87,6 +107,7 @@ def get_database_url():
"sqlalchemy.url en alembic.ini con placeholders ${...} no está soportado."
)
_reject_documentation_placeholder_host(url, "alembic.ini sqlalchemy.url")
return url

View File

@@ -134,7 +134,7 @@ Si `TEST_DATABASE_URL` apunta a una base con datos previos, los builders reutili
- PostgreSQL test database available.
- Environment variable:
- `TEST_DATABASE_URL=postgresql://user:pass@host:5432/db_name`
- `TEST_DATABASE_URL=postgresql://user:pass@127.0.0.1:5432/db_name` (sustituye por el host real alcanzable desde el runner; no uses el literal `host` de los ejemplos genéricos)
## Run commands