-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Bump go-fastly to v1.7.0 * Add golang-petname dep * Add NullProgress writer * Add UndoStack to pkg/common * Persist user email to global config file * Make `compute init` accept input interactively and add logic to provision service, domain and backend during initialization. * Surpress gosec G307 on file.Close() defers * Add RunIfError method to UndoStack which unwinds the stack if passed an error * Add text.Description() output helper to print term:description groupings. * Refactor compute init to use new helpers
- Loading branch information
Showing
18 changed files
with
656 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package common | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
) | ||
|
||
// UndoFn is a function with no arguments which returns an error or nil. | ||
type UndoFn func() error | ||
|
||
// UndoStack models a simple undo stack which consumers can use to store undo | ||
// stateful functions, such as a function to teardown API state if something | ||
// goes wrong during procedural commands, for example deleting a Fastly service | ||
// after it's been created. | ||
type UndoStack struct { | ||
states []UndoFn | ||
} | ||
|
||
// NewUndoStack constructs a new UndoStack. | ||
func NewUndoStack() *UndoStack { | ||
s := make([]UndoFn, 0, 1) | ||
stack := &UndoStack{ | ||
states: s, | ||
} | ||
return stack | ||
} | ||
|
||
// Pop method pops last added UndoFn element oof the stack and returns it. | ||
// If stack is empty Pop() returns nil. | ||
func (s *UndoStack) Pop() UndoFn { | ||
n := len(s.states) | ||
if n == 0 { | ||
return nil | ||
} | ||
v := s.states[n-1] | ||
s.states = s.states[:n-1] | ||
return v | ||
} | ||
|
||
// Push method pushes an Undoer element onto the UndoStack. | ||
func (s *UndoStack) Push(elem UndoFn) { | ||
s.states = append(s.states, elem) | ||
} | ||
|
||
// Len method returns the number of elements in the UndoStack. | ||
func (s *UndoStack) Len() int { | ||
return len(s.states) | ||
} | ||
|
||
// RunIfError unwinds the stack if a non-nil error is passed, by serially | ||
// calling each UndoFn function state in FIFO order. If any UndoFn returns an | ||
// error, it gets logged to the provided writer. Should be deferrerd, such as: | ||
// | ||
// undoStack := common.NewUndoStack() | ||
// defer undoStack.RunIfError(w, err) | ||
// | ||
func (s *UndoStack) RunIfError(w io.Writer, err error) { | ||
if err == nil { | ||
return | ||
} | ||
for i := len(s.states) - 1; i >= 0; i-- { | ||
if err := s.states[i](); err != nil { | ||
fmt.Fprintf(w, "%w", err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,20 +33,86 @@ func TestInit(t *testing.T) { | |
for _, testcase := range []struct { | ||
name string | ||
args []string | ||
configFile config.File | ||
api mock.API | ||
wantFiles []string | ||
unwantedFiles []string | ||
stdin string | ||
wantError string | ||
wantOutput []string | ||
manifestIncludes string | ||
}{ | ||
{ | ||
name: "unkown repository", | ||
args: []string{"compute", "init", "--from", "https://example.com/template"}, | ||
name: "no token", | ||
args: []string{"compute", "init"}, | ||
wantError: "no token provided", | ||
}, | ||
{ | ||
name: "unkown repository", | ||
args: []string{"compute", "init", "--from", "https://example.com/template"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainOK, | ||
CreateBackendFn: createBackendOK, | ||
DeleteServiceFn: deleteServiceOK, | ||
DeleteBackendFn: deleteBackendOK, | ||
DeleteDomainFn: deleteDomainOK, | ||
}, | ||
wantError: "error fetching package template: repository not found", | ||
}, | ||
{ | ||
name: "with name", | ||
args: []string{"compute", "init", "--name", "test"}, | ||
name: "create service error", | ||
args: []string{"compute", "init"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceError, | ||
}, | ||
wantError: "error creating service: fixture error", | ||
}, | ||
{ | ||
name: "create domain error", | ||
args: []string{"compute", "init"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainError, | ||
DeleteServiceFn: deleteServiceOK, | ||
}, | ||
wantError: "error creating domain: fixture error", | ||
}, | ||
{ | ||
name: "create backend error", | ||
args: []string{"compute", "init"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainOK, | ||
CreateBackendFn: createBackendError, | ||
DeleteServiceFn: deleteServiceOK, | ||
DeleteDomainFn: deleteDomainOK, | ||
}, | ||
wantError: "error creating backend: fixture error", | ||
}, | ||
{ | ||
name: "with name", | ||
args: []string{"compute", "init", "--name", "test"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainOK, | ||
CreateBackendFn: createBackendOK, | ||
}, | ||
wantOutput: []string{ | ||
"Initializing...", | ||
"Fetching package template...", | ||
|
@@ -55,20 +121,54 @@ func TestInit(t *testing.T) { | |
manifestIncludes: `name = "test"`, | ||
}, | ||
{ | ||
name: "with service", | ||
args: []string{"compute", "init", "--service-id", "test"}, | ||
name: "with description", | ||
args: []string{"compute", "init", "--description", "test"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainOK, | ||
CreateBackendFn: createBackendOK, | ||
}, | ||
wantOutput: []string{ | ||
"Initializing...", | ||
"Fetching package template...", | ||
"Updating package manifest..", | ||
}, | ||
manifestIncludes: `description = "test"`, | ||
}, | ||
{ | ||
name: "with author", | ||
args: []string{"compute", "init", "--author", "[email protected]"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainOK, | ||
CreateBackendFn: createBackendOK, | ||
}, | ||
wantOutput: []string{ | ||
"Initializing...", | ||
"Fetching package template...", | ||
"Updating package manifest..", | ||
}, | ||
manifestIncludes: `service_id = "test"`, | ||
manifestIncludes: `authors = ["test@example.com"]`, | ||
}, | ||
{ | ||
name: "default", | ||
args: []string{"compute", "init"}, | ||
name: "default", | ||
args: []string{"compute", "init"}, | ||
configFile: config.File{Token: "123"}, | ||
api: mock.API{ | ||
GetTokenSelfFn: tokenOK, | ||
GetUserFn: getUserOk, | ||
CreateServiceFn: createServiceOK, | ||
CreateDomainFn: createDomainOK, | ||
CreateBackendFn: createBackendOK, | ||
}, | ||
wantFiles: []string{ | ||
"cargo.toml", | ||
"Cargo.toml", | ||
"fastly.toml", | ||
"src/main.rs", | ||
}, | ||
|
@@ -108,12 +208,12 @@ func TestInit(t *testing.T) { | |
var ( | ||
args = testcase.args | ||
env = config.Environment{} | ||
file = config.File{} | ||
file = testcase.configFile | ||
appConfigFile = "/dev/null" | ||
clientFactory = mock.APIClient(mock.API{}) | ||
clientFactory = mock.APIClient(testcase.api) | ||
httpClient = http.DefaultClient | ||
versioner update.Versioner = nil | ||
in io.Reader = nil | ||
in io.Reader = bytes.NewBufferString(testcase.stdin) | ||
buf bytes.Buffer | ||
out io.Writer = common.NewSyncWriter(&buf) | ||
) | ||
|
@@ -836,6 +936,60 @@ func copyFile(t *testing.T, fromFilename, toFilename string) { | |
|
||
var errTest = errors.New("fixture error") | ||
|
||
func tokenOK() (*fastly.Token, error) { return &fastly.Token{}, nil } | ||
|
||
func getUserOk(i *fastly.GetUserInput) (*fastly.User, error) { | ||
return &fastly.User{Login: "[email protected]"}, nil | ||
} | ||
|
||
func createServiceOK(i *fastly.CreateServiceInput) (*fastly.Service, error) { | ||
return &fastly.Service{ | ||
ID: "12345", | ||
Name: i.Name, | ||
Type: i.Type, | ||
}, nil | ||
} | ||
|
||
func createServiceError(*fastly.CreateServiceInput) (*fastly.Service, error) { | ||
return nil, errTest | ||
} | ||
|
||
func deleteServiceOK(i *fastly.DeleteServiceInput) error { | ||
return nil | ||
} | ||
|
||
func createDomainOK(i *fastly.CreateDomainInput) (*fastly.Domain, error) { | ||
return &fastly.Domain{ | ||
ServiceID: i.Service, | ||
Version: i.Version, | ||
Name: i.Name, | ||
}, nil | ||
} | ||
|
||
func createDomainError(i *fastly.CreateDomainInput) (*fastly.Domain, error) { | ||
return nil, errTest | ||
} | ||
|
||
func deleteDomainOK(i *fastly.DeleteDomainInput) error { | ||
return nil | ||
} | ||
|
||
func createBackendOK(i *fastly.CreateBackendInput) (*fastly.Backend, error) { | ||
return &fastly.Backend{ | ||
ServiceID: i.Service, | ||
Version: i.Version, | ||
Name: i.Name, | ||
}, nil | ||
} | ||
|
||
func createBackendError(i *fastly.CreateBackendInput) (*fastly.Backend, error) { | ||
return nil, errTest | ||
} | ||
|
||
func deleteBackendOK(i *fastly.DeleteBackendInput) error { | ||
return nil | ||
} | ||
|
||
func latestVersionInactiveOk(i *fastly.LatestVersionInput) (*fastly.Version, error) { | ||
return &fastly.Version{ServiceID: i.Service, Number: 1, Active: false}, nil | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.