mirror of https://github.com/knative/func.git
665 lines
20 KiB
Go
665 lines
20 KiB
Go
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/AlecAivazis/survey/v2"
|
|
"github.com/ory/viper"
|
|
"github.com/spf13/cobra"
|
|
|
|
"knative.dev/func/pkg/config"
|
|
fn "knative.dev/func/pkg/functions"
|
|
)
|
|
|
|
// command constructors
|
|
// --------------------
|
|
|
|
func NewRepositoryCmd(newClient ClientFactory) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Short: "Manage installed template repositories",
|
|
Use: "repository",
|
|
Aliases: []string{"repo", "repositories"},
|
|
Long: `
|
|
NAME
|
|
{{rootCmdUse}} - Manage set of installed repositories.
|
|
|
|
SYNOPSIS
|
|
{{rootCmdUse}} repo [-c|--confirm] [-v|--verbose]
|
|
{{rootCmdUse}} repo list [-r|--repositories] [-c|--confirm] [-v|--verbose]
|
|
{{rootCmdUse}} repo add <name> <url>[-r|--repositories] [-c|--confirm] [-v|--verbose]
|
|
{{rootCmdUse}} repo rename <old> <new> [-r|--repositories] [-c|--confirm] [-v|--verbose]
|
|
{{rootCmdUse}} repo remove <name> [-r|--repositories] [-c|--confirm] [-v|--verbose]
|
|
|
|
DESCRIPTION
|
|
Manage template repositories installed on disk at either the default location
|
|
(~/.config/func/repositories) or the location specified by the --repository
|
|
flag. Once added, a template from the repository can be used when creating
|
|
a new function.
|
|
|
|
Interactive Prompts:
|
|
To complete these commands interactively, pass the --confirm (-c) flag to
|
|
the 'repository' command, or any of the inidivual subcommands.
|
|
|
|
The Default Repository:
|
|
The default repository is not stored on disk, but embedded in the binary and
|
|
can be used without explicitly specifying the name. The default repository
|
|
is always listed first, and is assumed when creating a new function without
|
|
specifying a repository name prefix.
|
|
For example, to create a new Go function using the 'http' template from the
|
|
default repository.
|
|
$ {{rootCmdUse}} create -l go -t http
|
|
|
|
The Repository Flag:
|
|
Installing repositories locally is optional. To use a template from a remote
|
|
repository directly, it is possible to use the --repository flag on create.
|
|
This leaves the local disk untouched. For example, To create a function using
|
|
the Boson Project Hello-World template without installing the template
|
|
repository locally, use the --repository (-r) flag on create:
|
|
$ {{rootCmdUse}} create -l go \
|
|
--template hello-world \
|
|
--repository https://github.com/boson-project/templates
|
|
|
|
Alternative Repositories Location:
|
|
Repositories are stored on disk in ~/.config/func/repositories by default.
|
|
This location can be altered by setting the FUNC_REPOSITORIES_PATH
|
|
environment variable.
|
|
|
|
|
|
COMMANDS
|
|
|
|
With no arguments, this help text is shown. To manage repositories with
|
|
an interactive prompt, use the use the --confirm (-c) flag.
|
|
$ {{rootCmdUse}} repository -c
|
|
|
|
add
|
|
Add a new repository to the installed set.
|
|
$ {{rootCmdUse}} repository add <name> <URL>
|
|
|
|
For Example, to add the Boson Project repository:
|
|
$ {{rootCmdUse}} repository add boson https://github.com/boson-project/templates
|
|
|
|
Once added, a function can be created with templates from the new repository
|
|
by prefixing the template name with the repository. For example, to create
|
|
a new function using the Go Hello World template:
|
|
$ {{rootCmdUse}} create -l go -t boson/hello-world
|
|
|
|
list
|
|
List all available repositories, including the installed default
|
|
repository. Repositories available are listed by name. To see the URL
|
|
which was used to install remotes, use --verbose (-v).
|
|
|
|
rename
|
|
Rename a previously installed repository from <old> to <new>. Only installed
|
|
repositories can be renamed.
|
|
$ {{rootCmdUse}} repository rename <name> <new name>
|
|
|
|
remove
|
|
Remove a repository by name. Removes the repository from local storage
|
|
entirely. When in confirm mode (--confirm) it will confirm before
|
|
deletion, but in regular mode this is done immediately, so please use
|
|
caution, especially when using an altered repositories location
|
|
(via the FUNC_REPOSITORIES_PATH environment variable).
|
|
$ {{rootCmdUse}} repository remove <name>
|
|
|
|
EXAMPLES
|
|
o Run in confirmation mode (interactive prompts) using the --confirm flag
|
|
$ {{rootCmdUse}} repository -c
|
|
|
|
o Add a repository and create a new function using a template from it:
|
|
$ {{rootCmdUse}} repository add functastic https://github.com/knative-extensions/func-tastic
|
|
$ {{rootCmdUse}} repository list
|
|
default
|
|
functastic
|
|
$ {{rootCmdUse}} create -l go -t functastic/hello-world
|
|
...
|
|
|
|
o Add a repository specifying the branch to use (metacontroller):
|
|
$ {{rootCmdUse}} repository add metacontroller https://github.com/knative-extensions/func-tastic#metacontroler
|
|
$ {{rootCmdUse}} repository list
|
|
default
|
|
metacontroller
|
|
$ {{rootCmdUse}} create -l node -t metacontroller/metacontroller
|
|
...
|
|
|
|
o List all repositories including the URL from which remotes were installed
|
|
$ {{rootCmdUse}} repository list -v
|
|
default
|
|
metacontroller https://github.com/knative-extensions/func-tastic#metacontroller
|
|
|
|
o Rename an installed repository
|
|
$ {{rootCmdUse}} repository list
|
|
default
|
|
boson
|
|
$ {{rootCmdUse}} repository rename boson functastic
|
|
$ {{rootCmdUse}} repository list
|
|
default
|
|
functastic
|
|
|
|
o Remove an installed repository
|
|
$ {{rootCmdUse}} repository list
|
|
default
|
|
functastic
|
|
$ {{rootCmdUse}} repository remove functastic
|
|
$ {{rootCmdUse}} repository list
|
|
default
|
|
`,
|
|
SuggestFor: []string{"repositories", "repos", "template", "templates", "pack", "packs"},
|
|
PreRunE: bindEnv("confirm", "verbose"),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runRepository(cmd, args, newClient)
|
|
},
|
|
}
|
|
|
|
cfg, err := config.NewDefault()
|
|
if err != nil {
|
|
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
|
|
}
|
|
addConfirmFlag(cmd, cfg.Confirm)
|
|
addVerboseFlag(cmd, cfg.Verbose)
|
|
|
|
cmd.AddCommand(NewRepositoryListCmd(newClient))
|
|
cmd.AddCommand(NewRepositoryAddCmd(newClient))
|
|
cmd.AddCommand(NewRepositoryRenameCmd(newClient))
|
|
cmd.AddCommand(NewRepositoryRemoveCmd(newClient))
|
|
|
|
return cmd
|
|
}
|
|
|
|
func NewRepositoryListCmd(newClient ClientFactory) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Short: "List repositories",
|
|
Use: "list",
|
|
Aliases: []string{"ls"},
|
|
PreRunE: bindEnv("confirm", "verbose"),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runRepositoryList(cmd, newClient)
|
|
},
|
|
}
|
|
|
|
cfg, err := config.NewDefault()
|
|
if err != nil {
|
|
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
|
|
}
|
|
addConfirmFlag(cmd, cfg.Confirm)
|
|
addVerboseFlag(cmd, cfg.Verbose)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func NewRepositoryAddCmd(newClient ClientFactory) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Short: "Add a repository",
|
|
Use: "add <name> <url>",
|
|
SuggestFor: []string{"ad", "install"},
|
|
PreRunE: bindEnv("confirm", "verbose"),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runRepositoryAdd(cmd, args, newClient)
|
|
},
|
|
}
|
|
|
|
cfg, err := config.NewDefault()
|
|
if err != nil {
|
|
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
|
|
}
|
|
addConfirmFlag(cmd, cfg.Confirm)
|
|
addVerboseFlag(cmd, cfg.Verbose)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func NewRepositoryRenameCmd(newClient ClientFactory) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Short: "Rename a repository",
|
|
Use: "rename <old> <new>",
|
|
Aliases: []string{"mv"},
|
|
PreRunE: bindEnv("confirm", "verbose"),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runRepositoryRename(cmd, args, newClient)
|
|
},
|
|
}
|
|
|
|
cfg, err := config.NewDefault()
|
|
if err != nil {
|
|
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
|
|
}
|
|
addConfirmFlag(cmd, cfg.Confirm)
|
|
addVerboseFlag(cmd, cfg.Verbose)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func NewRepositoryRemoveCmd(newClient ClientFactory) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Short: "Remove a repository",
|
|
Use: "remove <name>",
|
|
Aliases: []string{"rm"},
|
|
SuggestFor: []string{"delete", "del"},
|
|
PreRunE: bindEnv("confirm", "verbose"),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runRepositoryRemove(cmd, args, newClient)
|
|
},
|
|
}
|
|
|
|
cfg, err := config.NewDefault()
|
|
if err != nil {
|
|
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
|
|
}
|
|
addConfirmFlag(cmd, cfg.Confirm)
|
|
addVerboseFlag(cmd, cfg.Verbose)
|
|
|
|
return cmd
|
|
}
|
|
|
|
// command implementations
|
|
// -----------------------
|
|
|
|
// Run
|
|
// (list by default or interactive with -c|--confirm)
|
|
func runRepository(cmd *cobra.Command, args []string, newClient ClientFactory) (err error) {
|
|
cfg, err := newRepositoryConfig()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// If in noninteractive, normal mode the help text is shown
|
|
if !cfg.Confirm {
|
|
return cmd.Help()
|
|
}
|
|
|
|
// If in interactive mode, the user chan choose which subcommand to invoke
|
|
// Prompt for action to perform
|
|
question := &survey.Question{
|
|
Name: "Action",
|
|
Prompt: &survey.Select{
|
|
Message: "Operation to perform:",
|
|
Options: []string{"list", "add", "rename", "remove"},
|
|
Default: "list",
|
|
}}
|
|
answer := struct{ Action string }{}
|
|
if err = survey.Ask([]*survey.Question{question}, &answer); err != nil {
|
|
return
|
|
}
|
|
|
|
// Run the command indicated
|
|
switch answer.Action {
|
|
case "list":
|
|
return runRepositoryList(cmd, newClient)
|
|
case "add":
|
|
return runRepositoryAdd(cmd, args, newClient)
|
|
case "rename":
|
|
return runRepositoryRename(cmd, args, newClient)
|
|
case "remove":
|
|
return runRepositoryRemove(cmd, args, newClient)
|
|
}
|
|
return fmt.Errorf("invalid action '%v'", answer.Action) // Unreachable
|
|
}
|
|
|
|
// List
|
|
func runRepositoryList(_ *cobra.Command, newClient ClientFactory) (err error) {
|
|
cfg, err := newRepositoryConfig()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
client, done := newClient(ClientConfig{Verbose: cfg.Verbose})
|
|
defer done()
|
|
|
|
// List all repositories given a client instantiated about config.
|
|
rr, err := client.Repositories().All()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Print repository names, or name plus url if verbose
|
|
// This follows the format of `git remote`, as it is likely familiar.
|
|
for _, r := range rr {
|
|
if cfg.Verbose {
|
|
fmt.Fprintln(os.Stdout, r.Name+"\t"+r.URL())
|
|
} else {
|
|
fmt.Fprintln(os.Stdout, r.Name)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Add
|
|
func runRepositoryAdd(_ *cobra.Command, args []string, newClient ClientFactory) (err error) {
|
|
// Supports both composable, discrete CLI commands or prompt-based "config"
|
|
// by setting the argument values (name and ulr) to value of positional args,
|
|
// but only requires them if not prompting. If prompting, those values
|
|
// become the prompt defaults.
|
|
|
|
cfg, err := newRepositoryConfig()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Adding a repository requires there be a config path structure on disk
|
|
if err = config.CreatePaths(); err != nil {
|
|
return
|
|
}
|
|
|
|
// Create a client instance which utilizes the given repositories path.
|
|
// Note that this MAY not be in the config structure if the environment
|
|
// variable to override said path was provided explicitly.
|
|
// TODO: rectify this inconsitency: the config default path structure will
|
|
// be created in XDG_CONFIG_HOME/func even if the repo path environment
|
|
// was set to some other location on disk.
|
|
client, done := newClient(ClientConfig{Verbose: cfg.Verbose})
|
|
defer done()
|
|
|
|
// Preconditions
|
|
// If not confirming/prompting, assert the args were both provided.
|
|
if len(args) != 2 && !cfg.Confirm {
|
|
return fmt.Errorf("usage: func repository add <name> <url>")
|
|
}
|
|
|
|
// Extract Params
|
|
// Populate a struct with the arguments (if provided)
|
|
params := struct {
|
|
Name string
|
|
URL string
|
|
}{}
|
|
if len(args) > 0 {
|
|
params.Name = args[0]
|
|
}
|
|
if len(args) > 1 {
|
|
params.URL = args[1]
|
|
}
|
|
|
|
// Prompt/Confirm
|
|
// If confirming/prompting, interactively populate the params from the user
|
|
// (using the current values as defaults)
|
|
//
|
|
// If terminal not interactive, effective values are echoed.
|
|
//
|
|
// Note that empty values can be passed to the final client's Add method if:
|
|
// Argument(s) not provided
|
|
// Confirming (-c|--confirm)
|
|
// Is a noninteractive terminal
|
|
// This is an expected case. The empty value will be echoed to stdout, the
|
|
// API will be invoked, and a helpful error message will indicate that the
|
|
// request is missing required parameters.
|
|
if cfg.Confirm && interactiveTerminal() {
|
|
questions := []*survey.Question{
|
|
{
|
|
Name: "Name",
|
|
Validate: survey.Required,
|
|
Prompt: &survey.Input{
|
|
Message: "Name for the new repository:",
|
|
Default: params.Name,
|
|
},
|
|
}, {
|
|
Name: "URL",
|
|
Validate: survey.Required,
|
|
Prompt: &survey.Input{
|
|
Message: "URL of the new repository:",
|
|
Default: params.URL,
|
|
},
|
|
},
|
|
}
|
|
if err = survey.Ask(questions, ¶ms); err != nil {
|
|
return
|
|
// not checking for terminal.InterruptError because failure to complete,
|
|
// for whatever reason, should exit the program non-zero.
|
|
}
|
|
} else if cfg.Confirm {
|
|
fmt.Fprintf(os.Stdout, "Name: %v\n", params.Name)
|
|
fmt.Fprintf(os.Stdout, "URL: %v\n", params.URL)
|
|
}
|
|
|
|
// Add repository
|
|
var n string
|
|
if n, err = client.Repositories().Add(params.Name, params.URL); err != nil {
|
|
return
|
|
}
|
|
if cfg.Verbose {
|
|
fmt.Fprintf(os.Stdout, "Repository added: %s\n", n)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Rename
|
|
func runRepositoryRename(_ *cobra.Command, args []string, newClient ClientFactory) (err error) {
|
|
cfg, err := newRepositoryConfig()
|
|
if err != nil {
|
|
return
|
|
}
|
|
client, done := newClient(ClientConfig{Verbose: cfg.Verbose})
|
|
defer done()
|
|
|
|
// Preconditions
|
|
if len(args) != 2 && !cfg.Confirm {
|
|
return fmt.Errorf("usage: func repository rename <old> <new>")
|
|
}
|
|
|
|
// Extract Params
|
|
params := struct {
|
|
Old string
|
|
New string
|
|
}{}
|
|
if len(args) > 0 {
|
|
params.Old = args[0]
|
|
}
|
|
if len(args) > 1 {
|
|
params.New = args[1]
|
|
}
|
|
|
|
// Repositories installed according to the client
|
|
// (does not include the builtin default)
|
|
repositories, err := installedRepositories(client)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Confirm (interactive prompt mode)
|
|
if cfg.Confirm && interactiveTerminal() {
|
|
questions := []*survey.Question{
|
|
{
|
|
Name: "Old",
|
|
Validate: survey.Required,
|
|
Prompt: &survey.Select{
|
|
Message: "Repository to rename:",
|
|
Options: repositories,
|
|
},
|
|
}, {
|
|
Name: "New",
|
|
Validate: survey.Required,
|
|
Prompt: &survey.Input{
|
|
Message: "New name:",
|
|
Default: params.New,
|
|
},
|
|
},
|
|
}
|
|
if err = survey.Ask(questions, ¶ms); err != nil {
|
|
return // for any reason, including interrupt, is an nonzero exit
|
|
}
|
|
} else if cfg.Confirm {
|
|
fmt.Fprintf(os.Stdout, "Old: %v\n", params.Old)
|
|
fmt.Fprintf(os.Stdout, "New: %v\n", params.New)
|
|
}
|
|
|
|
// Rename the repository
|
|
if err = client.Repositories().Rename(params.Old, params.New); err != nil {
|
|
return
|
|
}
|
|
if cfg.Verbose {
|
|
fmt.Fprintln(os.Stdout, "Repository renamed")
|
|
}
|
|
return
|
|
}
|
|
|
|
// Remove
|
|
func runRepositoryRemove(_ *cobra.Command, args []string, newClient ClientFactory) (err error) {
|
|
cfg, err := newRepositoryConfig()
|
|
if err != nil {
|
|
return
|
|
}
|
|
client, done := newClient(ClientConfig{Verbose: cfg.Verbose})
|
|
defer done()
|
|
|
|
// Preconditions
|
|
if len(args) != 1 && !cfg.Confirm {
|
|
return fmt.Errorf("usage: func repository remove <name>")
|
|
}
|
|
|
|
// Extract param(s)
|
|
params := struct {
|
|
Name string
|
|
Sure bool
|
|
}{}
|
|
if len(args) > 0 {
|
|
params.Name = args[0]
|
|
}
|
|
// "Are you sure" confirmation flag
|
|
// (not using name 'Confirm' to avoid confustion with cfg.Confirm)
|
|
// defaults to Yes. This is debatable, but I don't want to choose the repo
|
|
// to remove and then have to see a prompt and then have to hit 'y'. Just
|
|
// prompting once to make sure, which requires another press of enter, seems
|
|
// sufficient.
|
|
params.Sure = true
|
|
|
|
// Repositories installed according to the client
|
|
// (does not include the builtin default)
|
|
repositories, err := installedRepositories(client)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if len(repositories) == 0 {
|
|
return errors.New("no repositories installed. use 'add' to install")
|
|
}
|
|
|
|
// Confirm (interactive prompt mode)
|
|
if cfg.Confirm && interactiveTerminal() {
|
|
questions := []*survey.Question{
|
|
{
|
|
Name: "Name",
|
|
Validate: survey.Required,
|
|
Prompt: &survey.Select{
|
|
Message: "Repository to remove:",
|
|
Options: repositories,
|
|
},
|
|
}, {
|
|
Name: "Sure",
|
|
Prompt: &survey.Confirm{
|
|
Message: "This will remove the repository from local disk. Are you sure?",
|
|
Default: params.Sure,
|
|
},
|
|
},
|
|
}
|
|
if err = survey.Ask(questions, ¶ms); err != nil {
|
|
return // for any reason, including interrupt, is a nonzero exit
|
|
}
|
|
} else if cfg.Confirm {
|
|
fmt.Fprintf(os.Stdout, "Repository: %v\n", params.Name)
|
|
}
|
|
|
|
// Cancel if they got cold feet.
|
|
if !params.Sure {
|
|
// While an argument could be made to the contrary, I believe it is
|
|
// important than an abort by the user, either by answering no to the
|
|
// confirmation or by an os interrupt such as ^C be considered an error,
|
|
// and thus a non-zero program exit. This is because a user may have
|
|
// chained the command, and an abort (for whatever reason) should cancel
|
|
// the whole chain. For example, given the command:
|
|
// func repo rm -cv && doSomethingOnSuccess
|
|
// The trailing command 'doSomethignOnSuccess' should not be evaluated if
|
|
// the first, `func repo rm`, does not exit 0.
|
|
if cfg.Verbose {
|
|
fmt.Fprintln(os.Stdout, "Repository remove canceled")
|
|
}
|
|
return fmt.Errorf("repository removal canceled")
|
|
}
|
|
|
|
// Remove the repository
|
|
if err = client.Repositories().Remove(params.Name); err != nil {
|
|
return
|
|
}
|
|
if cfg.Verbose {
|
|
fmt.Fprintln(os.Stdout, "Repository removed")
|
|
}
|
|
return
|
|
}
|
|
|
|
// Installed repositories
|
|
// All repositories which have been installed (does not include builtin)
|
|
func installedRepositories(client *fn.Client) ([]string, error) {
|
|
// Client API contract stipulates the list always lists the defeault builtin
|
|
// repo, and always lists it at index 0
|
|
repositories, err := client.Repositories().List()
|
|
if err != nil {
|
|
return []string{}, err
|
|
}
|
|
return repositories[1:], nil
|
|
}
|
|
|
|
// client config
|
|
// -------------
|
|
|
|
// repositoryConfig used for instantiating a fn.Client
|
|
type repositoryConfig struct {
|
|
Verbose bool // Enables verbose logging
|
|
Confirm bool // Enables interactive confirmation/prompting mode
|
|
}
|
|
|
|
// newRepositoryConfig creates a configuration suitable for use instantiating the
|
|
// fn Client. Note that parameters for the individual commands (add, remove etc)
|
|
// are collected separately in their requisite run functions.
|
|
func newRepositoryConfig() (cfg repositoryConfig, err error) {
|
|
// initial config is populated based on flags, which are themselves
|
|
// first populated by static defaults, then environment variables,
|
|
// finally command flags.
|
|
cfg = repositoryConfig{
|
|
Verbose: viper.GetBool("verbose"),
|
|
Confirm: viper.GetBool("confirm"),
|
|
}
|
|
|
|
// If not in confirm (interactive prompting) mode,
|
|
// this struct is complete.
|
|
if !cfg.Confirm {
|
|
return
|
|
}
|
|
|
|
// Prompt the terminal for interactive input using the current values
|
|
// as defaults. (noninteractive terminals are a noop)
|
|
if interactiveTerminal() {
|
|
return cfg.prompt()
|
|
}
|
|
|
|
// Noninteractive terminals in confirm/prompt mode simply echo
|
|
// effective values to stdout.
|
|
fmt.Fprintf(os.Stdout, "Verbose logging: %v\n", cfg.Verbose)
|
|
return
|
|
}
|
|
|
|
// prompt returns a config with values populated from interactivly prompting
|
|
// the user.
|
|
func (c repositoryConfig) prompt() (repositoryConfig, error) {
|
|
// These prompts are overly verbose, as the user calling --confirm likely
|
|
// only cares about the individual command-specific values (for example
|
|
// "name" and "url" when calling "add". However, we want to provide the
|
|
// ability to interactively choose _all_ options if the user really wants
|
|
// to, therefore these prompts are only shown if the user is "confirming
|
|
// verbosely", for example `func repository add -cv`. (of course the
|
|
// associated flags, environment variables etc are still respected. Just
|
|
// no prompts unless verbose)
|
|
if !c.Verbose || !interactiveTerminal() {
|
|
return c, nil
|
|
}
|
|
|
|
qs := []*survey.Question{
|
|
{
|
|
Name: "Verbose",
|
|
Prompt: &survey.Confirm{
|
|
Message: "Enable verbose logging:",
|
|
Default: c.Verbose,
|
|
},
|
|
},
|
|
}
|
|
err := survey.Ask(qs, &c)
|
|
return c, err
|
|
}
|