1
0
mirror of https://github.com/go-task/task.git synced 2024-12-14 10:52:43 +02:00

Merge branch 'Eun-master'

This commit is contained in:
Andrey Nering 2018-08-05 13:02:22 -03:00
commit fb9061480d
7 changed files with 122 additions and 37 deletions

View File

@ -640,6 +640,39 @@ tasks:
Dry run mode (`--dry`) compiles and steps through each task, printing the commands
that would be run without executing them. This is useful for debugging your Taskfiles.
## Ignore errors
You have the option to ignore errors during command execution.
Given the following Taskfile:
```yml
version: '2'
tasks:
echo:
cmds:
- exit 1
- echo "Hello World"
```
Task will abort the execution after running `exit 1` because the status code `1` stands for `EXIT_FAILURE`.
However it is possible to continue with execution using `ignore_error`:
```yml
version: '2'
tasks:
echo:
cmds:
- cmd: exit 1
ignore_error: true
- echo "Hello World"
```
`ignore_error` can also be set for a task, which mean errors will be supressed
for all commands. But keep in mind this option won't propagate to other tasks
called either by `deps` or `cmds`!
## Output syntax
By default, Task just redirect the STDOUT and STDERR of the running commands

View File

@ -7,10 +7,11 @@ import (
// Cmd is a task command
type Cmd struct {
Cmd string
Silent bool
Task string
Vars Vars
Cmd string
Silent bool
Task string
Vars Vars
IgnoreError bool
}
// Dep is a task dependency
@ -38,12 +39,14 @@ func (c *Cmd) UnmarshalYAML(unmarshal func(interface{}) error) error {
return nil
}
var cmdStruct struct {
Cmd string
Silent bool
Cmd string
Silent bool
IgnoreError bool `yaml:"ignore_error"`
}
if err := unmarshal(&cmdStruct); err == nil && cmdStruct.Cmd != "" {
c.Cmd = cmdStruct.Cmd
c.Silent = cmdStruct.Silent
c.IgnoreError = cmdStruct.IgnoreError
return nil
}
var taskCall struct {

View File

@ -5,17 +5,18 @@ type Tasks map[string]*Task
// Task represents a task
type Task struct {
Task string
Cmds []*Cmd
Deps []*Dep
Desc string
Sources []string
Generates []string
Status []string
Dir string
Vars Vars
Env Vars
Silent bool
Method string
Prefix string
Task string
Cmds []*Cmd
Deps []*Dep
Desc string
Sources []string
Generates []string
Status []string
Dir string
Vars Vars
Env Vars
Silent bool
Method string
Prefix string
IgnoreError bool `yaml:"ignore_error"`
}

14
task.go
View File

@ -19,6 +19,7 @@ import (
"github.com/Masterminds/semver"
"golang.org/x/sync/errgroup"
"mvdan.cc/sh/interp"
)
const (
@ -181,6 +182,12 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
if err2 := statusOnError(t); err2 != nil {
e.Logger.VerboseErrf("task: error cleaning status on error: %v", err2)
}
if _, ok := err.(interp.ExitCode); ok && t.IgnoreError {
e.Logger.VerboseErrf("task: task error ignored: %v", err)
continue
}
return &taskRunError{t.Task, err}
}
}
@ -221,7 +228,7 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi
defer stdOut.Close()
defer stdErr.Close()
return execext.RunCommand(&execext.RunCommandOptions{
err := execext.RunCommand(&execext.RunCommandOptions{
Context: ctx,
Command: cmd.Cmd,
Dir: t.Dir,
@ -230,6 +237,11 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi
Stdout: stdOut,
Stderr: stdErr,
})
if _, ok := err.(interp.ExitCode); ok && cmd.IgnoreError {
e.Logger.VerboseErrf("task: command error ignored: %v", err)
return nil
}
return err
default:
return nil
}

View File

@ -53,7 +53,6 @@ func (fct fileContentTest) Run(t *testing.T) {
assert.Equal(t, expectContent, s, "unexpected file content")
})
}
}
func TestEnv(t *testing.T) {
@ -414,6 +413,22 @@ func TestTaskVersion(t *testing.T) {
}
}
func TestTaskIgnoreErrors(t *testing.T) {
const dir = "testdata/ignore_errors"
e := task.Executor{
Dir: dir,
Stdout: ioutil.Discard,
Stderr: ioutil.Discard,
}
assert.NoError(t, e.Setup())
assert.NoError(t, e.Run(taskfile.Call{Task: "task-should-pass"}))
assert.Error(t, e.Run(taskfile.Call{Task: "task-should-fail"}))
assert.NoError(t, e.Run(taskfile.Call{Task: "cmd-should-pass"}))
assert.Error(t, e.Run(taskfile.Call{Task: "cmd-should-fail"}))
}
func TestExpand(t *testing.T) {
const dir = "testdata/expand"

20
testdata/ignore_errors/Taskfile.yml vendored Normal file
View File

@ -0,0 +1,20 @@
version: '2'
tasks:
task-should-pass:
cmds:
- exit 1
ignore_error: true
task-should-fail:
cmds:
- exit 1
cmd-should-pass:
cmds:
- cmd: exit 1
ignore_error: true
cmd-should-fail:
cmds:
- cmd: exit 1

View File

@ -24,17 +24,18 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
r := templater.Templater{Vars: vars}
new := taskfile.Task{
Task: origTask.Task,
Desc: r.Replace(origTask.Desc),
Sources: r.ReplaceSlice(origTask.Sources),
Generates: r.ReplaceSlice(origTask.Generates),
Status: r.ReplaceSlice(origTask.Status),
Dir: r.Replace(origTask.Dir),
Vars: nil,
Env: r.ReplaceVars(origTask.Env),
Silent: origTask.Silent,
Method: r.Replace(origTask.Method),
Prefix: r.Replace(origTask.Prefix),
Task: origTask.Task,
Desc: r.Replace(origTask.Desc),
Sources: r.ReplaceSlice(origTask.Sources),
Generates: r.ReplaceSlice(origTask.Generates),
Status: r.ReplaceSlice(origTask.Status),
Dir: r.Replace(origTask.Dir),
Vars: nil,
Env: r.ReplaceVars(origTask.Env),
Silent: origTask.Silent,
Method: r.Replace(origTask.Method),
Prefix: r.Replace(origTask.Prefix),
IgnoreError: origTask.IgnoreError,
}
new.Dir, err = shell.Expand(new.Dir, nil)
if err != nil {
@ -58,12 +59,12 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
new.Cmds = make([]*taskfile.Cmd, len(origTask.Cmds))
for i, cmd := range origTask.Cmds {
new.Cmds[i] = &taskfile.Cmd{
Task: r.Replace(cmd.Task),
Silent: cmd.Silent,
Cmd: r.Replace(cmd.Cmd),
Vars: r.ReplaceVars(cmd.Vars),
Task: r.Replace(cmd.Task),
Silent: cmd.Silent,
Cmd: r.Replace(cmd.Cmd),
Vars: r.ReplaceVars(cmd.Vars),
IgnoreError: cmd.IgnoreError,
}
}
}
if len(origTask.Deps) > 0 {