Test / test (push) Successful in 2m1s
Release / gates (push) Successful in 1m57s
Release / build (amd64, freebsd) (push) Successful in 1m26s
Release / build (amd64, linux) (push) Successful in 1m30s
Release / build (arm64, freebsd) (push) Successful in 1m28s
Release / build (arm64, linux) (push) Successful in 1m49s
Release / build (loong64, linux) (push) Successful in 1m30s
Release / build (riscv64, linux) (push) Successful in 1m29s
Release / release (push) Successful in 41s
Assisted-by: GLM 5.3 Flash
131 lines
4.3 KiB
Markdown
131 lines
4.3 KiB
Markdown
# Development
|
|
|
|
How to work on nuntius.
|
|
|
|
## Prerequisites
|
|
|
|
- Go 1.27.1, the version recorded in `go.mod`, the newest stable release.
|
|
- [just](https://github.com/casey/just) for the recipes.
|
|
- gcc for `just gates`: the race detector needs cgo.
|
|
|
|
Nothing else. There is no Node, no Python, and no third-party Go module
|
|
beyond the first-party [`interpres`](https://sourcedock.dev/petrbalvin/interpres)
|
|
TOML parser.
|
|
|
|
## Setup
|
|
|
|
```sh
|
|
git clone https://sourcedock.dev/petrbalvin/nuntius.git
|
|
cd nuntius
|
|
just build
|
|
```
|
|
|
|
Configuration lives in TOML, read from `/etc/nuntius/config.toml` by
|
|
default; the `NUNTIUS_CONFIG` environment variable points the server at any
|
|
file you like, which keeps development free of root-owned paths:
|
|
|
|
```sh
|
|
export NUNTIUS_CONFIG=./config.toml
|
|
export NUNTIUS_SMTP_PASSWORD=admin # the placeholder the template references
|
|
just run # first start writes the starter config
|
|
```
|
|
|
|
The starter forms point at example.com addresses, so submissions return
|
|
`500 send_failed` until `config.toml` carries real SMTP settings; strict
|
|
environment expansion means every `${VAR}` the config references must be set
|
|
before startup.
|
|
|
|
## Recipes
|
|
|
|
Every recipe in the project's file, taken from the file itself:
|
|
|
|
| Recipe | What it does |
|
|
|--------|--------------|
|
|
| `just default` | prints the recipe list |
|
|
| `just build` | `CGO_ENABLED=0 go build -trimpath -buildvcs=true -ldflags "-s -w"` into `bin/nuntius` |
|
|
| `just test` | the suite with no test cache, then the 80 % coverage floor over `./internal/...` |
|
|
| `just race` | the same suite under the race detector |
|
|
| `just unit` | fast scoped run for iterating: cached, no race, no coverage |
|
|
| `just fuzz` | time-boxed fuzz of one target in one package |
|
|
| `just bench` | benchmarks |
|
|
| `just fmt` | `gofmt -w .` |
|
|
| `just fmt-check` | zero gofmt diff; prints nothing when everything is formatted |
|
|
| `just vet` | `go vet ./...` and `go fix -diff ./...` |
|
|
| `just gates` | build, fmt-check, vet, test, race: the definition of done, once per task |
|
|
| `just clean` | removes `bin/` and `coverage.out` |
|
|
| `just install` | builds, then copies the binary into `~/.local/bin` (override with `BINDIR`) |
|
|
| `just uninstall` | removes the installed binary |
|
|
| `just run` | `go run -buildvcs=true ./cmd/server` |
|
|
| `just dev` | the same as `run`: nuntius carries no watch or reload tool |
|
|
| `just coverage-html` | HTML coverage report from the gate's profile; an extension, not a gate |
|
|
|
|
The test, race, unit and fuzz recipes run under a cgroup memory fence, so a
|
|
runaway test dies at the ceiling instead of eating the machine.
|
|
|
|
## Running a single test
|
|
|
|
```sh
|
|
go test -run TestName ./internal/handler/
|
|
```
|
|
|
|
Add `-v` for the sub-test names, and `-race` when the change touches
|
|
concurrency. `-count=1` defeats the test cache when a result looks stale;
|
|
`just unit` keeps the cache on purpose, because a scoped iterating run wants
|
|
to be instant.
|
|
|
|
## Coverage
|
|
|
|
```sh
|
|
just test
|
|
go tool cover -func=coverage.out
|
|
```
|
|
|
|
The `total:` line is the number that matters, and it stays at 80 percent or
|
|
more. Coverage is measured over the logic packages only; `cmd/server` is
|
|
thin glue around them. For the HTML map:
|
|
|
|
```sh
|
|
just coverage-html
|
|
```
|
|
|
|
## Benchmarks
|
|
|
|
```sh
|
|
just bench
|
|
```
|
|
|
|
Benchmark on an idle machine, and compare only runs made in one process
|
|
against each other: runs in separate processes, or on a loaded machine,
|
|
differ by more than the effects being measured.
|
|
|
|
## Fuzzing
|
|
|
|
Two fuzz targets exist: `FuzzValidate` in `internal/contactform` and
|
|
`FuzzLoadConfig` in `internal/config`. They are exploration, never a gate;
|
|
time-box one explicitly:
|
|
|
|
```sh
|
|
just fuzz FuzzValidate ./internal/contactform 30s
|
|
```
|
|
|
|
## Debugging the build
|
|
|
|
```sh
|
|
go build -gcflags='-m' ./... # inlining decisions
|
|
go build -gcflags='-S' ./... # what the compiler generated
|
|
```
|
|
|
|
## Continuous integration
|
|
|
|
Workflows live in `.gitea/workflows/` and run on the project's own runners.
|
|
They are written by hand rather than through `just`, but they enforce the
|
|
same set of gates, so a green `just gates` locally is the fastest way to a
|
|
green pipeline. The per-workflow table is in
|
|
[CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
|
|
## Releases
|
|
|
|
Releases are cut by merging `development` into `main` and tagging `vX.Y.Z`.
|
|
The tag drives the release workflow, which builds the assets and publishes
|
|
the notes it extracted from `CHANGELOG.md`.
|