Adopt golib/pg for migrations and pool construction #6

Open
unkin-agent wants to merge 1 commits from benvin/adopt-golib-pg into main
Member

Why

encapi applied its schema as one cumulative IF NOT EXISTS blob re-executed
inline on every start. It grows forever, records nothing about what has run, and
cannot express a change that is not a fresh CREATE. git.unkin.net/unkin/golib
now owns that mechanism (versioned files, schema_migrations, advisory lock), so
encapi should keep the SQL and drop the runner.

How

  • Move the DDL verbatim into migrations/0001_init.sql, embedded via
    migrations.FS. It stays IF NOT EXISTS-guarded, so the first start against
    the live database re-runs it as a no-op and only lands the tracking row.
  • Build the pool with pg.NewMigrated under the lock name encapi-migrations,
    and delete the inline migrate(). database.New now takes a context and a
    logger; main.go passes the signal context, so a start queued on the
    migration lock still dies on SIGTERM.
  • Render the DSN with pg.DSN. The env var contract is unchanged
    DBHOST/DBPORT/DBUSER/DBPASS/DBNAME/DBSSL are still resolved by
    internal/config, not pg.DSNFromEnv, because encapi defaults DBUSER and
    DBNAME to encapi where DSNFromEnv treats both as required.
  • Guards: embedded set must match migrations/, every CREATE must be
    idempotent, the derived advisory key is pinned to its computed value, and a
    container test proves the adoption path over a database that predates
    schema_migrations. make test-short now covers ./migrations/....
  • Plumb GOPRIVATE=git.unkin.net for the first cross-repo Go dependency:
    Makefile export, Dockerfile ENV, woodpecker Go steps, README note.

Full suite green with Postgres via testcontainers; gofmt/vet/pre-commit clean.

## Why encapi applied its schema as one cumulative `IF NOT EXISTS` blob re-executed inline on every start. It grows forever, records nothing about what has run, and cannot express a change that is not a fresh `CREATE`. `git.unkin.net/unkin/golib` now owns that mechanism (versioned files, `schema_migrations`, advisory lock), so encapi should keep the SQL and drop the runner. ## How - Move the DDL verbatim into `migrations/0001_init.sql`, embedded via `migrations.FS`. It stays `IF NOT EXISTS`-guarded, so the first start against the live database re-runs it as a no-op and only lands the tracking row. - Build the pool with `pg.NewMigrated` under the lock name `encapi-migrations`, and delete the inline `migrate()`. `database.New` now takes a context and a logger; `main.go` passes the signal context, so a start queued on the migration lock still dies on SIGTERM. - Render the DSN with `pg.DSN`. **The env var contract is unchanged** — `DBHOST/DBPORT/DBUSER/DBPASS/DBNAME/DBSSL` are still resolved by `internal/config`, not `pg.DSNFromEnv`, because encapi defaults `DBUSER` and `DBNAME` to `encapi` where `DSNFromEnv` treats both as required. - Guards: embedded set must match `migrations/`, every `CREATE` must be idempotent, the derived advisory key is pinned to its computed value, and a container test proves the adoption path over a database that predates `schema_migrations`. `make test-short` now covers `./migrations/...`. - Plumb `GOPRIVATE=git.unkin.net` for the first cross-repo Go dependency: Makefile export, Dockerfile `ENV`, woodpecker Go steps, README note. Full suite green with Postgres via testcontainers; gofmt/vet/pre-commit clean.
unkin-agent added 1 commit 2026-09-02 00:17:31 +10:00
Adopt golib/pg for migrations and pool construction
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
42307f285f
encapi's schema was a cumulative IF NOT EXISTS blob re-executed inline on every
start: it grows forever, records nothing, and cannot express a change that is
not a fresh CREATE. golib owns that mechanism now, so encapi keeps the SQL and
drops the runner.

- Move the DDL verbatim into migrations/0001_init.sql, embedded via
  migrations.FS. It stays IF NOT EXISTS-guarded, so the first start against the
  live database re-runs it as a no-op and only lands the schema_migrations row.
- Build the pool with pg.NewMigrated under the advisory lock named
  encapi-migrations, and delete the inline migrate(). database.New now takes a
  context and a logger; main.go hands it the signal context so a start blocked
  on the migration lock still dies on SIGTERM.
- Render the DSN with pg.DSN. The env var contract is untouched — the fields are
  still resolved by internal/config, because encapi defaults DBUSER and DBNAME
  to "encapi" where pg.DSNFromEnv treats both as required.
- Guard the set: embedded files must match migrations/, every CREATE must be
  idempotent, the derived lock key is pinned, and a container test proves the
  adoption path over a database that predates schema_migrations.
- Plumb GOPRIVATE=git.unkin.net for the first cross-repo Go dependency:
  exported by the Makefile, set in the Dockerfile and the woodpecker Go steps,
  documented in the README.
All checks were successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Required
Details
ci/woodpecker/pr/test Pipeline was successful
Required
Details
ci/woodpecker/pr/build Pipeline was successful
Required
Details
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin benvin/adopt-golib-pg:benvin/adopt-golib-pg
git checkout benvin/adopt-golib-pg
Sign in to join this conversation.