diff --git a/README.md b/README.md index 49059b70..16221645 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,28 @@ task2: Will stop at the moment the dependencies of `task2` are executed. +### Calling a task from another task + +When a task has many dependencies, they are executed concurrently. This will +often result in a faster build pipeline. But in some situations you may need +to call other tasks serially. For this just prefix a command with `^`: + +```yml +a-task: + cmds: + - ^another-task + - ^even-another-task + - echo "Both done" + +another-task: + cmds: + - ... + +even-another-task: + cmds: + - ... +``` + ### Prevent task from running when not necessary If a task generates something, you can inform Task the source and generated diff --git a/task.go b/task.go index 984a5531..d21c47de 100644 --- a/task.go +++ b/task.go @@ -74,13 +74,17 @@ func Run() { // RunTask runs a task by its name func RunTask(name string) error { - mu.Lock() - if _, found := runnedTasks[name]; found { + if strings.HasPrefix(name, "^") { + name = strings.TrimPrefix(name, "^") + } else { + mu.Lock() + if _, found := runnedTasks[name]; found { + mu.Unlock() + return &cyclicDepError{name} + } + runnedTasks[name] = struct{}{} mu.Unlock() - return &cyclicDepError{name} } - runnedTasks[name] = struct{}{} - mu.Unlock() t, ok := Tasks[name] if !ok { @@ -174,6 +178,14 @@ func (t *Task) runCommand(i int) error { if err != nil { return err } + + if strings.HasPrefix(c, "^") { + if err = RunTask(c); err != nil { + return err + } + return nil + } + dir, err := ReplaceVariables(t.Dir, vars) if err != nil { return err diff --git a/task_test.go b/task_test.go index a82fcfb7..8ce72515 100644 --- a/task_test.go +++ b/task_test.go @@ -85,3 +85,30 @@ func TestVars(t *testing.T) { } } } + +func TestTaskCall(t *testing.T) { + const dir = "testdata/task_call" + + files := []string{ + "foo.txt", + "bar.txt", + } + + for _, f := range files { + _ = os.Remove(filepath.Join(dir, f)) + } + + c := exec.Command("task") + c.Dir = dir + + if err := c.Run(); err != nil { + t.Error(err) + return + } + + for _, f := range files { + if _, err := os.Stat(filepath.Join(dir, f)); err != nil { + t.Error(err) + } + } +} diff --git a/testdata/task_call/.gitignore b/testdata/task_call/.gitignore new file mode 100644 index 00000000..2211df63 --- /dev/null +++ b/testdata/task_call/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/testdata/task_call/Taskfile.yml b/testdata/task_call/Taskfile.yml new file mode 100644 index 00000000..2c034418 --- /dev/null +++ b/testdata/task_call/Taskfile.yml @@ -0,0 +1,20 @@ +default: + cmds: + - ^set-foo + - ^print + - ^set-bar + - ^print + +print: + cmds: + - echo text > {{.FILE}} + +set-foo: + set: FILE + cmds: + - echo foo.txt + +set-bar: + set: FILE + cmds: + - echo bar.txt