Files
interpres/docs/DEVELOPMENT.md
T
petrbalvin 9a1b922712
Test / test (push) Failing after 24s
ci: fence the test recipes and rebuild the pipelines around the gate set
Assisted-by: DeepSeek V4.1 Flash
2026-10-04 21:15:21 +02:00

119 lines
5.1 KiB
Markdown

# Development
How to work on interpres.
## Prerequisites
- Go 1.27.1, the version the `go` directive in `go.mod` declares.
- [just](https://github.com/casey/just) for the recipes.
- The `toml-test` binary on `PATH` for the compliance recipe, installed with
`go install github.com/toml-lang/toml-test/v2/cmd/toml-test@v2.2.0`.
The module has no third-party dependencies, so there is nothing else to fetch.
## Setup
```sh
git clone https://sourcedock.dev/petrbalvin/interpres.git
cd interpres
just build
just test
```
## Recipes
Every recipe in the project's justfile, and what it does. Taken from the file
itself, so the names and the list match it exactly; `just` with no arguments
prints the same list.
| Recipe | What it does |
|---|---|
| `just gates` | the definition of done: build, format check, vet, the test suite with the coverage floor, and the race detector |
| `just build` | compiles `./cmd/interpres-decode` into `bin/interpres-decode`, with `-trimpath -buildvcs=true` |
| `just test` | the suite with no cache, then the coverage floor of 80 percent from `coverage.out`, under the memory fence |
| `just race` | the same suite under the race detector, fenced too |
| `just unit ./... TestName` | a fast scoped run for iterating; the second argument is a `-run` pattern, `.*` by default, fenced |
| `just fuzz FuzzParse . 30s` | time-boxed fuzzing of one target in exactly one package; `go test -fuzz` rejects `./...`; never a gate, fenced |
| `just bench` | benchmarks, `-benchmem -count=5`, on an idle machine only |
| `just fmt` | `gofmt -w .`, format in place |
| `just fmt-check` | `gofmt -l .`, zero diff |
| `just vet` | `go vet ./...` and `go fix -diff ./...` |
| `just run` | `go run ./cmd/interpres-decode`, reads TOML from stdin |
| `just dev` | the same run, for iterating |
| `just example` | `go run ./examples/basic`, the usage tour |
| `just toml-test` | builds the adapter and runs the official toml-test compliance suite against it, decoder and encoder |
| `just coverage-html` | `just test`, then `go tool cover -html` into `coverage.html` |
| `just install` | builds, then copies the binary into `~/.local/bin` (`BINDIR` overrides) |
| `just uninstall` | removes the installed binary |
| `just clean` | removes `bin/` and `coverage.out` |
| `just cross` | cross-compile smoke of the library and the command for arm64, loong64, riscv64 and the browser and edge runtimes; a hand-run convenience, not a gate |
| `just release-check X.Y.Z` | the release pre-flight: the branch, a clean tree, a sync with origin, the gates, and a CHANGELOG section ready to release |
| `just docs-drift` | compares the toml-test counts the documentation quotes with a live suite run |
## Running a single test
```sh
just unit ./... TestParseMultilineString
go test -run 'TestRejectsSpecInvalid/table_over_array' ./...
go test ./cmd/interpres-decode/
```
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.
## Coverage
```sh
just test
go tool cover -func=coverage.out
just coverage-html
```
`just test` prints the total itself and fails below 80 percent, which is the
same floor CI enforces. The profile is `coverage.out`; the HTML map is
`coverage.html`. Both are ignored by git.
## Benchmarks
```sh
just bench
```
Benchmark on an idle machine, and compare only runs made in one process against
each other. The recipe sweeps `./...` five times with `-benchmem`. The binding
measurement method, and what counts as a result, is in
[docs/BENCHMARKING.md](BENCHMARKING.md).
## 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 between them they
carry the same set of gates, so a green `just gates` locally is the fastest
way to a green pipeline.
| Workflow | Trigger | What it does |
|---|---|---|
| `test.yml` | push or pull request to `development` | format check, vet, and the suite's short layer with the 80 percent coverage floor, inside the two-minute push budget |
| `suite.yml` | `workflow_dispatch`, by hand | the complete gate set minus race: build, format, vet, modernisation, the full suite and the coverage floor |
| `release.yml` | a `v*` tag | tag validation, then the Gitea release from the CHANGELOG section and nothing else. No gate runs at the tag: the tree was tested on every push, and a library ships no assets |
Race never runs in CI: it belongs to the local `just gates`, which races the
tree on the machine at the keyboard before the commit. The toml-test
compliance suite is a local recipe (`just toml-test`) and a development record
rather than a push gate.
## Releases
Releases are cut by merging `development` into `main` and tagging `vX.Y.Z`. The
tag drives the release workflow: it validates the tag, extracts the matching
`## [X.Y.Z]` section from `CHANGELOG.md`, and publishes the release with that
section as its body. No gate runs at the tag; a library ships no binaries, so
the release carries the notes and nothing else.