mirror of
https://github.com/go-task/task.git
synced 2025-01-20 04:59:37 +02:00
feat: aliases
feat: add aliases to --list and --list-all flags feat: add aliases to --summary feat: enable aliases for included tasks tests: added alias unit tests
This commit is contained in:
parent
d2061ec898
commit
376a6182eb
10
errors.go
10
errors.go
@ -3,6 +3,7 @@ package task
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
)
|
||||
@ -20,6 +21,15 @@ func (err *taskNotFoundError) Error() string {
|
||||
return fmt.Sprintf(`task: Task %q not found`, err.taskName)
|
||||
}
|
||||
|
||||
type multipleTasksWithAliasError struct {
|
||||
aliasName string
|
||||
taskNames []string
|
||||
}
|
||||
|
||||
func (err *multipleTasksWithAliasError) Error() string {
|
||||
return fmt.Sprintf(`task: Multiple tasks (%s) with alias %q found`, strings.Join(err.taskNames, ", "), err.aliasName)
|
||||
}
|
||||
|
||||
type taskInternalError struct {
|
||||
taskName string
|
||||
}
|
||||
|
3
go.mod
3
go.mod
@ -9,6 +9,7 @@ require (
|
||||
github.com/radovskyb/watcher v1.0.7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.0
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
mvdan.cc/sh/v3 v3.6.0-0.dev.0.20220704111049-a6e3029cd899
|
||||
@ -19,7 +20,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
)
|
||||
|
9
go.sum
9
go.sum
@ -7,7 +7,7 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF
|
||||
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
@ -34,16 +34,17 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
3
help.go
3
help.go
@ -44,8 +44,9 @@ func (e *Executor) printTasks(listAll bool) {
|
||||
// Format in tab-separated columns with a tab stop of 8.
|
||||
w := tabwriter.NewWriter(e.Stdout, 0, 8, 6, ' ', 0)
|
||||
for _, task := range tasks {
|
||||
taskNames := append([]string{task.Task}, task.Aliases...)
|
||||
e.Logger.FOutf(w, logger.Yellow, "* ")
|
||||
e.Logger.FOutf(w, logger.Green, task.Task)
|
||||
e.Logger.FOutf(w, logger.Green, strings.Join(taskNames, "|"))
|
||||
e.Logger.FOutf(w, logger.Default, ": \t%s", task.Desc)
|
||||
fmt.Fprint(w, "\n")
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ func PrintTask(l *logger.Logger, t *taskfile.Task) {
|
||||
printTaskName(l, t)
|
||||
printTaskDescribingText(t, l)
|
||||
printTaskDependencies(l, t)
|
||||
printTaskAliases(l, t)
|
||||
printTaskCommands(l, t)
|
||||
}
|
||||
|
||||
@ -61,6 +62,18 @@ func printTaskName(l *logger.Logger, t *taskfile.Task) {
|
||||
l.Outf(logger.Default, "")
|
||||
}
|
||||
|
||||
func printTaskAliases(l *logger.Logger, t *taskfile.Task) {
|
||||
if len(t.Aliases) == 0 {
|
||||
return
|
||||
}
|
||||
l.Outf(logger.Default, "")
|
||||
l.Outf(logger.Default, "aliases:")
|
||||
for _, alias := range t.Aliases {
|
||||
l.FOutf(l.Stdout, logger.Default, " - ")
|
||||
l.Outf(logger.Cyan, alias)
|
||||
}
|
||||
}
|
||||
|
||||
func hasDescription(t *taskfile.Task) bool {
|
||||
return t.Desc != ""
|
||||
}
|
||||
|
53
task.go
53
task.go
@ -16,6 +16,7 @@ import (
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@ -63,16 +64,15 @@ type Executor struct {
|
||||
// Run runs Task
|
||||
func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
||||
// check if given tasks exist
|
||||
for _, c := range calls {
|
||||
t, ok := e.Taskfile.Tasks[c.Task]
|
||||
if !ok {
|
||||
// FIXME: move to the main package
|
||||
for _, call := range calls {
|
||||
task, err := e.GetTask(call)
|
||||
if err != nil {
|
||||
e.ListTasksWithDesc()
|
||||
return &taskNotFoundError{taskName: c.Task}
|
||||
return err
|
||||
}
|
||||
if t.Internal {
|
||||
if task.Internal {
|
||||
e.ListTasksWithDesc()
|
||||
return &taskInternalError{taskName: c.Task}
|
||||
return &taskInternalError{taskName: call.Task}
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,8 +112,8 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !e.Watch && atomic.AddInt32(e.taskCallCount[call.Task], 1) >= MaximumTaskCall {
|
||||
return &MaximumTaskCallExceededError{task: call.Task}
|
||||
if !e.Watch && atomic.AddInt32(e.taskCallCount[t.Task], 1) >= MaximumTaskCall {
|
||||
return &MaximumTaskCallExceededError{task: t.Task}
|
||||
}
|
||||
|
||||
release := e.acquireConcurrencyLimit()
|
||||
@ -330,3 +330,38 @@ func (e *Executor) startExecution(ctx context.Context, t *taskfile.Task, execute
|
||||
|
||||
return execute(ctx)
|
||||
}
|
||||
|
||||
// GetTask will return the task with the name matching the given call from the taskfile.
|
||||
// If no task is found, it will search for tasks with a matching alias.
|
||||
// If multiple tasks contain the same alias or no matches are found an error is returned.
|
||||
func (e *Executor) GetTask(call taskfile.Call) (*taskfile.Task, error) {
|
||||
// Search for a matching task
|
||||
matchingTask, ok := e.Taskfile.Tasks[call.Task]
|
||||
if ok {
|
||||
return matchingTask, nil
|
||||
}
|
||||
|
||||
// If didn't find one, search for a task with a matching alias
|
||||
var aliasedTasks []string
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if slices.Contains(task.Aliases, call.Task) {
|
||||
aliasedTasks = append(aliasedTasks, task.Task)
|
||||
matchingTask = task
|
||||
}
|
||||
}
|
||||
// If we found multiple tasks
|
||||
if len(aliasedTasks) > 1 {
|
||||
return nil, &multipleTasksWithAliasError{
|
||||
aliasName: call.Task,
|
||||
taskNames: aliasedTasks,
|
||||
}
|
||||
}
|
||||
// If we found no tasks
|
||||
if len(aliasedTasks) == 0 {
|
||||
return nil, &taskNotFoundError{
|
||||
taskName: call.Task,
|
||||
}
|
||||
}
|
||||
|
||||
return matchingTask, nil
|
||||
}
|
||||
|
56
task_test.go
56
task_test.go
@ -476,6 +476,58 @@ func TestStatusChecksum(t *testing.T) {
|
||||
assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String())
|
||||
}
|
||||
|
||||
func TestAlias(t *testing.T) {
|
||||
const dir = "testdata/alias"
|
||||
|
||||
data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias.txt"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "f"}))
|
||||
assert.Equal(t, string(data), buff.String())
|
||||
}
|
||||
|
||||
func TestDuplicateAlias(t *testing.T) {
|
||||
const dir = "testdata/alias"
|
||||
|
||||
data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias-duplicate.txt"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.Error(t, e.Run(context.Background(), taskfile.Call{Task: "x"}))
|
||||
assert.Equal(t, string(data), buff.String())
|
||||
}
|
||||
|
||||
func TestAliasSummary(t *testing.T) {
|
||||
const dir = "testdata/alias"
|
||||
|
||||
data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias-summary.txt"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Summary: true,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "f"}))
|
||||
assert.Equal(t, string(data), buff.String())
|
||||
}
|
||||
|
||||
func TestLabelUpToDate(t *testing.T) {
|
||||
const dir = "testdata/label_uptodate"
|
||||
|
||||
@ -989,7 +1041,7 @@ func TestIncludesInternal(t *testing.T) {
|
||||
|
||||
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
||||
if test.expectedErr {
|
||||
assert.Error(t, err, test.expectedErr)
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@ -1029,7 +1081,7 @@ func TestInternalTask(t *testing.T) {
|
||||
|
||||
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
||||
if test.expectedErr {
|
||||
assert.Error(t, err, test.expectedErr)
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@ -55,6 +55,9 @@ func Merge(t1, t2 *Taskfile, internal bool, namespaces ...string) error {
|
||||
cmd.Task = taskNameWithNamespace(cmd.Task, namespaces...)
|
||||
}
|
||||
}
|
||||
for i, alias := range v.Aliases {
|
||||
v.Aliases[i] = taskNameWithNamespace(alias, namespaces...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -11,6 +11,7 @@ type Task struct {
|
||||
Label string
|
||||
Desc string
|
||||
Summary string
|
||||
Aliases []string
|
||||
Sources []string
|
||||
Generates []string
|
||||
Status []string
|
||||
@ -56,6 +57,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Label string
|
||||
Desc string
|
||||
Summary string
|
||||
Aliases []string
|
||||
Sources []string
|
||||
Generates []string
|
||||
Status []string
|
||||
@ -78,6 +80,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
t.Deps = task.Deps
|
||||
t.Label = task.Label
|
||||
t.Desc = task.Desc
|
||||
t.Aliases = task.Aliases
|
||||
t.Summary = task.Summary
|
||||
t.Sources = task.Sources
|
||||
t.Generates = task.Generates
|
||||
|
18
testdata/alias/Taskfile.yml
vendored
Normal file
18
testdata/alias/Taskfile.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included:
|
||||
taskfile: Taskfile2.yml
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
aliases: [f, x]
|
||||
cmds:
|
||||
- echo "foo"
|
||||
- task: b
|
||||
|
||||
bar:
|
||||
aliases: [b, x]
|
||||
cmds:
|
||||
- echo "bar"
|
||||
- task: included:q
|
7
testdata/alias/Taskfile2.yml
vendored
Normal file
7
testdata/alias/Taskfile2.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
qux:
|
||||
aliases: [q, x]
|
||||
cmds:
|
||||
- echo "qux"
|
1
testdata/alias/alias-duplicate.txt
vendored
Normal file
1
testdata/alias/alias-duplicate.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
task: No tasks with description available. Try --list-all to list all tasks
|
11
testdata/alias/alias-summary.txt
vendored
Normal file
11
testdata/alias/alias-summary.txt
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
task: foo
|
||||
|
||||
(task does not have description or summary)
|
||||
|
||||
aliases:
|
||||
- f
|
||||
- x
|
||||
|
||||
commands:
|
||||
- echo "foo"
|
||||
- Task: b
|
6
testdata/alias/alias.txt
vendored
Normal file
6
testdata/alias/alias.txt
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
task: [foo] echo "foo"
|
||||
foo
|
||||
task: [bar] echo "bar"
|
||||
bar
|
||||
task: [included:qux] echo "qux"
|
||||
qux
|
@ -22,13 +22,12 @@ 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}
|
||||
origTask, err := e.GetTask(call)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var vars *taskfile.Vars
|
||||
var err error
|
||||
if evaluateShVars {
|
||||
vars, err = e.Compiler.GetVariables(origTask, call)
|
||||
} else {
|
||||
@ -50,6 +49,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
||||
Label: r.Replace(origTask.Label),
|
||||
Desc: r.Replace(origTask.Desc),
|
||||
Summary: r.Replace(origTask.Summary),
|
||||
Aliases: origTask.Aliases,
|
||||
Sources: r.ReplaceSlice(origTask.Sources),
|
||||
Generates: r.ReplaceSlice(origTask.Generates),
|
||||
Dir: r.Replace(origTask.Dir),
|
||||
|
Loading…
x
Reference in New Issue
Block a user