feat: non-interactive / headless mode for CI environments - #149
Conversation
- Auto-detect TTY via go-isatty; skip keyboard when stdin is not a terminal - Add --no-input flag for explicit headless override - Gate ANSI cursor-hide sequences and welcome message on Interactive mode - Thread Interactive bool through RunOptions into CLI.Run() - Fix TestRunConnectCmd_SuccessConnect: remove conditional /dev/tty error acceptance - Add TestInitRunOptions_Interactive and TestRunConnectCmd_NoInputFlag tests - Promote go-isatty to direct dependency (was already indirect via fatih/color) - Document CI usage in README with GitHub Actions example Fixes: wsget fails with 'keyboard input failed: open /dev/tty: no such device or address' when running with --request or --input in CI environments.
There was a problem hiding this comment.
Pull request overview
This PR makes wsget safe to run in non-interactive/headless environments (CI, Docker, scripts) by avoiding unconditional keyboard initialization and suppressing terminal-only UI behavior when no terminal is present.
Changes:
- Add
--no-inputand auto-detect non-interactive runs viaisatty, skipping the keyboard goroutine when headless. - Thread an
Interactiveflag throughRunOptionsand gate cursor/welcome output on it. - Update tests and documentation; promote
go-isattyto a direct dependency.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents headless/CI usage patterns and examples. |
pkg/core/cli.go |
Adds RunOptions.Interactive and gates cursor/welcome UI on it. |
pkg/cmd/init.go |
Registers --no-input flag to disable interactive input explicitly. |
pkg/cmd/connect.go |
Computes interactivity via isatty and conditionally starts keyboard handling; passes interactivity into RunOptions. |
pkg/cmd/connect_test.go |
Adds/adjusts tests around interactive behavior and --no-input. |
go.mod |
Makes github.com/mattn/go-isatty a direct dependency. |
.gitignore |
Adds .taskman/ to ignored paths. |
Suppressed comments (1)
pkg/cmd/connect_test.go:328
- Same isolation issue as above:
configDiris unset, so the test writes into the current user's home directory (~/.wsget). Uset.TempDir()here as well to avoid polluting developer machines / CI runners.
args := &flags{
request: "test request",
waitResponse: 1,
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #149 +/- ##
==========================================
- Coverage 90.01% 89.55% -0.46%
==========================================
Files 25 25
Lines 1852 1858 +6
==========================================
- Hits 1667 1664 -3
- Misses 108 117 +9
Partials 77 77 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (3)
pkg/cmd/connect.go:208
- The doc comment for initRunOptions is now out of date: it still says the function takes a single parameter, but the signature includes the new
interactiveparameter. This makes it harder to understand what drives terminal UI behavior.
// initRunOptions initializes and returns a RunOptions struct based on the provided flags.
// It takes a single parameter args of type *flags which contains the command-line arguments.
// It returns a pointer to cli.RunOptions and an error.
// It returns an error if it fails to open the specified output file.
func initRunOptions(args *flags, interactive bool) (opts *core.RunOptions, err error) {
pkg/cmd/connect_test.go:315
TestRunConnectCmd_NoInputFlagisn’t deterministic about validating thenoInputoverride: in typicalgo testruns stdin is already non-TTY, so the keyboard goroutine would be skipped even ifnoInputwere ignored. Consider extracting the interactive/headless detection into a small pure helper (e.g., based on booleans) and unit-testing the combinations so the--no-inputbehavior is actually asserted.
request: "test request",
waitResponse: 1,
noInput: true,
configDir: tmpConfigDir,
}
pkg/cmd/connect.go:132
isatty.IsTerminalalone can miss terminals under Cygwin/MSYS environments. To make interactive detection more robust across platforms, includeisatty.IsCygwinTerminalin the TTY checks for stdin/stdout.
inputEnabled := !args.noInput && isatty.IsTerminal(os.Stdin.Fd())
uiInteractive := inputEnabled && isatty.IsTerminal(os.Stdout.Fd())
Problem
Running
wsgetin CI (GitHub Actions, Docker, any environment without/dev/tty) fails even when using--requestor--inputflags:The keyboard goroutine was always started unconditionally, even in fully scripted runs that never need user input.
Solution
Auto-detect via
isatty— if stdin is not a terminal, keyboard initialization is skipped entirely. No flags needed; works automatically in CI.Explicit
--no-inputflag — overrides auto-detection for edge cases.Gate terminal UI on interactive mode — ANSI cursor-hide sequences and the welcome message are now suppressed in headless runs.
Changes
pkg/core/cli.goInteractive booltoRunOptions; gate cursor/welcome on itpkg/cmd/init.gonoInput booltoflags; register--no-inputflagpkg/cmd/connect.goisatty.IsTerminal; wrap keyboard goroutine inif isInteractivepkg/cmd/connect_test.go/dev/ttyerror acceptance; add new testsgo.modgo-isattyfrom indirect → direct (was already pulled in viafatih/color)README.mdUsage
Testing
TestRunConnectCmd_SuccessConnect: previously acceptedopen /dev/ttyerrors as valid outcomes; now unconditionally passesTestInitRunOptions_Interactive— verifiesInteractiveflag threads correctlyTestRunConnectCmd_NoInputFlag— end-to-end test withnoInput: truego test ./...