From 7ca502e6f1cacee78d7debc3c731cef21f46d192 Mon Sep 17 00:00:00 2001 From: Graham Dennis Date: Sun, 8 Jun 2025 16:21:27 +1000 Subject: [PATCH 1/2] fix: Task failure errors include stack of running tasks. Previously if a task was run as a dependency of another task, the error message simply reported something like: ``` exit status 1 ``` It is desirable instead to name the root task and all child tasks in the tree to the failing task. After this PR, the error message will read: ``` task: Failed to run task "root": task: Failed to run task "failing-task": exit status 1 ``` --- errors/errors_task.go | 4 ++++ task.go | 14 +++++++------- task_test.go | 4 +++- ...ition-a_precondition_was_not_met-err-run.golden | 2 +- ...econdition_in_cmd_fails_the_task-err-run.golden | 2 +- ...ion_in_dependency_fails_the_task-err-run.golden | 2 +- ..._raise_errors.TaskCancelledError-err-run.golden | 2 +- ...stops_task-test_Enter_stops_task-err-run.golden | 2 +- ..._task-test_junk_value_stops_task-err-run.golden | 2 +- ...-test_stops_task-test_stops_task-err-run.golden | 2 +- 10 files changed, 21 insertions(+), 15 deletions(-) diff --git a/errors/errors_task.go b/errors/errors_task.go index 8e840c793d..27db0852e6 100644 --- a/errors/errors_task.go +++ b/errors/errors_task.go @@ -52,6 +52,10 @@ func (err *TaskRunError) TaskExitCode() int { return err.Code() } +func (err *TaskRunError) Unwrap() error { + return err.Err +} + // TaskInternalError when the user attempts to invoke a task that is internal. type TaskInternalError struct { TaskName string diff --git a/task.go b/task.go index 0b762c6140..f5c0d294d6 100644 --- a/task.go +++ b/task.go @@ -150,7 +150,7 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error { release := e.acquireConcurrencyLimit() defer release() - return e.startExecution(ctx, t, func(ctx context.Context) error { + if err = e.startExecution(ctx, t, func(ctx context.Context) error { e.Logger.VerboseErrf(logger.Magenta, "task: %q started\n", call.Task) if err := e.runDeps(ctx, t); err != nil { return err @@ -229,16 +229,16 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error { deferredExitCode = exitCode } - if call.Indirect { - return err - } - - return &errors.TaskRunError{TaskName: t.Task, Err: err} + return err } } e.Logger.VerboseErrf(logger.Magenta, "task: %q finished\n", call.Task) return nil - }) + }); err != nil { + return &errors.TaskRunError{TaskName: t.Task, Err: err} + } + + return nil } func (e *Executor) mkdir(t *ast.Task) error { diff --git a/task_test.go b/task_test.go index 7b986662cd..a69bc9f0f4 100644 --- a/task_test.go +++ b/task_test.go @@ -547,7 +547,9 @@ func TestCyclicDep(t *testing.T) { task.WithStderr(io.Discard), ) require.NoError(t, e.Setup()) - assert.IsType(t, &errors.TaskCalledTooManyTimesError{}, e.Run(context.Background(), &task.Call{Task: "task-1"})) + err := e.Run(context.Background(), &task.Call{Task: "task-1"}) + var taskCalledTooManyTimesError *errors.TaskCalledTooManyTimesError + assert.ErrorAs(t, err, &taskCalledTooManyTimesError) } func TestTaskVersion(t *testing.T) { diff --git a/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden b/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden index 6952491ef1..839c74baa6 100644 --- a/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden +++ b/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden @@ -1 +1 @@ -task: precondition not met \ No newline at end of file +task: Failed to run task "impossible": task: precondition not met \ No newline at end of file diff --git a/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden b/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden index 7e11556349..14ae8d1227 100644 --- a/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden +++ b/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden @@ -1 +1 @@ -task: Failed to run task "executes_failing_task_as_cmd": task: precondition not met \ No newline at end of file +task: Failed to run task "executes_failing_task_as_cmd": task: Failed to run task "impossible": task: precondition not met \ No newline at end of file diff --git a/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden b/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden index 6952491ef1..a4ee7b3f55 100644 --- a/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden +++ b/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden @@ -1 +1 @@ -task: precondition not met \ No newline at end of file +task: Failed to run task "depends_on_impossible": task: Failed to run task "impossible": task: precondition not met \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden b/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden index 8e26430213..a2e7b643d3 100644 --- a/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden +++ b/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden @@ -1 +1 @@ -task: Task "foo" cancelled by user \ No newline at end of file +task: Failed to run task "foo": task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden b/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden index 8e26430213..a2e7b643d3 100644 --- a/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden +++ b/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden @@ -1 +1 @@ -task: Task "foo" cancelled by user \ No newline at end of file +task: Failed to run task "foo": task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden b/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden index 8e26430213..a2e7b643d3 100644 --- a/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden +++ b/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden @@ -1 +1 @@ -task: Task "foo" cancelled by user \ No newline at end of file +task: Failed to run task "foo": task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden b/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden index 8e26430213..a2e7b643d3 100644 --- a/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden +++ b/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden @@ -1 +1 @@ -task: Task "foo" cancelled by user \ No newline at end of file +task: Failed to run task "foo": task: Task "foo" cancelled by user \ No newline at end of file From 2501edfa6d0b7f52a1f01ecc7f196add5958c3a9 Mon Sep 17 00:00:00 2001 From: Graham Dennis Date: Mon, 9 Jun 2025 08:49:41 +1000 Subject: [PATCH 2/2] fix: Ensure that task labels are used in error messages when present --- executor_test.go | 9 +++++++++ task.go | 2 +- testdata/label_error/Taskfile.yml | 7 +++++++ .../testdata/TestLabel-label_in_error-err-run.golden | 1 + .../label_error/testdata/TestLabel-label_in_error.golden | 1 + 5 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 testdata/label_error/Taskfile.yml create mode 100644 testdata/label_error/testdata/TestLabel-label_in_error-err-run.golden create mode 100644 testdata/label_error/testdata/TestLabel-label_in_error.golden diff --git a/executor_test.go b/executor_test.go index 4d1677db21..f5e6c6b0d1 100644 --- a/executor_test.go +++ b/executor_test.go @@ -665,6 +665,15 @@ func TestLabel(t *testing.T) { ), WithTask("foo"), ) + + NewExecutorTest(t, + WithName("label in error"), + WithExecutorOptions( + task.WithDir("testdata/label_error"), + ), + WithTask("foo"), + WithRunError(), + ) } func TestPromptInSummary(t *testing.T) { diff --git a/task.go b/task.go index f5c0d294d6..34f2ed5e61 100644 --- a/task.go +++ b/task.go @@ -235,7 +235,7 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error { e.Logger.VerboseErrf(logger.Magenta, "task: %q finished\n", call.Task) return nil }); err != nil { - return &errors.TaskRunError{TaskName: t.Task, Err: err} + return &errors.TaskRunError{TaskName: t.Name(), Err: err} } return nil diff --git a/testdata/label_error/Taskfile.yml b/testdata/label_error/Taskfile.yml new file mode 100644 index 0000000000..fe795ebd19 --- /dev/null +++ b/testdata/label_error/Taskfile.yml @@ -0,0 +1,7 @@ +version: '3' + +tasks: + foo: + label: "foobar" + cmds: + - "false" diff --git a/testdata/label_error/testdata/TestLabel-label_in_error-err-run.golden b/testdata/label_error/testdata/TestLabel-label_in_error-err-run.golden new file mode 100644 index 0000000000..67e166bc95 --- /dev/null +++ b/testdata/label_error/testdata/TestLabel-label_in_error-err-run.golden @@ -0,0 +1 @@ +task: Failed to run task "foobar": exit status 1 \ No newline at end of file diff --git a/testdata/label_error/testdata/TestLabel-label_in_error.golden b/testdata/label_error/testdata/TestLabel-label_in_error.golden new file mode 100644 index 0000000000..9ac0e341fc --- /dev/null +++ b/testdata/label_error/testdata/TestLabel-label_in_error.golden @@ -0,0 +1 @@ +task: [foobar] false