mirror of
https://github.com/go-task/task.git
synced 2025-01-20 04:59:37 +02:00
initial pass at deferred commands
This commit is contained in:
parent
1c782c599f
commit
69e9effc88
14
task.go
14
task.go
@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/internal/compiler"
|
"github.com/go-task/task/v3/internal/compiler"
|
||||||
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
|
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 {
|
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 err := e.runCommand(ctx, t, call, i); err != nil {
|
||||||
if err2 := e.statusOnError(t); err2 != nil {
|
if err2 := e.statusOnError(t); err2 != nil {
|
||||||
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v", err2)
|
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()
|
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 {
|
func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfile.Call, i int) error {
|
||||||
cmd := t.Cmds[i]
|
cmd := t.Cmds[i]
|
||||||
|
|
||||||
|
26
task_test.go
26
task_test.go
@ -1044,6 +1044,32 @@ func TestRunOnlyRunsJobsHashOnce(t *testing.T) {
|
|||||||
tt.Run(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) {
|
func TestIgnoreNilElements(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -7,6 +7,7 @@ type Cmd struct {
|
|||||||
Task string
|
Task string
|
||||||
Vars *Vars
|
Vars *Vars
|
||||||
IgnoreError bool
|
IgnoreError bool
|
||||||
|
Defer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dep is a task dependency
|
// Dep is a task dependency
|
||||||
@ -33,6 +34,18 @@ func (c *Cmd) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
c.IgnoreError = cmdStruct.IgnoreError
|
c.IgnoreError = cmdStruct.IgnoreError
|
||||||
return nil
|
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 {
|
var taskCall struct {
|
||||||
Task string
|
Task string
|
||||||
Vars *Vars
|
Vars *Vars
|
||||||
|
@ -19,6 +19,8 @@ vars:
|
|||||||
PARAM1: VALUE1
|
PARAM1: VALUE1
|
||||||
PARAM2: VALUE2
|
PARAM2: VALUE2
|
||||||
`
|
`
|
||||||
|
yamlDeferredTask = `defer: ^some_task`
|
||||||
|
yamlDeferredCmd = `defer: echo 'test'`
|
||||||
)
|
)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
content string
|
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,
|
yamlDep,
|
||||||
&taskfile.Dep{},
|
&taskfile.Dep{},
|
||||||
|
12
testdata/deferred/Taskfile.yml
vendored
Normal file
12
testdata/deferred/Taskfile.yml
vendored
Normal 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
|
@ -102,6 +102,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
|||||||
Cmd: r.Replace(cmd.Cmd),
|
Cmd: r.Replace(cmd.Cmd),
|
||||||
Vars: r.ReplaceVars(cmd.Vars),
|
Vars: r.ReplaceVars(cmd.Vars),
|
||||||
IgnoreError: cmd.IgnoreError,
|
IgnoreError: cmd.IgnoreError,
|
||||||
|
Defer: cmd.Defer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user