Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new global flags related to interactivity prompts and default values #568

Merged
merged 8 commits into from
May 30, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions pkg/app/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,20 @@ func Run(opts RunOpts) error {
// therefore if you add/remove a global flag you will also need to update
// the globalFlags map in pkg/app/usage.go which is used for usage rendering.
//
// NOTE: Global flags, unlike command flags, must be unique. For example, if
// you try to use a letter that is already taken by any other command flag,
// then kingpin will trigger a runtime panic 🎉
// NOTE: Global flags, unlike command flags, must be unique. This means BOTH
// the long flag and the short flag identifiers must be unique. If you try to
// reuse an identifier (long or short), then kingpin will trigger a runtime
// panic 🎉
//
// NOTE: Short flags CAN be safely reused across commands.
tokenHelp := fmt.Sprintf("Fastly API token (or via %s)", env.Token)
app.Flag("token", tokenHelp).Short('t').StringVar(&globals.Flag.Token)
app.Flag("accept-defaults", "Accept default options for all interactive prompts apart from Yes/No confirmations").Short('d').BoolVar(&globals.Flag.AcceptDefaults)
app.Flag("auto-yes", "Answer yes automatically to all Yes/No confirmations. This may suppress security warnings").Short('y').BoolVar(&globals.Flag.AutoYes)
app.Flag("endpoint", "Fastly API endpoint").Hidden().StringVar(&globals.Flag.Endpoint)
app.Flag("non-interactive", "Do not prompt for user input - suitable for CI processes. Equivalent to --accept-defaults and --auto-yes").Short('i').BoolVar(&globals.Flag.NonInteractive)
app.Flag("profile", "Switch account profile for single command execution (see also: 'fastly profile switch')").Short('o').StringVar(&globals.Flag.Profile)
app.Flag("token", tokenHelp).Short('t').StringVar(&globals.Flag.Token)
app.Flag("verbose", "Verbose logging").Short('v').BoolVar(&globals.Flag.Verbose)
app.Flag("endpoint", "Fastly API endpoint").Hidden().StringVar(&globals.Flag.Endpoint)

commands := defineCommands(app, &globals, md, opts)
command, name, err := processCommandInput(opts, app, &globals, commands)
Expand Down
53 changes: 32 additions & 21 deletions pkg/app/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,16 @@ A tool to interact with the Fastly API

GLOBAL FLAGS
--help Show context-sensitive help.
-t, --token=TOKEN Fastly API token (or via FASTLY_API_TOKEN)
-d, --accept-defaults Accept default options for all interactive prompts
apart from Yes/No confirmations
-y, --auto-yes Answer yes automatically to all Yes/No confirmations.
This may suppress security warnings
-i, --non-interactive Do not prompt for user input - suitable for CI
processes. Equivalent to --accept-defaults and
--auto-yes
-o, --profile=PROFILE Switch account profile for single command execution
(see also: 'fastly profile switch')
-t, --token=TOKEN Fastly API token (or via FASTLY_API_TOKEN)
-v, --verbose Verbose logging

COMMANDS
Expand Down Expand Up @@ -229,9 +236,16 @@ USAGE

GLOBAL FLAGS
--help Show context-sensitive help.
-t, --token=TOKEN Fastly API token (or via FASTLY_API_TOKEN)
-d, --accept-defaults Accept default options for all interactive prompts
apart from Yes/No confirmations
-y, --auto-yes Answer yes automatically to all Yes/No confirmations.
This may suppress security warnings
-i, --non-interactive Do not prompt for user input - suitable for CI
processes. Equivalent to --accept-defaults and
--auto-yes
-o, --profile=PROFILE Switch account profile for single command execution
(see also: 'fastly profile switch')
-t, --token=TOKEN Fastly API token (or via FASTLY_API_TOKEN)
-v, --verbose Verbose logging

SUBCOMMANDS
Expand Down Expand Up @@ -299,9 +313,16 @@ A tool to interact with the Fastly API

GLOBAL FLAGS
--help Show context-sensitive help.
-t, --token=TOKEN Fastly API token (or via FASTLY_API_TOKEN)
-d, --accept-defaults Accept default options for all interactive prompts
apart from Yes/No confirmations
-y, --auto-yes Answer yes automatically to all Yes/No confirmations.
This may suppress security warnings
-i, --non-interactive Do not prompt for user input - suitable for CI
processes. Equivalent to --accept-defaults and
--auto-yes
-o, --profile=PROFILE Switch account profile for single command execution
(see also: 'fastly profile switch')
-t, --token=TOKEN Fastly API token (or via FASTLY_API_TOKEN)
-v, --verbose Verbose logging

COMMANDS
Expand Down Expand Up @@ -642,13 +663,11 @@ COMMANDS
compute build [<flags>]
Build a Compute@Edge package locally

--accept-custom-build Skip confirmation prompts when running custom build
commands
--include-source Include source code in built package
--language=LANGUAGE Language type
--name=NAME Package name
--skip-verification Skip verification steps and force build
--timeout=TIMEOUT Timeout, in seconds, for the build compilation step
--include-source Include source code in built package
--language=LANGUAGE Language type
--name=NAME Package name
--skip-verification Skip verification steps and force build
--timeout=TIMEOUT Timeout, in seconds, for the build compilation step

compute deploy [<flags>]
Deploy a package to a Fastly Compute@Edge service
Expand All @@ -659,8 +678,6 @@ COMMANDS
The name of the service
--version=VERSION 'latest', 'active', or the number of a specific
version
--accept-defaults Accept default values for all prompts and
perform deploy non-interactively
--comment=COMMENT Human-readable comment
--domain=DOMAIN The name of the domain associated to the
package
Expand All @@ -671,7 +688,7 @@ COMMANDS
Initialize a new Compute@Edge package locally

-n, --name=NAME Name of package, falls back to --directory
-d, --description=DESCRIPTION Description of the package
--description=DESCRIPTION Description of the package
-p, --directory=DIRECTORY Destination to write the new package,
defaulting to the current directory
-a, --author=AUTHOR ... Author(s) of the package
Expand All @@ -690,10 +707,6 @@ COMMANDS
compute publish [<flags>]
Build and deploy a Compute@Edge package to a Fastly service

--accept-custom-build Skip confirmation prompts when running custom
build commands
--accept-defaults Accept default values for all prompts and
perform deploy non-interactively
--comment=COMMENT Human-readable comment
--domain=DOMAIN The name of the domain associated to the
package
Expand All @@ -714,8 +727,6 @@ COMMANDS
compute serve [<flags>]
Build and run a Compute@Edge package locally

--accept-custom-build Skip confirmation prompts when running custom build
commands
--addr="127.0.0.1:7676" The IPv4 address and port to listen on
--env=ENV The environment configuration to use (e.g. stage)
--file="bin/main.wasm" The Wasm file to run
Expand Down Expand Up @@ -4737,7 +4748,7 @@ COMMANDS
then fastly.toml)
--service-name=SERVICE-NAME
The name of the service
-i, --snippet-id=SNIPPET-ID Alphanumeric string identifying a VCL Snippet
--snippet-id=SNIPPET-ID Alphanumeric string identifying a VCL Snippet

