Skip to content

Commit 966ea89

Browse files
committed
feat: add cli prompts
1 parent cb1dde5 commit 966ea89

File tree

2 files changed

+98
-52
lines changed

2 files changed

+98
-52
lines changed

cmd/create.go

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ package cmd
22

33
import (
44
"fmt"
5-
"regexp"
65

7-
"github.com/AlecAivazis/survey/v2"
6+
"github.com/onkernel/cli/pkg/create"
87
"github.com/spf13/cobra"
98
)
109

@@ -21,68 +20,28 @@ func init() {
2120
createCmd.Flags().String("template", "", "Template to use for the application")
2221
}
2322

24-
const defaultAppName = "my-kernel-app"
25-
26-
// projectNameValidator ensures the project name is safe for file systems and package managers.
27-
func projectNameValidator(val any) error {
28-
str, ok := val.(string)
29-
if !ok {
30-
return fmt.Errorf("invalid input type")
31-
}
32-
33-
// Project name must be non-empty
34-
if len(str) == 0 {
35-
return fmt.Errorf("project name cannot be empty")
36-
}
23+
func runCreateApp(cmd *cobra.Command, args []string) error {
24+
appName, _ := cmd.Flags().GetString("name")
25+
language, _ := cmd.Flags().GetString("language")
26+
template, _ := cmd.Flags().GetString("template")
3727

38-
// Validate project name: only letters, numbers, underscores, and hyphens
39-
// This regex prevents special characters that might break shell commands or filesystem paths.
40-
matched, err := regexp.MatchString(`^[A-Za-z\-_\d]+$`, str)
28+
appName, err := create.PromptForAppName(appName)
4129
if err != nil {
42-
return err
43-
}
44-
if !matched {
45-
return fmt.Errorf("project name may only include letters, numbers, underscores, and hyphens")
46-
}
47-
return nil
48-
}
49-
50-
// promptForAppName prompts the user for the application name if not provided
51-
func promptForAppName(providedAppName string) (string, error) {
52-
if providedAppName != "" {
53-
return providedAppName, nil
54-
}
55-
56-
var appName string
57-
prompt := &survey.Input{
58-
Message: "What is the name of your project?",
59-
Default: defaultAppName,
30+
return fmt.Errorf("failed to get app name: %w", err)
6031
}
6132

62-
err := survey.AskOne(prompt, &appName, survey.WithValidator(projectNameValidator))
33+
language, err = create.PromptForLanguage(language)
6334
if err != nil {
64-
return "", err
35+
return fmt.Errorf("failed to get language: %w", err)
6536
}
6637

67-
return appName, nil
68-
}
69-
70-
func runCreateApp(cmd *cobra.Command, args []string) error {
71-
providedAppName, _ := cmd.Flags().GetString("name")
72-
language, _ := cmd.Flags().GetString("language")
73-
template, _ := cmd.Flags().GetString("template")
74-
75-
// Prompt for app name if not provided
76-
appName, err := promptForAppName(providedAppName)
38+
template, err = create.PromptForTemplate(template)
7739
if err != nil {
78-
return fmt.Errorf("failed to get app name: %w", err)
40+
return fmt.Errorf("failed to get template: %w", err)
7941
}
8042

8143
fmt.Printf("Creating application '%s' with language '%s' and template '%s'...\n", appName, language, template)
8244

83-
// TODO: prompt the user for the language of the app, suggest a default language (typescript)
84-
// TODO: prompt the user for the template of the app, suggest a default template (sample-app)
85-
8645
// TODO: create the project structure
8746

8847
// print "Creating a new TypeScript Sample App" or similar. Essentially the language and template name combined.

pkg/create/prompts.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package create
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
7+
"github.com/AlecAivazis/survey/v2"
8+
)
9+
10+
const defaultAppName = "my-kernel-app"
11+
12+
// projectNameValidator ensures the project name is safe for file systems and package managers.
13+
func projectNameValidator(val any) error {
14+
str, ok := val.(string)
15+
if !ok {
16+
return fmt.Errorf("invalid input type")
17+
}
18+
19+
// Project name must be non-empty
20+
if len(str) == 0 {
21+
return fmt.Errorf("project name cannot be empty")
22+
}
23+
24+
// Validate project name: only letters, numbers, underscores, and hyphens
25+
// This regex prevents special characters that might break shell commands or filesystem paths.
26+
matched, err := regexp.MatchString(`^[A-Za-z\-_\d]+$`, str)
27+
if err != nil {
28+
return err
29+
}
30+
if !matched {
31+
return fmt.Errorf("project name may only include letters, numbers, underscores, and hyphens")
32+
}
33+
return nil
34+
}
35+
36+
// PromptForAppName prompts the user for the application name if not provided
37+
func PromptForAppName(providedAppName string) (string, error) {
38+
if providedAppName != "" {
39+
return providedAppName, nil
40+
}
41+
42+
var appName string
43+
prompt := &survey.Input{
44+
Message: "What is the name of your project?",
45+
Default: defaultAppName,
46+
}
47+
48+
if err := survey.AskOne(prompt, &appName, survey.WithValidator(projectNameValidator)); err != nil {
49+
return "", err
50+
}
51+
52+
return appName, nil
53+
}
54+
55+
func PromptForLanguage(providedLanguage string) (string, error) {
56+
if providedLanguage != "" {
57+
return providedLanguage, nil
58+
}
59+
var language string
60+
languagePrompt := &survey.Select{
61+
Message: "Choose a programming language:",
62+
// TODO: create constants so that more languages can be added later
63+
Options: []string{"typescript", "python"},
64+
Default: "typescript",
65+
}
66+
if err := survey.AskOne(languagePrompt, &language); err != nil {
67+
return "", err
68+
}
69+
return language, nil
70+
}
71+
72+
func PromptForTemplate(providedTemplate string) (string, error) {
73+
if providedTemplate != "" {
74+
return providedTemplate, nil
75+
}
76+
77+
var template string
78+
templatePrompt := &survey.Select{
79+
Message: "Choose a template:",
80+
Options: []string{"sample-app"},
81+
Default: "sample-app",
82+
}
83+
if err := survey.AskOne(templatePrompt, &template); err != nil {
84+
return "", err
85+
}
86+
return template, nil
87+
}

0 commit comments

Comments
 (0)