Skip to content

feat(settings): add new confirmation settings to control default/invalid input behavior#138

Merged
water-sucks merged 1 commit intonix-community:mainfrom
water-sucks:improve-confirmation-input-dialog
Nov 26, 2025
Merged

feat(settings): add new confirmation settings to control default/invalid input behavior#138
water-sucks merged 1 commit intonix-community:mainfrom
water-sucks:improve-confirmation-input-dialog

Conversation

@water-sucks
Copy link
Copy Markdown
Collaborator

@water-sucks water-sucks commented Nov 26, 2025

Description

The confirmation prompt was a bit flaky and didn't respect the no_confirm setting, and always defaulted to a response of "no" if no input/invalid input was given.

Since this behavior may not be expected by all users, this PR makes it configurable through some new settings; confirmation.always (skip entirely), confirmation.invalid (to control what to do when invalid input is given, defaults to retrying), and confirmation.empty (to control what to do when no input is given, defaults to treating it as a "no" input, like before).

This also deprecates the no_confirm option that was unused anyway, and tells users to use confirmation.always. It will be removed in a future release.

Summary by CodeRabbit

  • New Features

    • Added configurable confirmation settings to control when prompts are shown and can be skipped.
    • Confirmation prompts now support configurable behaviors for empty or invalid answers (retry, default yes/no) and will re-prompt as configured.
    • Common operations (activate, delete, rollback, switch) and SSH host-key confirmation follow the new confirmation logic.
  • Chores

    • Enabled traversal of command run hooks during execution.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 26, 2025

Walkthrough

Adds configurable confirmation behaviors and wiring: new ConfirmationSettings and ConfirmationPromptBehavior, updated Settings, completion helpers, and docs; ConfirmationInput now accepts ConfirmationPromptOptions and implements scanner-based re-prompting; command handlers and SSH host-key prompt use the new options; enables cobra traversal run hooks.

Changes

Cohort / File(s) Summary
Settings Configuration
internal/settings/settings.go
Adds ConfirmationSettings to Settings with Always, Invalid, Empty; introduces ConfirmationPromptBehavior type and constants (retry, default-yes, default-no); adds AvailableConfirmationPromptSettings, UnmarshalText, default initialization, docs entries, and deprecation handling for no_confirm. Also changes SetValue pointer handling to reflect.Pointer.
Completion Helpers
internal/settings/completion.go
Introduces generic stringCompletionFunc and completeConfirmationBehaviorKey; refactors boolean completion to reuse helper; registers completions for confirmation.empty and confirmation.invalid.
Confirmation Utility
internal/cmd/utils/confirmation.go
Adds ConfirmationPromptOptions struct; changes ConfirmationInput signature to accept options; implements scanner-based prompt loop handling empty/invalid inputs per configured behaviors (Retry, DefaultYes, DefaultNo) and returns confirmation result or errors.
Command Handlers
cmd/apply/apply.go, cmd/generation/delete/delete.go, cmd/generation/rollback/rollback.go, cmd/generation/switch/switch.go
Gate confirmation on both opts.AlwaysConfirm and cfg.Confirmation.Always; pass ConfirmationPromptOptions (sourced from cfg.Confirmation.Invalid / cfg.Confirmation.Empty) to ConfirmationInput; handle errors and negative confirmation consistently.
SSH Host Key Confirmation
internal/system/ssh.go
Replaces plain prompt call with ConfirmationInput using ConfirmationPromptOptions with both behaviors set to ConfirmationPromptRetry (hard-coded retry behavior) for unknown-host confirmation flow.
Root Command Init
cmd/root/root.go
Enables cobra.EnableTraverseRunHooks = true before executing the main command.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Cmd as Command Handler
    participant Cfg as Config
    participant Utils as ConfirmationInput

    User->>Cmd: run command
    Cmd->>Cfg: read cfg.Confirmation
    alt opts.AlwaysConfirm OR Cfg.Confirmation.Always
        Cmd->>Cmd: skip confirmation -> proceed
    else
        Cmd->>Utils: ConfirmationInput(msg, ConfirmationPromptOptions)
        loop prompt loop
            Utils->>User: display prompt
            User->>Utils: input (y/n/empty/invalid)
            alt empty
                Utils->>Utils: apply EmptyBehavior (Retry / DefaultYes / DefaultNo)
            else invalid
                Utils->>Utils: apply InvalidBehavior (Retry / DefaultYes / DefaultNo)
            else valid
                Utils->>Cmd: return result
            end
        end
        alt confirmed
            Cmd->>Cmd: proceed action
        else not confirmed
            Cmd->>User: abort / log
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing attention:
    • internal/settings/settings.go: default initialization, UnmarshalText parsing, and deprecation handling for no_confirm.
    • internal/cmd/utils/confirmation.go: scanner loop correctness, EOF/scanner error handling, and all behavior branches.
    • Command handlers: consistent gating logic and correct construction/passing of ConfirmationPromptOptions.
    • internal/system/ssh.go: intentional hard-coded retry behavior for host-key prompts.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding new confirmation settings to control prompt behavior for invalid/empty input.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34a1302 and 4c6acac.

