Prompts
This guide covers prompts. You will learn how to:
- Ask for text, with a default and validation
- Ask for a password
- Offer a list of choices
- Ask for confirmation
- Run Commands with nobody to answer
- Ask follow-up questions only when they help
Overview
A prompt asks a person for something the command line didn't give, such as a title or which database to use. Every prompt is answered by a flag the Command declares, which makes the same answer something you can always pass instead:
- When the command line, or the flag's environment variable, gives the flag, the prompt returns its value without asking.
- When nobody can answer, the prompt returns the flag's default. A required prompt without one fails with an error naming the flag to pass. Nobody can answer in Agent mode, with
--no-interaction, or when stdin or stderr isn't a terminal, as in CI. - Otherwise it asks, and sets the flag to the answer, so the variable bound to the flag holds it.
Prompts take the context Run received, so Ctrl+C ends a prompt and the Command exits with status 130.
Ask for text
c.Input asks for a line of text, answered by the flag you name. The flag's default is the default answer, which the person accepts by pressing Enter:
Flags: func(f *cli.FlagSet) {
f.StringVar(&title, "title", "", "The post's title")
},
Run: func(ctx context.Context, c *cli.Call) (cli.Result, error) {
title, err := c.Input(ctx, "title", "What is the post's title?", cli.Required())
if err != nil {
return nil, err
}
…
},? What is the post's title? Hello, worldValidate answers
cli.Required() refuses an empty answer, and cli.Validate checks each answer with your function. A person sees the error and is asked again; a flag that fails the check is a usage error:
title, err := c.Input(ctx, "title", "What is the post's title?", cli.Required(), cli.Validate(func(s string) error {
if len(s) > 80 {
return errors.New("keep it under 80 characters")
}
return nil
}))The answer is parsed as the flag's type, so a prompt for an int flag refuses an answer that isn't a number, and the variable bound to the flag holds the number.
Ask for a password
c.Password asks for a secret without showing what the person types. Give its flag an environment variable with Env, so scripts pass the secret without putting it on the command line, where other users of the machine can see it:
f.StringVar(&token, "token", "", "The API token")
f.Env("token", "API_TOKEN") token, err := c.Password(ctx, "token", "Your API token?", cli.Required())Errors never include the secret.
Offer choices
c.Select asks the person to choose one of a list, with the arrow keys and Enter. The flag's default is selected first, and a value passed on the command line must be one of the choices:
f.StringVar(&db, "db", "sqlite", "The database") db, err := c.Select(ctx, "db", "Which database?", []string{"sqlite", "postgres", "mysql"})? Which database? (↑/↓ and Enter)
❯ sqlite
postgres
mysqlIn a terminal that can't move the cursor (TERM=dumb), the choices are numbered and the person types a number.
Ask for confirmation
c.Confirm asks a yes or no question, answered by a bool flag. When nobody can answer, it returns the flag's default, which is false unless you declare otherwise, so nothing is confirmed without a person or the flag:
f.BoolVar(&force, "force", false, "Overwrite an existing file") if _, err := os.Stat(path); err == nil {
ok, err := c.Confirm(ctx, "force", "Overwrite "+path+"?")
if err != nil {
return nil, err
}
if !ok {
return nil, &cli.Error{Code: "exists", Message: path + " already exists", Fix: "Pass --force to overwrite it"}
}
}? Overwrite app/controllers/posts.go? (y/N)Run with nobody to answer
In Agent mode, with --no-interaction, or without a terminal, a prompt answers itself from its flag, and a required prompt with no value fails with exit status 2 and the flag to pass:
$ act make:controller posts --no-interaction
Error: --title is required.
No one can answer the prompt "What is the post's title?" here
Fix: Pass --title=<value>Agents get the same error as JSON, with the code missing_flag, and retry with the flag.
Ask follow-up questions only when they help
c.Given() reports whether the person passed any flag, and c.Interactive() whether a person can answer at all. Ask optional follow-up questions only when both say so: someone who passed flags has shown what they want, and a script has nobody to ask:
if !c.Given() && c.Interactive() {
if _, err := c.Confirm(ctx, "resource", "Add the resource actions?"); err != nil {
return nil, err
}
}See also: Flags, Testing Commands, Agent mode