1
0
mirror of https://github.com/go-task/task.git synced 2025-01-04 03:48:02 +02:00

initial pass at deferred commands

This commit is contained in:
Jacob McCollum 2021-12-15 00:03:37 -05:00
parent 1c782c599f
commit 69e9effc88
6 changed files with 78 additions and 0 deletions

14
task.go
View File

@ -8,6 +8,7 @@ import (
"os"
"sync"
"sync/atomic"
"time"
"github.com/go-task/task/v3/internal/compiler"
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
@ -339,6 +340,11 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
}
for i := range t.Cmds {
if t.Cmds[i].Defer {
defer e.runDeferred(t, call, i)
continue
}
if err := e.runCommand(ctx, t, call, i); err != nil {
if err2 := e.statusOnError(t); err2 != nil {
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v", err2)
@ -395,6 +401,14 @@ func (e *Executor) runDeps(ctx context.Context, t *taskfile.Task) error {
return g.Wait()
}
func (e *Executor) runDeferred(t *taskfile.Task, call taskfile.Call, i int) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
if err := e.runCommand(ctx, t, call, i); err != nil {
e.Logger.VerboseErrf(logger.Yellow, `task: ignored error in deferred cmd: %s`, err.Error())
}
}
func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfile.Call, i int) error {
cmd := t.Cmds[i]

View File

@ -1044,6 +1044,32 @@ func TestRunOnlyRunsJobsHashOnce(t *testing.T) {
tt.Run(t)
}
func TestDeferredCmds(t *testing.T) {
const dir = "testdata/deferred"
var buff bytes.Buffer
e := task.Executor{
Dir: dir,
Stdout: &buff,
Stderr: &buff,
}
assert.NoError(t, e.Setup())
expectedOutputOrder := strings.TrimSpace(`
task: [task-2] echo 'cmd ran'
cmd ran
task: [task-2] exit 1
task: [task-2] echo 'failing' && exit 2
failing
task: [task-2] echo 'echo ran'
echo ran
task: [task-1] echo 'task-1 ran'
task-1 ran
`)
assert.Error(t, e.Run(context.Background(), taskfile.Call{Task: "task-2"}))
fmt.Println(buff.String())
assert.Contains(t, buff.String(), expectedOutputOrder)
}
func TestIgnoreNilElements(t *testing.T) {
tests := []struct {
name string

View File

@ -7,6 +7,7 @@ type Cmd struct {
Task string
Vars *Vars
IgnoreError bool
Defer bool
}
// Dep is a task dependency
@ -33,6 +34,18 @@ func (c *Cmd) UnmarshalYAML(unmarshal func(interface{}) error) error {
c.IgnoreError = cmdStruct.IgnoreError
return nil
}
var deferredCmd struct {
Defer string
}
if err := unmarshal(&deferredCmd); err == nil && deferredCmd.Defer != "" {
c.Defer = true
if strings.HasPrefix(deferredCmd.Defer, "^") {
c.Task = strings.TrimPrefix(deferredCmd.Defer, "^")
} else {
c.Cmd = deferredCmd.Defer
}
return nil
}
var taskCall struct {
Task string
Vars *Vars

View File

@ -19,6 +19,8 @@ vars:
PARAM1: VALUE1
PARAM2: VALUE2
`
yamlDeferredTask = `defer: ^some_task`
yamlDeferredCmd = `defer: echo 'test'`
)
tests := []struct {
content string
@ -41,6 +43,16 @@ vars:
},
}},
},
{
yamlDeferredCmd,
&taskfile.Cmd{},
&taskfile.Cmd{Cmd: "echo 'test'", Defer: true},
},
{
yamlDeferredTask,
&taskfile.Cmd{},
&taskfile.Cmd{Task: "some_task", Defer: true},
},
{
yamlDep,
&taskfile.Dep{},

12
testdata/deferred/Taskfile.yml vendored Normal file
View File

@ -0,0 +1,12 @@
version: "3"
tasks:
task-1:
- echo 'task-1 ran'
task-2:
- defer: "^task-1"
- defer: echo 'echo ran'
- defer: echo 'failing' && exit 2
- echo 'cmd ran'
- exit 1

View File

@ -102,6 +102,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
Cmd: r.Replace(cmd.Cmd),
Vars: r.ReplaceVars(cmd.Vars),
IgnoreError: cmd.IgnoreError,
Defer: cmd.Defer,
})
}
}