From 55fc62a4fe34bb85f1cd8426bc8650ed8b3ce8bb Mon Sep 17 00:00:00 2001 From: Amolith Date: Fri, 10 Apr 2026 08:39:11 -0600 Subject: [PATCH] Add spec for non-interactive execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit keld is often invoked from systemd timers, cron jobs, CI pipelines, and shell scripts with no controlling terminal. Capture the intended behaviour as a Gherkin feature ahead of implementation. The spec covers four rules: without a terminal keld never launches the TUI, non-interactive mode requires explicit inputs (with specific errors when preset selection, backup paths, or the subcommand itself is missing), interactive mode is preserved when a terminal is attached, and KELD_NONINTERACTIVE overrides terminal detection as a fallback for users who want scripted behaviour on a terminal. Pure spec, no automation — matches the other files under features/. --- features/non_interactive.feature | 86 ++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 features/non_interactive.feature diff --git a/features/non_interactive.feature b/features/non_interactive.feature new file mode 100644 index 0000000000000000000000000000000000000000..71dceca1f1a3671b5846258a57d4d49d9c8a24d2 --- /dev/null +++ b/features/non_interactive.feature @@ -0,0 +1,86 @@ +Feature: Non-interactive execution + + keld is often invoked from systemd timers, cron jobs, CI pipelines, + and shell scripts where no controlling terminal is attached. In those + contexts it must run restic directly without attempting to launch the + interactive TUI. When a user wants scripted behaviour even on a + terminal, an environment variable provides an escape hatch. + + Rule: Without a terminal keld never launches the interactive TUI + + Scenario: Wrapped subcommand runs restic when the preset supplies everything + Given keld is invoked with a wrapped subcommand and no positional arguments + And standard input is not a terminal + And the selected preset supplies every value the command needs + When keld runs + Then restic is executed with the resolved configuration + And no interactive TUI is launched + + Scenario: Wrapped subcommand runs restic when positional arguments cover missing values + Given keld is invoked with a wrapped subcommand and positional arguments + And standard input is not a terminal + When keld runs + Then restic is executed with the resolved configuration + And no interactive TUI is launched + + Scenario: --show-command prints the resolved command without launching the TUI + Given keld is invoked non-interactively with --show-command + When keld runs + Then the resolved restic command is printed + And keld exits successfully without executing restic + And no interactive TUI is launched + + Rule: Non-interactive mode requires explicit inputs + + Scenario: Multiple presets are configured and none is specified + Given the configuration defines more than one preset + And keld is invoked non-interactively without --preset + When keld runs + Then keld fails with an error naming the --preset flag + And the error lists the available presets + And no interactive TUI is launched + + Scenario: Backup invoked with no paths available + Given keld is invoked non-interactively with the backup subcommand + And no paths are provided on the command line + And the resolved preset defines no backup paths + When keld runs + Then keld fails with an error naming the missing paths + And no interactive TUI is launched + + Scenario: Bare keld with no subcommand + Given keld is invoked non-interactively with no subcommand + When keld runs + Then keld fails with an error naming the missing subcommand + And no interactive TUI is launched + + Rule: Interactive mode is preserved when a terminal is attached + + Scenario: Wrapped subcommand with no arguments opens the session + Given keld is invoked with a wrapped subcommand and no positional arguments + And standard input is a terminal + When keld runs + Then the interactive session is launched with the command pre-selected + + Scenario: Bare keld opens the command menu + Given keld is invoked with no subcommand + And standard input is a terminal + When keld runs + Then the interactive session is launched starting at the command menu + + Rule: KELD_NONINTERACTIVE overrides terminal detection + + Scenario: Environment variable forces non-interactive behaviour on a terminal + Given keld is invoked with a wrapped subcommand and no positional arguments + And standard input is a terminal + And KELD_NONINTERACTIVE is set to a non-empty value + When keld runs + Then restic is executed with the resolved configuration + And no interactive TUI is launched + + Scenario: Empty KELD_NONINTERACTIVE is treated as unset + Given keld is invoked with a wrapped subcommand and no positional arguments + And standard input is a terminal + And KELD_NONINTERACTIVE is set to an empty value + When keld runs + Then the interactive session is launched with the command pre-selected