From a7337b64261bc8bcb7ef2b21b81485747ece499d Mon Sep 17 00:00:00 2001 From: Philippe L'ATTENTION Date: Mon, 14 Sep 2026 13:41:12 +0400 Subject: [PATCH] Start postgres:18+ images: pin PGDATA below the data mount postgres:18+ images abort when a volume is mounted on their pre-18 default data directory (/var/lib/postgresql/data), which is exactly what the generated db service did. An explicit PGDATA one level below the mount is accepted by every major from 13 to 18, so the mount stays where it is and existing configs keep working; stacks created before this pick the new layout up with `reset-db`. Release v0.1.0-beta.21. Claude-Session: https://claude.ai/code/session_01WgWTM3kM3C2eLM6wcZuMhU --- README.md | 2 +- package.json | 2 +- src/core/compose-model.ts | 14 ++++++++++++-- test/core/compose-model.test.ts | 8 ++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2e24fc9..b7bfd6b 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ export default defineConfig({ version: "18.0", // required — image tag, and part of the DB template cache key serviceName: "odoo", // default — compose service to exec/log against databaseServiceName: "db", // default - postgresImage: "postgres:16", // default + postgresImage: "postgres:16", // default; postgres:18 images work too build: { // default: none — the CLI GENERATES a Dockerfile from this aptPackages: ["tesseract-ocr"], // (FROM odoo:, apt layer, pip layer, then COPYs) pipRequirements: ["backend/requirements.txt"], diff --git a/package.json b/package.json index a85ed63..a916711 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@basaltbytes/odoo-agentic-dev", - "version": "0.1.0-beta.20", + "version": "0.1.0-beta.21", "description": "Agent-friendly local Odoo development runtime: worktree-isolated databases, ports, and Docker Compose stacks", "keywords": [ "agentic", diff --git a/src/core/compose-model.ts b/src/core/compose-model.ts index dc874f5..6df03fe 100644 --- a/src/core/compose-model.ts +++ b/src/core/compose-model.ts @@ -10,6 +10,8 @@ export type ComposeModel = { }; export const GENERATED_COMPOSE_RELATIVE_PATH = ".odoo-agentic-dev/compose.generated.yml"; +export const POSTGRES_DATA_MOUNT = "/var/lib/postgresql/data"; +export const POSTGRES_DATA_DIR = `${POSTGRES_DATA_MOUNT}/pgdata`; export const POSTGRES_HEALTHCHECK_COMMAND = 'test "$(cat /proc/1/comm)" = postgres && pg_isready -U odoo -d postgres'; @@ -102,14 +104,22 @@ export const buildComposeModel = ( [dbService]: { image: recipe.odoo.postgresImage, restart: "unless-stopped", - environment: { POSTGRES_USER: "odoo", POSTGRES_PASSWORD: "odoo", POSTGRES_DB: "postgres" }, + environment: { + POSTGRES_USER: "odoo", + POSTGRES_PASSWORD: "odoo", + POSTGRES_DB: "postgres", + // postgres:18+ images refuse a volume mounted on their pre-18 default + // data directory (/var/lib/postgresql/data). An explicit PGDATA below the + // mount keeps one layout that every major from 13 to 18 accepts. + PGDATA: POSTGRES_DATA_DIR, + }, healthcheck: { test: ["CMD-SHELL", POSTGRES_HEALTHCHECK_COMMAND], interval: "2s", timeout: "5s", retries: 30, }, - volumes: ["db-data:/var/lib/postgresql/data"], + volumes: [`db-data:${POSTGRES_DATA_MOUNT}`], labels, }, [odooService]: { diff --git a/test/core/compose-model.test.ts b/test/core/compose-model.test.ts index b758381..0a1862b 100644 --- a/test/core/compose-model.test.ts +++ b/test/core/compose-model.test.ts @@ -29,6 +29,14 @@ describe("buildComposeModel", () => { expect(parse(renderComposeYaml(model))).toEqual(JSON.parse(JSON.stringify(model))); }); + it("keeps the database under an explicit PGDATA so postgres 13 to 18+ images all start", () => { + // postgres:18+ images abort when a volume sits on their pre-18 default data + // directory; an explicit PGDATA below the mount is accepted by every major. + const db = model.services["db"] as Record; + expect(db["environment"]["PGDATA"]).toBe("/var/lib/postgresql/data/pgdata"); + expect(db["volumes"]).toEqual(["db-data:/var/lib/postgresql/data"]); + }); + it("uses build+image when a dockerfile is configured", () => { const odoo = model.services["odoo"] as Record; expect(odoo["build"]).toEqual({ context: ".", dockerfile: "Dockerfile.odoo" });