Skip to content

Commit 7dc9ec8

Browse files
acmoreclaude
andcommitted
feat(cli): add prompt system for interactive init
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 92e44c6 commit 7dc9ec8

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

internal/cli/prompt.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
8+
"github.com/acmore/okdev/internal/config"
9+
)
10+
11+
// InitOverrides holds flag-provided values that skip prompting.
12+
type InitOverrides struct {
13+
Name string
14+
Namespace string
15+
}
16+
17+
// applyOverrides applies non-empty flag values to template vars.
18+
func applyOverrides(vars *config.TemplateVars, o InitOverrides) {
19+
if o.Name != "" {
20+
vars.Name = o.Name
21+
}
22+
if o.Namespace != "" {
23+
vars.Namespace = o.Namespace
24+
}
25+
}
26+
27+
// detectDefaultName returns a sensible default for the environment name
28+
// based on the current directory (git repo basename).
29+
func detectDefaultName() string {
30+
wd, err := os.Getwd()
31+
if err != nil {
32+
return "my-project"
33+
}
34+
return filepath.Base(wd)
35+
}
36+
37+
// promptInteractive runs interactive prompts to fill in template vars.
38+
// Only prompts for values not already set by flags.
39+
// When nonInteractive is true, uses defaults without prompting.
40+
func promptInteractive(vars *config.TemplateVars, nonInteractive bool) error {
41+
if vars.Name == "" {
42+
vars.Name = detectDefaultName()
43+
}
44+
if nonInteractive {
45+
return nil
46+
}
47+
48+
// Interactive prompts using basic fmt.Scanln.
49+
// Each prompt shows the current default and allows the user to accept or override.
50+
var input string
51+
52+
input = promptString("Environment name", vars.Name)
53+
if input != "" {
54+
vars.Name = input
55+
}
56+
57+
input = promptString("Namespace", vars.Namespace)
58+
if input != "" {
59+
vars.Namespace = input
60+
}
61+
62+
input = promptString("Sidecar image", vars.SidecarImage)
63+
if input != "" {
64+
vars.SidecarImage = input
65+
}
66+
67+
input = promptString("Sync local path", vars.SyncLocal)
68+
if input != "" {
69+
vars.SyncLocal = input
70+
}
71+
72+
input = promptString("Sync remote path", vars.SyncRemote)
73+
if input != "" {
74+
vars.SyncRemote = input
75+
}
76+
77+
input = promptString("SSH user", vars.SSHUser)
78+
if input != "" {
79+
vars.SSHUser = input
80+
}
81+
82+
return nil
83+
}
84+
85+
// promptString prints a prompt with a default and reads user input.
86+
// Returns empty string if user accepts default (just presses Enter).
87+
func promptString(label, defaultVal string) string {
88+
fmt.Printf("? %s: (%s) ", label, defaultVal)
89+
var input string
90+
fmt.Scanln(&input)
91+
return input
92+
}

internal/cli/prompt_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package cli
2+
3+
import (
4+
"testing"
5+
6+
"github.com/acmore/okdev/internal/config"
7+
)
8+
9+
func TestApplyFlagOverrides(t *testing.T) {
10+
vars := config.NewTemplateVars()
11+
overrides := InitOverrides{
12+
Name: "my-env",
13+
Namespace: "staging",
14+
}
15+
applyOverrides(vars, overrides)
16+
17+
if vars.Name != "my-env" {
18+
t.Fatalf("expected name my-env, got %q", vars.Name)
19+
}
20+
if vars.Namespace != "staging" {
21+
t.Fatalf("expected namespace staging, got %q", vars.Namespace)
22+
}
23+
}
24+
25+
func TestApplyFlagOverridesEmptyNoChange(t *testing.T) {
26+
vars := config.NewTemplateVars()
27+
vars.Name = "original"
28+
overrides := InitOverrides{}
29+
applyOverrides(vars, overrides)
30+
31+
if vars.Name != "original" {
32+
t.Fatalf("expected name to remain original, got %q", vars.Name)
33+
}
34+
}

0 commit comments

Comments
 (0)