Skip to content

Test across macOS, Windows and two Go versions - #69

Merged
korya merged 2 commits into
masterfrom
korya-ci-build-matrix
Aug 8, 2026
Merged

Test across macOS, Windows and two Go versions#69
korya merged 2 commits into
masterfrom
korya-ci-build-matrix

Conversation

@korya

@korya korya commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Problem

A CLI published for five platforms had its test suite run on one.

CI was a single job: ubuntu-latest, one Go version, no matrix. macOS and Windows users — and everyone installing the binaries v0.1.0 now publishes for them — were running code whose tests had never executed on their operating system.

The exposure is not theoretical. net.Dialer timeout and keep-alive semantics differ on Windows; hostMapping splits on strings.Index(v, ":"), which meets IPv6 literals and drive-letter-shaped inputs differently; printPayload classifies printable runes and line endings; and the 71/91/93/103 exit-code contract is worth confirming per platform rather than assuming.

Solution

Six test legs — three operating systems by two Go versions — with static analysis left on Linux.

fail-fast: false, so a red platform reports its own failure instead of cancelling the evidence from the other five. The empty Go version resolves through go-version-file: go.mod, verified against the action's resolveVersionInput(): an empty go-version falls through to the file rather than erroring. The stable leg catches a regression on the next Go release instead of whenever go.mod next moves.

Static checks stay single-platform on purpose. gosec and golangci-lint reach the same verdict everywhere, so putting the two slowest checks on six runners buys output that cannot differ. just static-checks names that half, and pre-commit is now that plus the tests — the same eight recipes it always ran, regrouped.

Both caveats the issue asked to settle were checked before writing any YAML: extractions/setup-just runs its own CI on windows-latest, and golangci-lint-action exposes install-only.

Other Changes

The lint action stops linting on its own. Without install-only: true it runs golangci-lint with its own defaults, and then just lint runs it again with the repository's configuration — every build has been linting twice.

Notes for the reviewer

Draft on purpose. This is the first time the suite has run on macOS or Windows, and the point of the change is to find out what breaks. Anything red here is a real finding about the tool, not about the workflow — I will work through failures before marking it ready.

Related:

🤖 Generated with Claude Code

korya and others added 2 commits August 7, 2026 21:45
CI ran one configuration -- ubuntu-latest, one Go version -- for a CLI
published on five platforms. Everyone not on Linux was running a binary
whose test suite had never executed on their operating system.

The code is less OS-neutral than it looks. Socket timeout behaviour under
net.Dialer, colon handling in host mappings around IPv6 literals, printable
-rune classification in the payload dumper, and the exit-code contract are
all places where Linux is not the general case.

Six legs now: three operating systems by two Go versions, where the empty
version means whatever go.mod requires and 'stable' catches a regression on
the next Go release instead of whenever go.mod happens to move next.
fail-fast is off, so one red platform reports its own failure rather than
cancelling the evidence from the other five.

Static analysis stays on Linux alone. gosec and golangci-lint reach the same
verdict everywhere, so spreading them across the matrix would triple the two
slowest checks for output that cannot differ. `just static-checks` names that
half; pre-commit is now that plus the tests, which is the same set it always
ran.

The lint action also stops linting on its own. It runs golangci-lint unless
told to install only, so every build linted twice -- once with the action's
defaults and once with the repository's own configuration through `just
lint`.

Refs #51

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019EMMhgmTkbzAsmeNy97PrP
The three jobs ran concurrently, so a vet or lint failure occupied six
runners while they discovered the same thing six times, and goreleaser
packaged a binary whose tests had not finished on any platform.

Ordering them costs wall-clock time and buys a cheaper failure: the static
checks are the fastest and the most likely to be what is wrong, so they go
first, and packaging happens only once every platform agrees.

fail-fast stays off within the matrix. Serialising the phases is the point;
serialising the platforms against each other is not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019EMMhgmTkbzAsmeNy97PrP
@korya
korya marked this pull request as ready for review August 8, 2026 01:53
@korya
korya merged commit ba799c7 into master Aug 8, 2026
8 checks passed
@korya
korya deleted the korya-ci-build-matrix branch August 8, 2026 01:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant