Files
petrbalvin af4ee19703
Release / gates (push) Successful in 4m38s
Test / test (push) Successful in 5m16s
Release / release (push) Successful in 35s
feat: initial release
Assisted-by: GLM 5.3 Flash
2026-09-03 10:00:00 +02:00

110 lines
4.7 KiB
YAML

# Test, Go. Push and pull request to development. Never on main.
#
# The gates are the ones the justfile's `gates` recipe runs, minus race: the shared
# runner box cannot afford the race detector on every push, so it lives in race.yml,
# dispatched by hand. The box is small and sits beside Gitea, so parallelism is bounded
# on purpose and everything runs in one job; extra jobs would duplicate the checkout,
# the Go setup and the dependency download without buying any parallelism.
#
# Every step is one command, so the step that fails is the gate that failed, and no shell
# option has to be trusted for the run to stop. The scripted steps are Perl, not shell and
# not Python: Perl behaves the same on both runner images, there is no bashism to trip over
# on ash, and it is one language instead of two. The Perl uses builtins only, because
# nothing beyond `perl` itself may be assumed present.
#
# Project facts the template had to bend for: the portable build runs at the toolchain
# default with nothing pinned, the oracle digests are recorded per platform there, and
# the package pattern is the logic packages of the project's justfile `packages`,
# which keeps the main-program examples out of the suite. The benchmark smoke that
# once rode along here is retired outright: the minimum degree battery's 3-D mesh
# scan alone runs for minutes on one core and allocates terabytes cumulatively, so
# no form of it fits the shared box, and benchmarking is deliberate work on a
# developer machine, where the battery is survivable and the numbers are the point.
name: Test
on:
push:
branches: [development]
pull_request:
branches: [development]
env:
# One core: parallelism buys no speed here and costs memory the box does not have.
GOFLAGS: -p=1
GOMAXPROCS: "2"
# A superseded run of the same ref is cancelled instead of queueing behind one that
# no longer matters. Verified on Gitea 1.27.1 on 2026-09-17: a queued run whose ref
# moved on is cancelled before it ever reaches the runner, while a run already
# dispatched there runs to completion.
concurrency:
group: ${{ gitea.workflow }}-${{ gitea.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: fedora
timeout-minutes: 10
steps:
- name: Install git and Perl
# The runner images are minimal: checkout needs git and the scripted steps
# below are Perl. Both installs are no-ops where the package already exists.
run: dnf install -y git perl
- uses: actions/checkout@v7
- uses: actions/setup-go@v6
with:
# The module is the source of truth for the version, so it cannot drift.
go-version-file: go.mod
cache: true
# The steps follow the `gates` order of the justfile contract: build, format,
# vet, test. The vet gate is go vet and go fix -diff, two steps here.
- name: Build
# The examples are main programs; the build is what compiles them.
run: go build ./...
- name: Format
run: |
perl -e '
open(my $g, q{-|}, q{gofmt}, q{-l}, q{.}) or die qq{gofmt: $!};
my @bad = <$g>;
close($g);
print @bad;
exit(@bad ? 1 : 0);
'
- name: Vet
run: go vet ./...
- name: Modernise
# Exits non-zero when it has something to rewrite, so it needs no output capture.
run: go fix -diff ./...
- name: Tests
# Equal to `packages` in the project's justfile, so the floor is the same
# number the local gate reports. The inner timeout matches the job's, so a
# hanging test reports its own goroutine dump rather than a silent job kill.
# The local `just test` allows 30 minutes for a warm 32-core box; this
# runner is one shared core, where the suite stays well inside the ten
# minutes its budget has always allowed.
run: go test -count=1 -timeout 10m -coverprofile=coverage.out . ./internal/... ./grad/... ./integrate/... ./io/... ./linalg/... ./optim/... ./signal/... ./spmd/... ./stats/...
- name: Coverage floor
run: |
perl -e '
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);
'
- name: Oracle digests for this platform
# TestOracle verifies the pinned digest block for GOOS/GOARCH and skips
# loudly with instructions when the platform has none yet.
run: go test -run TestOracle -v .