chore: add lint to GH actions CI

This commit is contained in:
Matej Vasek 2020-07-29 17:47:08 +02:00 committed by GitHub
parent c3d983907d
commit 4677b3452f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 210 additions and 108 deletions

View File

@ -23,3 +23,5 @@ jobs:
run: make test
- name: Build
run: make build
- name: Lint
run: make check

View File

@ -23,3 +23,5 @@ jobs:
run: make test
- name: Build
run: make build
- name: Lint
run: make check

View File

@ -13,3 +13,5 @@ jobs:
run: make test
- name: Build
run: make build
- name: Lint
run: make check

View File

@ -58,6 +58,12 @@ latest:
# (run by CI only for releases)
docker push $(REPO):latest
bin/golangci-lint:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./bin v1.27.0
check: bin/golangci-lint
./bin/golangci-lint run --enable=unconvert,prealloc,bodyclose
clean:
rm -f $(WINDOWS) $(LINUX) $(DARWIN)
-@rm -f coverage.out

View File

@ -61,7 +61,8 @@ func (n *Builder) Build(name, runtime, path string) (image string, err error) {
err = cmd.Run()
if err != nil {
// TODO: sanitize stderr from appsody, or submit a PR to remove duplicates etc.
err = errors.New(fmt.Sprintf("%v. %v", string(stderr.Bytes()), err.Error()))
err = fmt.Errorf("%v. %v", stderr.String(), err.Error())
return
}
// remove the superfluous app-deploy.yaml
@ -69,7 +70,7 @@ func (n *Builder) Build(name, runtime, path string) (image string, err error) {
if _, err = os.Stat(cfg); err == nil {
err = os.Remove(cfg)
if err != nil {
fmt.Fprintf(os.Stderr, fmt.Sprintf("unable to remove superfluous appsody config: %v\n", err))
fmt.Fprintf(os.Stderr,"unable to remove superfluous appsody config: %v\n", err)
}
}
return

View File

@ -52,11 +52,11 @@ func (n *Initializer) Initialize(name, runtime, path string) error {
stackName, ok := StackShortNames[runtime]
if !ok {
runtimes := []string{}
for k, _ := range StackShortNames {
for k := range StackShortNames {
runtimes = append(runtimes, k)
}
return errors.New(fmt.Sprintf("Unrecognized runtime '%v'. Please choose one: %v.", runtime, strings.Join(runtimes, ", ")))
return fmt.Errorf("Unrecognized runtime '%v'. Please choose one: %v.", runtime, strings.Join(runtimes, ", "))
}
// set up the command, specifying a sanitized project name and connecting
@ -78,7 +78,7 @@ func (n *Initializer) Initialize(name, runtime, path string) error {
err = cmd.Run()
if err != nil {
// TODO: sanitize stderr from appsody, or submit a PR to remove duplicates etc.
err = errors.New(fmt.Sprintf("%v. %v", string(stderr.Bytes()), err.Error()))
err = fmt.Errorf("%v. %v", stderr.String(), err.Error())
}
return err
}

View File

@ -343,7 +343,7 @@ func (c *Client) Update(root string) (err error) {
if !f.Initialized() {
// TODO: this needs a test.
return errors.New(fmt.Sprintf("the given path '%v' does not contain an initialized Function. Please create one at this path before updating.", root))
return fmt.Errorf("the given path '%v' does not contain an initialized Function. Please create one at this path before updating.", root)
}
// Build an image from the current state of the service function's implementation.
@ -373,7 +373,7 @@ func (c *Client) Run(root string) error {
if !f.Initialized() {
// TODO: this needs a test.
return errors.New(fmt.Sprintf("the given path '%v' does not contain an initialized Function. Please create one at this path in order to run.", root))
return fmt.Errorf("the given path '%v' does not contain an initialized Function. Please create one at this path in order to run.", root)
}
// delegate to concrete implementation of runner entirely.
@ -400,7 +400,7 @@ func (c *Client) Describe(name, root string) (fd FunctionDescription, err error)
return fd, err
}
if !f.Initialized() {
return fd, errors.New(fmt.Sprintf("%v is not initialized", f.name))
return fd, fmt.Errorf("%v is not initialized", f.name)
}
return c.describer.Describe(f.name)
}
@ -419,7 +419,7 @@ func (c *Client) Remove(name, root string) error {
return err
}
if !f.Initialized() {
return errors.New(fmt.Sprintf("%v is not initialized", f.name))
return fmt.Errorf("%v is not initialized", f.name)
}
return c.remover.Remove(f.name)
}

View File

@ -1,7 +1,6 @@
package faas_test
import (
"errors"
"fmt"
"os"
"path/filepath"
@ -45,7 +44,10 @@ func TestCreate(t *testing.T) {
// Create the test function root
root := "testdata/example.com/admin"
os.MkdirAll(root, 0700)
err = os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
// A supported langauge should not error
@ -61,7 +63,10 @@ func TestCreateUnderivableName(t *testing.T) {
// Create the test function root
root := "testdata/example.com/admin"
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
// Instantiation without an explicit service name, but no derivable service
@ -127,7 +132,10 @@ func TestCreateDelegates(t *testing.T) {
)
// Create the test function root
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
client, err := faas.New(
@ -166,7 +174,7 @@ func TestCreateDelegates(t *testing.T) {
// function code. For this test, it is a name derived from the test path.
// An example image name is returned.
builder.BuildFn = func(name2, path2 string) (string, error) {
if name != name {
if name != name2 {
t.Fatalf("builder expected name %v, got '%v'", name, name2)
}
expectedPath, err := filepath.Abs(root)
@ -242,11 +250,17 @@ func TestCreateLocal(t *testing.T) {
)
// Create the test function root
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
// Create the test function root
os.MkdirAll(root, 0700)
err = os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
client, err := faas.New(
@ -288,7 +302,10 @@ func TestCreateInternal(t *testing.T) {
func TestCreateDomain(t *testing.T) {
// Create the test function root
root := "testdata/example.com/admin"
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
// the mock dns provider does nothing but receive the caluclated
@ -321,7 +338,10 @@ func TestCreateDomain(t *testing.T) {
func TestCreateSubdomain(t *testing.T) {
// Create the test function root
root := "testdata/example.com/admin"
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
dnsProvider := mock.NewDNSProvider()
@ -397,7 +417,7 @@ func TestUpdate(t *testing.T) {
// function code. For this test, it is a name derived from the test path.
// An example image name is returned.
builder.BuildFn = func(name2, path2 string) (string, error) {
if name != name {
if name != name2 {
t.Fatalf("builder expected name %v, got '%v'", name, name2)
}
// The final image name will be determined by the builder implementation,
@ -485,12 +505,15 @@ func TestRemoveUninitializedFails(t *testing.T) {
root = "testdata/example.com/admin"
remover = mock.NewRemover()
)
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
// Create a remover delegate which fails if invoked.
remover.RemoveFn = func(name string) error {
return errors.New(fmt.Sprintf("remove invoked for unitialized function %v", name))
return fmt.Errorf("remove invoked for unitialized function %v", name)
}
// Instantiate the client with the failing remover.
@ -549,7 +572,10 @@ func TestWithName(t *testing.T) {
// Path which would derive to service.groupA.example.com were it not for the
// explicitly provided name.
path := "testdata/example.com/groupA/service"
os.MkdirAll(path, 0700)
err := os.MkdirAll(path, 0700)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
initializer := mock.NewInitializer()

View File

@ -35,8 +35,8 @@ source <(faas completion bash)
return errors.New("missing argument")
}
if args[0] == "bash" {
root.GenBashCompletion(os.Stdout)
return nil
err = root.GenBashCompletion(os.Stdout)
return err
}
if args[0] == "zsh" {
// manually edited script based on `root.GenZshCompletion(os.Stdout)`

View File

@ -29,7 +29,7 @@ func CompleteFunctionList(cmd *cobra.Command, args []string, toComplete string)
}
func CompleteRuntimeList(cmd *cobra.Command, args []string, toComplete string) (strings []string, directive cobra.ShellCompDirective) {
strings = make([]string, 0, len(appsody.StackShortNames))
for lang, _ := range appsody.StackShortNames {
for lang := range appsody.StackShortNames {
strings = append(strings, lang)
}
directive = cobra.ShellCompDirectiveDefault
@ -62,7 +62,7 @@ func CompleteRegistryList(cmd *cobra.Command, args []string, toComplete string)
return
}
strings = make([]string, len(auth))
for reg, _ := range auth {
for reg := range auth {
strings = append(strings, reg)
}
directive = cobra.ShellCompDirectiveDefault

View File

@ -3,13 +3,11 @@ package cmd
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/mitchellh/go-homedir"
"github.com/ory/viper"
"github.com/spf13/cobra"
"os"
"path/filepath"
"github.com/boson-project/faas"
"github.com/boson-project/faas/buildpacks"
@ -30,7 +28,10 @@ func init() {
createCmd.Flags().StringP("namespace", "s", "", "namespace at image registry (usually username or org name). $FAAS_NAMESPACE")
createCmd.Flags().StringP("template", "t", embedded.DefaultTemplate, "Function template (ex: 'http','events'). $FAAS_TEMPLATE")
createCmd.Flags().StringP("templates", "", filepath.Join(configPath(), "faas", "templates"), "Extensible templates path. $FAAS_TEMPLATES")
createCmd.RegisterFlagCompletionFunc("registry", CompleteRegistryList)
err := createCmd.RegisterFlagCompletionFunc("registry", CompleteRegistryList)
if err != nil {
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
}
}
// The create command invokes the Funciton Client to create a new,
@ -44,13 +45,13 @@ var createCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
RunE: create,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlag("local", cmd.Flags().Lookup("local"))
viper.BindPFlag("internal", cmd.Flags().Lookup("internal"))
viper.BindPFlag("name", cmd.Flags().Lookup("name"))
viper.BindPFlag("registry", cmd.Flags().Lookup("registry"))
viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace"))
viper.BindPFlag("template", cmd.Flags().Lookup("template"))
viper.BindPFlag("templates", cmd.Flags().Lookup("templates"))
flags := []string{"local", "internal", "name", "registry", "namespace", "template", "templates"}
for _, f := range flags {
err := viper.BindPFlag(f, cmd.Flags().Lookup(f))
if err != nil {
panic(err)
}
}
},
}
@ -224,13 +225,6 @@ func promptForName(label string, config createConfig) (string, error) {
return prompt.ForString("Name of service function", config.Name, prompt.WithRequired(true)), nil
}
// acceptable answers: y,yes,Y,YES,1
var confirmExp = regexp.MustCompile("(?i)y(?:es)?|1")
func fromYN(s string) bool {
return confirmExp.MatchString(s)
}
func configPath() (path string) {
if path = os.Getenv("XDG_CONFIG_HOME"); path != "" {
return

View File

@ -1,6 +1,7 @@
package cmd
import (
"fmt"
"github.com/boson-project/faas"
"github.com/boson-project/faas/knative"
"github.com/ory/viper"
@ -10,7 +11,10 @@ import (
func init() {
root.AddCommand(deleteCmd)
deleteCmd.Flags().StringP("name", "n", "", "optionally specify an explicit name to remove, overriding path-derivation. $FAAS_NAME")
deleteCmd.RegisterFlagCompletionFunc("name", CompleteFunctionList)
err := deleteCmd.RegisterFlagCompletionFunc("name", CompleteFunctionList)
if err != nil {
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
}
}
var deleteCmd = &cobra.Command{
@ -20,7 +24,10 @@ var deleteCmd = &cobra.Command{
SuggestFor: []string{"remove", "rm"},
RunE: delete,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlag("name", cmd.Flags().Lookup("name"))
err := viper.BindPFlag("name", cmd.Flags().Lookup("name"))
if err != nil {
panic(err)
}
},
}

View File

@ -21,9 +21,15 @@ func init() {
describeCmd.Flags().StringP("name", "n", "", "optionally specify an explicit name for the serive, overriding path-derivation. $FAAS_NAME")
describeCmd.RegisterFlagCompletionFunc("name", CompleteFunctionList)
err := describeCmd.RegisterFlagCompletionFunc("name", CompleteFunctionList)
if err != nil {
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
}
describeCmd.RegisterFlagCompletionFunc("output", CompleteOutputFormatList)
err = describeCmd.RegisterFlagCompletionFunc("output", CompleteOutputFormatList)
if err != nil {
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
}
}
var describeCmd = &cobra.Command{
@ -35,8 +41,14 @@ var describeCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
RunE: describe,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlag("output", cmd.Flags().Lookup("output"))
viper.BindPFlag("name", cmd.Flags().Lookup("name"))
err := viper.BindPFlag("output", cmd.Flags().Lookup("output"))
if err != nil {
panic(err)
}
err = viper.BindPFlag("name", cmd.Flags().Lookup("name"))
if err != nil {
panic(err)
}
},
}

View File

@ -40,7 +40,10 @@ func init() {
// which thus overrides both the default and the value read in from the
// config file (i.e. flags always take highest precidence).
root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", verbose, "print verbose logs")
viper.BindPFlag("verbose", root.PersistentFlags().Lookup("verbose"))
err := viper.BindPFlag("verbose", root.PersistentFlags().Lookup("verbose"))
if err != nil {
panic(err)
}
// Override the --version template to match the output format from the
// version subcommand: nothing but the version.

View File

@ -17,7 +17,10 @@ func init() {
root.AddCommand(updateCmd)
updateCmd.Flags().StringP("registry", "r", "quay.io", "image registry (ex: quay.io). $FAAS_REGISTRY")
updateCmd.Flags().StringP("namespace", "s", "", "namespace at image registry (usually username or org name). $FAAS_NAMESPACE")
updateCmd.RegisterFlagCompletionFunc("registry", CompleteRegistryList)
err := updateCmd.RegisterFlagCompletionFunc("registry", CompleteRegistryList)
if err != nil {
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
}
}
var updateCmd = &cobra.Command{
@ -27,8 +30,14 @@ var updateCmd = &cobra.Command{
SuggestFor: []string{"push", "deploy"},
RunE: update,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlag("registry", cmd.Flags().Lookup("registry"))
viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace"))
err := viper.BindPFlag("registry", cmd.Flags().Lookup("registry"))
if err != nil {
panic(err)
}
err = viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace"))
if err != nil {
panic(err)
}
},
}

View File

@ -47,7 +47,7 @@ func (n *Pusher) Push(image string) (err error) {
err = cmd.Run()
if err != nil {
// TODO: sanitize stderr from appsody, or submit a PR to remove duplicates etc.
err = errors.New(fmt.Sprintf("%v. %v", string(stderr.Bytes()), err.Error()))
err = fmt.Errorf("%v. %v", stderr.String(), err.Error())
}
return
}

View File

@ -39,7 +39,7 @@ type file interface {
// a pkger FileAccessor.
// Path is relative to the go module root.
func init() {
pkger.Include("/templates")
_ = pkger.Include("/templates")
}
type Initializer struct {
@ -68,7 +68,7 @@ func (n *Initializer) Initialize(runtime, template string, dest string) error {
if n.templates != "" {
return copyFilesystem(n.templates, runtime, template, dest)
}
return errors.New(fmt.Sprintf("A template for runtime '%v' template '%v' was not found internally and no extended repository path was defined.", runtime, template))
return fmt.Errorf("A template for runtime '%v' template '%v' was not found internally and no extended repository path was defined.", runtime, template)
}
func copyEmbedded(runtime, template, dest string) error {

View File

@ -14,10 +14,13 @@ func TestInitialize(t *testing.T) {
testFile = "handle.go"
template = "http"
)
os.MkdirAll(path, 0744)
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
err := NewInitializer("").Initialize("go", template, path)
err = NewInitializer("").Initialize("go", template, path)
if err != nil {
t.Fatal(err)
}
@ -35,10 +38,13 @@ func TestDefaultTemplate(t *testing.T) {
testFile = "handle.go"
template = ""
)
os.MkdirAll(path, 0744)
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
err := NewInitializer("").Initialize("go", template, path)
err = NewInitializer("").Initialize("go", template, path)
if err != nil {
t.Fatal(err)
}
@ -64,11 +70,14 @@ func TestCustom(t *testing.T) {
template = "boson-experimental/json"
// repos = "testdata/templates"
)
os.MkdirAll(path, 0744)
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
// Unrecognized runtime/template should error
err := NewInitializer("").Initialize("go", template, path)
err = NewInitializer("").Initialize("go", template, path)
if err == nil {
t.Fatal("An unrecognized runtime/template should generate an error")
}
@ -91,7 +100,10 @@ func TestCustom(t *testing.T) {
// written with the same mode from whence they came
func TestEmbeddedFileMode(t *testing.T) {
var path = "testdata/example.com/www"
os.MkdirAll(path, 0744)
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
// Initialize a quarkus app from the embedded templates.
@ -119,11 +131,14 @@ func TestFileMode(t *testing.T) {
path = "testdata/example.com/www"
template = "boson-experimental/http"
)
os.MkdirAll(path, 0744)
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
// Initialize a quarkus app from the custom repo in ./testdata
if err := NewInitializer("testdata/templates").Initialize("quarkus", template, path); err != nil {
if err = NewInitializer("testdata/templates").Initialize("quarkus", template, path); err != nil {
t.Fatal(err)
}

View File

@ -15,8 +15,6 @@ type Function struct {
root string
runtime string // will be empty unless initialized/until initialized
name string // will be empty unless initialized/until initialized.
initializer Initializer
}
func NewFunction(root string) (f *Function, err error) {
@ -55,7 +53,7 @@ func (f *Function) Initialize(runtime, context, name string, domainSearchLimit i
if err != nil {
return
} else if len(files) > 0 {
return errors.New(fmt.Sprintf("The chosen directory '%v' contains contentious files: %v. Has the Service Function already been created? Try either using a different directory, deleting the service function if it exists, or manually removing the files.", f.root, files))
return fmt.Errorf("The chosen directory '%v' contains contentious files: %v. Has the Service Function already been created? Try either using a different directory, deleting the service function if it exists, or manually removing the files.", f.root, files)
}
// Ensure there are no non-hidden files, and again none of the aforementioned contentious files.

View File

@ -1,6 +1,7 @@
package faas
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
@ -85,7 +86,11 @@ func TestApplyConfig(t *testing.T) {
// Create a temporary directory
root := "./testdata/example.com/cfgtest"
cfgFile := filepath.Join(root, ConfigFileName)
os.MkdirAll(root, 0700)
err := os.MkdirAll(root, 0700)
if err != nil {
fmt.Println("Error on TestApplyConfig: ", err)
return
}
defer os.RemoveAll(root)
c := Function{name: "staticDefault"}

View File

@ -57,7 +57,7 @@ func (d *Updater) Update(name, image string) (err error) {
// Run the command, echoing captured stderr as well ass the cmd internal error.
if err = cmd.Run(); err != nil {
// TODO: sanitize stderr from appsody, or submit a PR to remove duplicates etc.
return errors.New(fmt.Sprintf("%v. %v", string(stderr.Bytes()), err.Error()))
return fmt.Errorf("%v. %v", stderr.String(), err.Error())
}
// TODO: explicitly pull address:

View File

@ -2,7 +2,6 @@ package knative
import (
"bytes"
"errors"
"fmt"
"github.com/boson-project/faas"
"github.com/boson-project/faas/k8s"
@ -30,13 +29,14 @@ func (deployer *Deployer) Deploy(name, image string) (address string, err error)
}
nn := strings.Split(name, ".")
if len(nn) < 3 {
err = errors.New(fmt.Sprintf("invalid service name '%v', must be at least three parts.\n", name))
err = fmt.Errorf("invalid service name '%v', must be at least three parts.\n", name)
return
}
subDomain := nn[0]
domain := strings.Join(nn[1:], ".")
output := io.Writer(nil)
var output io.Writer
if deployer.Verbose {
output = os.Stdout
} else {

View File

@ -27,7 +27,7 @@ func (remover *Remover) Remove(name string) (err error) {
return
}
output := io.Writer(nil)
var output io.Writer
if remover.Verbose {
output = os.Stdout
} else {

View File

@ -85,7 +85,7 @@ func (d *Deployer) Deploy(name, image string) (address string, err error) {
nn := strings.Split(name, ".")
if len(nn) < 3 {
err = errors.New(fmt.Sprintf("invalid service name '%v', must be at least three parts.\n", name))
err = fmt.Errorf("invalid service name '%v', must be at least three parts.\n", name)
}
subdomain := nn[0]
domain := strings.Join(nn[1:], ".")
@ -122,7 +122,7 @@ func (d *Deployer) Deploy(name, image string) (address string, err error) {
err = cmd.Run()
if err != nil {
// TODO: sanitize stderr from appsody, or submit a PR to remove duplicates etc.
err = errors.New(fmt.Sprintf("%v. %v", string(stderr.Bytes()), err.Error()))
err = fmt.Errorf("%v. %v", stderr.String(), err.Error())
return
}

View File

@ -54,7 +54,7 @@ func (d *Remover) Remove(name string) (err error) {
// Run the command, echoing captured stderr as well as the cmd internal error.
err = cmd.Run()
if err != nil {
err = errors.New(fmt.Sprintf("%v. %v", string(stderr.Bytes()), err.Error()))
err = fmt.Errorf("%v. %v", stderr.String(), err.Error())
}
return
}

View File

@ -1,7 +1,6 @@
package mock
import (
"errors"
"fmt"
"strings"
)
@ -22,7 +21,7 @@ func NewInitializer() *Initializer {
func (i *Initializer) Initialize(runtime, template, path string) error {
i.InitializeInvoked = true
if !i.supportsRuntime(runtime) {
return errors.New(fmt.Sprintf("unsupported runtime '%v'", runtime))
return fmt.Errorf("unsupported runtime '%v'", runtime)
}
return i.InitializeFn(runtime, template, path)
}

View File

@ -196,7 +196,7 @@ func (b *Bar) overwrite(prefix string) {
func (b *Bar) spin(ch <-chan time.Time) {
spinner := []string{"|", "/", "-", "\\"}
idx := 0
for _ = range ch {
for range ch {
// Writes the spinner frame at the beginning of the previous line, moving
// the cursor back to the beginning of the current line for any errors or
// informative messages.

View File

@ -98,14 +98,23 @@ func ForString(label string, dflt string, options ...Option) string {
}
func writeStringLabel(p *stringPrompt) {
p.out.Write([]byte(p.label))
_, err := p.out.Write([]byte(p.label))
if err != nil {
panic(err)
}
if p.dflt != "" {
if p.label != "" {
p.out.Write([]byte(" "))
_, err = p.out.Write([]byte(" "))
if err != nil {
panic(err)
}
}
fmt.Fprintf(p.out, "(%v)", p.dflt)
}
p.out.Write([]byte(p.delim))
_, err = p.out.Write([]byte(p.delim))
if err != nil {
panic(err)
}
}
func readString(p *stringPrompt) (s string, err error) {
@ -151,16 +160,25 @@ func ForBool(label string, dflt bool, options ...Option) bool {
}
func writeBoolLabel(p *boolPrompt) {
p.out.Write([]byte(p.label))
if p.label != "" {
p.out.Write([]byte(" "))
_, err := p.out.Write([]byte(p.label))
if err != nil {
panic(err)
}
if p.dflt == true {
if p.label != "" {
_, err = p.out.Write([]byte(" "))
if err != nil {
panic(err)
}
}
if p.dflt {
fmt.Fprint(p.out, "(Y/n)")
} else {
fmt.Fprint(p.out, "(y/N)")
}
p.out.Write([]byte(p.delim))
_, err = p.out.Write([]byte(p.delim))
if err != nil {
panic(err)
}
}
func readBool(p *boolPrompt) (bool, error) {
@ -194,6 +212,9 @@ func isFalsy(confirm string) bool {
}
func writeError(err error, p *prompt) {
p.out.Write([]byte("\n"))
_, _err := p.out.Write([]byte("\n"))
if _err != nil {
panic(_err)
}
fmt.Fprintln(p.out, err)
}

View File

@ -18,8 +18,8 @@ func TestForStringLabel(t *testing.T) {
// Empty label
_ = prompt.ForString("", "",
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != ": " {
t.Fatalf("expected output to be ': ', got '%v'\n", string(out.Bytes()))
if out.String() != ": " {
t.Fatalf("expected output to be ': ', got '%v'\n", out.String())
}
out.Reset()
@ -30,8 +30,8 @@ func TestForStringLabel(t *testing.T) {
// Populated lable
_ = prompt.ForString("Name", "",
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != "Name: " {
t.Fatalf("expected 'Name', got '%v'\n", string(out.Bytes()))
if out.String() != "Name: " {
t.Fatalf("expected 'Name', got '%v'\n", out.String())
}
}
@ -45,8 +45,8 @@ func TestForStringLabelDefault(t *testing.T) {
// No lablel but a default
_ = prompt.ForString("", "Alice",
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != "(Alice): " {
t.Fatalf("expected '(Alice): ', got '%v'\n", string(out.Bytes()))
if out.String() != "(Alice): " {
t.Fatalf("expected '(Alice): ', got '%v'\n", out.String())
}
out.Reset()
@ -56,8 +56,8 @@ func TestForStringLabelDefault(t *testing.T) {
// Label with default
_ = prompt.ForString("Name", "Alice",
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != "Name (Alice): " {
t.Fatalf("expected 'Name (Alice): ', got '%v'\n", string(out.Bytes()))
if out.String()!= "Name (Alice): " {
t.Fatalf("expected 'Name (Alice): ', got '%v'\n", out.String())
}
}
@ -71,8 +71,8 @@ func TestWithDelimiter(t *testing.T) {
prompt.WithInput(&in),
prompt.WithOutput(&out),
prompt.WithDelimiter("Δ"))
if string(out.Bytes()) != "Δ" {
t.Fatalf("expected output to be 'Δ', got '%v'\n", string(out.Bytes()))
if out.String() != "Δ" {
t.Fatalf("expected output to be 'Δ', got '%v'\n", out.String())
}
}
@ -119,7 +119,7 @@ func TestForStringRequired(t *testing.T) {
prompt.WithRequired(true),
prompt.WithRetryLimit(1)) // makes the output buffer easier to confirm
output := string(out.Bytes())
output := out.String()
expected := ": \nplease enter a value\n: "
if output != expected {
t.Fatalf("Unexpected prompt received for a required value. expected '%v', got '%v'", expected, output)
@ -150,8 +150,8 @@ func TestForBoolLabel(t *testing.T) {
// Empty label, default false
_ = prompt.ForBool("", false,
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != "(y/N): " {
t.Fatalf("expected output to be '(y/N): ', got '%v'\n", string(out.Bytes()))
if out.String() != "(y/N): " {
t.Fatalf("expected output to be '(y/N): ', got '%v'\n", out.String())
}
out.Reset()
@ -162,8 +162,8 @@ func TestForBoolLabel(t *testing.T) {
// Empty label, default true
_ = prompt.ForBool("", true,
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != "(Y/n): " {
t.Fatalf("expected output to be '(Y/n): ', got '%v'\n", string(out.Bytes()))
if out.String() != "(Y/n): " {
t.Fatalf("expected output to be '(Y/n): ', got '%v'\n", out.String())
}
out.Reset()
@ -174,8 +174,8 @@ func TestForBoolLabel(t *testing.T) {
// Populated lablel default false
_ = prompt.ForBool("Local", false,
prompt.WithInput(&in), prompt.WithOutput(&out))
if string(out.Bytes()) != "Local (y/N): " {
t.Fatalf("expected 'Local (y/N): ', got '%v'\n", string(out.Bytes()))
if out.String() != "Local (y/N): " {
t.Fatalf("expected 'Local (y/N): ', got '%v'\n", out.String())
}
}