From 05600601ffa544fa64cb1ee1bf6e52950ff3a5ed Mon Sep 17 00:00:00 2001 From: Tobias Salzmann Date: Tue, 10 Jul 2018 10:44:58 +0200 Subject: [PATCH] add ignoreError option --- internal/execext/exec.go | 24 ++++++++++----- internal/taskfile/call.go | 5 ++-- internal/taskfile/cmd.go | 32 ++++++++++++-------- task.go | 19 ++++++------ task_test.go | 45 ++++++++++++++++++++++++++++- testdata/ignore_errors/Taskfile.yml | 15 ++++++++++ variables.go | 10 +++---- 7 files changed, 113 insertions(+), 37 deletions(-) create mode 100644 testdata/ignore_errors/Taskfile.yml diff --git a/internal/execext/exec.go b/internal/execext/exec.go index f86003bb..4428bd39 100644 --- a/internal/execext/exec.go +++ b/internal/execext/exec.go @@ -13,13 +13,14 @@ import ( // RunCommandOptions is the options for the RunCommand func type RunCommandOptions struct { - Context context.Context - Command string - Dir string - Env []string - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer + Context context.Context + Command string + Dir string + Env []string + Stdin io.Reader + Stdout io.Writer + Stderr io.Writer + IgnoreErrorCode bool } var ( @@ -62,5 +63,12 @@ func RunCommand(opts *RunCommandOptions) error { if err = r.Reset(); err != nil { return err } - return r.Run(p) + if err = r.Run(p); err != nil { + if opts.IgnoreErrorCode { + if _, ok := err.(interp.ExitCode); ok { + return nil + } + } + } + return err } diff --git a/internal/taskfile/call.go b/internal/taskfile/call.go index eec41031..3b3ac725 100644 --- a/internal/taskfile/call.go +++ b/internal/taskfile/call.go @@ -2,6 +2,7 @@ package taskfile // Call is the parameters to a task call type Call struct { - Task string - Vars Vars + Task string + Vars Vars + IgnoreError bool } diff --git a/internal/taskfile/cmd.go b/internal/taskfile/cmd.go index f2bae2fc..78fdd370 100644 --- a/internal/taskfile/cmd.go +++ b/internal/taskfile/cmd.go @@ -7,16 +7,18 @@ 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 type Dep struct { - Task string - Vars Vars + Task string + Vars Vars + IgnoreError bool } var ( @@ -38,21 +40,25 @@ 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:"ignoreError"` } 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 { - Task string - Vars Vars + Task string + Vars Vars + IgnoreError bool `yaml:"ignoreError"` } if err := unmarshal(&taskCall); err == nil { c.Task = taskCall.Task c.Vars = taskCall.Vars + c.IgnoreError = taskCall.IgnoreError return nil } return ErrCantUnmarshalCmd @@ -66,12 +72,14 @@ func (d *Dep) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } var taskCall struct { - Task string - Vars Vars + Task string + Vars Vars + IgnoreError bool `yaml:"ignoreError"` } if err := unmarshal(&taskCall); err == nil { d.Task = taskCall.Task d.Vars = taskCall.Vars + d.IgnoreError = taskCall.IgnoreError return nil } return ErrCantUnmarshalDep diff --git a/task.go b/task.go index f8805bd3..500e4112 100644 --- a/task.go +++ b/task.go @@ -188,7 +188,7 @@ func (e *Executor) runDeps(ctx context.Context, t *taskfile.Task) error { d := d g.Go(func() error { - return e.RunTask(ctx, taskfile.Call{Task: d.Task, Vars: d.Vars}) + return e.RunTask(ctx, taskfile.Call{Task: d.Task, Vars: d.Vars, IgnoreError: d.IgnoreError}) }) } @@ -200,7 +200,7 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi switch { case cmd.Task != "": - return e.RunTask(ctx, taskfile.Call{Task: cmd.Task, Vars: cmd.Vars}) + return e.RunTask(ctx, taskfile.Call{Task: cmd.Task, Vars: cmd.Vars, IgnoreError: cmd.IgnoreError || call.IgnoreError}) case cmd.Cmd != "": if e.Verbose || (!cmd.Silent && !t.Silent && !e.Silent) { e.Logger.Errf(cmd.Cmd) @@ -212,13 +212,14 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi defer stdErr.Close() return execext.RunCommand(&execext.RunCommandOptions{ - Context: ctx, - Command: cmd.Cmd, - Dir: t.Dir, - Env: getEnviron(t), - Stdin: e.Stdin, - Stdout: stdOut, - Stderr: stdErr, + Context: ctx, + Command: cmd.Cmd, + Dir: t.Dir, + Env: getEnviron(t), + Stdin: e.Stdin, + Stdout: stdOut, + Stderr: stdErr, + IgnoreErrorCode: cmd.IgnoreError || call.IgnoreError, }) default: return nil diff --git a/task_test.go b/task_test.go index 6e48faa8..4176eeab 100644 --- a/task_test.go +++ b/task_test.go @@ -52,7 +52,6 @@ func (fct fileContentTest) Run(t *testing.T) { assert.Equal(t, expectContent, s, "unexpected file content") }) } - } func TestEnv(t *testing.T) { @@ -412,3 +411,47 @@ func TestTaskVersion(t *testing.T) { }) } } + +func TestTaskIgnoreErrors(t *testing.T) { + const dir = "testdata/ignore_errors" + + t.Run("CmdShouldPass", func(t *testing.T) { + e := task.Executor{ + Dir: dir, + Stdout: ioutil.Discard, + Stderr: ioutil.Discard, + } + assert.NoError(t, e.Setup()) + assert.NoError(t, e.Run(taskfile.Call{Task: "CmdShouldPass"})) + }) + + t.Run("CmdShouldFail", func(t *testing.T) { + e := task.Executor{ + Dir: dir, + Stdout: ioutil.Discard, + Stderr: ioutil.Discard, + } + assert.NoError(t, e.Setup()) + assert.Error(t, e.Run(taskfile.Call{Task: "CmdShouldFail"})) + }) + + t.Run("TaskShouldPass", func(t *testing.T) { + e := task.Executor{ + Dir: dir, + Stdout: ioutil.Discard, + Stderr: ioutil.Discard, + } + assert.NoError(t, e.Setup()) + assert.NoError(t, e.Run(taskfile.Call{Task: "TaskShouldPass"})) + }) + + t.Run("TaskShouldFail", func(t *testing.T) { + e := task.Executor{ + Dir: dir, + Stdout: ioutil.Discard, + Stderr: ioutil.Discard, + } + assert.NoError(t, e.Setup()) + assert.Error(t, e.Run(taskfile.Call{Task: "TaskShouldFail"})) + }) +} diff --git a/testdata/ignore_errors/Taskfile.yml b/testdata/ignore_errors/Taskfile.yml new file mode 100644 index 00000000..3e5a67c5 --- /dev/null +++ b/testdata/ignore_errors/Taskfile.yml @@ -0,0 +1,15 @@ +CmdShouldPass: + cmds: + - cmd: UnknownCommandThatNeverWillExist + ignoreError: true +CmdShouldFail: + cmds: + - cmd: UnknownCommandThatNeverWillExist + +TaskShouldPass: + cmds: + - task: CmdShouldFail + ignoreError: true +TaskShouldFail: + cmds: + - task: CmdShouldFail \ No newline at end of file diff --git a/variables.go b/variables.go index ce8a4127..a30679d0 100644 --- a/variables.go +++ b/variables.go @@ -62,12 +62,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 {