feat: support excluding task namespaces (#2959)

This commit is contained in:
星尘
2026-08-10 22:23:51 +08:00
committed by GitHub
parent fc49c72647
commit 2888867c94
8 changed files with 78 additions and 10 deletions

View File

@@ -1717,6 +1717,25 @@ func TestIncludesWithExclude(t *testing.T) {
require.Error(t, err)
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "included:foo:child"})
require.NoError(t, err)
assert.Equal(t, "foo:child\n", buff.String())
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "included:namespace"})
require.NoError(t, err)
assert.Equal(t, "namespace\n", buff.String())
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "included:namespace:one"})
require.Error(t, err)
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "included:namespace-other:one"})
require.NoError(t, err)
assert.Equal(t, "namespace-other:one\n", buff.String())
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "bar"})
require.Error(t, err)
buff.Reset()
@@ -1724,6 +1743,20 @@ func TestIncludesWithExclude(t *testing.T) {
err = e.Run(t.Context(), &task.Call{Task: "foo"})
require.NoError(t, err)
assert.Equal(t, "foo\n", buff.String())
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "namespace"})
require.NoError(t, err)
assert.Equal(t, "namespace\n", buff.String())
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "namespace:two"})
require.Error(t, err)
buff.Reset()
err = e.Run(t.Context(), &task.Call{Task: "namespace-other:one"})
require.NoError(t, err)
assert.Equal(t, "namespace-other:one\n", buff.String())
}
func TestIncludedTaskfileVarMerging(t *testing.T) {

View File

@@ -37,6 +37,27 @@ type (
IncludeElement orderedmap.Element[string, *Include]
)
func (include *Include) isTaskExcluded(name string) bool {
if include == nil {
return false
}
for _, exclude := range include.Excludes {
namespace, ok := strings.CutSuffix(exclude, NamespaceSeparator+"*")
if ok {
if namespace != "" && strings.HasPrefix(name, namespace+NamespaceSeparator) {
return true
}
continue
}
if name == exclude {
return true
}
}
return false
}
// NewIncludes creates a new instance of Includes and initializes it with the
// provided set of elements, if any. The elements are added in the order they
// are passed.

View File

@@ -130,8 +130,9 @@ func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars)
task.Internal = task.Internal || (include != nil && include.Internal)
taskName := name
// if the task is in the exclude list, don't add it to the merged taskfile
if slices.Contains(include.Excludes, name) {
// If the task or its namespace is in the exclude list, don't add it to
// the merged taskfile.
if include.isTaskExcluded(name) {
continue
}

View File

@@ -4,12 +4,14 @@ includes:
included:
taskfile: ./included/Taskfile.yml
excludes:
- foo
- foo
- namespace:*
included_flatten:
taskfile: ./included/Taskfile.yml
flatten: true
excludes:
- bar
- namespace:*
tasks:
default:

View File

@@ -2,4 +2,9 @@ version: '3'
tasks:
foo: echo foo
foo:child: echo foo:child
bar: echo bar
namespace: echo namespace
namespace:one: echo namespace:one
namespace:two: echo namespace:two
namespace-other:one: echo namespace-other:one

View File

@@ -412,8 +412,10 @@ You can do this by using the
### Exclude tasks from being included
You can exclude tasks from being included by using the `excludes` option. This
option takes the list of tasks to be excluded from this include.
You can exclude tasks or entire namespaces from being included by using the
`excludes` option. This option takes the list of tasks or namespaces to be
excluded from this include. Task names are matched exactly. To exclude a
namespace, append `:*` to its name.
::: code-group
@@ -423,7 +425,7 @@ version: '3'
includes:
included:
taskfile: ./Included.yml
excludes: [foo]
excludes: [foo, 'internal:*', 'debug:*']
```
```yaml [Included.yml]
@@ -432,11 +434,14 @@ version: '3'
tasks:
foo: echo "Foo"
bar: echo "Bar"
internal:setup: echo "Internal setup"
debug:status: echo "Debug status"
```
:::
`task included:foo` will throw an error because the `foo` task is excluded but
`task included:foo`, `task included:internal:setup`, and
`task included:debug:status` will throw errors because they are excluded, but
`task included:bar` will work and display `Bar`.
It's compatible with the `flatten` option.

View File

@@ -308,13 +308,14 @@ includes:
### `excludes`
- **Type**: `[]string`
- **Description**: Tasks to exclude from inclusion
- **Description**: Task names or namespace patterns ending in `:*` to exclude
from inclusion
```yaml
includes:
shared:
taskfile: ./shared.yml
excludes: [internal-setup, debug-only]
excludes: [internal-setup, 'debug:*', 'experimental:*']
```
### `vars`

View File

@@ -746,7 +746,7 @@
}
},
"excludes": {
"description": "A list of tasks to be excluded from inclusion.",
"description": "A list of task names or namespace patterns ending in `:*` to be excluded from inclusion.",
"type": "array",
"items": {
"type": "string"