From 0dbeaaf18708a882a2e7e513e57a910b4855cc75 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Fri, 26 Dec 2025 21:02:33 +0100 Subject: [PATCH] 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. --- setup.go | 3 ++- taskfile/ast/graph.go | 5 ++++- taskfile/ast/taskfile.go | 12 ++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/setup.go b/setup.go index 8b3eca10..b1940886 100644 --- a/setup.go +++ b/setup.go @@ -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 diff --git a/taskfile/ast/graph.go b/taskfile/ast/graph.go index b6c27438..ab961b7d 100644 --- a/taskfile/ast/graph.go +++ b/taskfile/ast/graph.go @@ -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 } diff --git a/taskfile/ast/taskfile.go b/taskfile/ast/taskfile.go index 4ae1dbac..a56d2262 100644 --- a/taskfile/ast/taskfile.go +++ b/taskfile/ast/taskfile.go @@ -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) }