mirror of
https://github.com/go-task/task.git
synced 2025-01-04 03:48:02 +02:00
feat: suggest the most similar task name when a given task does not exist
This commit is contained in:
parent
d2061ec898
commit
3e5ee2332a
13
errors.go
13
errors.go
@ -13,11 +13,20 @@ var (
|
||||
)
|
||||
|
||||
type taskNotFoundError struct {
|
||||
taskName string
|
||||
taskName string
|
||||
didYouMean string
|
||||
}
|
||||
|
||||
func (err *taskNotFoundError) Error() string {
|
||||
return fmt.Sprintf(`task: Task %q not found`, err.taskName)
|
||||
if err.didYouMean != "" {
|
||||
return fmt.Sprintf(
|
||||
`task: Task %q does not exist. Did you mean %q?`,
|
||||
err.taskName,
|
||||
err.didYouMean,
|
||||
)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`task: Task %q does not exist`, err.taskName)
|
||||
}
|
||||
|
||||
type taskInternalError struct {
|
||||
|
1
go.mod
1
go.mod
@ -7,6 +7,7 @@ require (
|
||||
github.com/mattn/go-zglob v0.0.3
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/radovskyb/watcher v1.0.7
|
||||
github.com/sajari/fuzzy v1.0.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.0
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
|
2
go.sum
2
go.sum
@ -26,6 +26,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE=
|
||||
github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY=
|
||||
github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
2
help.go
2
help.go
@ -78,7 +78,7 @@ func (e *Executor) tasksWithDesc() (tasks []*taskfile.Task) {
|
||||
return
|
||||
}
|
||||
|
||||
// PrintTaskNames prints only the task names in a Taskfile.
|
||||
// ListTaskNames prints only the task names in a Taskfile.
|
||||
// Only tasks with a non-empty description are printed if allTasks is false.
|
||||
// Otherwise, all task names are printed.
|
||||
func (e *Executor) ListTaskNames(allTasks bool) {
|
||||
|
19
setup.go
19
setup.go
@ -17,6 +17,8 @@ import (
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/read"
|
||||
|
||||
"github.com/sajari/fuzzy"
|
||||
)
|
||||
|
||||
func (e *Executor) Setup() error {
|
||||
@ -28,6 +30,8 @@ func (e *Executor) Setup() error {
|
||||
return err
|
||||
}
|
||||
|
||||
e.setupFuzzyModel()
|
||||
|
||||
v, err := e.Taskfile.ParsedVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -85,6 +89,21 @@ func (e *Executor) readTaskfile() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Executor) setupFuzzyModel() {
|
||||
if e.Taskfile != nil {
|
||||
model := fuzzy.NewModel()
|
||||
model.SetThreshold(1) // because we want to build grammar based on every task name
|
||||
|
||||
var words []string
|
||||
for taskName := range e.Taskfile.Tasks {
|
||||
words = append(words, taskName)
|
||||
}
|
||||
|
||||
model.Train(words)
|
||||
e.fuzzyModel = model
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) setupTempDir() error {
|
||||
if e.TempDir != "" {
|
||||
return nil
|
||||
|
11
task.go
11
task.go
@ -16,6 +16,7 @@ import (
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/sajari/fuzzy"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@ -51,7 +52,8 @@ type Executor struct {
|
||||
Output output.Output
|
||||
OutputStyle taskfile.Output
|
||||
|
||||
taskvars *taskfile.Vars
|
||||
taskvars *taskfile.Vars
|
||||
fuzzyModel *fuzzy.Model
|
||||
|
||||
concurrencySemaphore chan struct{}
|
||||
taskCallCount map[string]*int32
|
||||
@ -68,7 +70,12 @@ func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
||||
if !ok {
|
||||
// FIXME: move to the main package
|
||||
e.ListTasksWithDesc()
|
||||
return &taskNotFoundError{taskName: c.Task}
|
||||
|
||||
didYouMean := ""
|
||||
if e.fuzzyModel != nil {
|
||||
didYouMean = e.fuzzyModel.SpellCheck(c.Task)
|
||||
}
|
||||
return &taskNotFoundError{taskName: c.Task, didYouMean: didYouMean}
|
||||
}
|
||||
if t.Internal {
|
||||
e.ListTasksWithDesc()
|
||||
|
@ -24,7 +24,11 @@ func (e *Executor) FastCompiledTask(call taskfile.Call) (*taskfile.Task, error)
|
||||
func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskfile.Task, error) {
|
||||
origTask, ok := e.Taskfile.Tasks[call.Task]
|
||||
if !ok {
|
||||
return nil, &taskNotFoundError{call.Task}
|
||||
didYouMean := ""
|
||||
if e.fuzzyModel != nil {
|
||||
didYouMean = e.fuzzyModel.SpellCheck(call.Task)
|
||||
}
|
||||
return nil, &taskNotFoundError{taskName: call.Task, didYouMean: didYouMean}
|
||||
}
|
||||
|
||||
var vars *taskfile.Vars
|
||||
|
Loading…
Reference in New Issue
Block a user