[IMP] ci: test the ISOLATE addons in their own database
website_sale_disable_cart removes the cart from every website once installed, which breaks website_membership_signup_required when CI installs everything together. The repo is shared by clients that never install them together: run_tests.py now tests each ISOLATE addon in its own database, after the rest, and ci.yml isolates website_sale_disable_cart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ca526d55cc
commit
87c2d1d1d3
3 changed files with 73 additions and 36 deletions
|
|
@ -8,7 +8,12 @@ los del core ni los de la OCA.
|
|||
tools/ci/run_tests.py [addon ...]
|
||||
|
||||
Sin argumentos prueba todos los addons instalables del repo menos los de
|
||||
EXCLUDE. Odoo y los repos de los que dependen los addons se toman de ODOO_SRC
|
||||
EXCLUDE. Los de ISOLATE se prueban cada uno en su propia base de datos, después
|
||||
del resto: son los que cambian el comportamiento de otros con solo estar
|
||||
instalados (website_sale_disable_cart quita el carrito a todos los sitios web),
|
||||
y el repo lo comparten varios clientes que no los instalan juntos.
|
||||
|
||||
Odoo y los repos de los que dependen los addons se toman de ODOO_SRC
|
||||
(un checkout por carpeta; en el runner es un montaje, ver
|
||||
tools/issue_bot/README.md), menos las carpetas de ODOO_SRC_SKIP, y la conexión
|
||||
a PostgreSQL, de las variables PG*.
|
||||
|
|
@ -33,7 +38,6 @@ from pathlib import Path
|
|||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
ODOO_SRC = Path(os.environ.get("ODOO_SRC", "/odoo-src/18.0"))
|
||||
SKIP = set(os.environ.get("ODOO_SRC_SKIP", "").replace(",", " ").split())
|
||||
DB = os.environ.get("PGDATABASE", "test")
|
||||
POT_DIR = os.environ.get("BOT_POT_DIR")
|
||||
POT_KEEP_DAYS = 14
|
||||
|
|
@ -54,8 +58,9 @@ _logger = logging.getLogger("ci")
|
|||
def find_sources():
|
||||
"""Devuelve odoo-bin y el addons_path: el repo y lo que haya en ODOO_SRC."""
|
||||
odoo_bin, paths = None, [REPO]
|
||||
skip = env_list("ODOO_SRC_SKIP")
|
||||
for src in sorted(ODOO_SRC.iterdir()):
|
||||
if src.name in SKIP:
|
||||
if src.name in skip:
|
||||
_logger.info("Se omite %s (ODOO_SRC_SKIP)", src)
|
||||
elif (src / "odoo-bin").is_file():
|
||||
odoo_bin = src / "odoo-bin"
|
||||
|
|
@ -67,6 +72,10 @@ def find_sources():
|
|||
return odoo_bin, paths
|
||||
|
||||
|
||||
def env_list(name):
|
||||
return set(os.environ.get(name, "").replace(",", " ").split())
|
||||
|
||||
|
||||
def read_manifests(paths):
|
||||
manifests = {}
|
||||
for path in paths:
|
||||
|
|
@ -101,12 +110,12 @@ def wait_for_postgres(timeout=60):
|
|||
time.sleep(1)
|
||||
|
||||
|
||||
def odoo(odoo_bin, paths, *args):
|
||||
def odoo(odoo_bin, paths, db, *args):
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(odoo_bin),
|
||||
f"--addons-path={','.join(map(str, paths))}",
|
||||
f"--database={DB}",
|
||||
f"--database={db}",
|
||||
# Con --test-enable Odoo levanta su servidor HTTP para los tours, y
|
||||
# el runner lanza el job en la red del host: sin esto escucharía en
|
||||
# todas las interfaces de la máquina. Los tests lo buscan en
|
||||
|
|
@ -119,8 +128,11 @@ def odoo(odoo_bin, paths, *args):
|
|||
return subprocess.run(cmd, check=False).returncode
|
||||
|
||||
|
||||
def export_pots(odoo_bin, paths, addons):
|
||||
"""Deja en BOT_POT_DIR/<commit> el .pot de cada addon ya instalado."""
|
||||
def export_pots(odoo_bin, paths, runs):
|
||||
"""Deja en BOT_POT_DIR/<commit> el .pot de cada addon ya instalado.
|
||||
|
||||
`runs` es una lista de (base de datos, addons instalados en ella).
|
||||
"""
|
||||
pot_dir = Path(POT_DIR)
|
||||
head = subprocess.run(
|
||||
["git", "rev-parse", "HEAD"],
|
||||
|
|
@ -136,21 +148,22 @@ def export_pots(odoo_bin, paths, addons):
|
|||
for stale in (out, tmp):
|
||||
shutil.rmtree(stale, ignore_errors=True)
|
||||
tmp.mkdir(parents=True)
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(odoo_bin),
|
||||
"shell",
|
||||
f"--addons-path={','.join(map(str, paths))}",
|
||||
f"--database={DB}",
|
||||
"--no-http",
|
||||
"--log-level=warn",
|
||||
]
|
||||
_logger.info("Exportando los .pot a %s", out)
|
||||
script = EXPORT_POTS.format(addons=addons, out=str(tmp))
|
||||
if subprocess.run(cmd, input=script, text=True, check=False).returncode:
|
||||
_logger.warning("No se han podido exportar los .pot")
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
return
|
||||
for db, addons in runs:
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(odoo_bin),
|
||||
"shell",
|
||||
f"--addons-path={','.join(map(str, paths))}",
|
||||
f"--database={db}",
|
||||
"--no-http",
|
||||
"--log-level=warn",
|
||||
]
|
||||
script = EXPORT_POTS.format(addons=addons, out=str(tmp))
|
||||
if subprocess.run(cmd, input=script, text=True, check=False).returncode:
|
||||
_logger.warning("No se han podido exportar los .pot")
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
return
|
||||
tmp.rename(out)
|
||||
limit = time.time() - POT_KEEP_DAYS * 86400
|
||||
for old in pot_dir.iterdir():
|
||||
|
|
@ -158,12 +171,27 @@ def export_pots(odoo_bin, paths, addons):
|
|||
shutil.rmtree(old, ignore_errors=True)
|
||||
|
||||
|
||||
def run_tests(odoo_bin, paths, manifests, db, addons):
|
||||
"""Crea `db` con las dependencias de `addons` y los instala con sus tests."""
|
||||
dependencies = sorted(
|
||||
{dep for addon in addons for dep in manifests[addon].get("depends", [])}
|
||||
- set(addons)
|
||||
)
|
||||
subprocess.run(["dropdb", "--if-exists", db], check=True)
|
||||
_logger.info("Instalando las dependencias: %s", ", ".join(dependencies))
|
||||
init = ["--init", ",".join(dependencies), "--log-level=warn"]
|
||||
if odoo(odoo_bin, paths, db, *init):
|
||||
sys.exit("No se ha podido crear la base de datos con las dependencias")
|
||||
_logger.info("Probando: %s", ", ".join(addons))
|
||||
return odoo(odoo_bin, paths, db, "--init", ",".join(addons), "--test-enable")
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
odoo_bin, paths = find_sources()
|
||||
manifests = read_manifests(paths)
|
||||
repo_addons = sorted(m.parent.name for m in REPO.glob("*/__manifest__.py"))
|
||||
exclude = set(os.environ.get("EXCLUDE", "").replace(",", " ").split())
|
||||
exclude = env_list("EXCLUDE")
|
||||
addons = sys.argv[1:] or [
|
||||
addon
|
||||
for addon in repo_addons
|
||||
|
|
@ -189,27 +217,25 @@ def main():
|
|||
"(tools/issue_bot/runner/ en el repo de ecocentral) o el addon a "
|
||||
"EXCLUDE."
|
||||
)
|
||||
dependencies = sorted(
|
||||
{dep for addon in addons for dep in manifests[addon].get("depends", [])}
|
||||
- set(addons)
|
||||
)
|
||||
isolate = env_list("ISOLATE")
|
||||
together = [addon for addon in addons if addon not in isolate]
|
||||
runs = [(DB, together)] if together else []
|
||||
runs += [(f"{DB}_{addon}", [addon]) for addon in addons if addon in isolate]
|
||||
|
||||
wait_for_postgres()
|
||||
subprocess.run(["dropdb", "--if-exists", DB], check=True)
|
||||
_logger.info("Instalando las dependencias: %s", ", ".join(dependencies))
|
||||
init = ["--init", ",".join(dependencies), "--log-level=warn"]
|
||||
if odoo(odoo_bin, paths, *init):
|
||||
sys.exit("No se ha podido crear la base de datos con las dependencias")
|
||||
_logger.info("Probando: %s", ", ".join(addons))
|
||||
result = odoo(odoo_bin, paths, "--init", ",".join(addons), "--test-enable")
|
||||
if not result and POT_DIR:
|
||||
failed = []
|
||||
for db, run_addons in runs:
|
||||
if run_tests(odoo_bin, paths, manifests, db, run_addons):
|
||||
failed.append(db)
|
||||
if failed:
|
||||
sys.exit(f"Fallan los tests en: {', '.join(failed)}")
|
||||
if POT_DIR:
|
||||
# Que falte la caché no es un fallo de los tests: el bot de revisión
|
||||
# se queda sin las traducciones y lo dice.
|
||||
try:
|
||||
export_pots(odoo_bin, paths, addons)
|
||||
export_pots(odoo_bin, paths, runs)
|
||||
except OSError as e:
|
||||
_logger.warning("No se han podido exportar los .pot: %s", e)
|
||||
sys.exit(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue