Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- breaking(domain) - service-version oriented `domain` commands have been moved under the `service domain` command. Versionless `domain-v1` commands have been moved to the `domain` command ([#1615](https://github.com/fastly/cli/pull/1615))

### Enhancements:
- feat(setup): Add interactive setup wizard for CLI configuration with API token and SSO authentication options
- feat(rust): Allow testing with prerelease Rust versions ([#1604](https://github.com/fastly/cli/pull/1604))
- feat(compute/hashfiles): remove hashsum subcommand ([#1608](https://github.com/fastly/cli/pull/1608))
- feat(ngwaf/rules): add support for CRUD operations for NGWAF rules ([#1605](https://github.com/fastly/cli/pull/1605))
Expand Down
1 change: 1 addition & 0 deletions pkg/app/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ complete -F _fastly_bash_autocomplete fastly
Args: "--completion-bash",
WantOutput: `help
sso
setup
auth-token
compute
config
Expand Down
3 changes: 3 additions & 0 deletions pkg/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ import (
servicevclsnippet "github.com/fastly/cli/pkg/commands/service/vcl/snippet"
serviceversion "github.com/fastly/cli/pkg/commands/service/version"
"github.com/fastly/cli/pkg/commands/serviceauth"
"github.com/fastly/cli/pkg/commands/setup"
"github.com/fastly/cli/pkg/commands/shellcomplete"
"github.com/fastly/cli/pkg/commands/sso"
"github.com/fastly/cli/pkg/commands/stats"
Expand Down Expand Up @@ -149,6 +150,7 @@ func Define( // nolint:revive // function-length
// placement of the `sso` subcommand not look too odd we place it at the
// beginning of the list of commands.
ssoCmdRoot := sso.NewRootCommand(app, data)
setupCmdRoot := setup.NewRootCommand(app, data, ssoCmdRoot)

authtokenCmdRoot := authtoken.NewRootCommand(app, data)
authtokenCreate := authtoken.NewCreateCommand(authtokenCmdRoot.CmdClause, data)
Expand Down Expand Up @@ -1329,6 +1331,7 @@ func Define( // nolint:revive // function-length
serviceVersionStage,
serviceVersionUnstage,
serviceVersionUpdate,
setupCmdRoot,
ssoCmdRoot,
statsCmdRoot,
statsHistorical,
Expand Down
63 changes: 8 additions & 55 deletions pkg/commands/profile/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@ package profile

import (
"context"
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strings"

"github.com/fastly/go-fastly/v12/fastly"

"github.com/fastly/cli/pkg/api"
"github.com/fastly/cli/pkg/argparser"
"github.com/fastly/cli/pkg/commands/sso"
"github.com/fastly/cli/pkg/config"
fsterr "github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/profile"
Expand Down Expand Up @@ -141,7 +136,7 @@ func (c *CreateCommand) staticTokenFlow(makeDefault bool, in io.Reader, out io.W

func promptForToken(in io.Reader, out io.Writer, errLog fsterr.LogInterface) (string, error) {
text.Output(out, "An API token is used to authenticate requests to the Fastly API. To create a token, visit https://manage.fastly.com/account/personal/tokens\n\n")
token, err := text.InputSecure(out, text.Prompt("Fastly API token: "), in, validateTokenNotEmpty)
token, err := text.InputSecure(out, text.Prompt("Fastly API token: "), in, profile.ValidateTokenNotEmpty)
if err != nil {
errLog.Add(err)
return "", err
Expand All @@ -150,17 +145,6 @@ func promptForToken(in io.Reader, out io.Writer, errLog fsterr.LogInterface) (st
return token, nil
}

func validateTokenNotEmpty(s string) error {
if s == "" {
return ErrEmptyToken
}
return nil
}

// ErrEmptyToken is returned when a user tries to supply an empty string as a
// token in the terminal prompt.
var ErrEmptyToken = errors.New("token cannot be empty")

// validateToken ensures the token can be used to acquire user data.
func (c *CreateCommand) validateToken(token, endpoint string, spinner text.Spinner) (string, error) {
var (
Expand Down Expand Up @@ -217,53 +201,22 @@ func (c *CreateCommand) validateToken(token, endpoint string, spinner text.Spinn
func (c *CreateCommand) updateInMemCfg(email, token, endpoint string, makeDefault bool, spinner text.Spinner) error {
return spinner.Process("Persisting configuration", func(_ *text.SpinnerWrapper) error {
c.Globals.Config.Fastly.APIEndpoint = endpoint

if c.Globals.Config.Profiles == nil {
c.Globals.Config.Profiles = make(config.Profiles)
}
c.Globals.Config.Profiles[c.profile] = &config.Profile{
Default: makeDefault,
Email: email,
Token: token,
}

// If the user wants the newly created profile to be their new default, then
// we'll call SetDefault for its side effect of resetting all other profiles
// to have their Default field set to false.
if makeDefault {
if p, ok := profile.SetDefault(c.profile, c.Globals.Config.Profiles); ok {
c.Globals.Config.Profiles = p
}
}
c.Globals.Config.Profiles = profile.Create(
c.profile,
c.Globals.Config.Profiles,
email,
token,
makeDefault,
)
return nil
})
}

func (c *CreateCommand) persistCfg() error {
// TODO: The following directory checks should be encapsulated by the
// File.Write() method as this chunk of code is duplicated in various places.
// Consider consolidating with pkg/filesystem/directory.go
// This function is itself duplicated in pkg/commands/profile/update.go
dir := filepath.Dir(c.Globals.ConfigPath)
fi, err := os.Stat(dir)
switch {
case err == nil && !fi.IsDir():
return fmt.Errorf("config file path %s isn't a directory", dir)
case err != nil && errors.Is(err, fs.ErrNotExist):
if err := os.MkdirAll(dir, config.DirectoryPermissions); err != nil {
c.Globals.ErrLog.AddWithContext(err, map[string]any{
"Directory": dir,
"Permissions": config.DirectoryPermissions,
})
return fmt.Errorf("error creating config file directory: %w", err)
}
}

if err := c.Globals.Config.Write(c.Globals.ConfigPath); err != nil {
c.Globals.ErrLog.Add(err)
return fmt.Errorf("error saving config file: %w", err)
}

return nil
}

Expand Down
Loading