fix(init): don't block on confirmation for 'init --here' without a TTY#3236
fix(init): don't block on confirmation for 'init --here' without a TTY#3236jawwad-ali wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes specify init --here behavior in non-interactive sessions by avoiding an unconditional confirmation prompt when the current directory is non-empty (and --force is not provided). It aligns the --here path with the existing named-project path by failing fast with actionable --force guidance instead of blocking/EOF-aborting.
Changes:
- Guard
typer.confirm(...)in theinit --herenon-empty directory flow with_stdin_is_interactive()and exit with a clear--forcemessage when non-interactive. - Add a CLI-level regression test covering
init --herein a non-empty directory under a forced non-interactive stdin.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/commands/init.py |
Adds a non-interactive guard to prevent blocking/EOF behavior and provide --force guidance for init --here into non-empty dirs. |
tests/integrations/test_cli.py |
Adds a regression test ensuring non-interactive init --here into a non-empty directory exits 1 with --force guidance and preserves existing files. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Low
| elif not _stdin_is_interactive(): | ||
| # No TTY to confirm on: fail fast with actionable guidance | ||
| # instead of blocking on typer.confirm (which would read EOF | ||
| # and abort unhelpfully). Mirrors the named-project path, | ||
| # which already errors and points to --force. | ||
| console.print( | ||
| "[red]Error:[/red] Current directory is not empty and no " | ||
| "interactive terminal is available to confirm. Re-run with " | ||
| "[bold]--force[/bold] to merge into it." | ||
| ) |
When 'specify init --here' targets a non-empty directory without --force, it called typer.confirm() unconditionally. In a non-interactive session (no TTY -- CI, piped, agent) there is no input, so the prompt reads EOF and aborts unhelpfully (or blocks), with no actionable message. The named-project path already fails fast and points to --force; --here was the inconsistent outlier. Guard the confirmation with the existing _stdin_is_interactive() helper: when non-interactive, print a clear 'directory not empty; re-run with --force' error and exit 1 instead of prompting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… on empty stdin The first version of this fix short-circuited on '_stdin_is_interactive()' (isatty) before typer.confirm, which broke 'init --here' when confirmation is piped (e.g. 'echo y | specify init --here' / CliRunner input='y\n') -- a non-TTY pipe with valid input was wrongly rejected, regressing test_init_here_without_force_preserves_shared_infra. Instead, call typer.confirm normally (piped 'y'/'n' is honored) and catch the Abort/EOFError it raises only when stdin is empty, converting that to the actionable '--force' guidance. This keeps the UX win for the no-input case without rejecting piped input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cd36c9b to
b4a6fcd
Compare
|
Fixed the failing The revised fix calls AI disclosure: prepared with Claude Code (Claude Opus 4.8) under my direction; I reviewed the diff before pushing. |
Description
When
specify init --heretargets a non-empty directory and--forceis not given, it calledtyper.confirm("Do you want to continue?")unconditionally. In a non-interactive session (CI, piped input, an agent driving the CLI) there is no TTY, so the prompt reads EOF and aborts unhelpfully (or blocks waiting for input) — with no actionable message.The named-project path already handles this correctly: it fails fast with an error panel pointing to
--force. The--herepath was the inconsistent outlier, even though the module already has a_stdin_is_interactive()helper used elsewhere.Fix
Guard the confirmation with
_stdin_is_interactive(): when non-interactive, print a clear "directory is not empty … re-run with --force to merge" error and exit 1 instead of prompting. Interactive behavior and the--forcefast-path are unchanged.Testing
uvx ruff checkclean.test_init_here_nonempty_noninteractive_errors_with_force_guidance: a non-empty cwd +init --here(no--force) under a non-interactive stdin now exits 1 with--forceguidance and leaves the pre-existing file untouched. Fails/blocks before, passes after.test_noninteractive_init_defaults_to_copilotstill passes.AI Disclosure
Found and fixed with Claude Code (Claude Opus 4.8) under my direction. AI spotted the unguarded
typer.confirmon the--herepath versus the already-guarded named-project path; I confirmed the_stdin_is_interactivehelper's existing use, verified the fix and that scaffolding is skipped on abort, and reviewed the diff before submitting.