mirror of
https://github.com/go-task/task.git
synced 2026-08-29 10:08:27 +02:00
fix: support .MATCH in wildcard include vars
This commit is contained in:
@@ -11,6 +11,9 @@
|
|||||||
(#2184 by @jubr).
|
(#2184 by @jubr).
|
||||||
- Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing
|
- Fixed `joinUrl` collapsing the `//` in a URL scheme (e.g. producing
|
||||||
`http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin).
|
`http:/localhost` instead of `http://localhost`) (#2915 by @vsaraikin).
|
||||||
|
- Fixed `.MATCH` not being available in the `vars` of an include declared with a
|
||||||
|
wildcard namespace (e.g. `'stack:*'`), so `{{index .MATCH 0}}` can now be used
|
||||||
|
to feed captured segments into the included Taskfile (#2732 by @vmaerten).
|
||||||
|
|
||||||
## v3.52.0 - 2026-07-02
|
## v3.52.0 - 2026-07-02
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,15 @@ func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// MATCH is populated by GetTask from the wildcard match. Expose it early so
|
||||||
|
// that include vars coming from a wildcard include namespace can reference
|
||||||
|
// the captured segments, e.g. `{{index .MATCH 0}}`. It is re-set identically
|
||||||
|
// when call.Vars is ranged below, which is harmless.
|
||||||
|
if call != nil && call.Vars != nil {
|
||||||
|
if match, ok := call.Vars.Get("MATCH"); ok {
|
||||||
|
result.Set("MATCH", match)
|
||||||
|
}
|
||||||
|
}
|
||||||
if t != nil {
|
if t != nil {
|
||||||
for k, v := range t.IncludeVars.All() {
|
for k, v := range t.IncludeVars.All() {
|
||||||
if err := rangeFunc(k, v); err != nil {
|
if err := rangeFunc(k, v); err != nil {
|
||||||
|
|||||||
49
task_test.go
49
task_test.go
@@ -3040,6 +3040,55 @@ func TestWildcard(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIncludesWildcardVars(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
call string
|
||||||
|
expectedOutput string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "match feeds include var",
|
||||||
|
call: "stack:prod:deploy",
|
||||||
|
expectedOutput: "Deploying to prod\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "different match",
|
||||||
|
call: "stack:staging:deploy",
|
||||||
|
expectedOutput: "Deploying to staging\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no match",
|
||||||
|
call: "stack:deploy",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.call, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := task.NewExecutor(
|
||||||
|
task.WithDir("testdata/includes_wildcard_vars"),
|
||||||
|
task.WithStdout(&buff),
|
||||||
|
task.WithStderr(&buff),
|
||||||
|
task.WithSilent(true),
|
||||||
|
task.WithForce(true),
|
||||||
|
)
|
||||||
|
require.NoError(t, e.Setup())
|
||||||
|
if test.wantErr {
|
||||||
|
require.Error(t, e.Run(t.Context(), &task.Call{Task: test.call}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, e.Run(t.Context(), &task.Call{Task: test.call}))
|
||||||
|
assert.Equal(t, test.expectedOutput, buff.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// enableExperimentForTest enables the experiment behind pointer e for the duration of test t and sub-tests,
|
// enableExperimentForTest enables the experiment behind pointer e for the duration of test t and sub-tests,
|
||||||
// with the experiment being restored to its previous state when tests complete.
|
// with the experiment being restored to its previous state when tests complete.
|
||||||
//
|
//
|
||||||
|
|||||||
7
testdata/includes_wildcard_vars/Taskfile.yml
vendored
Normal file
7
testdata/includes_wildcard_vars/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
includes:
|
||||||
|
'stack:*':
|
||||||
|
taskfile: ./stack/Taskfile.yml
|
||||||
|
vars:
|
||||||
|
ENV: '{{index .MATCH 0}}'
|
||||||
6
testdata/includes_wildcard_vars/stack/Taskfile.yml
vendored
Normal file
6
testdata/includes_wildcard_vars/stack/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
deploy:
|
||||||
|
cmds:
|
||||||
|
- echo "Deploying to {{.ENV}}"
|
||||||
@@ -461,6 +461,31 @@ includes:
|
|||||||
DOCKER_IMAGE: frontend_image
|
DOCKER_IMAGE: frontend_image
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also use a [wildcard](#wildcard-arguments) in the include's namespace and
|
||||||
|
reference the captured segments through the `.MATCH` variable when setting the
|
||||||
|
include vars. This lets a single include be reused across many namespaces without
|
||||||
|
the included Taskfile needing to know how the value is extracted:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
'stack:*':
|
||||||
|
taskfile: ./taskfiles/Stack.yml
|
||||||
|
vars:
|
||||||
|
ENV: '{{index .MATCH 0}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Running `task stack:prod:deploy` sets `ENV` to `prod` for the included Taskfile.
|
||||||
|
|
||||||
|
::: info
|
||||||
|
|
||||||
|
`.MATCH` is only available in the include's `vars`. The `taskfile` and `dir`
|
||||||
|
fields are resolved when Taskfiles are loaded and merged, before any task is
|
||||||
|
called, so no wildcard has been matched yet at that point.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
### Namespace aliases
|
### Namespace aliases
|
||||||
|
|
||||||
When including a Taskfile, you can give the namespace a list of `aliases`. This
|
When including a Taskfile, you can give the namespace a list of `aliases`. This
|
||||||
|
|||||||
Reference in New Issue
Block a user