1
0
mirror of https://github.com/go-task/task.git synced 2025-04-21 12:17:07 +02:00

Merge pull request #755 from BrunoDelor/feature/carry-error-code

Add --exit-code (-x) flag to enable carrying error codes from task cmds
This commit is contained in:
Andrey Nering 2022-06-11 19:53:24 -03:00 committed by GitHub
commit 63aad1e501
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 5 deletions

View File

@ -68,6 +68,7 @@ func main() {
silent bool silent bool
dry bool dry bool
summary bool summary bool
exitCode bool
parallel bool parallel bool
concurrency int concurrency int
dir string dir string
@ -89,6 +90,7 @@ func main() {
pflag.BoolVarP(&parallel, "parallel", "p", false, "executes tasks provided on command line in parallel") pflag.BoolVarP(&parallel, "parallel", "p", false, "executes tasks provided on command line in parallel")
pflag.BoolVar(&dry, "dry", false, "compiles and prints tasks in the order that they would be run, without executing them") pflag.BoolVar(&dry, "dry", false, "compiles and prints tasks in the order that they would be run, without executing them")
pflag.BoolVar(&summary, "summary", false, "show summary about a task") pflag.BoolVar(&summary, "summary", false, "show summary about a task")
pflag.BoolVarP(&exitCode, "exit-code", "x", false, "pass-through the exit code of the task command")
pflag.StringVarP(&dir, "dir", "d", "", "sets directory of execution") pflag.StringVarP(&dir, "dir", "d", "", "sets directory of execution")
pflag.StringVarP(&entrypoint, "taskfile", "t", "", `choose which Taskfile to run. Defaults to "Taskfile.yml"`) pflag.StringVarP(&entrypoint, "taskfile", "t", "", `choose which Taskfile to run. Defaults to "Taskfile.yml"`)
pflag.StringVarP(&output.Name, "output", "o", "", "sets output style: [interleaved|group|prefixed]") pflag.StringVarP(&output.Name, "output", "o", "", "sets output style: [interleaved|group|prefixed]")
@ -216,7 +218,13 @@ func main() {
if err := e.Run(ctx, calls...); err != nil { if err := e.Run(ctx, calls...); err != nil {
e.Logger.Errf(logger.Red, "%v", err) e.Logger.Errf(logger.Red, "%v", err)
os.Exit(1) code := 1
if exitCode {
if tre, ok := err.(*task.TaskRunError); ok {
code = tre.ExitCode()
}
}
os.Exit(code)
} }
} }

View File

@ -3,6 +3,7 @@ package task
import ( import (
"errors" "errors"
"fmt" "fmt"
"mvdan.cc/sh/v3/interp"
) )
var ( var (
@ -18,15 +19,23 @@ func (err *taskNotFoundError) Error() string {
return fmt.Sprintf(`task: Task "%s" not found`, err.taskName) return fmt.Sprintf(`task: Task "%s" not found`, err.taskName)
} }
type taskRunError struct { type TaskRunError struct {
taskName string taskName string
err error err error
} }
func (err *taskRunError) Error() string { func (err *TaskRunError) Error() string {
return fmt.Sprintf(`task: Failed to run task "%s": %v`, err.taskName, err.err) return fmt.Sprintf(`task: Failed to run task "%s": %v`, err.taskName, err.err)
} }
func (err *TaskRunError) ExitCode() int {
if c, ok := interp.IsExitStatus(err.err); ok {
return int(c)
}
return 1
}
// MaximumTaskCallExceededError is returned when a task is called too // MaximumTaskCallExceededError is returned when a task is called too
// many times. In this case you probably have a cyclic dependendy or // many times. In this case you probably have a cyclic dependendy or
// infinite loop // infinite loop

View File

@ -363,7 +363,7 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
continue continue
} }
return &taskRunError{t.Task, err} return &TaskRunError{t.Task, err}
} }
} }
e.Logger.VerboseErrf(logger.Magenta, `task: "%s" finished`, call.Task) e.Logger.VerboseErrf(logger.Magenta, `task: "%s" finished`, call.Task)

View File

@ -1275,3 +1275,22 @@ VAR_2 is included-default-var2
t.Log(buff.String()) t.Log(buff.String())
assert.Equal(t, strings.TrimSpace(buff.String()), expectedOutputOrder) assert.Equal(t, strings.TrimSpace(buff.String()), expectedOutputOrder)
} }
func TestErrorCode(t *testing.T) {
const dir = "testdata/error_code"
var buff bytes.Buffer
e := &task.Executor{
Dir: dir,
Stdout: &buff,
Stderr: &buff,
Silent: true,
}
assert.NoError(t, e.Setup())
err := e.Run(context.Background(), taskfile.Call{Task: "test-exit-code"})
assert.Error(t, err)
casted, ok := err.(*task.TaskRunError)
assert.True(t, ok, "cannot cast returned error to *task.TaskRunError")
assert.Equal(t, 42, casted.ExitCode(), "unexpected exit code from task")
}

6
testdata/error_code/Taskfile.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: '3'
tasks:
test-exit-code:
cmds:
- exit 42

View File

@ -88,7 +88,7 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
} }
func isContextError(err error) bool { func isContextError(err error) bool {
if taskRunErr, ok := err.(*taskRunError); ok { if taskRunErr, ok := err.(*TaskRunError); ok {
err = taskRunErr.err err = taskRunErr.err
} }