Skip to content
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

Improving error message for typos on kool run #252

Merged
merged 1 commit into from
Feb 1, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 30 additions & 1 deletion cmd/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,31 @@ package parser

import (
"errors"
"kool-dev/kool/cmd/builder"
"fmt"
"os"
"path"
"sort"
"strings"

"kool-dev/kool/cmd/builder"
)

// ErrPossibleTypo implements error interface and can be used
// to determine specific situations of not-found scripts but
// where similar names exist, indicating a possible typo
type ErrPossibleTypo struct {
similars []string
}

// Error formats a default string with the similar names found
func (e *ErrPossibleTypo) Error() string {
if len(e.similars) == 1 {
return fmt.Sprintf("did you mean '%s'?", e.similars[0])
}

return fmt.Sprintf("did you mean one of ['%s']?", strings.Join(e.similars, "', '"))
}

// Parser defines the functions required for handling kool.yml files.
type Parser interface {
AddLookupPath(string) error
Expand Down Expand Up @@ -67,6 +85,7 @@ func (p *DefaultParser) Parse(script string) (commands []builder.Command, err er
parsedFile *KoolYaml
found bool
previouslyFound bool
similarScripts []string
)

if len(p.targetFiles) == 0 {
Expand All @@ -92,8 +111,18 @@ func (p *DefaultParser) Parse(script string) (commands []builder.Command, err er
// in another file! let's warn about that
err = ErrMultipleDefinedScript
}
} else {
// we could not find the intented script so let's check for a typo
if foundSimilar, similars := parsedFile.GetSimilars(script); foundSimilar {
similarScripts = append(similarScripts, similars...)
}
}
}

if err == nil && len(commands) == 0 && similarScripts != nil && len(similarScripts) > 0 {
err = &ErrPossibleTypo{similarScripts}
}

return
}

Expand Down
21 changes: 21 additions & 0 deletions cmd/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@ import (
"kool-dev/kool/cmd/builder"
"os"
"path"
"strings"
"testing"
)

func TestErrPossibleTypo(t *testing.T) {
err := &ErrPossibleTypo{[]string{"script1"}}

if !strings.Contains(err.Error(), "script1") {
t.Errorf("unexpected error message: %s", err.Error())
}

err = &ErrPossibleTypo{[]string{"script1", "script2"}}

if !strings.Contains(err.Error(), "script1") || !strings.Contains(err.Error(), "script2") {
t.Errorf("unexpected error message [2]: %s", err.Error())
}
}

func TestDefaultParser(t *testing.T) {
var p Parser = NewParser()

Expand Down Expand Up @@ -67,6 +82,12 @@ func TestParserParse(t *testing.T) {
t.Error("failed to parse testing kool.yml")
}

if _, err = p.Parse("testin"); err == nil {
t.Error("unexpected non-error on typo")
} else if _, foundSimilar := err.(*ErrPossibleTypo); !foundSimilar {
t.Errorf("unexpected error; should be ErrPossibleTypo; got %s", err)
}

if commands, err = p.Parse("invalid"); err != nil {
t.Errorf("unexpected error; error: %s", err)
}
Expand Down
17 changes: 17 additions & 0 deletions cmd/parser/yml.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ import (
"kool-dev/kool/cmd/builder"
"os"

"github.com/agnivade/levenshtein"
"gopkg.in/yaml.v2"
)

// SimilarThreshold represents the minimal Levenshteindistance of two
// script names for them to be considered similarss
const SimilarThreshold int = 2

type yamlMarshalFnType func(interface{}) ([]byte, error)

// KoolYaml holds the structure for parsing the custom commands file
Expand Down Expand Up @@ -70,6 +75,18 @@ func (y *KoolYaml) HasScript(script string) (has bool) {
return
}

// GetSimilars checks for scripts with similar name.
func (y *KoolYaml) GetSimilars(script string) (has bool, similars []string) {
var name string
for name = range y.Scripts {
if levenshtein.ComputeDistance(name, script) < SimilarThreshold {
has = true
similars = append(similars, name)
}
}
return
}

// ParseCommands parsed the given script from kool.yml file onto a list
// of commands parsed.
func (y *KoolYaml) ParseCommands(script string) (commands []builder.Command, err error) {
Expand Down
4 changes: 4 additions & 0 deletions cmd/parser/yml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func TestParseKoolYaml(t *testing.T) {
return
}

if hasSimilars, similars := parsed.GetSimilars("single-lne"); !hasSimilars || len(similars) != 1 {
t.Errorf("unexpected return on GetSimilars %v - %v", hasSimilars, similars)
}

if cmds, err = parsed.ParseCommands("single-line"); err != nil {
t.Errorf("failed to parse proper single-line; error: %s", err)
return
Expand Down
8 changes: 3 additions & 5 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,20 @@ func NewKoolRun() *KoolRun {
// Execute runs the run logic with incoming arguments.
func (r *KoolRun) Execute(originalArgs []string) (err error) {
var (
script string
args []string
script string = originalArgs[0]
args []string = originalArgs[1:]
)

// look for kool.yml on current working directory
_ = r.parser.AddLookupPath(r.envStorage.Get("PWD"))
// look for kool.yml on kool folder within user home directory
_ = r.parser.AddLookupPath(path.Join(r.envStorage.Get("HOME"), "kool"))

script = originalArgs[0]
args = originalArgs[1:]

if r.commands, err = r.parser.Parse(script); err != nil {
if parser.IsMultipleDefinedScriptError(err) {
// we should just warn the user about multiple finds for the script
r.Warning("Attention: the script was found in more than one kool.yml file")
err = nil
} else {
return
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.14

require (
github.com/AlecAivazis/survey/v2 v2.1.1
github.com/agnivade/levenshtein v1.1.0
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
github.com/blang/semver v3.5.1+incompatible
github.com/creack/pty v1.1.11
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
Expand Down Expand Up @@ -95,6 +98,7 @@ github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd h1:uVsMph
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
Expand Down