Add Windows support - #496
Conversation
`GOOS=windows go build ./...` currently fails on exactly two lines:
internal/telemetry/delegate.go:66:41: unknown field Setpgid in struct
literal of type syscall.SysProcAttr
internal/sidecar/terminal.go:16:28: undefined: syscall.SIGWINCH
Everything else in the tree is already portable: it is CGO_ENABLED=0 pure Go
with no existing build constraints, go-keyring supports Windows Credential
Manager, x/term supports Windows consoles, and coder/websocket is pure Go.
telemetry: move the process-group call behind build tags as detachProcess.
Unix keeps SysProcAttr{Setpgid: true}; Windows uses CreationFlags with
CREATE_NEW_PROCESS_GROUP, which is the equivalent way to keep console
control events sent to the parent's group away from the child.
sidecar: split terminal.go into terminal_unix.go (unchanged) and a new
terminal_windows.go. Windows has no SIGWINCH, so the Windows build polls
term.GetSize every 250ms and calls WindowChange only when the size actually
differs. A no-op stub would also compile, but remote PTY resize would then
silently stop working on Windows.
goreleaser: add windows to goos, and ship Windows archives as .zip.
Verified: builds pass for windows/amd64, windows/arm64, darwin/arm64 and
linux/amd64; go vet is clean under GOOS=windows; existing tests pass.
Not verified: the polling resize path has not been exercised on a real
Windows console — this was cross-compiled and unit-tested from macOS.
|
Follow-up: the PR body said the polling resize path and the process-group change had only been Environments
Independently configured — different builds, different hardware, different shells. The binary runs nativelyExit 0 on both machines, full cobra command tree loads. Package tests, run nativelyCross-compiled
Six failures are identical across both machines, so they are not environment-specific:
(A had a seventh, None of them are in the files this PR changes. Two distinct causes, neither caused by this patch:
So: this PR makes chunk build and run on Windows. It does not make the test suite green Not verified
Happy to swap the resize implementation for a no-op stub if you would rather not carry a |
|
One refinement on the sync failures, to save anyone a wrong lead. I suggested they might be stale fixture state — a So: reproducible from clean state on two independently configured Windows machines, and not explained by leftover state. I don't have a mechanism for you beyond that — flagging it as an open question rather than a diagnosis, since these are untouched by this PR either way. |
TestMain builds the receiverbin stub with an explicit `-o` path, and `go build` does not append `.exe` when the output path is given. Windows then cannot execute the result: os/exec appends extensions from PATHEXT when looking up a name that has none, so it searches for receiverbin.exe and finds nothing. The stub therefore built successfully and never started, and TestDelegateDestination_Close_DeliversToSegment failed with "received 0 events, want 1" after its 5s timeout. Verified on Windows 11 (10.0.26200) with go1.26.5 windows/amd64: the package fails before this change and passes after it. Confirmed by substituting a no-op detachProcess that the failure was independent of this branch's CREATE_NEW_PROCESS_GROUP change. No behaviour change off Windows.
|
Pushed The telemetry failure was a real bug, and it is fixed
That is precisely the test that exercises the The actual cause is in receiverBinPath = filepath.Join(dir, "receiverbin")
build := exec.Command("go", "build", "-o", receiverBinPath, "./testdata/receiverbin")
Consequence worth stating plainly: this also means Correction:
|
| package | result |
|---|---|
internal/telemetry |
pass |
internal/sidecar |
7 fail — 1 POSIX-permissions assumption, 6 SSH fixture |
Both remaining classes are independent of this branch. I am happy to take either on in a
separate PR if useful, but did not want to widen this one further without asking.
Problem
GOOS=windows go build ./...fails on exactly two lines:Nothing else in the tree blocks it. The module is
CGO_ENABLED=0pure Go with no existingbuild constraints,
zalando/go-keyringsupports Windows Credential Manager,x/termsupports Windows consoles, and
coder/websocketis pure Go.Changes
internal/telemetry— moved the process-group call behind build tags asdetachProcess:SysProcAttr{Setpgid: true}.CreationFlags: CREATE_NEW_PROCESS_GROUP, the equivalent way to keep consolecontrol events sent to the parent's group away from the detached telemetry subprocess.
internal/sidecar— splitterminal.gointoterminal_unix.go(logic unchanged) and anew
terminal_windows.go.Windows has no
SIGWINCH, so the Windows build pollsterm.GetSizeevery 250 ms and callsWindowChangeonly when the size actually differs. A no-op stub would also compile, butremote PTY resize would then silently stop working on Windows — polling keeps the behaviour.
Happy to switch to a no-op if you would rather not carry a ticker.
.goreleaser.yaml— addedwindowstogoos, and aformat_overridesentry so Windowsarchives ship as
.zip.Verification
GOOS=windows GOARCH=amd64 go build ./...GOOS=windows GOARCH=arm64 go build ./...GOOS=darwin GOARCH=arm64 go build ./...GOOS=linux GOARCH=amd64 go build ./...GOOS=windows go vet ./internal/...go test ./internal/...gofmt -l .What is not verified
This was cross-compiled and unit-tested from macOS. The polling resize path has not run on
a real Windows console. If you have Windows CI or a reviewer on Windows, that is the part
worth exercising before merge.
Also note the two
format_overrides/formatskeys follow current goreleaser schema; ifyour release pipeline pins an older version, that stanza may need the singular
formatkeyinstead.