# PostgreSQL overlay for the test stack. Layer it on compose.test.yml: # # docker compose -f compose.test.yml -f compose.test.postgres.yml up -d --build # # It adds the database and the one setting that switches the engine. Without # this file the stack is on SQLite, which is what an unconfigured install uses # and what the product must keep working as. # # PostgreSQL 14 on purpose: it is the oldest release the product supports, so # it is the one worth testing. A newer server would hide a 14 incompatibility. # The connection string, written once. Everything that needs it takes it from # here, so the stack and the copy can never drift onto two different databases. x-database-url: &database-url "postgres://maintenant:e2e-throwaway-password@db:5432/maintenant?sslmode=disable" services: db: image: postgres:14-alpine container_name: maintenant-test-db restart: unless-stopped environment: POSTGRES_USER: maintenant POSTGRES_PASSWORD: e2e-throwaway-password POSTGRES_DB: maintenant volumes: - maintenant_test_db:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U maintenant -d maintenant"] interval: 3s timeout: 3s retries: 20 ports: # Exposed so the copy command and psql can reach it from the host. - "127.0.0.1:${E2E_DB_PORT:-15433}:5432" maintenant: environment: # sslmode=disable because the test server speaks plaintext on a private # network. Towards a real database, leave sslmode out and the product # adds require by itself. MAINTENANT_DATABASE_URL: *database-url depends_on: db: condition: service_healthy # The migration from the docs, as a one-shot service: # https://docs.maintenant.dev/guides/postgresql/#migrating-an-existing-install # # docker compose -f compose.test.yml -f compose.test.postgres.yml \ # run --rm copy-store # # Stop the instance first: the source must not move during the copy. The # profile keeps it out of `up`, and `run` enables the profile by itself. # # It runs the released image, the released entrypoint and the same unprivileged # user as the instance, so what is exercised is the command an operator types, # not a convenient approximation of it. copy-store: profiles: ["migrate"] image: ghcr.io/kolapsis/maintenant:test build: context: . args: VERSION: "e2e" COMMIT: "e2e" BUILD_DATE: "2026-01-01" read_only: true security_opt: - no-new-privileges:true tmpfs: - /tmp:noexec,nosuid,size=64m volumes: # The same volume the instance writes to: the copy reads the real file # the stack has been filling, and opens it read-only. - maintenant_test_data:/data # No MAINTENANT_DATABASE_URL here on purpose: the source is the local file, # and the target is the argument. Giving it both would blur which is which. command: - "--db" - "/data/maintenant.db" - "--copy-store-to" - *database-url - "--yes" depends_on: db: condition: service_healthy volumes: maintenant_test_db: