Skip to content

Commit

Permalink
refactor: all the things
Browse files Browse the repository at this point in the history
  • Loading branch information
Integralist committed Nov 14, 2023
1 parent 6ef7348 commit 253abe5
Show file tree
Hide file tree
Showing 370 changed files with 2,537 additions and 3,060 deletions.
271 changes: 108 additions & 163 deletions pkg/app/run.go

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pkg/app/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/fastly/cli/pkg/app"
"github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/testutil"
)

Expand Down Expand Up @@ -122,8 +123,8 @@ whoami
outC <- buf.String()
}()

app.Init = func(_ []string, _ io.Reader) (app.RunOpts, error) {
return testutil.NewRunOpts(testcase.Args, &stdout), nil
app.Init = func(_ []string, _ io.Reader) (*global.Data, error) {
return testutil.MockGlobalData(testcase.Args, &stdout), nil
}
err := app.Run(testcase.Args, nil)
if err != nil {
Expand Down
46 changes: 22 additions & 24 deletions pkg/app/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,29 +208,27 @@ const VerboseUsageTemplate = `{{define "FormatCommands" -}}
// processing the incoming command request from the user, as well as handling
// the various places where help output can be displayed.
func processCommandInput(
args []string,
out io.Writer,
data *global.Data,
app *kingpin.Application,
g *global.Data,
commands []cmd.Command,
) (command cmd.Command, cmdName string, err error) {
// As the `help` command model gets privately added as a side-effect of
// kingpin.Parse, we cannot add the `--format json` flag to the model.
// Therefore, we have to manually parse the args slice here to check for the
// existence of `help --format json`, if present we print usage JSON and
// exit early.
if cmd.ArgsIsHelpJSON(args) {
if cmd.ArgsIsHelpJSON(data.Args) {
j, err := UsageJSON(app)
if err != nil {
g.ErrLog.Add(err)
data.ErrLog.Add(err)
return command, cmdName, err
}
fmt.Fprintf(out, "%s", j)
return command, strings.Join(args, ""), nil
fmt.Fprintf(data.Output, "%s", j)
return command, strings.Join(data.Args, ""), nil
}

// Use partial application to generate help output function.
help := displayHelp(g.ErrLog, args, app, out, io.Discard)
help := displayHelp(data.ErrLog, data.Args, app, data.Output, io.Discard)

// Handle parse errors and display contextual usage if possible. Due to bugs
// and an obsession for lots of output side-effects in the kingpin.Parse
Expand All @@ -251,14 +249,14 @@ func processCommandInput(
// But it's useful to have it implemented so it's ready to roll when we do.
var vars map[string]any

if cmd.IsVerboseAndQuiet(args) {
if cmd.IsVerboseAndQuiet(data.Args) {
return command, cmdName, fsterr.RemediationError{
Inner: errors.New("--verbose and --quiet flag provided"),
Remediation: "Either remove both --verbose and --quiet flags, or one of them.",
}
}

if cmd.IsHelpFlagOnly(args) && len(args) == 1 {
if cmd.IsHelpFlagOnly(data.Args) && len(data.Args) == 1 {
return command, cmdName, fsterr.SkipExitError{
Skip: true,
Err: help(vars, nil),
Expand All @@ -285,17 +283,17 @@ func processCommandInput(
//
// ctx.SelectedCommand will be nil if only a flag like --verbose or -v is
// provided but with no actual command set so we check with IsGlobalFlagsOnly.
noargs := len(args) == 0
globalFlagsOnly := cmd.IsGlobalFlagsOnly(args)
ctx, err := app.ParseContext(args)
if err != nil && !cmd.IsCompletion(args) || noargs || globalFlagsOnly {
noargs := len(data.Args) == 0
globalFlagsOnly := cmd.IsGlobalFlagsOnly(data.Args)
ctx, err := app.ParseContext(data.Args)
if err != nil && !cmd.IsCompletion(data.Args) || noargs || globalFlagsOnly {
if noargs || globalFlagsOnly {
err = fmt.Errorf("command not specified")
}
return command, cmdName, help(vars, err)
}

if len(args) == 1 && args[0] == "--" {
if len(data.Args) == 1 && data.Args[0] == "--" {
return command, cmdName, fsterr.RemediationError{
Inner: errors.New("-- is invalid input when not followed by a positional argument"),
Remediation: "If looking for help output try: `fastly help` for full command list or `fastly --help` for command summary.",
Expand All @@ -311,14 +309,14 @@ func processCommandInput(
// completion flag, as that depends on kingpin.Parse() being called, and so
// the `ctx` is otherwise empty.
var found bool
if !noargs && !globalFlagsOnly && !cmd.IsHelpOnly(args) && !cmd.IsHelpFlagOnly(args) && !cmd.IsCompletion(args) && !cmd.IsCompletionScript(args) {
if !noargs && !globalFlagsOnly && !cmd.IsHelpOnly(data.Args) && !cmd.IsHelpFlagOnly(data.Args) && !cmd.IsCompletion(data.Args) && !cmd.IsCompletionScript(data.Args) {
command, found = cmd.Select(ctx.SelectedCommand.FullCommand(), commands)
if !found {
return command, cmdName, help(vars, err)
}
}

if cmd.ContextHasHelpFlag(ctx) && !cmd.IsHelpFlagOnly(args) {
if cmd.ContextHasHelpFlag(ctx) && !cmd.IsHelpFlagOnly(data.Args) {
return command, cmdName, fsterr.SkipExitError{
Skip: true,
Err: help(vars, nil),
Expand All @@ -345,21 +343,21 @@ func processCommandInput(
// caller passes --completion-bash because adding a command to the arguments
// list in that scenario would cause Kingpin logic to fail (as it expects the
// flag to be used on its own).
if cmd.IsCompletionScript(args) {
args = append(args, "shellcomplete")
if cmd.IsCompletionScript(data.Args) {
data.Args = append(data.Args, "shellcomplete")
}

cmdName, err = app.Parse(args)
cmdName, err = app.Parse(data.Args)
if err != nil {
return command, "", help(vars, err)
}

// Restore output writers
app.Writers(out, io.Discard)
app.Writers(data.Output, io.Discard)

// Kingpin generates shell completion as a side-effect of kingpin.Parse() so
// we allow it to call os.Exit, only if a completion flag is present.
if cmd.IsCompletion(args) || cmd.IsCompletionScript(args) {
if cmd.IsCompletion(data.Args) || cmd.IsCompletionScript(data.Args) {
app.Terminate(os.Exit)
return command, "shell-autocomplete", nil
}
Expand All @@ -372,14 +370,14 @@ func processCommandInput(
return command, cmdName, fsterr.SkipExitError{
Skip: true,
Err: fsterr.RemediationError{
Prefix: useFullHelpOutput(app, args, out).String(),
Prefix: useFullHelpOutput(app, data.Args, data.Output).String(),
},
}
}

// Catch scenario where user wants to view help with the following format:
// fastly --help <command>
if cmd.IsHelpFlagOnly(args) {
if cmd.IsHelpFlagOnly(data.Args) {
return command, cmdName, fsterr.SkipExitError{
Skip: true,
Err: help(vars, nil),
Expand Down
51 changes: 24 additions & 27 deletions pkg/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,17 @@ type WellKnownEndpoints struct {
Token string `json:"token_endpoint"`
}

// Starter defines the behaviour for the authentication server.
type Starter interface {
// Runner defines the behaviour for the authentication server.
type Runner interface {
// AuthURL returns a fully qualified authorization_endpoint.
// i.e. path + audience + scope + code_challenge etc.
AuthURL() (string, error)
// GetResult returns the results channel
GetResult() chan AuthorizationResult
// SetAccountEndpoint sets the account endpoint.
SetAccountEndpoint(endpoint string)
// SetEndpoint sets the API endpoint.
SetAPIEndpoint(endpoint string)
// SetVerifier sets the code verifier.
SetVerifier(verifier *oidc.S256Verifier)
// Start starts a local server for handling authentication processing.
Start() error
}
Expand All @@ -76,6 +77,25 @@ type Server struct {
WellKnownEndpoints WellKnownEndpoints
}

// AuthURL returns a fully qualified authorization_endpoint.
// i.e. path + audience + scope + code_challenge etc.
func (s Server) AuthURL() (string, error) {
challenge, err := oidc.CreateCodeChallenge(s.Verifier)
if err != nil {
return "", err
}

authorizationURL := fmt.Sprintf(
"%s?audience=%s"+
"&scope=openid"+
"&response_type=code&client_id=%s"+
"&code_challenge=%s"+
"&code_challenge_method=S256&redirect_uri=%s",
s.WellKnownEndpoints.Auth, s.APIEndpoint, ClientID, challenge, RedirectURL)

return authorizationURL, nil
}

// GetResult returns the result channel.
func (s Server) GetResult() chan AuthorizationResult {
return s.Result
Expand Down Expand Up @@ -233,29 +253,6 @@ type AuthorizationResult struct {
SessionToken string
}

// GenVerifier creates a code verifier.
func GenVerifier() (*oidc.S256Verifier, error) {
return oidc.NewCodeVerifier()
}

// GenURL constructs the required authorization_endpoint path.
func GenURL(accountEndpoint, apiEndpoint string, verifier *oidc.S256Verifier) (string, error) {
challenge, err := oidc.CreateCodeChallenge(verifier)
if err != nil {
return "", err
}

authorizationURL := fmt.Sprintf(
"%s/realms/fastly/protocol/openid-connect/auth?audience=%s"+
"&scope=openid"+
"&response_type=code&client_id=%s"+
"&code_challenge=%s"+
"&code_challenge_method=S256&redirect_uri=%s",
accountEndpoint, apiEndpoint, ClientID, challenge, RedirectURL)

return authorizationURL, nil
}

// GetJWT constructs and calls the token_endpoint path, returning a JWT
// containing the access and refresh tokens and associated TTLs.
func GetJWT(accountEndpoint, codeVerifier, authorizationCode string) (JWT, error) {
Expand Down
21 changes: 11 additions & 10 deletions pkg/commands/acl/acl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/fastly/go-fastly/v8/fastly"

"github.com/fastly/cli/pkg/app"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/mock"
"github.com/fastly/cli/pkg/testutil"
)
Expand Down Expand Up @@ -88,8 +89,8 @@ func TestACLCreate(t *testing.T) {
testcase := &scenarios[testcaseIdx]
t.Run(testcase.Name, func(t *testing.T) {
var stdout bytes.Buffer
app.Init = func(_ []string, _ io.Reader) (app.RunOpts, error) {
opts := testutil.NewRunOpts(testcase.Args, &stdout)
app.Init = func(_ []string, _ io.Reader) (*global.Data, error) {
opts := testutil.MockGlobalData(testcase.Args, &stdout)
opts.APIClientFactory = mock.APIClient(testcase.API)
return opts, nil
}
Expand Down Expand Up @@ -167,8 +168,8 @@ func TestACLDelete(t *testing.T) {
testcase := &scenarios[testcaseIdx]
t.Run(testcase.Name, func(t *testing.T) {
var stdout bytes.Buffer
app.Init = func(_ []string, _ io.Reader) (app.RunOpts, error) {
opts := testutil.NewRunOpts(testcase.Args, &stdout)
app.Init = func(_ []string, _ io.Reader) (*global.Data, error) {
opts := testutil.MockGlobalData(testcase.Args, &stdout)
opts.APIClientFactory = mock.APIClient(testcase.API)
return opts, nil
}
Expand Down Expand Up @@ -232,8 +233,8 @@ func TestACLDescribe(t *testing.T) {
testcase := &scenarios[testcaseIdx]
t.Run(testcase.Name, func(t *testing.T) {
var stdout bytes.Buffer
app.Init = func(_ []string, _ io.Reader) (app.RunOpts, error) {
opts := testutil.NewRunOpts(testcase.Args, &stdout)
app.Init = func(_ []string, _ io.Reader) (*global.Data, error) {
opts := testutil.MockGlobalData(testcase.Args, &stdout)
opts.APIClientFactory = mock.APIClient(testcase.API)
return opts, nil
}
Expand Down Expand Up @@ -301,8 +302,8 @@ func TestACLList(t *testing.T) {
testcase := &scenarios[testcaseIdx]
t.Run(testcase.Name, func(t *testing.T) {
var stdout bytes.Buffer
app.Init = func(_ []string, _ io.Reader) (app.RunOpts, error) {
opts := testutil.NewRunOpts(testcase.Args, &stdout)
app.Init = func(_ []string, _ io.Reader) (*global.Data, error) {
opts := testutil.MockGlobalData(testcase.Args, &stdout)
opts.APIClientFactory = mock.APIClient(testcase.API)
return opts, nil
}
Expand Down Expand Up @@ -394,8 +395,8 @@ func TestACLUpdate(t *testing.T) {
testcase := &scenarios[testcaseIdx]
t.Run(testcase.Name, func(t *testing.T) {
var stdout bytes.Buffer
app.Init = func(_ []string, _ io.Reader) (app.RunOpts, error) {
opts := testutil.NewRunOpts(testcase.Args, &stdout)
app.Init = func(_ []string, _ io.Reader) (*global.Data, error) {
opts := testutil.MockGlobalData(testcase.Args, &stdout)
opts.APIClientFactory = mock.APIClient(testcase.API)
return opts, nil
}
Expand Down
9 changes: 3 additions & 6 deletions pkg/commands/acl/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ import (
"github.com/fastly/cli/pkg/cmd"
"github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/manifest"
"github.com/fastly/cli/pkg/text"
)

// NewCreateCommand returns a usable command registered under the parent.
func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand {
func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand {
c := CreateCommand{
Base: cmd.Base{
Globals: g,
},
manifest: m,
}

c.CmdClause = parent.Command("create", "Create a new ACL attached to the specified service version").Alias("add")
Expand All @@ -40,7 +38,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C
c.RegisterFlag(cmd.StringFlagOpts{
Name: cmd.FlagServiceIDName,
Description: cmd.FlagServiceIDDesc,
Dst: &c.manifest.Flag.ServiceID,
Dst: &g.Manifest.Flag.ServiceID,
Short: 's',
})
c.RegisterFlag(cmd.StringFlagOpts{
Expand All @@ -58,7 +56,6 @@ type CreateCommand struct {
cmd.Base

autoClone cmd.OptionalAutoClone
manifest manifest.Data
name cmd.OptionalString
serviceName cmd.OptionalServiceNameID
serviceVersion cmd.OptionalServiceVersion
Expand All @@ -70,7 +67,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error {
AutoCloneFlag: c.autoClone,
APIClient: c.Globals.APIClient,
ErrLog: c.Globals.ErrLog,
Manifest: c.manifest,
Manifest: *c.Globals.Manifest,
Out: out,
ServiceNameFlag: c.serviceName,
ServiceVersionFlag: c.serviceVersion,
Expand Down
9 changes: 3 additions & 6 deletions pkg/commands/acl/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ import (
"github.com/fastly/cli/pkg/cmd"
"github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/manifest"
"github.com/fastly/cli/pkg/text"
)

// NewDeleteCommand returns a usable command registered under the parent.
func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand {
func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand {
c := DeleteCommand{
Base: cmd.Base{
Globals: g,
},
manifest: m,
}
c.CmdClause = parent.Command("delete", "Delete an ACL from the specified service version").Alias("remove")

Expand All @@ -39,7 +37,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D
c.RegisterFlag(cmd.StringFlagOpts{
Name: cmd.FlagServiceIDName,
Description: cmd.FlagServiceIDDesc,
Dst: &c.manifest.Flag.ServiceID,
Dst: &g.Manifest.Flag.ServiceID,
Short: 's',
})
c.RegisterFlag(cmd.StringFlagOpts{
Expand All @@ -57,7 +55,6 @@ type DeleteCommand struct {
cmd.Base

autoClone cmd.OptionalAutoClone
manifest manifest.Data
name string
serviceName cmd.OptionalServiceNameID
serviceVersion cmd.OptionalServiceVersion
Expand All @@ -68,7 +65,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error {
serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{
AutoCloneFlag: c.autoClone,
APIClient: c.Globals.APIClient,
Manifest: c.manifest,
Manifest: *c.Globals.Manifest,
Out: out,
ServiceNameFlag: c.serviceName,
ServiceVersionFlag: c.serviceVersion,
Expand Down
Loading

0 comments on commit 253abe5

Please sign in to comment.