📒 Files selected for processing (9)
  • cmd/apply/apply.go (1 hunks)
  • cmd/generation/delete/delete.go (1 hunks)
  • cmd/generation/rollback/rollback.go (1 hunks)
  • cmd/generation/switch/switch.go (1 hunks)
  • cmd/root/root.go (1 hunks)
  • internal/cmd/utils/confirmation.go (1 hunks)
  • internal/settings/completion.go (1 hunks)
  • internal/settings/settings.go (10 hunks)
  • internal/system/ssh.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • cmd/root/root.go
  • cmd/apply/apply.go
  • cmd/generation/rollback/rollback.go
  • internal/system/ssh.go
🧰 Additional context used
🧬 Code graph analysis (5)
cmd/generation/switch/switch.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
internal/cmd/utils/confirmation.go (1)
internal/settings/settings.go (4)
  • ConfirmationPromptBehavior (62-62)
  • ConfirmationPromptRetry (65-65)
  • ConfirmationPromptDefaultNo (67-67)
  • ConfirmationPromptDefaultYes (66-66)
internal/settings/completion.go (1)
internal/settings/settings.go (1)
  • AvailableConfirmationPromptSettings (70-74)
internal/settings/settings.go (1)
internal/settings/errors.go (1)
  • SettingsError (7-10)
cmd/generation/delete/delete.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build/Test
🔇 Additional comments (9)
cmd/generation/delete/delete.go (1)

168-181: LGTM! Confirmation flow correctly implements the new behavior.

The gating logic properly checks both the command-line flag (--yes) and the configuration setting (confirmation.always), ensuring the prompt is skipped when either is enabled. The call to ConfirmationInput correctly passes the configured behaviors for invalid and empty input.

cmd/generation/switch/switch.go (1)

146-161: LGTM! Confirmation implementation is consistent across commands.

The activation confirmation follows the same pattern as other commands in this PR, with proper gating logic and configured prompt behaviors.

internal/settings/completion.go (2)

191-208: LGTM! Clean refactoring for extensible completion support.

The introduction of stringCompletionFunc as a generic helper reduces code duplication and makes it easy to add completion support for new enum-like settings.


210-218: LGTM! Completion wiring for new confirmation settings.

The mapping correctly connects the new confirmation.empty and confirmation.invalid settings to their completion function, providing users with valid values when using shell completion.

internal/cmd/utils/confirmation.go (1)

18-70: LGTM! Both previous issues have been resolved.

The implementation correctly addresses the concerns raised in earlier reviews:

  1. Fixed: Line 31 now trims and lowercases input before checking if it's empty (line 33), preventing the potential panic when accessing input[0] on whitespace-only input.

  2. Fixed: Line 67 now correctly references opts.InvalidBehavior in the error message (previously incorrectly referenced opts.EmptyBehavior).

The scanner-based approach properly supports re-prompting, and the behavior switches comprehensively handle all configured cases with appropriate user feedback.

internal/settings/settings.go (4)

39-43: LGTM! Well-structured confirmation behavior types.

The ConfirmationPromptBehavior type with its constants and UnmarshalText validation method follows Go best practices for enum-like types. The implementation correctly validates input and provides clear error messages for invalid values.

