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
2 changes: 2 additions & 0 deletions executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,8 @@ func TestForCmds(t *testing.T) {
{name: "loop-generates-glob"},
{name: "loop-vars"},
{name: "loop-vars-sh"},
{name: "loop-vars-ref"},
{name: "loop-vars-ref-as"},
{name: "loop-task"},
{name: "loop-task-as"},
{name: "loop-different-tasks"},
Expand Down
18 changes: 15 additions & 3 deletions internal/templater/templater.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ func (r *Cache) Err() error {
}

func ResolveRef(ref string, cache *Cache) any {
return ResolveRefWithExtra(ref, cache, nil)
}

// ResolveRefWithExtra resolves a ref string using the cache plus any
// additional data (e.g. loop variables) provided in extra.
func ResolveRefWithExtra(ref string, cache *Cache, extra map[string]any) any {
// If there is already an error, do nothing
if cache.err != nil {
return nil
Expand All @@ -42,15 +48,21 @@ func ResolveRef(ref string, cache *Cache) any {
cache.cacheMap = cache.Vars.ToCacheMap()
}

data := cache.cacheMap
if len(extra) > 0 {
data = maps.Clone(cache.cacheMap)
maps.Copy(data, extra)
}

if ref == "." {
return cache.cacheMap
return data
}
t, err := template.New("resolver").Funcs(templateFuncs).Parse(fmt.Sprintf("{{%s}}", ref))
if err != nil {
cache.err = err
return nil
}
val, err := t.Resolve(cache.cacheMap)
val, err := t.Resolve(data)
if err != nil {
cache.err = err
return nil
Expand Down Expand Up @@ -121,7 +133,7 @@ func ReplaceVar(v ast.Var, cache *Cache) ast.Var {

func ReplaceVarWithExtra(v ast.Var, cache *Cache, extra map[string]any) ast.Var {
if v.Ref != "" {
return ast.Var{Value: ResolveRef(v.Ref, cache)}
return ast.Var{Value: ResolveRefWithExtra(v.Ref, cache, extra)}
}
return ast.Var{
Value: ReplaceWithExtra(v.Value, cache, extra),
Expand Down
20 changes: 20 additions & 0 deletions internal/templater/templater_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package templater

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/go-task/task/v3/taskfile/ast"
)

func TestReplaceVarWithExtra_ResolvesRefFromExtra(t *testing.T) {
t.Parallel()

cache := Cache{Vars: ast.NewVars()}
extra := map[string]any{"ITEM": "a"}

got := ReplaceVarWithExtra(ast.Var{Ref: ".ITEM"}, &cache, extra)

require.Equal(t, "a", got.Value)
}
29 changes: 29 additions & 0 deletions testdata/for/cmds/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,35 @@ tasks:
var: FOO
cmd: cat "{{.ITEM}}"

# Loop variable passed by ref should work (currently broken)
loop-vars-ref:
vars:
FOO: "a b"
cmds:
- for:
var: FOO
task: process
vars:
THING:
ref: .ITEM

# Loop variable with alias passed by ref
loop-vars-ref-as:
vars:
FOO: "x y"
cmds:
- for:
var: FOO
as: VAL
task: process
vars:
THING:
ref: .VAL

process:
internal: true
cmd: echo "{{.THING}}"

# Loop over another task
loop-task:
vars:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x
y
2 changes: 2 additions & 0 deletions testdata/for/cmds/testdata/TestForCmds-loop-vars-ref.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a
b