Adopt golib/pg for migrations and pool construction
artifactapi's schema was a ~180-line inline DDL blob re-executed on every start, growing an ALTER TABLE ... IF NOT EXISTS line per change with nothing recording what had run. golib/pg already owns that mechanic for the estate, so move the SQL into a versioned, embedded set and let the library apply it. - Depend on git.unkin.net/unkin/golib v0.1.0. - Move the DDL verbatim to migrations/0001_init.sql, embedded via the new migrations package, and build the pool with pg.NewMigrated (LockName "artifactapi-migrations"). The runner adds a cluster-wide advisory lock the old blob never took, so replicas starting together queue instead of racing each other through the DDL. - The live database has the schema but no schema_migrations, so its first start on this build re-runs 0001. Every statement is IF NOT EXISTS-guarded, so that run is a no-op landing only the tracking row; a container-backed test drops the row from a migrated database and asserts exactly that, and a static guard keeps future migrations additive and idempotent. - Keep config.DatabaseDSN as the DSN source rather than pg.DSNFromEnv: the variable names match, but golib has no default user or database name, and artifactapi documents and ships DBUSER/DBNAME defaults of "artifacts". The deployed env var contract is unchanged. - Guard the embedded set against migrations/ and pin the derived advisory key, so neither can drift unnoticed. - 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.
This commit is contained in:
@@ -321,6 +321,28 @@ S3/MinIO ─── content-addressable blob storage (blobs/sha256/{hash})
|
||||
|
||||
S3 client supports MinIO, Ceph RGW, and AWS S3 (via minio-go).
|
||||
|
||||
### Schema migrations
|
||||
|
||||
The SQL schema lives in `migrations/` as numbered `.sql` files, embedded into
|
||||
the binary and applied at startup before the server listens, so there is no
|
||||
mirrored copy of the schema in the deployment to drift out of sync.
|
||||
|
||||
The runner is [`golib/pg`](https://git.unkin.net/unkin/golib)'s `pg.NewMigrated`
|
||||
— artifactapi owns the SQL, the shared library owns the mechanics.
|
||||
|
||||
Each start takes `pg_advisory_lock` on a fixed key (FNV-1a/64 of the lock name
|
||||
`artifactapi-migrations`), creates `schema_migrations` (`version`, `applied_at`)
|
||||
if missing, and applies every embedded file whose filename is not yet recorded —
|
||||
in lexical (version) order, each file's SQL and its tracking row in one
|
||||
transaction — then unlocks. Replicas starting together queue on the lock and
|
||||
then find nothing to do.
|
||||
|
||||
A file absent from `schema_migrations` is re-run even when the database already
|
||||
has the schema, which is how a database migrated by the old untracked inline DDL
|
||||
picks `0001_init.sql` up: the statements are `IF NOT EXISTS`-guarded, so the
|
||||
re-run is a no-op that only lands the tracking row. New migrations must stay
|
||||
additive and idempotent for the same reason; a test enforces it.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
@@ -331,6 +353,7 @@ S3 client supports MinIO, Ceph RGW, and AWS S3 (via minio-go).
|
||||
| `DBUSER` | `artifacts` | PostgreSQL user |
|
||||
| `DBPASS` | | PostgreSQL password |
|
||||
| `DBNAME` | `artifacts` | PostgreSQL database |
|
||||
| `DBSSL` | `disable` | PostgreSQL `sslmode` |
|
||||
| `REDIS_URL` | `redis://localhost:6379` | Redis URL |
|
||||
| `MINIO_ENDPOINT` | `localhost:9000` | S3 endpoint |
|
||||
| `MINIO_ACCESS_KEY` | | S3 access key |
|
||||
@@ -358,6 +381,22 @@ make lint # golangci-lint + go vet
|
||||
make fmt # gofmt + goimports
|
||||
```
|
||||
|
||||
### `GOPRIVATE`
|
||||
|
||||
artifactapi depends on `git.unkin.net/unkin/golib`, which is served by Gitea and
|
||||
is unknown to `proxy.golang.org` / `sum.golang.org`. Module resolution therefore
|
||||
needs:
|
||||
|
||||
```
|
||||
export GOPRIVATE=git.unkin.net
|
||||
```
|
||||
|
||||
The `Makefile` exports it for every target, and the `Dockerfile` and the
|
||||
woodpecker Go steps set it themselves, so `make build|test|lint` and CI work on
|
||||
a clean checkout. Only bare `go` commands run outside `make` need it in your
|
||||
shell — set it there (or in your shell profile) rather than with `go env -w`,
|
||||
which is machine state this repo cannot carry.
|
||||
|
||||
### TUI
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user