From 8baba71cc3e832bc578f22f1cfedbe1b6b4fca14 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Sun, 19 Jul 2026 23:06:14 +0200 Subject: [PATCH 1/2] feat: support enum.ref in interactive prompts --- CHANGELOG.md | 3 +++ requires.go | 16 +++++++++++++- requires_internal_test.go | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 requires_internal_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index bc921400c5..72ec5c474f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ (#2184 by @jubr). - Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing `http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin). +- Added support for `enum.ref` in `--interactive` prompts. Required vars using + `enum.ref` now show the selection list like static enums, instead of falling + back to free-form input (#2817 by @vmaerten). ## v3.52.0 - 2026-07-02 diff --git a/requires.go b/requires.go index f235a3d013..e425f83ce3 100644 --- a/requires.go +++ b/requires.go @@ -7,6 +7,7 @@ import ( "github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/internal/input" + "github.com/go-task/task/v3/internal/templater" "github.com/go-task/task/v3/internal/term" "github.com/go-task/task/v3/taskfile/ast" ) @@ -45,7 +46,7 @@ func (e *Executor) promptDepsVars(calls []*Call) error { for _, v := range getMissingRequiredVars(compiledTask) { if !varsMap.Has(v.Name) { - varsMap.Set(v.Name, v) + varsMap.Set(v.Name, resolveEnumRefForPrompt(v, compiledTask.Vars)) } } @@ -216,3 +217,16 @@ func getEnumValues(e *ast.Enum) []string { } return e.Value } + +// resolveEnumRefForPrompt returns a copy of v with its enum ref resolved into +// concrete values, so the interactive prompter can show a Select. Refs that +// depend on dynamic vars may not resolve here and fall back to free-form input. +func resolveEnumRefForPrompt(v *ast.VarsWithValidation, vars *ast.Vars) *ast.VarsWithValidation { + if v.Enum == nil || v.Enum.Ref == "" || len(v.Enum.Value) > 0 { + return v + } + vCopy := v.DeepCopy() + cache := &templater.Cache{Vars: vars} + _ = resolveEnumRefs(&ast.Requires{Vars: []*ast.VarsWithValidation{vCopy}}, cache) + return vCopy +} diff --git a/requires_internal_test.go b/requires_internal_test.go new file mode 100644 index 0000000000..fcfd6a1af9 --- /dev/null +++ b/requires_internal_test.go @@ -0,0 +1,44 @@ +package task + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/go-task/task/v3/taskfile/ast" +) + +func TestResolveEnumRefForPrompt(t *testing.T) { + t.Parallel() + + vars := ast.NewVars() + vars.Set("ALLOWED_ENVS", ast.Var{Value: []any{"dev", "staging", "prod"}}) + + t.Run("resolves a static ref into values", func(t *testing.T) { + t.Parallel() + + v := &ast.VarsWithValidation{Name: "ENV", Enum: &ast.Enum{Ref: ".ALLOWED_ENVS"}} + + resolved := resolveEnumRefForPrompt(v, vars) + + require.Equal(t, []string{"dev", "staging", "prod"}, getEnumValues(resolved.Enum)) + require.Empty(t, v.Enum.Value, "input var must not be mutated") + require.Equal(t, ".ALLOWED_ENVS", v.Enum.Ref) + }) + + t.Run("leaves an unresolvable ref as-is", func(t *testing.T) { + t.Parallel() + + v := &ast.VarsWithValidation{Name: "ENV", Enum: &ast.Enum{Ref: ".NONEXISTENT"}} + + require.Empty(t, getEnumValues(resolveEnumRefForPrompt(v, vars).Enum)) + }) + + t.Run("passes through a static enum unchanged", func(t *testing.T) { + t.Parallel() + + v := &ast.VarsWithValidation{Name: "ENV", Enum: &ast.Enum{Value: []string{"a", "b"}}} + + require.Same(t, v, resolveEnumRefForPrompt(v, vars)) + }) +} From 3aec873f2d0cea207f4474824c4684f09155bb38 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Mon, 20 Jul 2026 18:07:01 +0200 Subject: [PATCH 2/2] Trigger Build