Also applies to: 62-85


212-216: LGTM! Sensible default confirmation behaviors.

The defaults are well-chosen:

  • Always: false enables prompts by default
  • Invalid: Retry is safer than auto-defaulting on invalid input
  • Empty: DefaultNo provides conservative behavior, preserving the previous default

292-298: LGTM! Excellent deprecation path for no_confirm.

The validation logic properly handles the deprecated setting by:

  • Warning users with a clear deprecation message and migration hint
  • Automatically translating no_confirm to confirmation.always to preserve existing behavior
  • Allowing configurations to continue working while encouraging migration

326-326: The project's minimum Go version is 1.25, which fully supports reflect.Pointer.

The change from reflect.Ptr to reflect.Pointer is compatible. Go 1.25 (specified in go.mod) exceeds the Go 1.18 minimum requirement where reflect.Pointer was introduced. The old reflect.Ptr name remains as a deprecated alias, but using the new name is the recommended approach for forward compatibility.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
internal/system/ssh.go (1)

213-219: Use the defined constant for consistency.

The hard-coded "retry" string literals work correctly since ConfirmationPromptBehavior is a string type, but using the settings.ConfirmationPromptRetry constant would be more type-safe and maintainable. If the constant value ever changes, this code would silently diverge.

 				confirm, err := cmdUtils.ConfirmationInput("Are you sure you want to continue connecting?", cmdUtils.ConfirmationPromptOptions{
 					// Copy the default SSH behavior of retrying for invalid input.
 					// Disregard user configuration in this case, since this is mimicking
 					// OpenSSH's behavior.
-					InvalidBehavior: "retry",
-					EmptyBehavior:   "retry",
+					InvalidBehavior: settings.ConfirmationPromptRetry,
+					EmptyBehavior:   settings.ConfirmationPromptRetry,
 				})

Note: This requires importing settings if not already imported via the cmdUtils path.

internal/settings/completion.go (1)

211-218: Consider extracting a shared completion function.

The two anonymous functions for "confirmation.empty" and "confirmation.invalid" are identical. While this is fine for just two entries, you could reduce duplication with a helper:

+func confirmationPromptCompletionFunc(key, candidate string) ([]string, cobra.ShellCompDirective) {
+	return stringCompletionFunc(key, candidate, AvailableConfirmationPromptSettings)
+}
+
 var completionValueFuncs = map[string]CompletionValueFunc{
-	"confirmation.empty": func(key, candidate string) ([]string, cobra.ShellCompDirective) {
-		return stringCompletionFunc(key, candidate, AvailableConfirmationPromptSettings)
-	},
-	"confirmation.invalid": func(key, candidate string) ([]string, cobra.ShellCompDirective) {
-		return stringCompletionFunc(key, candidate, AvailableConfirmationPromptSettings)
-	},
+	"confirmation.empty":   confirmationPromptCompletionFunc,
+	"confirmation.invalid": confirmationPromptCompletionFunc,
 }
internal/cmd/utils/confirmation.go (1)

43-43: Consider returning an error instead of panicking for unhandled enum values.

While panic is acceptable for exhaustive enum handling, returning an error would be more robust if configuration values are corrupted or if there's a version mismatch between the settings and this code.

Example refactor for line 43:

 		default:
-			panic("unhandled case " + opts.EmptyBehavior)
+			return false, fmt.Errorf("unhandled EmptyBehavior case: %s", opts.EmptyBehavior)

Apply a similar pattern for line 67.

Also applies to: 67-67

internal/settings/settings.go (1)

326-331: Defensive pointer handling added to reflection logic.

This enhancement handles pointer fields in the settings traversal. While no pointer fields are currently present in the Settings struct, this defensive programming improves robustness for future changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c764622 and 9051058.

📒 Files selected for processing (9)
  • cmd/apply/apply.go (1 hunks)
  • cmd/generation/delete/delete.go (1 hunks)
  • cmd/generation/rollback/rollback.go (1 hunks)
  • cmd/generation/switch/switch.go (1 hunks)
  • cmd/root/root.go (1 hunks)
  • internal/cmd/utils/confirmation.go (1 hunks)
  • internal/settings/completion.go (2 hunks)
  • internal/settings/settings.go (10 hunks)
  • internal/system/ssh.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
