44b2eb2cc3
The README was 1,240 lines of reference material and still described a SQLite quick start. It is now a short tour (highlights, screenshots of the web UI, an accurate quick start against Postgres), and each topic has its own page under docs/ with an index: deployment, configuration, Alertmanager, incidents, notifications, escalation, dead man's switches, single sign-on, web UI, API and development. SERVICE-ACCOUNTS.md is rewritten from a proposal into a reference, and TEAM-LOOKUP.md is gone with the endpoint it described. The "Upgrading to ..." sections for an unreleased product are dropped. Claude-Session: https://claude.ai/code/session_016mBLURvJoMuUEr9cB2RpUN
94 lines
5.1 KiB
Markdown
94 lines
5.1 KiB
Markdown
# Development and releasing
|
|
|
|
_Building, testing and releasing the server._ Back to the [README](../README.md) and the [documentation index](./README.md).
|
|
|
|
## Upgrading
|
|
|
|
The schema is a single baseline (`internal/db/migrations/001_schema.sql`) and no
|
|
release has shipped yet, so there is no upgrade path from earlier development
|
|
databases: start from an empty one. Changes after the first release arrive as
|
|
new numbered migrations.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
make test-db # start a local Postgres for the tests (podman or docker)
|
|
make test # run all tests
|
|
go build ./... # compile all packages
|
|
go run ./cmd/terdut # run locally (needs TERDUT_DB_DSN)
|
|
```
|
|
|
|
The tests need a real Postgres, because the server does — there is no in-memory Postgres.
|
|
`TERDUT_TEST_DSN` says where it is, `make test-db` starts
|
|
one on port 5433 and prints the DSN, and `make test-db-stop` removes it. Each test gets its
|
|
own schema on that server, so tests cannot see each other's rows. An unset `TERDUT_TEST_DSN`
|
|
fails the suite rather than skipping it: a run that quietly tests nothing is worse than one
|
|
that does not run.
|
|
|
|
`make fmt lint test helm-lint` is the gate. It mirrors `.gitea/workflows/ci.yaml` step for
|
|
step, so a green run here means a green pipeline — with one deliberate exception: `make test`
|
|
adds `-race`, which CI does not. The sweeper, the notifier goroutine and the dead man's switch
|
|
sweep all run concurrently against the same database, and a race between them would surface as
|
|
a flaky incident in production rather than as a red build.
|
|
|
|
The web UI lives in `internal/web/static/` as plain HTML, CSS and ES modules,
|
|
embedded into the binary with `go:embed`. It has no build step and no npm, so
|
|
editing a file and restarting the server is the whole loop.
|
|
|
|
## Releasing
|
|
|
|
```
|
|
push or PR → ci.yaml gofmt, go vet, go test -race
|
|
govulncheck, gitleaks
|
|
helm lint + render
|
|
push tag vX.Y.Z → release.yaml the same gate, then publish:
|
|
git.ryuvia.com/niklas/terdut-server:vX.Y.Z
|
|
oci://git.ryuvia.com/niklas/terdut-server X.Y.Z
|
|
then trivy-scan the pushed image
|
|
PR to Ryuvia/charts → bump the wrapper chart to X.Y.Z; on merge
|
|
Flux reconciles and the release rolls out
|
|
```
|
|
|
|
Both artifacts go to the **personal** Gitea namespace rather than `ryuvia`, because Gitea
|
|
scopes package visibility to the owner with no per-package override — so `ryuvia/*` is private
|
|
because the org is. Publishing to `niklas` keeps them anonymously pullable, which is why no
|
|
pull secret is needed in the cluster. Same reasoning, and the same choice, as riksdata and
|
|
rd-web.
|
|
|
|
Saying **"Release"** runs all three rows: the `release` skill commits, pushes, tags, waits for
|
|
the pipeline, and opens the `Ryuvia/charts` PR, stopping before the merge. See
|
|
`~/.claude/skills/release/`, or `.release.conf` here for this repo's part of it.
|
|
|
|
The chart is published **only** from the tag, by the `chart` job. There used to be a second
|
|
publisher on every `charts/**` push to main, and the two raced for the same chart version with
|
|
different answers — chart 0.9.0 went out reading `appVersion: "latest"` that way. One
|
|
publisher, triggered by the tag (`766f439`). The cost is that a chart-only change has no
|
|
version of its own and rides the next app tag.
|
|
|
|
Both workflows are thin drivers over the Makefile: `ci.yaml` runs `make fmt lint test` and
|
|
`make helm-lint`, `release.yaml` adds `make binaries`, `make push`, `make helm-package` and
|
|
`make helm-push`. That is deliberate — it is what makes a green local gate and a green
|
|
pipeline the same code rather than two descriptions of it, and it is how riksdata and rd-web
|
|
have always worked.
|
|
|
|
`make push` builds and pushes in one step, unlike those two, because the image is
|
|
`linux/amd64,linux/arm64` and buildx cannot load a multi-platform result into the local image
|
|
store. `make build` stays single-platform and local-only. Both refuse `VERSION=dev`:
|
|
publishing is one command, so it is also one command to run by accident. Publishing happens
|
|
by pushing a tag.
|
|
|
|
Two things the release process needs to know about this repo:
|
|
|
|
- **The image scan runs after publishing**, like riksdata's and rd-web's: trivy cannot read
|
|
a locally built image on this runner, so it pulls the pushed one. A red `scan-image` means
|
|
do not bump the wrapper chart to that version — it cannot unpublish anything. The image is
|
|
`FROM scratch`, so trivy sees exactly one target, the Go binary and its module graph.
|
|
- **The wrapper chart's `values.yaml` has two `tag:` lines** — the app image and the python
|
|
backup sidecar — so `chart-bump` is given `--image` to say which one moves. Once the wrapper
|
|
chart drops the sidecar and declares a `postgresql` CR instead, there is one `tag:` line
|
|
again, and `--image` becomes belt and braces.
|
|
|
|
The wrapper chart must have **its own `version:` bumped in the same commit**. Flux reconciles
|
|
with `reconcileStrategy: ChartVersion`, so a chart whose version did not change produces no
|
|
new artifact and the change is never deployed — with no error anywhere.
|