fix: resolve dynamic enum refs in interactive prompts by vmaerten · Pull Request #3070 · go-task/task · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
36 changes: 36 additions & 0 deletions executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,42 @@ func TestSecretVars(t *testing.T) {
)
}

func TestInteractiveEnumRef(t *testing.T) {
t.Parallel()
for _, name := range []string{"deploy", "pipeline", "chained", "default-value", "explicit", "empty", "waiting-for-answer", "cached", "already-provided"} {
input := "j\r"
if name == "empty" {
input = "api\r"
}
opts := []ExecutorTestOption{
WithName(name),
WithTask(name),
WithInput(input),
WithExecutorOptions(
task.WithDir("testdata/interactive_enum_ref"),
task.WithAssumeTerm(true),
task.WithInteractive(true),
task.WithSilent(true),
),
WithPostProcessFn(func(t *testing.T, output []byte) []byte {
t.Helper()
// The final value verifies selection; discard terminal redraws,
// whose escape sequences depend on the platform and environment.
start := bytes.Index(output, []byte("Selected "))
require.NotEqual(t, -1, start)
return output[start:]
}),
}
if name == "cached" {
opts = append(opts, WithVar("COUNT_FILE", filepath.Join(t.TempDir(), "count")))
}
if name == "already-provided" {
opts = append(opts, WithTask("deploy"), WithVar("SERVICE", "db"))
}
NewExecutorTest(t, opts...)
}
}

func TestRequires(t *testing.T) {
t.Parallel()
NewExecutorTest(t,
Expand Down
23 changes: 21 additions & 2 deletions requires.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,28 @@ func (e *Executor) promptDepsVars(calls []*Call) error {
return err
}

for _, v := range getMissingRequiredVars(compiledTask) {
missing := getMissingRequiredVars(compiledTask)
vars := compiledTask.Vars
for _, v := range missing {
if varsMap.Has(v.Name) || v.Enum == nil || v.Enum.Ref == "" {
continue
}
t, err := e.GetTask(call)
if err != nil {
return err
}
// Resolve once per call, using the compiler's existing shell cache.
// Some shell variables need the answers we haven't prompted for yet;
// retain the fast prompt fallback when early evaluation fails.
if evaluated, err := e.Compiler.GetVariables(t, call); err == nil {
vars = evaluated
}
break
}

for _, v := range missing {
if !varsMap.Has(v.Name) {
varsMap.Set(v.Name, refs.ResolveEnum(v, compiledTask.Vars))
varsMap.Set(v.Name, refs.ResolveEnum(v, vars))
}
}

Expand Down
86 changes: 86 additions & 0 deletions testdata/interactive_enum_ref/Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
version: '3'

vars:
AVAILABLE_SERVICES:
sh: printf 'api\nweb\ndb\n'
ALLOWED_ENVS: [dev, staging, prod]

tasks:
deploy:
requires:
vars:
- name: SERVICE
enum:
ref: .AVAILABLE_SERVICES | splitLines | compact
cmds:
- echo "Selected {{.SERVICE}}"

pipeline:
deps: [deploy]

chained:
vars:
JSON:
sh: printf '["api","web","db"]'
SERVICES:
ref: .JSON | fromJson
requires:
vars:
- name: SERVICE
enum: {ref: .SERVICES}
cmds:
- echo "Selected {{.SERVICE}}"

default-value:
requires:
vars:
- name: SERVICE
enum:
ref: '.AVAILABLE_SERVICES | default "incorrect" | splitLines | compact'
cmds:
- echo "Selected {{.SERVICE}}"

cached:
vars:
SERVICES:
sh: printf x >> '{{.COUNT_FILE}}'; printf 'api\nweb\ndb\n'
requires:
vars:
- name: SERVICE
enum: {ref: .SERVICES | splitLines | compact}
cmds:
- echo "Selected {{.SERVICE}}"
- test "$(cat '{{.COUNT_FILE}}')" = x

empty:
vars:
SERVICES:
sh: printf ''
requires:
vars:
- name: SERVICE
enum: {ref: .SERVICES | splitLines | compact}
cmds:
- echo "Selected {{.SERVICE}}"

waiting-for-answer:
vars:
RESULT:
sh: test -n '{{.ENV}}' && printf '{{.ENV}}'
requires:
vars:
- name: ENV
enum: {ref: .ALLOWED_ENVS}
cmds:
- echo "Selected {{.RESULT}}"

explicit:
vars:
RESULT:
sh: test -n '{{.SERVICE}}' && printf '{{.SERVICE}}'
requires:
vars:
- name: SERVICE
enum: [api, web, db]
cmds:
- echo "Selected {{.RESULT}}"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected db
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected web
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected web
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected web
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected web
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected api
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected web
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Selected web
Loading