fix(review): require terminal stdin for interactive mode · Entire
fix(review): require terminal stdin for interactive mode
1ac87bc→main·
dipree·3d ago·2 files·+11 added/-12 removed
Sessions
01KXGSC7YR34K5TTMAVFH7PCMAView transcript
Changes
2
cmd/entire/cli/review
Mcmd.go+5/-5
Mconfigure_test.go+6/-7
272 unmodified lines
273
274
275
276
277
276
277
278
279
280
281
1 unmodified line
283
284
285
285
286
287
288
289
290
291
290
291
292
293
294
272 unmodified lines
// reviewCommandIsInteractive treats a real terminal on both stdin and stdout
// as authoritative for this explicitly user-invoked command. This avoids
// suppressing the review wizard when a normal shell inherits an agent sentinel
// or GIT_TERMINAL_PROMPT=0. The fallback preserves controlling-TTY detection
// for callers whose stdio is not wired directly to the terminal.
// or GIT_TERMINAL_PROMPT=0, while requiring the exact stdin consumed by huh and
// Bubble Tea to accept keypresses. A controlling /dev/tty alone is insufficient
// because the command may still have piped stdin.
func reviewCommandIsInteractive(cmd *cobra.Command) bool {
testTTY := os.Getenv(interactive.EnvTestTTY)
ci := os.Getenv("CI")
1 unmodified line
return reviewTTYIsInteractive(
interactive.IsTerminalReader(cmd.InOrStdin()),
interactive.IsTerminalWriter(cmd.OutOrStdout()),
interactive.CanPromptInteractively(),
hardDisabled,
)
}
func reviewTTYIsInteractive(stdinTTY, stdoutTTY, canPrompt, hardDisabled bool) bool {
return !hardDisabled && stdoutTTY && (stdinTTY || canPrompt)
}
func reviewTTYIsInteractive(stdinTTY, stdoutTTY, hardDisabled bool) bool {
return !hardDisabled && stdinTTY && stdoutTTY
}
func (o reviewConfigureOptions) scripted() bool {
Mcmd/entire/cli/review/cmd.go+5/-5
94 unmodified lines
95
96
97
98
98
99
100
102
103
104
105
101
102
103
104
105
106
107
108
109
111
112
110
111
112
113
114
94 unmodified lines
name string
stdinTTY bool
stdoutTTY bool
canPrompt bool
hardDisabled bool
want bool
}{
{name: "direct terminal overrides inherited sentinel", stdinTTY: true, stdoutTTY: true, canPrompt: false, want: true},
{name: "controlling terminal fallback", stdinTTY: false, stdoutTTY: true, canPrompt: true, want: true},
{name: "captured stdout", stdinTTY: true, stdoutTTY: false, canPrompt: true, want: false},
{name: "agent with piped stdin", stdinTTY: false, stdoutTTY: true, canPrompt: false, want: false},
{name: "direct terminal overrides inherited sentinel", stdinTTY: true, stdoutTTY: true, want: true},
{name: "controlling terminal does not override piped stdin", stdinTTY: false, stdoutTTY: true, want: false},
{name: "captured stdout", stdinTTY: true, stdoutTTY: false, want: false},
{name: "agent with piped stdin", stdinTTY: false, stdoutTTY: true, want: false},
{name: "explicitly forced non-interactive", stdinTTY: true, stdoutTTY: true, hardDisabled: true, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := reviewTTYIsInteractive(tt.stdinTTY, tt.stdoutTTY, tt.canPrompt, tt.hardDisabled); got != tt.want {
t.Fatalf("reviewTTYIsInteractive(%v, %v, %v, %v) = %v, want %v", tt.stdinTTY, tt.stdoutTTY, tt.canPrompt, tt.hardDisabled, got, tt.want)
if got := reviewTTYIsInteractive(tt.stdinTTY, tt.stdoutTTY, tt.hardDisabled); got != tt.want {
t.Fatalf("reviewTTYIsInteractive(%v, %v, %v) = %v, want %v", tt.stdinTTY, tt.stdoutTTY, tt.hardDisabled, got, tt.want)
}
}
}
Mcmd/entire/cli/review/configure_test.go+6/-7