Repository: go-task/task (Go)

Issue:
--exit-code doesn't work for nested tasks
### Setup

```yaml
# ./Taskfile.yml

version: "3"

tasks:
  direct:
    cmds:
      - exit 42

  indirect:
    cmds:
      - task: direct
```

### Test

```console
$ task direct --exit-code; echo $?
task: [direct] exit 42
task: Failed to run task "direct": exit status 42
42
$ task indirect --exit-code; echo $?
task: [direct] exit 42
task: Failed to run task "indirect": task: Failed to run task "direct": exit status 42
201
```

#### Expected result

```
42
42
```

#### Actual result

```
42
201
```

### Environment

- Task version: Task version: v3.27.1
- Operating system: x86_64 GNU/Linux
- Experiments enabled:



Discussion:
@Zebradil Thanks for the bug report. I've done a bit of digging and pushed up a PR: #1270. Please feel free to check it and see if it works for you.
Hey @pd93, thanks a lot for the quick fix. I have tested it, works as expected now.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 170d5a24ec..658e245d15 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
 
 - Fixed variable propagation in multi-level includes (#778, #996, #1256 by
   @hudclark).
+- Fixed a bug where the `--exit-code` code flag was not returning the correct
+  exit code when calling commands indirectly (#1266, #1270 by @pd93).
 
 ## v3.27.1 - 2023-06-30
 
diff --git a/task.go b/task.go
index 7cca798035..cb55955403 100644
--- a/task.go
+++ b/task.go
@@ -239,6 +239,10 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
 					continue
 				}
 
+				if !call.Direct {
+					return err
+				}
+
 				return &errors.TaskRunError{TaskName: t.Task, Err: err}
 			}
 		}


Test patch:
diff --git a/task_test.go b/task_test.go
index c3b2bc3e86..950a1b36b9 100644
--- a/task_test.go
+++ b/task_test.go
@@ -1823,21 +1823,39 @@ Hello bar
 
 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,
+	tests := []struct {
+		name     string
+		task     string
+		expected int
+	}{
+		{
+			name:     "direct task",
+			task:     "direct",
+			expected: 42,
+		}, {
+			name:     "indirect task",
+			task:     "indirect",
+			expected: 42,
+		},
 	}
-	require.NoError(t, e.Setup())
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			var buff bytes.Buffer
+			e := &task.Executor{
+				Dir:    dir,
+				Stdout: &buff,
+				Stderr: &buff,
+				Silent: true,
+			}
+			require.NoError(t, e.Setup())
 
-	err := e.Run(context.Background(), taskfile.Call{Task: "test-exit-code"})
-	require.Error(t, err)
-	casted, ok := err.(*errors.TaskRunError)
-	assert.True(t, ok, "cannot cast returned error to *task.TaskRunError")
-	assert.Equal(t, 42, casted.TaskExitCode(), "unexpected exit code from task")
+			err := e.Run(context.Background(), taskfile.Call{Task: test.task, Direct: true})
+			require.Error(t, err)
+			taskRunErr, ok := err.(*errors.TaskRunError)
+			assert.True(t, ok, "cannot cast returned error to *task.TaskRunError")
+			assert.Equal(t, test.expected, taskRunErr.TaskExitCode(), "unexpected exit code from task")
+		})
+	}
 }
 
 func TestEvaluateSymlinksInPaths(t *testing.T) {
diff --git a/testdata/error_code/Taskfile.yml b/testdata/error_code/Taskfile.yml
index b2c83ff883..ac5a2b6965 100644
--- a/testdata/error_code/Taskfile.yml
+++ b/testdata/error_code/Taskfile.yml
@@ -1,6 +1,10 @@
 version: '3'
 
 tasks:
-  test-exit-code:
+  direct:
     cmds:
       - exit 42
+
+  indirect:
+    cmds:
+      - task: direct