internal/system/ssh.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
cmd/generation/delete/delete.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
internal/settings/completion.go (1)
internal/settings/settings.go (1)
  • AvailableConfirmationPromptSettings (70-74)
cmd/generation/rollback/rollback.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
cmd/generation/switch/switch.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
internal/cmd/utils/confirmation.go (1)
internal/settings/settings.go (4)
  • ConfirmationPromptBehavior (62-62)
  • ConfirmationPromptRetry (65-65)
  • ConfirmationPromptDefaultNo (67-67)
  • ConfirmationPromptDefaultYes (66-66)
cmd/apply/apply.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
internal/settings/settings.go (1)
internal/settings/errors.go (1)
  • SettingsError (7-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build/Test
🔇 Additional comments (13)
cmd/root/root.go (1)

167-168: LGTM!

Enabling cobra.EnableTraverseRunHooks ensures that PersistentPreRunE hooks execute for all subcommands, which is necessary for the confirmation settings to be properly loaded and validated before commands like apply, delete, rollback, and switch run.

cmd/generation/delete/delete.go (1)

168-181: LGTM!

The confirmation logic correctly combines the --yes flag (AlwaysConfirm) with the new cfg.Confirmation.Always setting, and properly passes the configured Invalid and Empty behaviors to the prompt. Error handling is appropriately maintained.

cmd/apply/apply.go (1)

504-519: LGTM!

The confirmation logic correctly integrates the new configuration-driven prompt behavior. Note that on confirmation denial, this command returns an error (line 517), while delete.go returns nil. This appears intentional since apply treats denial as an error state (skipping activation is considered a failure), whereas delete treats it as a graceful exit. The pattern is consistent with the command semantics.

cmd/generation/switch/switch.go (1)

146-161: LGTM!

The confirmation logic is consistent with the pattern used in apply.go and rollback.go. The prompt options are correctly sourced from configuration, and the error handling on confirmation denial matches other activation commands.

cmd/generation/rollback/rollback.go (1)

94-109: LGTM!

The confirmation flow correctly integrates with the new configuration-driven prompt system, maintaining consistency with other activation commands (apply, switch).

internal/settings/completion.go (1)

190-208: LGTM!

Good refactoring to extract stringCompletionFunc as a reusable helper. The boolCompletionFunc delegation keeps the code DRY.

internal/cmd/utils/confirmation.go (1)

13-16: LGTM!

The struct definition is clear and appropriately uses the ConfirmationPromptBehavior type from the settings package.

internal/settings/settings.go (6)

39-74: LGTM!

The new confirmation settings types and constants are well-designed and follow Go conventions. The string-based enum pattern with descriptive mappings is idiomatic and clear.


76-85: LGTM!

The UnmarshalText implementation correctly validates configuration values at parse time, preventing invalid enum values from reaching the runtime code.


99-100: LGTM!

The documentation entries are comprehensive and clearly explain the new settings. The deprecation notice for no_confirm appropriately guides users to the new confirmation.always setting.

Also applies to: 144-158, 177-181


212-216: LGTM!

The default values are sensible and align with the PR objectives. Defaulting Empty to DefaultNo preserves the previous behavior, and defaulting Invalid to Retry ensures users provide valid input.


292-298: LGTM!

The deprecation handling for NoConfirm is well-implemented. It warns users while automatically migrating to the new setting, ensuring backward compatibility.


379-384: LGTM!

The bolded helper is simple and appropriate for its current use in static documentation strings. The warning about lack of escaping is appropriately documented.

@water-sucks water-sucks force-pushed the improve-confirmation-input-dialog branch from 9051058 to 34a1302 Compare November 26, 2025 13:23
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/cmd/utils/confirmation.go (1)

25-29: Consider checking Scan() return value for EOF detection.

When stdin is closed or EOF is reached, scanner.Scan() returns false without setting an error. Currently, this results in an infinite loop with empty input being processed repeatedly. Consider checking the return value to handle EOF gracefully.

-		_ = scanner.Scan()
-		input = scanner.Text()
-		if err := scanner.Err(); err != nil {
-			return false, err
-		}
+		if !scanner.Scan() {
+			if err := scanner.Err(); err != nil {
+				return false, err
+			}
+			// EOF reached - treat as empty input
+			input = ""
+		} else {
+			input = scanner.Text()
+		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9051058 and 34a1302.

📒 Files selected for processing (9)
  • cmd/apply/apply.go (1 hunks)
  • cmd/generation/delete/delete.go (1 hunks)
  • cmd/generation/rollback/rollback.go (1 hunks)
  • cmd/generation/switch/switch.go (1 hunks)
  • cmd/root/root.go (1 hunks)
  • internal/cmd/utils/confirmation.go (1 hunks)
  • internal/settings/completion.go (1 hunks)
  • internal/settings/settings.go (10 hunks)
  • internal/system/ssh.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • cmd/root/root.go
  • cmd/generation/delete/delete.go
  • internal/system/ssh.go
  • internal/settings/completion.go
  • cmd/generation/rollback/rollback.go
  • cmd/apply/apply.go
🧰 Additional context used
🧬 Code graph analysis (3)
cmd/generation/switch/switch.go (1)
internal/cmd/utils/confirmation.go (2)
  • ConfirmationInput (18-70)
  • ConfirmationPromptOptions (13-16)
internal/cmd/utils/confirmation.go (1)
internal/settings/settings.go (4)
  • ConfirmationPromptBehavior (62-62)
  • ConfirmationPromptRetry (65-65)
  • ConfirmationPromptDefaultNo (67-67)
  • ConfirmationPromptDefaultYes (66-66)
internal/settings/settings.go (1)
internal/settings/errors.go (1)
  • SettingsError (7-10)
🔇 Additional comments (5)
internal/cmd/utils/confirmation.go (1)

31-47: Previous concern addressed: whitespace input no longer causes panic.

The input is now trimmed before the empty check on line 33, which correctly handles whitespace-only input. This resolves the previously identified issue.

cmd/generation/switch/switch.go (1)

146-161: LGTM!

The confirmation logic correctly respects both the CLI flag (--yes) and the configuration setting (cfg.Confirmation.Always). The ConfirmationPromptOptions are properly populated from configuration.

internal/settings/settings.go (3)

292-298: Good deprecation handling with automatic migration.

The validation correctly warns about the deprecated no_confirm setting and automatically migrates its effect to cfg.Confirmation.Always = true. This maintains backward compatibility while guiding users to the new setting.


212-216: Default values are sensible and backward-compatible.

The defaults (Always: false, Invalid: retry, Empty: default-no) preserve the previous behavior where empty input defaulted to "no" while introducing the more user-friendly retry behavior for invalid input.


62-68: Given that I cannot access the repository directly to verify the concern, I'll provide a rewritten review comment based on the technical analysis of what was provided:

SetValue may not correctly validate ConfirmationPromptBehavior fields if used.

The ConfirmationPromptBehavior type is based on string, and while SetValue correctly identifies it via reflect.Kind() returning reflect.String, calling current.SetString(value) bypasses the UnmarshalText validation. This would allow invalid values like "foo" to be set directly.

If SetValue is used for Confirmation.Invalid or Confirmation.Empty fields, consider adding validation:

 			case reflect.String:
+				// Validate ConfirmationPromptBehavior values
+				if current.Type().Name() == "ConfirmationPromptBehavior" {
+					if _, ok := AvailableConfirmationPromptSettings[value]; !ok {
+						return SettingsError{Field: field, Message: fmt.Sprintf("invalid value '%s' for confirmation behavior", value)}
+					}
+				}
 				current.SetString(value)

@water-sucks water-sucks force-pushed the improve-confirmation-input-dialog branch from 34a1302 to 4c6acac Compare November 26, 2025 13:32
@water-sucks water-sucks merged commit efc9493 into nix-community:main Nov 26, 2025
2 checks passed
@water-sucks water-sucks deleted the improve-confirmation-input-dialog branch November 26, 2025 13:39
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.

1 participant