feat: interactive setup wizard for first-run and netssh configure
Release / release (push) Successful in 1m36s
Release / release (push) Successful in 1m36s
- Auto-detects missing config (netbox.url empty) and launches wizard - `netssh configure` re-runs the wizard anytime to change settings - 3-page huh form: NetBox connection, SSH defaults, resolver & cache - Saves to ~/.config/netssh.yaml (permissions 0600) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+36
-7
@@ -16,12 +16,14 @@ import (
|
||||
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/config"
|
||||
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
|
||||
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/resolver"
|
||||
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/setup"
|
||||
internalssh "git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/ssh"
|
||||
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/tui"
|
||||
)
|
||||
|
||||
// managedSubcommands are dispatched to cobra; everything else is treated as SSH wrapper mode.
|
||||
var managedSubcommands = map[string]bool{
|
||||
"configure": true,
|
||||
"search": true,
|
||||
"cache": true,
|
||||
"completion": true,
|
||||
@@ -47,12 +49,28 @@ func main() {
|
||||
runSSHWrapper(args)
|
||||
}
|
||||
|
||||
// runSSHWrapper resolves the target hostname via NetBox and execs the native ssh binary.
|
||||
func runSSHWrapper(args []string) {
|
||||
// loadConfigOrSetup loads the config and runs the setup wizard if NetBox is not configured.
|
||||
func loadConfigOrSetup() *config.Config {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
fatalf("config: %v", err)
|
||||
}
|
||||
if cfg.NetBox.URL == "" {
|
||||
fmt.Fprintln(os.Stderr, "No configuration found. Starting setup…")
|
||||
if err := setup.RunWizard(cfg); err != nil {
|
||||
fatalf("setup: %v", err)
|
||||
}
|
||||
cfg, err = config.Load()
|
||||
if err != nil {
|
||||
fatalf("config: %v", err)
|
||||
}
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
// runSSHWrapper resolves the target hostname via NetBox and execs the native ssh binary.
|
||||
func runSSHWrapper(args []string) {
|
||||
cfg := loadConfigOrSetup()
|
||||
|
||||
parsed := internalssh.Parse(args)
|
||||
if parsed == nil {
|
||||
@@ -127,10 +145,7 @@ func connect(ip string, parsed *internalssh.ParsedArgs, originalArgs []string) {
|
||||
|
||||
// runTUI starts the interactive host search.
|
||||
func runTUI() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
fatalf("config: %v", err)
|
||||
}
|
||||
cfg := loadConfigOrSetup()
|
||||
|
||||
c := cache.New(cfg.Cache.Path, cfg.Cache.TTL)
|
||||
_ = c.Load()
|
||||
@@ -193,10 +208,24 @@ func rootCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
// cobra automatically adds a "completion" subcommand
|
||||
root.AddCommand(searchCmd(), cacheCmd())
|
||||
root.AddCommand(configureCmd(), searchCmd(), cacheCmd())
|
||||
return root
|
||||
}
|
||||
|
||||
func configureCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "configure",
|
||||
Short: "Interactively configure netssh",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, _ := config.Load()
|
||||
if cfg == nil {
|
||||
cfg = &config.Config{}
|
||||
}
|
||||
return setup.RunWizard(cfg)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func searchCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "search <query>",
|
||||
|
||||
Reference in New Issue
Block a user