Guard root TUI entry against non-interactive env
Amolith
created 1 month ago
Bare keld with no subcommand now checks isInteractive() before entering
the TUI. In non-interactive environments, returns a clear error message
directing the user to specify a subcommand instead of crashing with a
bubbletea TTY error.
Task: td-MY949DM
Change summary
cmd/root.go | 5 ++++
cmd/root_noninteractive_test.go | 38 +++++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
Detailed changes
@@ -44,6 +44,11 @@ var rootCmd = &cobra.Command{
TraverseChildren: true,
RunE: func(cmd *cobra.Command, _ []string) error {
+ // Bare keld with no subcommand requires a tty.
+ if !isInteractive() {
+ return fmt.Errorf("keld: no subcommand specified; non-interactive mode requires a subcommand (e.g. 'keld backup')")
+ }
+
commandName, preset, overrides, err := runInteractive("")
if err != nil {
return err
@@ -0,0 +1,38 @@
+package cmd
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestRootRunNonInteractiveRequiresSubcommand(t *testing.T) {
+ // Not parallel: mutates package-level isStdinTerminal.
+
+ // Override stdin terminal check to simulate non-interactive environment.
+ original := isStdinTerminal
+ t.Cleanup(func() {
+ isStdinTerminal = original
+ })
+ isStdinTerminal = func() bool { return false }
+
+ // Reset root command flags to defaults.
+ setRootFlagValuesForTest(t, "", false, "")
+ t.Setenv("KELD_CONFIG_FILE", "")
+ t.Setenv("KELD_DRYRUN", "")
+
+ err := rootCmd.RunE(rootCmd, nil)
+ if err == nil {
+ t.Fatal("expected error for bare keld in non-interactive mode, got nil")
+ }
+
+ errMsg := err.Error()
+ // Should NOT be a bubbletea TTY error.
+ if strings.Contains(errMsg, "bubbletea") || strings.Contains(errMsg, "TTY") {
+ t.Fatalf("non-interactive mode incorrectly tried to open TTY: %v", err)
+ }
+
+ // Should mention missing subcommand.
+ if !strings.Contains(errMsg, "subcommand") {
+ t.Fatalf("expected error to mention subcommand, got: %v", err)
+ }
+}