# Test, Go. Push and pull request to development. Never on main. # # The push path owns a two-minute budget end to end, so it carries exactly the gates # that fit it: the format check, go vet, the suite's short layer and the coverage # floor. There is no build step (go test compiles what it runs) and the modernisation # gate (`go fix -diff`) belongs to the suite workflow, which is dispatched by hand. # Nothing is installed: the fedora job image carries git, perl and node (verified on # the runner, 2026-10-04), and no pipeline ever installs gcc or runs the race detector. # # The live ptrace sessions and the other deliberate-run categories skip under # testing.Short: they need the machine to themselves and belong to the suite workflow # and to the local `just test`, never to every push. # # 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 with # builtins only: Fedora packages the Perl modules separately, so nothing beyond `perl` # itself may be assumed present, and there is no bashism to trip over. 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 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: 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: Tests # The pattern is `packages` in the project's justfile, so the floor is the # same number the local gate reports: the logic packages, since a thin cmd/ # and a ptrace-bound debug package would drag the total under it. No timeout # anywhere: `-timeout 0` disables go test's own ten-minute default, because a # run that does not finish is a defect to find and a timeout only hides it. run: go test -short -count=1 -timeout 0 -coverprofile=coverage.out ./arch/... ./asm/... ./ast/... ./disasm/... ./format/... ./lexer/... ./lint/... ./lsp/... ./parser/... ./token/... ./verify/... - name: Tests outside the coverage set # The CLI's exit codes and manual-page guard and the debugger's # architecture-neutral units, still tested but outside the profile the floor # is computed from. `-short` skips the debugger's live ptrace sessions. run: go test -short -count=1 -timeout 0 ./cmd/... ./debug/... - 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); '