diff --git a/CHANGELOG.md b/CHANGELOG.md index f77aab0a..0950eecf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +- Add ability to specify vars when including a Taskfile. + [Check out the documentation](http://localhost:3000/#/usage?id=vars-of-included-taskfiles) + for more information. + ([#677](https://github.com/go-task/task/pull/677)). + ## v3.11.0 - 2022-01-19 - Task now supports printing begin and end messages when using the `group` diff --git a/docs/usage.md b/docs/usage.md index e59ea659..b334ca20 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -187,6 +187,31 @@ tasks: - echo "This command can still be successfully executed if ./tests/Taskfile.yml does not exist" ``` +### Vars of included Taskfiles + +You can also specify variables when including a Taskfile. This may be useful +for having reusable Taskfile that can be tweaked or even included more than once: + +```yaml +version: '3' + +includes: + backend: + taskfile: ./taskfiles/Docker.yml + vars: + DOCKER_IMAGE: backend_image + + frontend: + taskfile: ./taskfiles/Docker.yml + vars: + DOCKER_IMAGE: frontend_image +``` + +> NOTE: Vars declared in the included Taskfile have preference over the +included ones! If you want a variable in an included Taskfile to be overridable +use the [default function](https://go-task.github.io/slim-sprig/defaults.html): +`MY_VAR: '{{.MY_VAR | default "my-default-value"}}'`. + ## Task directory By default, tasks will be executed in the directory where the Taskfile is @@ -535,6 +560,8 @@ They are listed below in order of importance (e.g. most important first): - Variables declared in the task definition - Variables given while calling a task from another (See [Calling another task](#calling-another-task) above) +- Variables of the [included Taskfile](#including-other-taskfiles) (when the task is included) +- Variables of the [inclusion of the Taskfile](#vars-of-included-taskfiles) (when the task is included) - Global variables (those declared in the `vars:` option in the Taskfile) - Environment variables diff --git a/internal/compiler/v3/compiler_v3.go b/internal/compiler/v3/compiler_v3.go index 3634d2e7..4ccce500 100644 --- a/internal/compiler/v3/compiler_v3.go +++ b/internal/compiler/v3/compiler_v3.go @@ -74,12 +74,35 @@ func (c *CompilerV3) getVariables(t *taskfile.Task, call *taskfile.Call, evaluat } rangeFunc := getRangeFunc(c.Dir) + var taskRangeFunc func(k string, v taskfile.Var) error + if t != nil { + // NOTE(@andreynering): We're manually joining these paths here because + // this is the raw task, not the compiled one. + tr := templater.Templater{Vars: result, RemoveNoValue: true} + dir := tr.Replace(t.Dir) + if err := tr.Err(); err != nil { + return nil, err + } + if !filepath.IsAbs(dir) { + dir = filepath.Join(c.Dir, dir) + } + taskRangeFunc = getRangeFunc(dir) + } + if err := c.TaskfileEnv.Range(rangeFunc); err != nil { return nil, err } if err := c.TaskfileVars.Range(rangeFunc); err != nil { return nil, err } + if t != nil { + if err := t.IncludedTaskfileVars.Range(taskRangeFunc); err != nil { + return nil, err + } + if err := t.IncludeVars.Range(rangeFunc); err != nil { + return nil, err + } + } if t == nil || call == nil { return result, nil @@ -88,19 +111,6 @@ func (c *CompilerV3) getVariables(t *taskfile.Task, call *taskfile.Call, evaluat if err := call.Vars.Range(rangeFunc); err != nil { return nil, err } - - // NOTE(@andreynering): We're manually joining these paths here because - // this is the raw task, not the compiled one. - tr := templater.Templater{Vars: result, RemoveNoValue: true} - dir := tr.Replace(t.Dir) - if err := tr.Err(); err != nil { - return nil, err - } - if !filepath.IsAbs(dir) { - dir = filepath.Join(c.Dir, dir) - } - taskRangeFunc := getRangeFunc(dir) - if err := t.Vars.Range(taskRangeFunc); err != nil { return nil, err } diff --git a/task_test.go b/task_test.go index d4f820b1..9451a664 100644 --- a/task_test.go +++ b/task_test.go @@ -1232,16 +1232,16 @@ func TestIncludedVars(t *testing.T) { expectedOutputOrder := strings.TrimSpace(` task: [included1:task1] echo "VAR_1 is included1-var1" VAR_1 is included1-var1 -task: [included1:task1] echo "VAR_2 is incldued-default-var2" -VAR_2 is incldued-default-var2 +task: [included1:task1] echo "VAR_2 is included-default-var2" +VAR_2 is included-default-var2 task: [included2:task1] echo "VAR_1 is included2-var1" VAR_1 is included2-var1 -task: [included2:task1] echo "VAR_2 is incldued-default-var2" -VAR_2 is incldued-default-var2 +task: [included2:task1] echo "VAR_2 is included-default-var2" +VAR_2 is included-default-var2 task: [included3:task1] echo "VAR_1 is included-default-var1" VAR_1 is included-default-var1 -task: [included3:task1] echo "VAR_2 is incldued-default-var2" -VAR_2 is incldued-default-var2 +task: [included3:task1] echo "VAR_2 is included-default-var2" +VAR_2 is included-default-var2 `) assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "task1"})) t.Log(buff.String()) diff --git a/taskfile/read/taskfile.go b/taskfile/read/taskfile.go index ce103d51..46e30211 100644 --- a/taskfile/read/taskfile.go +++ b/taskfile/read/taskfile.go @@ -110,15 +110,11 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) { } for _, task := range includedTaskfile.Tasks { - if includedTask.Vars != nil { - if task.Vars == nil { - task.Vars = &taskfile.Vars{} - } - task.Vars.Merge(includedTask.Vars) - } if !filepath.IsAbs(task.Dir) { task.Dir = filepath.Join(includedTask.Dir, task.Dir) } + task.IncludeVars = includedTask.Vars + task.IncludedTaskfileVars = includedTaskfile.Vars } } diff --git a/taskfile/task.go b/taskfile/task.go index f9498eac..12484f0b 100644 --- a/taskfile/task.go +++ b/taskfile/task.go @@ -5,25 +5,27 @@ type Tasks map[string]*Task // Task represents a task type Task struct { - Task string - Cmds []*Cmd - Deps []*Dep - Label string - Desc string - Summary string - Sources []string - Generates []string - Status []string - Preconditions []*Precondition - Dir string - Vars *Vars - Env *Vars - Silent bool - Interactive bool - Method string - Prefix string - IgnoreError bool - Run string + Task string + Cmds []*Cmd + Deps []*Dep + Label string + Desc string + Summary string + Sources []string + Generates []string + Status []string + Preconditions []*Precondition + Dir string + Vars *Vars + Env *Vars + Silent bool + Interactive bool + Method string + Prefix string + IgnoreError bool + Run string + IncludeVars *Vars + IncludedTaskfileVars *Vars } func (t *Task) Name() string { diff --git a/testdata/include_with_vars/include/Taskfile.include.yml b/testdata/include_with_vars/include/Taskfile.include.yml index dd2a4e65..3bb7a68e 100644 --- a/testdata/include_with_vars/include/Taskfile.include.yml +++ b/testdata/include_with_vars/include/Taskfile.include.yml @@ -1,8 +1,8 @@ version: "3" vars: - VAR_1: included-default-var1 - VAR_2: incldued-default-var2 + VAR_1: '{{.VAR_1 | default "included-default-var1"}}' + VAR_2: '{{.VAR_2 | default "included-default-var2"}}' tasks: task1: diff --git a/variables.go b/variables.go index 6e69e4b6..b9faa720 100644 --- a/variables.go +++ b/variables.go @@ -46,21 +46,23 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf r := templater.Templater{Vars: vars, RemoveNoValue: v >= 3.0} new := taskfile.Task{ - Task: origTask.Task, - Label: r.Replace(origTask.Label), - Desc: r.Replace(origTask.Desc), - Summary: r.Replace(origTask.Summary), - Sources: r.ReplaceSlice(origTask.Sources), - Generates: r.ReplaceSlice(origTask.Generates), - Dir: r.Replace(origTask.Dir), - Vars: nil, - Env: nil, - Silent: origTask.Silent, - Interactive: origTask.Interactive, - Method: r.Replace(origTask.Method), - Prefix: r.Replace(origTask.Prefix), - IgnoreError: origTask.IgnoreError, - Run: r.Replace(origTask.Run), + Task: origTask.Task, + Label: r.Replace(origTask.Label), + Desc: r.Replace(origTask.Desc), + Summary: r.Replace(origTask.Summary), + Sources: r.ReplaceSlice(origTask.Sources), + Generates: r.ReplaceSlice(origTask.Generates), + Dir: r.Replace(origTask.Dir), + Vars: nil, + Env: nil, + Silent: origTask.Silent, + Interactive: origTask.Interactive, + Method: r.Replace(origTask.Method), + Prefix: r.Replace(origTask.Prefix), + IgnoreError: origTask.IgnoreError, + Run: r.Replace(origTask.Run), + IncludeVars: origTask.IncludeVars, + IncludedTaskfileVars: origTask.IncludedTaskfileVars, } new.Dir, err = execext.Expand(new.Dir) if err != nil {