Skip to content

feat: non-interactive / headless mode for CI environments - #149

Merged
ksysoev merged 3 commits into
mainfrom
feat/headless-non-interactive-mode
Aug 1, 2026
Merged

ksysoev merged 3 commits into
mainfrom
feat/headless-non-interactive-mode

Conversation

@ksysoev

@ksysoev ksysoev commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Problem

Running wsget in CI (GitHub Actions, Docker, any environment without /dev/tty) fails even when using --request or --input flags:

Use Enter to input request and send it, Ctrl+C to exit
Error: keyboard input failed: open /dev/tty: no such device or address

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-input flag — 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

File Change
pkg/core/cli.go Add Interactive bool to RunOptions; gate cursor/welcome on it
pkg/cmd/init.go Add noInput bool to flags; register --no-input flag
pkg/cmd/connect.go Compute isatty.IsTerminal; wrap keyboard goroutine in if isInteractive
pkg/cmd/connect_test.go Remove conditional /dev/tty error acceptance; add new tests
go.mod Promote go-isatty from indirect → direct (was already pulled in via fatih/color)
README.md Add CI / Headless Usage section with GitHub Actions example

Usage

# GitHub Actions / CI — works automatically, no flags needed
wsget wss://example.com -r '{"hello":"world"}' -w 5

# YAML script (must end with: - exit)
wsget wss://example.com -i script.yaml

# Explicit override
wsget wss://example.com --no-input -i script.yaml

Testing

  • Fixed TestRunConnectCmd_SuccessConnect: previously accepted open /dev/tty errors as valid outcomes; now unconditionally passes
  • Added TestInitRunOptions_Interactive — verifies Interactive flag threads correctly
  • Added TestRunConnectCmd_NoInputFlag — end-to-end test with noInput: true
  • All existing tests pass: go test ./...

- 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.
Copilot AI review requested due to automatic review settings August 1, 2026 09:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-input and auto-detect non-interactive runs via isatty, skipping the keyboard goroutine when headless.
  • Thread an Interactive flag through RunOptions and gate cursor/welcome output on it.
  • Update tests and documentation; promote go-isatty to 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: configDir is unset, so the test writes into the current user's home directory (~/.wsget). Use t.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.

Comment thread pkg/cmd/connect.go Outdated
Comment thread pkg/cmd/connect_test.go
Comment thread pkg/core/cli.go
@codecov-commenter

codecov-commenter commented Aug 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.15789% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.55%. Comparing base (671b7f4) to head (983a294).

Files with missing lines Patch % Lines
pkg/cmd/connect.go 46.15% 6 Missing and 1 partial ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ksysoev
ksysoev requested a review from Copilot August 1, 2026 10:13
@ksysoev ksysoev self-assigned this Aug 1, 2026
@ksysoev ksysoev linked an issue Aug 1, 2026 that may be closed by this pull request

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 interactive parameter. 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_NoInputFlag isn’t deterministic about validating the noInput override: in typical go test runs stdin is already non-TTY, so the keyboard goroutine would be skipped even if noInput were 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-input behavior is actually asserted.
		request:      "test request",
		waitResponse: 1,
		noInput:      true,
		configDir:    tmpConfigDir,
	}

pkg/cmd/connect.go:132

  • isatty.IsTerminal alone can miss terminals under Cygwin/MSYS environments. To make interactive detection more robust across platforms, include isatty.IsCygwinTerminal in the TTY checks for stdin/stdout.
	inputEnabled := !args.noInput && isatty.IsTerminal(os.Stdin.Fd())
	uiInteractive := inputEnabled && isatty.IsTerminal(os.Stdout.Fd())

@ksysoev
ksysoev merged commit 8263f55 into main Aug 1, 2026
5 checks passed
@ksysoev
ksysoev deleted the feat/headless-non-interactive-mode branch September 13, 2026 07:57
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.

Run wsget cli non-interactively (w/o /dev/tty)

3 participants