From ceccb754fe58b773486977afa6f1e2192bd99d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Balv=C3=ADn?= Date: Wed, 19 Aug 2026 14:31:00 +0200 Subject: [PATCH] build: canonical justfile Assisted-by: GLM 5.3 Flash --- justfile | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 justfile diff --git a/justfile b/justfile new file mode 100644 index 0000000..f1019a0 --- /dev/null +++ b/justfile @@ -0,0 +1,105 @@ +# interpres. +# +# Everything below the variable block is the standard recipe set from the `justfile` +# skill, identical in every repository; project values live in the variable block only. +binary := "interpres-decode" +package := "./cmd/interpres-decode" + +# What the test and bench recipes sweep. Scope this to the logic packages when a thin +# cmd/ drags the coverage floor down, for example "./internal/... ./pkg/...". Never name +# a directory the project does not have: a pattern that matches nothing is a setup +# failure, not an empty run. +packages := "./..." + +bindir := env_var_or_default("BINDIR", env_var("HOME") / ".local" / "bin") + +default: + @just --list + +# Compile. Zero errors, zero warnings. +build: + CGO_ENABLED=0 go build -ldflags "-s -w" -o bin/{{binary}} {{package}} + +# The test gate: the suite, no cache, the coverage floor. +test: + #!/usr/bin/env perl + system(q{go}, q{test}, q{-count=1}, q{-timeout}, q{30m}, + q{-coverprofile}, q{coverage.out}, qw({{packages}})) == 0 + or die qq{the test suite failed\n}; + open(my $c, q{-|}, q{go}, q{tool}, q{cover}, q{-func=coverage.out}) or die qq{cover: $!}; + my $total; + while (my $l = <$c>) { $total = $1 if $l =~ m{^total:\s+\S+\s+([0-9.]+)%} } + close($c); + die qq{no total line in coverage.out\n} unless defined $total; + printf qq{Total coverage: %s%%\n}, $total; + exit($total < 80 ? 1 : 0); + +# The same suite under the race detector. The expensive one. +race: + go test -race -count=1 -timeout 30m {{packages}} + +# Fast scoped run for iterating. This is the one that runs after every edit. +unit pkgs=packages run=".*": + go test {{pkgs}} -run '{{run}}' + +# Time-boxed fuzz of one target in one package. The package is required; never a gate. +fuzz target pkg fuzztime="60s": + go test -run '^$' -fuzz '{{target}}' -fuzztime={{fuzztime}} {{pkg}} + +# Benchmarks. On an idle machine only. +bench pkgs=packages: + go test -run '^$' -bench=. -benchmem -count=5 {{pkgs}} + +# Format in place. +fmt: + gofmt -w . + +# Zero diff. Prints nothing when everything is formatted. +fmt-check: + #!/usr/bin/env perl + open(my $g, q{-|}, q{gofmt}, q{-l}, q{.}) or die qq{gofmt: $!}; + my @bad = <$g>; + close($g); + print @bad; + exit(@bad ? 1 : 0); + +# Both static gates: go vet and go fix -diff. +vet: + go vet ./... + go fix -diff ./... + +# The definition of done, in one command. Once per task, never per edit. +gates: build fmt-check vet test race + +# Build artefacts only, not the installed binary. +clean: + rm -rf bin/ coverage.out + +# Build, then copy the binary into bindir. +install: build + install -d "{{bindir}}" + install -m 755 bin/{{binary}} "{{bindir}}/{{binary}}" + +# Remove the installed binary. +uninstall: + rm -f "{{bindir}}/{{binary}}" + +# Run the program. The flag is there because `go run` does not stamp the build otherwise. +run: + go run -buildvcs=true {{package}} + +# Run with watch or hot reload, where the project has one. +dev: + go run -buildvcs=true {{package}} + +# Runs the official toml-test compliance suite against the built adapter; toml-test must be on PATH (go install github.com/toml-lang/toml-test/cmd/toml-test@v1.6.0); not standard because no canonical recipe covers a domain compliance suite. +toml-test: build + toml-test bin/interpres-decode + +# Coverage report as an HTML map from the gate's profile; not standard because the gate needs only the numeric floor, and a browser artefact is exploration, not a gate. +coverage-html: test + go tool cover -html=coverage.out -o coverage.html + +# Runs the example program under examples/basic; not standard because `run` runs the adapter, and an example is documentation, not the product. +example: + go run ./examples/basic