Skip to content

Commit 566d8f9

Browse files
committed
feat: default to no confirmation prompts for CLI commands
The CLI commands all printed confirmation prompts for the various flags they exposed. This commit modifies that logic, so that there is no longer a `-y` flag, but instead a `--confirm` or `-c` flag for each command, and prompts are only displayed if using this flag. In most cases, the derived values are printed even if not prompted for. In call cases where the user is prompted, I have removed the "Verbose" prompt, as that seems less like a configuration option that needs to be confirmed, and more like just a CLI option for the current run which we can just accept as-is. The text for the prompts has also been reduced to one or two words. Also added are some checks around image naming and repositories, short circuiting failures that could occur if these are not specified or are unknown. For example, if a user does `faas init` and then `faas deploy` we don't yet know what the image name should be - one hasn't been built. Fixes: #91 Fixes: #90 Fixes: #89
1 parent 6c16e65 commit 566d8f9

File tree

8 files changed

+151
-81
lines changed

8 files changed

+151
-81
lines changed

client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ func (c *Client) Build(path string) (err error) {
369369
return
370370
}
371371

372-
// Derive Image from the path (preceidence is given to extant config)
372+
// Derive Image from the path (precedence is given to extant config)
373373
if f.Image, err = DerivedImage(path, c.repository); err != nil {
374374
return
375375
}

cmd/build.go

+33-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
46
"github.com/ory/viper"
57
"github.com/spf13/cobra"
68

