Test across macOS, Windows and two Go versions - #69
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.Dialertimeout and keep-alive semantics differ on Windows;hostMappingsplits onstrings.Index(v, ":"), which meets IPv6 literals and drive-letter-shaped inputs differently;printPayloadclassifies 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 throughgo-version-file: go.mod, verified against the action'sresolveVersionInput(): an emptygo-versionfalls through to the file rather than erroring. Thestableleg catches a regression on the next Go release instead of whenevergo.modnext 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-checksnames that half, andpre-commitis 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-justruns its own CI onwindows-latest, andgolangci-lint-actionexposesinstall-only.Other Changes
The lint action stops linting on its own. Without
install-only: trueit runs golangci-lint with its own defaults, and thenjust lintruns 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