feat(taskfile): skip var merge when SCOPED_INCLUDES enabled

When the SCOPED_INCLUDES experiment is enabled, variables from included
Taskfiles are no longer merged globally. They remain in their original
Taskfile within the DAG.

Exception: flatten includes still merge variables globally to allow
sharing common variables across multiple Taskfiles.
This commit is contained in:
Valentin Maerten
2025-12-26 21:02:33 +01:00
parent da927ad5fe
commit 0dbeaaf187
3 changed files with 14 additions and 6 deletions

View File

@@ -20,6 +20,7 @@ import (
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/output"
"github.com/go-task/task/v3/internal/version"
"github.com/go-task/task/v3/experiments"
"github.com/go-task/task/v3/taskfile"
"github.com/go-task/task/v3/taskfile/ast"
)
@@ -105,7 +106,7 @@ func (e *Executor) readTaskfile(node taskfile.Node) error {
return err
}
e.Graph = graph
if e.Taskfile, err = graph.Merge(); err != nil {
if e.Taskfile, err = graph.Merge(experiments.ScopedIncludes.Enabled()); err != nil {
return err
}
return nil

View File

@@ -57,7 +57,9 @@ func (tfg *TaskfileGraph) Root() (*TaskfileVertex, error) {
return tfg.Vertex(hashes[0])
}
func (tfg *TaskfileGraph) Merge() (*Taskfile, error) {
// Merge merges all included Taskfiles into the root Taskfile.
// If skipVarsMerge is true, variables are not merged (used for scoped includes).
func (tfg *TaskfileGraph) Merge(skipVarsMerge bool) (*Taskfile, error) {
hashes, err := graph.TopologicalSort(tfg.Graph)
if err != nil {
return nil, err
@@ -104,6 +106,7 @@ func (tfg *TaskfileGraph) Merge() (*Taskfile, error) {
if err := vertex.Taskfile.Merge(
includedVertex.Taskfile,
include,
skipVarsMerge,
); err != nil {
return err
}

View File

@@ -36,8 +36,9 @@ type Taskfile struct {
Interval time.Duration
}
// Merge merges the second Taskfile into the first
func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include) error {
// Merge merges the second Taskfile into the first.
// If skipVarsMerge is true, variables are not merged (used for scoped includes).
func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include, skipVarsMerge bool) error {
if !t1.Version.Equal(t2.Version) {
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
}
@@ -67,8 +68,11 @@ func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include) error {
}
}
}
t1.Vars.Merge(t2.Vars, include)
t1.Env.Merge(t2.Env, include)
// Only merge vars if not using scoped includes, or if flattening
if !skipVarsMerge || include.Flatten {
t1.Vars.Merge(t2.Vars, include)
t1.Env.Merge(t2.Env, include)
}
return t1.Tasks.Merge(t2.Tasks, include, t1.Vars)
}