@@ -11,22 +13,37 @@ import (
1113

1214
func init() {
1315
root.AddCommand(buildCmd)
16+
buildCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options - $FAAS_CONFIRM")
1417
buildCmd.Flags().StringP("image", "i", "", "Optional full image name, in form [registry]/[namespace]/[name]:[tag] for example quay.io/myrepo/project.name:latest (overrides --repository) - $FAAS_IMAGE")
1518
buildCmd.Flags().StringP("path", "p", cwd(), "Path to the Function project directory - $FAAS_PATH")
1619
buildCmd.Flags().StringP("repository", "r", "", "Repository for built images, ex 'docker.io/myuser' or just 'myuser'. Optional if --image provided. - $FAAS_REPOSITORY")
17-
buildCmd.Flags().BoolP("yes", "y", false, "When in interactive mode (attached to a TTY) skip prompts. - $FAAS_YES")
1820
}
1921

2022
var buildCmd = &cobra.Command{
2123
Use: "build [options]",
2224
Short: "Build an existing Function project as an OCI image",
2325
SuggestFor: []string{"biuld", "buidl", "built"},
24-
PreRunE: bindEnv("image", "path", "repository", "yes"),
26+
PreRunE: bindEnv("image", "path", "repository", "confirm"),
2527
RunE: runBuild,
2628
}
2729

2830
func runBuild(cmd *cobra.Command, _ []string) (err error) {
29-
config := newBuildConfig().Prompt()
31+
config := newBuildConfig()
32+
function, err := functionWithOverrides(config.Path, "", config.Image)
33+
if err != nil {
34+
return
35+
}
36+
37+
// If the Function does not yet have an image name, and one was not provided
38+
// on the command line AND a --repository was not provided, then we need to
39+
// prompt for a repository from which we can derive an image name.
40+
if function.Image == "" && config.Repository == "" {
41+
fmt.Print("A repository for Function images is required. For example, 'docker.io/tigerteam'.\n\n")
42+
config.Repository = prompt.ForString("Repository for Function images", "")
43+
if config.Repository == "" {
44+
return fmt.Errorf("Unable to determine Function image name")
45+
}
46+
}
3047

3148
builder := buildpacks.NewBuilder()
3249
builder.Verbose = config.Verbose
@@ -36,10 +53,7 @@ func runBuild(cmd *cobra.Command, _ []string) (err error) {
3653
faas.WithRepository(config.Repository), // for deriving image name when --image not provided explicitly.
3754
faas.WithBuilder(builder))
3855

39-
// overrideImage name for built images, if --image provided.
40-
if err = overrideImage(config.Path, config.Image); err != nil {
41-
return
42-
}
56+
config.Prompt()
4357

4458
return client.Build(config.Path)
4559
}
@@ -65,9 +79,9 @@ type buildConfig struct {
6579
// Verbose logging.
6680
Verbose bool
6781

68-
// Yes: agree to values arrived upon from environment plus flags plus defaults,
69-
// and skip the interactive prompting (only applicable when attached to a TTY).
70-
Yes bool
82+
// Confirm: confirm values arrived upon from environment plus flags plus defaults,
83+
// with interactive prompting (only applicable when attached to a TTY).
84+
Confirm bool
7185
}
7286

7387
func newBuildConfig() buildConfig {
@@ -76,21 +90,24 @@ func newBuildConfig() buildConfig {
7690
Path: viper.GetString("path"),
7791
Repository: viper.GetString("repository"),
7892
Verbose: viper.GetBool("verbose"), // defined on root
79-
Yes: viper.GetBool("yes"),
93+
Confirm: viper.GetBool("confirm"),
8094
}
8195
}
8296

8397
// Prompt the user with value of config members, allowing for interaractive changes.
84-
// Skipped if not in an interactive terminal (non-TTY), or if --yes (agree to
85-
// all prompts) was explicitly set.
98+
// Skipped if not in an interactive terminal (non-TTY), or if --confirm false (agree to
99+
// all prompts) was set (default).
86100
func (c buildConfig) Prompt() buildConfig {
87-
if !interactiveTerminal() || c.Yes {
101+
imageName := deriveImage(c.Image, c.Repository, c.Path)
102+
if !interactiveTerminal() || !c.Confirm {
103+
// If --confirm false or non-interactive, just print the image name
104+
fmt.Printf("Building image: %v\n", imageName)
88105
return c
89106
}
90107
return buildConfig{
91108
Path: prompt.ForString("Path to project directory", c.Path),
92-
Image: prompt.ForString("Resulting image name", deriveImage(c.Image, c.Repository, c.Path), prompt.WithRequired(true)),
93-
Verbose: prompt.ForBool("Verbose logging", c.Verbose),
109+
Image: prompt.ForString("Image name", imageName, prompt.WithRequired(true)),
110+
Verbose: c.Verbose,
94111
// Repository not prompted for as it would be confusing when combined with explicit image. Instead it is
95112
// inferred by the derived default for Image, which uses Repository for derivation.
96113
}

cmd/create.go

+33-16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"path/filepath"
66

7+
"github.com/ory/viper"
78
"github.com/spf13/cobra"
89

910
"github.com/boson-project/faas"
@@ -16,14 +17,14 @@ import (
1617

1718
func init() {
1819
root.AddCommand(createCmd)
20+
createCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options - $FAAS_CONFIRM")
1921
createCmd.Flags().StringP("image", "i", "", "Optional full image name, in form [registry]/[namespace]/[name]:[tag] for example quay.io/myrepo/project.name:latest (overrides --repository) - $FAAS_IMAGE")
2022
createCmd.Flags().StringP("namespace", "n", "", "Override namespace into which the Function is deployed (on supported platforms). Default is to use currently active underlying platform setting - $FAAS_NAMESPACE")
2123
createCmd.Flags().StringP("path", "p", cwd(), "Path to the new project directory - $FAAS_PATH")
2224
createCmd.Flags().StringP("repository", "r", "", "Repository for built images, ex 'docker.io/myuser' or just 'myuser'. Optional if --image provided. - $FAAS_REPOSITORY")
2325
createCmd.Flags().StringP("runtime", "l", faas.DefaultRuntime, "Function runtime language/framework. - $FAAS_RUNTIME")
2426
createCmd.Flags().StringP("templates", "", filepath.Join(configPath(), "faas", "templates"), "Extensible templates path. - $FAAS_TEMPLATES")
2527
createCmd.Flags().StringP("trigger", "t", faas.DefaultTrigger, "Function trigger (ex: 'http','events') - $FAAS_TRIGGER")
26-
createCmd.Flags().BoolP("yes", "y", false, "When in interactive mode (attached to a TTY) skip prompts. - $FAAS_YES")
2728

2829
var err error
2930
err = createCmd.RegisterFlagCompletionFunc("image", CompleteRegistryList)
@@ -40,7 +41,7 @@ var createCmd = &cobra.Command{
4041
Use: "create <name> [options]",
4142
Short: "Create a new Function, including initialization of local files and deployment.",
4243
SuggestFor: []string{"cerate", "new"},
43-
PreRunE: bindEnv("image", "namespace", "path", "repository", "runtime", "templates", "trigger", "yes"),
44+
PreRunE: bindEnv("image", "namespace", "path", "repository", "runtime", "templates", "trigger", "confirm"),
4445
RunE: runCreate,
4546
}
4647

@@ -55,20 +56,31 @@ func runCreate(cmd *cobra.Command, args []string) (err error) {
5556
Image: config.Image,
5657
}
5758

59+
if function.Image == "" && config.Repository == "" {
60+
fmt.Print("A repository for Function images is required. For example, 'docker.io/tigerteam'.\n\n")
61+
config.Repository = prompt.ForString("Repository for Function images", "")
62+
if config.Repository == "" {
63+
return fmt.Errorf("Unable to determine Function image name")
64+
}
65+
}
66+
67+
// Defined in root command
68+
verbose := viper.GetBool("verbose")
69+
5870
builder := buildpacks.NewBuilder()
59-
builder.Verbose = config.initConfig.Verbose
71+
builder.Verbose = verbose
6072

6173
pusher := docker.NewPusher()
62-
pusher.Verbose = config.initConfig.Verbose
74+
pusher.Verbose = verbose
6375

6476
deployer := knative.NewDeployer()
65-
deployer.Verbose = config.initConfig.Verbose
77+
deployer.Verbose = verbose
6678

6779
listener := progress.New()
68-
listener.Verbose = config.initConfig.Verbose
80+
listener.Verbose = verbose
6981

7082
client := faas.New(
71-
faas.WithVerbose(config.initConfig.Verbose),
83+
faas.WithVerbose(verbose),
7284
faas.WithTemplates(config.Templates),
7385
faas.WithRepository(config.Repository), // for deriving image name when --image not provided explicitly.
7486
faas.WithBuilder(builder),
@@ -95,20 +107,25 @@ func newCreateConfig(args []string) createConfig {
95107
}
96108

97109
// Prompt the user with value of config members, allowing for interaractive changes.
98-
// Skipped if not in an interactive terminal (non-TTY), or if --yes (agree to
99-
// all prompts) was explicitly set.
110+
// Skipped if not in an interactive terminal (non-TTY), or if --confirm (agree to
111+
// all prompts) was not explicitly set.
100112
func (c createConfig) Prompt() createConfig {
101-
if !interactiveTerminal() || c.initConfig.Yes {
113+
name := deriveName(c.Name, c.initConfig.Path)
114+
if !interactiveTerminal() || !c.initConfig.Confirm {
115+
// Just print the basics if not confirming
116+
fmt.Printf("Project path: %v\n", c.initConfig.Path)
117+
fmt.Printf("Project name: %v\n", name)
118+
fmt.Printf("Runtime: %v\n", c.Runtime)
119+
fmt.Printf("Trigger: %v\n", c.Trigger)
102120
return c
103121
}
104122
return createConfig{
105123
initConfig: initConfig{
106-
Path: prompt.ForString("Path to project directory", c.initConfig.Path),
107-
Name: prompt.ForString("Function project name", deriveName(c.Name, c.initConfig.Path), prompt.WithRequired(true)),
108-
Verbose: prompt.ForBool("Verbose logging", c.initConfig.Verbose),
109-
Runtime: prompt.ForString("Runtime of source", c.Runtime),
110-
Trigger: prompt.ForString("Function Trigger", c.Trigger),
111-
// Templates intentiopnally omitted from prompt for being an edge case.
124+
Path: prompt.ForString("Project path", c.initConfig.Path),
125+
Name: prompt.ForString("Project name", name, prompt.WithRequired(true)),
126+
Runtime: prompt.ForString("Runtime", c.Runtime),
127+
Trigger: prompt.ForString("Trigger", c.Trigger),
128+
// Templates intentionally omitted from prompt for being an edge case.
112129
},
113130
buildConfig: buildConfig{
114131
Repository: prompt.ForString("Repository for Function images", c.buildConfig.Repository),

cmd/delete.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import (
1111

1212
func init() {
1313
root.AddCommand(deleteCmd)
14+
deleteCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options - $FAAS_CONFIRM")
1415
deleteCmd.Flags().StringP("path", "p", cwd(), "Path to the project which should be deleted - $FAAS_PATH")
1516
deleteCmd.Flags().StringP("namespace", "n", "", "Override namespace in which to search for Functions. Default is to use currently active underlying platform setting - $FAAS_NAMESPACE")
16-
deleteCmd.Flags().BoolP("yes", "y", false, "When in interactive mode (attached to a TTY), skip prompting the user. - $FAAS_YES")
1717
}
1818

1919
var deleteCmd = &cobra.Command{
@@ -22,7 +22,7 @@ var deleteCmd = &cobra.Command{
2222
Long: `Removes the deployed Function by name, by explicit path, or by default for the current directory. No local files are deleted.`,
2323
SuggestFor: []string{"remove", "rm", "del"},
2424
ValidArgsFunction: CompleteFunctionList,
25-
PreRunE: bindEnv("path", "yes", "namespace"),
25+
PreRunE: bindEnv("path", "confirm", "namespace"),
2626
RunE: runDelete,
2727
}
2828

@@ -46,7 +46,6 @@ type deleteConfig struct {
4646
Namespace string
4747
Path string
4848
Verbose bool
49-
Yes bool
5049
}
5150

5251
// newDeleteConfig returns a config populated from the current execution context
@@ -61,15 +60,14 @@ func newDeleteConfig(args []string) deleteConfig {
6160
Namespace: viper.GetString("namespace"),
6261
Name: deriveName(name, viper.GetString("path")), // args[0] or derived
6362
Verbose: viper.GetBool("verbose"), // defined on root
64-
Yes: viper.GetBool("yes"),
6563
}
6664
}
6765

6866
// Prompt the user with value of config members, allowing for interaractive changes.
6967
// Skipped if not in an interactive terminal (non-TTY), or if --yes (agree to
7068
// all prompts) was explicitly set.
7169
func (c deleteConfig) Prompt() deleteConfig {
72-
if !interactiveTerminal() || c.Yes {
70+
if !interactiveTerminal() || !viper.GetBool("confirm") {
7371
return c
7472
}
7573
return deleteConfig{

cmd/deploy.go

+23-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
46
"github.com/ory/viper"
57
"github.com/spf13/cobra"
68

@@ -12,21 +14,31 @@ import (
1214

1315
func init() {
1416
root.AddCommand(deployCmd)
17+
deployCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options - $FAAS_CONFIRM")
1518
deployCmd.Flags().StringP("namespace", "n", "", "Override namespace into which the Function is deployed (on supported platforms). Default is to use currently active underlying platform setting - $FAAS_NAMESPACE")
1619
deployCmd.Flags().StringP("path", "p", cwd(), "Path to the function project directory - $FAAS_PATH")
17-
deployCmd.Flags().BoolP("yes", "y", false, "When in interactive mode (attached to a TTY) skip prompts. - $FAAS_YES")
1820
}
1921

2022
var deployCmd = &cobra.Command{
2123
Use: "deploy",
2224
Short: "Deploy an existing Function project to a cluster",
2325
SuggestFor: []string{"delpoy", "deplyo"},
24-
PreRunE: bindEnv("namespace", "path", "yes"),
26+
PreRunE: bindEnv("namespace", "path", "confirm"),
2527
RunE: runDeploy,
2628
}
2729

2830
func runDeploy(cmd *cobra.Command, _ []string) (err error) {
29-
config := newDeployConfig().Prompt()
31+
config := newDeployConfig()
32+
function, err := functionWithOverrides(config.Path, config.Namespace, "")
33+
if err != nil {
34+
return err
35+
}
36+
if function.Image == "" {
37+
return fmt.Errorf("Cannot determine the Function image name. Have you built it yet?")
38+
}
39+
40+
// Confirm or print configuration
41+
config.Prompt()
3042

3143
pusher := docker.NewPusher()
3244
pusher.Verbose = config.Verbose
@@ -39,11 +51,6 @@ func runDeploy(cmd *cobra.Command, _ []string) (err error) {
3951
faas.WithPusher(pusher),
4052
faas.WithDeployer(deployer))
4153

42-
// overrieNamespace into which the function is deployed, if --namespace provided.
43-
if err = overrideNamespace(config.Path, config.Namespace); err != nil {
44-
return
45-
}
46-
4754
return client.Deploy(config.Path)
4855

4956
// NOTE: Namespace is optional, default is that used by k8s client
@@ -66,9 +73,9 @@ type deployConfig struct {
6673
// Verbose logging.
6774
Verbose bool
6875

69-
// Yes: agree to values arrived upon from environment plus flags plus defaults,
70-
// and skip the interactive prompting (only applicable when attached to a TTY).
71-
Yes bool
76+
// Confirm: confirm values arrived upon from environment plus flags plus defaults,
77+
// with interactive prompting (only applicable when attached to a TTY).
78+
Confirm bool
7279
}
7380

7481
// newDeployConfig creates a buildConfig populated from command flags and
@@ -78,20 +85,20 @@ func newDeployConfig() deployConfig {
7885
Namespace: viper.GetString("namespace"),
7986
Path: viper.GetString("path"),
8087
Verbose: viper.GetBool("verbose"), // defined on root
81-
Yes: viper.GetBool("yes"),
88+
Confirm: viper.GetBool("confirm"),
8289
}
8390
}
8491

8592
// Prompt the user with value of config members, allowing for interaractive changes.
8693
// Skipped if not in an interactive terminal (non-TTY), or if --yes (agree to
8794
// all prompts) was explicitly set.
8895
func (c deployConfig) Prompt() deployConfig {
89-
if !interactiveTerminal() || c.Yes {
96+
if !interactiveTerminal() || !c.Confirm {
9097
return c
9198
}
9299
return deployConfig{
93-
Namespace: prompt.ForString("Override default namespace (optional)", c.Namespace),
94-
Path: prompt.ForString("Path to project directory", c.Path),
95-
Verbose: prompt.ForBool("Verbose logging", c.Verbose),
100+
Namespace: prompt.ForString("Namespace", c.Namespace),
101+
Path: prompt.ForString("Project path", c.Path),
102+
Verbose: c.Verbose,
96103
}
97104
}

0 commit comments

Comments
 (0)