133 lines
5.4 KiB
YAML
133 lines
5.4 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.
|
|
# The box is one core and 2 GB 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 three times 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
|
|
# Fedora packages the Perl modules separately and nothing beyond `perl` itself may be
|
|
# assumed present.
|
|
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:
|
|
- 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
|
|
|
|
- name: Install Perl
|
|
# The runner images are minimal and Perl is not guaranteed. The install is a
|
|
# no-op where it is already present; drop this step once verified on the box.
|
|
run: dnf install -y perl
|
|
|
|
# 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
|
|
run: go build ./...
|
|
|
|
- name: FreeBSD build (amd64)
|
|
# The debugger's ptrace surface and the JIT substrate are the two
|
|
# FreeBSD-portable layers the tree carries; the forge has no FreeBSD
|
|
# runner, so a push can only compile-gate them. Running the ptrace
|
|
# suite needs real FreeBSD hardware.
|
|
env:
|
|
GOOS: freebsd
|
|
GOARCH: amd64
|
|
run: go build ./...
|
|
|
|
- name: FreeBSD build (arm64)
|
|
env:
|
|
GOOS: freebsd
|
|
GOARCH: arm64
|
|
run: go build ./...
|
|
|
|
- name: FreeBSD build (riscv64)
|
|
env:
|
|
GOOS: freebsd
|
|
GOARCH: riscv64
|
|
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
|
|
# The suite must be fast: a push pipeline that cannot finish in a few minutes moves
|
|
# its heavy part behind a dispatch. The inner timeout matches the job's, so a
|
|
# hanging test reports its own goroutine dump rather than a silent job kill.
|
|
# The pattern is `packages` in the project's justfile: the logic packages, since a
|
|
# thin cmd/ would drag the total under the floor. release.yml runs the same
|
|
# command, so the floor is the same number everywhere. ./verify/... carries the
|
|
# live oracle-parity comparison against `go tool asm` (the TestGroundTruth
|
|
# suites); the runner's Go setup provides both the tool and GOROOT.
|
|
run: go test -count=1 -timeout 10m -coverprofile=coverage.out ./arch/... ./asm/... ./ast/... ./disasm/... ./format/... ./lexer/... ./lint/... ./lsp/... ./parser/... ./token/... ./verify/...
|
|
|
|
- name: Tests outside the coverage set
|
|
# The CLI and the debugger sit outside `packages` because a thin main and a
|
|
# ptrace-bound package pull the total under the floor, but their tests guard
|
|
# shipped surfaces: the command exit codes, the manual pages against the
|
|
# binary's own help, and the debugger's architecture-neutral units. They run
|
|
# here so the floor stays a product measure and nothing is left untested.
|
|
run: go test -count=1 -timeout 10m ./cmd/... ./debug/...
|
|
|
|
- name: Oracle parity
|
|
# Re-run the live go-tool-asm comparison as its own step so that a parity
|
|
# regression names the gate that failed instead of hiding inside the suite.
|
|
run: go test -count=1 -timeout 10m -run 'TestGroundTruth' ./verify/...
|
|
|
|
- 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);
|
|
'
|