8000 Define new --version and --autoclone flags by Integralist · Pull Request #300 · fastly/cli · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Define new --version and --autoclone flags #300

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

Merged
merged 18 commits into from
Jun 7, 2021
Merged
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
5 changes: 1 addition & 4 deletions pkg/api/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ type HTTPClient interface {

// Interface models the methods of the Fastly API client that we use.
// It exists to allow for easier testing, in combination with Mock.
//
// TODO(integralist):
// There are missing methods such as GetVersion from this list so review in
// future the missing features in CLI and implement here.
type Interface interface {
GetTokenSelf() (*fastly.Token, error)

Expand All @@ -33,6 +29,7 @@ type Interface interface {

CloneVersion(*fastly.CloneVersionInput) (*fastly.Version, error)
ListVersions(*fastly.ListVersionsInput) ([]*fastly.Version, error)
GetVersion(*fastly.GetVersionInput) (*fastly.Version, error)
UpdateVersion(*fastly.UpdateVersionInput) (*fastly.Version, error)
ActivateVersion(*fastly.ActivateVersionInput) (*fastly.Version, error)
DeactivateVersion(*fastly.DeactivateVersionInput) (*fastly.Version, error)
Expand Down
148 changes: 148 additions & 0 deletions pkg/cmd/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package cmd

import (
"fmt"
"io"
"sort"
"strconv"
"strings"

"github.com/fastly/cli/pkg/api"
"github.com/fastly/cli/pkg/text"
"github.com/fastly/go-fastly/v3/fastly"
"github.com/fastly/kingpin"
)

// ServiceVersionFlagOpts enables easy configuration of the --version flag
// defined via the NewServiceVersionFlag constructor.
//
// NOTE: The reason we define an 'optional' field rather than a 'required'
// field is because 99% of the use cases where --version is defined the flag
// will be required, and so we cater for the common case. Meaning only those
// subcommands that have --version as optional will need to set that field.
type ServiceVersionFlagOpts struct {
Dst *string
Optional bool
Action kingpin.Action
}

// SetServiceVersionFlag defines a --version flag that accepts multiple values
// such as 'latest', 'active' and numerical values which are then converted
// into the appropriate service version.
func (b Base) SetServiceVersionFlag(opts ServiceVersionFlagOpts, args ...string) {
clause := b.CmdClause.Flag("version", "'latest', 'active', or the number of a specific version")
if !opts.Optional {
clause = clause.Required()
} else {
clause = clause.Action(opts.Action)
}
clause.StringVar(opts.Dst)
}

// SetAutoCloneFlag defines a --autoclone flag that will cause a clone of the
// identified service version if it's found to be active or locked.
func (b Base) SetAutoCloneFlag(action kingpin.Action, dst *bool) {
b.CmdClause.Flag("autoclone", "If the selected service version is not editable, clone it and use the clone.").Action(action).BoolVar(dst)
}

// OptionalServiceVersion represents a Fastly service version.
type OptionalServiceVersion struct {
OptionalString
Client api.Interface
}

// Parse returns a service version based on the given user input.
func (sv *OptionalServiceVersion) Parse(sid string) (*fastly.Version, error) {
vs, err := sv.Client.ListVersions(&fastly.ListVersionsInput{
ServiceID: sid,
})
if err != nil || len(vs) == 0 {
return nil, fmt.Errorf("error listing service versions: %w", err)
}

// Sort versions into descending order.
sort.Slice(vs, func(i, j int) bool {
return vs[i].Number > vs[j].Number
})

var v *fastly.Version

switch strings.ToLower(sv.Value) {
case "latest":
return vs[0], nil
case "active":
v, err = getActiveVersion(vs)
case "":
return vs[0], nil
default:
v, err = getSpecifiedVersion(vs, sv.Value)
}
if err != nil {
return nil, err
}

return v, nil
}

// OptionalAutoClone defines a method set for abstracting the logic required to
// identify if a given service version needs to be cloned.
type OptionalAutoClone struct {
OptionalBool
Out io.Writer
Client api.Interface
}

// Parse returns a service version.
//
// The returned version is either the same as the input argument `v` or it's a
// cloned version if the input argument was either active or locked.
func (ac *OptionalAutoClone) Parse(v *fastly.Version, sid string, verbose bool) (*fastly.Version, error) {
// if user didn't provide --autoclone flag
if !ac.Value && (v.Active || v.Locked) {
return nil, fmt.Errorf("service version %d is not editable", v.Number)
}
if ac.Value && (v.Active || v.Locked) {
version, err := ac.Client.CloneVersion(&fastly.CloneVersionInput{
ServiceID: sid,
ServiceVersion: v.Number,
})
if err != nil {
return nil, fmt.Errorf("error cloning service version: %w", err)
}
if verbose {
msg := fmt.Sprintf("Service version %d is not editable, so it was automatically cloned because --autoclone is enabled. Now operating on version %d.", v.Number, version.Number)
text.Output(ac.Out, msg)
text.Break(ac.Out)
}
return version, nil
}

// Treat the function as a no-op if the version is editable.
return v, nil
}

// getActiveVersion returns the active service version.
func getActiveVersion(vs []*fastly.Version) (*fastly.Version, error) {
for _, v := range vs {
if v.Active {
return v, nil
}
}
return nil, fmt.Errorf("no active service version found")
}

// getSpecifiedVersion returns the specified service version.
func getSpecifiedVersion(vs []*fastly.Version, version string) (*fastly.Version, error) {
i, err := strconv.Atoi(version)
if err != nil {
return nil, err
}

for _, v := range vs {
if v.Number == i {
return v, nil
}
}

return nil, fmt.Errorf("specified service version not found: %s", version)
}
Loading
0