diff --git a/executor_test.go b/executor_test.go index d810e652f0..6e3ff3e1ec 100644 --- a/executor_test.go +++ b/executor_test.go @@ -1160,6 +1160,10 @@ func TestIf(t *testing.T) { // For loop with if {name: "if-in-for-loop", task: "if-in-for-loop", verbose: true}, + + // Task-level if with dynamic variable + {name: "task-if-dynamic-true", task: "task-if-dynamic-true"}, + {name: "task-if-dynamic-false", task: "task-if-dynamic-false", verbose: true}, } for _, test := range tests { diff --git a/task.go b/task.go index 0184793c91..54cda92762 100644 --- a/task.go +++ b/task.go @@ -148,6 +148,20 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error { return nil } + // Check required vars early (before template compilation) if we can't prompt. + // This gives a clear "missing required variables" error instead of a template error. + if !e.canPrompt() { + if err := e.areTaskRequiredVarsSet(t); err != nil { + return err + } + } + + t, err = e.CompiledTask(call) + if err != nil { + return err + } + + // Check if condition after CompiledTask so dynamic variables are resolved if strings.TrimSpace(t.If) != "" { if err := execext.RunCommand(ctx, &execext.RunCommandOptions{ Command: t.If, @@ -159,7 +173,7 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error { } } - // Prompt for missing required vars (just-in-time for sequential task calls) + // Prompt for missing required vars after if check (avoid prompting if task won't run) prompted, err := e.promptTaskVars(t, call) if err != nil { return err @@ -176,11 +190,6 @@ func (e *Executor) RunTask(ctx context.Context, call *Call) error { return err } - t, err = e.CompiledTask(call) - if err != nil { - return err - } - if err := e.areTaskRequiredVarsAllowedValuesSet(t); err != nil { return err } diff --git a/testdata/if/Taskfile.yml b/testdata/if/Taskfile.yml index 316b732ff0..72b72ed982 100644 --- a/testdata/if/Taskfile.yml +++ b/testdata/if/Taskfile.yml @@ -158,3 +158,21 @@ tasks: if: '{{ eq .ENV "dev" }}' cmds: - echo "should not appear" + + # Task-level if with dynamic variable (condition met) + task-if-dynamic-true: + vars: + ENABLE_FEATURE: + sh: 'echo "true"' + if: '{{ eq .ENABLE_FEATURE "true" }}' + cmds: + - echo "dynamic feature enabled" + + # Task-level if with dynamic variable (condition not met) + task-if-dynamic-false: + vars: + ENABLE_FEATURE: + sh: 'echo "false"' + if: '{{ eq .ENABLE_FEATURE "true" }}' + cmds: + - echo "should not appear" diff --git a/testdata/if/testdata/TestIf-task-if-dynamic-false.golden b/testdata/if/testdata/TestIf-task-if-dynamic-false.golden new file mode 100644 index 0000000000..f17ef42029 --- /dev/null +++ b/testdata/if/testdata/TestIf-task-if-dynamic-false.golden @@ -0,0 +1,2 @@ +task: dynamic variable: "echo \"false\"" result: "false" +task: if condition not met - skipped: "task-if-dynamic-false" diff --git a/testdata/if/testdata/TestIf-task-if-dynamic-true.golden b/testdata/if/testdata/TestIf-task-if-dynamic-true.golden new file mode 100644 index 0000000000..4d1ec95b6a --- /dev/null +++ b/testdata/if/testdata/TestIf-task-if-dynamic-true.golden @@ -0,0 +1 @@ +dynamic feature enabled