vcl snippet list --version=VERSION [<flags>]
List the uploaded VCL snippets for a particular service and version
Expand Down Expand Up @@ -4768,7 +4779,7 @@ COMMANDS
then fastly.toml)
--service-name=SERVICE-NAME
The name of the service
-i, --snippet-id=SNIPPET-ID Alphanumeric string identifying a VCL Snippet
--snippet-id=SNIPPET-ID Alphanumeric string identifying a VCL Snippet
--type=TYPE The location in generated VCL where the snippet
should be placed

Expand Down
17 changes: 11 additions & 6 deletions pkg/app/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,18 @@ var UsageTemplateFuncs = template.FuncMap{
}

// WARNING: kingpin has no way of decorating flags as being "global" therefore
// if you add/remove a global flag you will also need to update flag binding in
// pkg/app/app.go.
// if you add/remove a global flag you will also need to update the app.Flag()
// bindings in pkg/app/run.go.
//
// NOTE: These map is used to help populate the CLI 'usage' template renderer.
var globalFlags = map[string]bool{
"help": true,
"profile": true,
"token": true,
"verbose": true,
"accept-defaults": true,
"auto-yes": true,
"help": true,
"non-interactive": true,
"profile": true,
"token": true,
"verbose": true,
}

// VerboseUsageTemplate is the full-fat usage template, rendered when users type
Expand Down
18 changes: 8 additions & 10 deletions pkg/commands/compute/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@ type Toolchain interface {

// Flags represents the flags defined for the command.
type Flags struct {
AcceptCustomBuild bool
IncludeSrc bool
Lang string
PackageName string
SkipVerification bool
Timeout int
IncludeSrc bool
Lang string
PackageName string
SkipVerification bool
Timeout int
}

// BuildCommand produces a deployable artifact from files on the local disk.
Expand All @@ -67,7 +66,6 @@ func NewBuildCommand(parent cmd.Registerer, globals *config.Data, data manifest.

// NOTE: when updating these flags, be sure to update the composite commands:
// `compute publish` and `compute serve`.
c.CmdClause.Flag("accept-custom-build", "Skip confirmation prompts when running custom build commands").BoolVar(&c.Flags.AcceptCustomBuild)
c.CmdClause.Flag("include-source", "Include source code in built package").BoolVar(&c.Flags.IncludeSrc)
c.CmdClause.Flag("language", "Language type").StringVar(&c.Flags.Lang)
c.CmdClause.Flag("name", "Package name").StringVar(&c.Flags.PackageName)
Expand Down Expand Up @@ -183,7 +181,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) {
progress.Done()

if toolchain == "custom" {
if !c.Flags.AcceptCustomBuild {
if !c.Globals.Flag.AutoYes && !c.Globals.Flag.NonInteractive {
// NOTE: A third-party could share a project with a build command for a
// language that wouldn't normally require one (e.g. Rust), and do evil
// things. So we should notify the user and confirm they would like to
Expand All @@ -195,15 +193,15 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) {
}
}

if c.Globals.Verbose() && c.Flags.AcceptCustomBuild {
if c.Globals.Verbose() {
text.Break(out)
}

progress = text.ResetProgress(out, c.Globals.Verbose())
progress.Step(fmt.Sprintf("Building package using %s toolchain...", toolchain))

postBuildCallback := func() error {
if !c.Flags.AcceptCustomBuild {
if !c.Globals.Flag.AutoYes && !c.Globals.Flag.NonInteractive {
err := promptForBuildContinue(CustomPostBuildScriptMessage, c.Manifest.File.Scripts.PostBuild, out, in, c.Globals.Verbose())
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions pkg/commands/compute/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ func TestCustomBuild(t *testing.T) {
},
{
name: "avoid prompt confirmation",
args: args("compute build --accept-custom-build --language other"),
args: args("compute build --auto-yes --language other"),
fastlyManifest: `
manifest_version = 2
name = "test"
Expand Down Expand Up @@ -856,7 +856,7 @@ func TestCustomPostBuild(t *testing.T) {
},
{
name: "avoid prompt confirmation",
args: args("compute build --accept-custom-build"),
args: args("compute build --auto-yes"),
applicationConfig: config.File{
Language: config.Language{
Rust: config.Rust{
Expand Down
31 changes: 17 additions & 14 deletions pkg/commands/compute/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ type DeployCommand struct {

// NOTE: these are public so that the "publish" composite command can set the
// values appropriately before calling the Exec() function.
AcceptDefaults bool
Comment cmd.OptionalString
Domain string
Manifest manifest.Data
Expand Down Expand Up @@ -76,7 +75,6 @@ func NewDeployCommand(parent cmd.Registerer, globals *config.Data, data manifest
Dst: &c.ServiceVersion.Value,
Name: cmd.FlagVersionName,
})
c.CmdClause.Flag("accept-defaults", "Accept default values for all prompts and perform deploy non-interactively").BoolVar(&c.AcceptDefaults)
c.CmdClause.Flag("comment", "Human-readable comment").Action(c.Comment.Set).StringVar(&c.Comment.Value)
c.CmdClause.Flag("domain", "The name of the domain associated to the package").StringVar(&c.Domain)
c.CmdClause.Flag("name", "Package name").StringVar(&c.Manifest.Flag.Name)
Expand Down Expand Up @@ -122,7 +120,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {

if source == manifest.SourceUndefined {
newService = true
serviceID, serviceVersion, err = manageNoServiceIDFlow(c.AcceptDefaults, in, out, verbose, apiClient, pkgName, c.Package, errLog, &c.Manifest.File, activateTrial)
serviceID, serviceVersion, err = manageNoServiceIDFlow(c.Globals.Flag, in, out, verbose, apiClient, pkgName, c.Package, errLog, &c.Manifest.File, activateTrial)
if err != nil {
return err
}
Expand Down Expand Up @@ -154,7 +152,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {

domains := &setup.Domains{
APIClient: apiClient,
AcceptDefaults: c.AcceptDefaults,
AcceptDefaults: c.Globals.Flag.AcceptDefaults,
PackageDomain: c.Domain,
ServiceID: serviceID,
ServiceVersion: serviceVersion.Number,
Expand All @@ -177,7 +175,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {
if newService {
backends = &setup.Backends{
APIClient: apiClient,
AcceptDefaults: c.AcceptDefaults,
AcceptDefaults: c.Globals.Flag.AcceptDefaults,
ServiceID: serviceID,
ServiceVersion: serviceVersion.Number,
Setup: c.Manifest.File.Setup.Backends,
Expand All @@ -187,7 +185,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {

dictionaries = &setup.Dictionaries{
APIClient: apiClient,
AcceptDefaults: c.AcceptDefaults,
AcceptDefaults: c.Globals.Flag.AcceptDefaults,
ServiceID: serviceID,
ServiceVersion: serviceVersion.Number,
Setup: c.Manifest.File.Setup.Dictionaries,
Expand All @@ -196,9 +194,8 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {
}

loggers = &setup.Loggers{
AcceptDefaults: c.AcceptDefaults,
Setup: c.Manifest.File.Setup.Loggers,
Stdout: out,
Setup: c.Manifest.File.Setup.Loggers,
Stdout: out,
}
}

Expand Down Expand Up @@ -266,7 +263,9 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {

if err := domains.Create(); err != nil {
errLog.AddWithContext(err, map[string]interface{}{
"Accept defaults": c.AcceptDefaults,
"Accept defaults": c.Globals.Flag.AcceptDefaults,
"Auto-yes": c.Globals.Flag.AutoYes,
"Non-interactive": c.Globals.Flag.NonInteractive,
"Service ID": serviceID,
"Service Version": serviceVersion.Number,
})
Expand All @@ -283,7 +282,9 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {

if err := backends.Create(); err != nil {
errLog.AddWithContext(err, map[string]interface{}{
"Accept defaults": c.AcceptDefaults,
"Accept defaults": c.Globals.Flag.AcceptDefaults,
"Auto-yes": c.Globals.Flag.AutoYes,
"Non-interactive": c.Globals.Flag.NonInteractive,
"Service ID": serviceID,
"Service Version": serviceVersion.Number,
})
Expand All @@ -292,7 +293,9 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) {

if err := dictionaries.Create(); err != nil {
errLog.AddWithContext(err, map[string]interface{}{
"Accept defaults": c.AcceptDefaults,
"Accept defaults": c.Globals.Flag.AcceptDefaults,
"Auto-yes": c.Globals.Flag.AutoYes,
"Non-interactive": c.Globals.Flag.NonInteractive,
"Service ID": serviceID,
"Service Version": serviceVersion.Number,
})
Expand Down Expand Up @@ -544,7 +547,7 @@ func preconfigureActivateTrial(endpoint, token string, httpClient api.HTTPClient

// manageNoServiceIDFlow handles creating a new service when no Service ID is found.
func manageNoServiceIDFlow(
acceptDefaults bool,
globalFlags config.Flag,
in io.Reader,
out io.Writer,
verbose bool,
Expand All @@ -554,7 +557,7 @@ func manageNoServiceIDFlow(
manifestFile *manifest.File,
activateTrial activator,
) (serviceID string, serviceVersion *fastly.Version, err error) {
if !acceptDefaults {
if !globalFlags.AutoYes && !globalFlags.NonInteractive {
text.Break(out)
text.Output(out, "There is no Fastly service associated with this package. To connect to an existing service add the Service ID to the fastly.toml file, otherwise follow the prompts to create a service now.")
text.Break(out)
Expand Down
Loading