mirror of
https://github.com/go-task/task.git
synced 2025-03-17 21:08:01 +02:00
Merge branch 'internal-tasks' of https://github.com/pd93/task into pd93-internal-tasks
This commit is contained in:
commit
4a5c1e9ec4
@ -194,6 +194,21 @@ tasks:
|
||||
- echo "This command can still be successfully executed if ./tests/Taskfile.yml does not exist"
|
||||
```
|
||||
|
||||
### Internal includes
|
||||
|
||||
Includes marked as internal will set all the tasks of the included file to be
|
||||
internal as well (See the [Internal Tasks](#internal-tasks) section below). This is useful when including utility tasks that are not
|
||||
intended to be used directly by the user.
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
tests:
|
||||
taskfile: ./taskfiles/Utils.yml
|
||||
internal: true
|
||||
```
|
||||
|
||||
### Vars of included Taskfiles
|
||||
|
||||
You can also specify variables when including a Taskfile. This may be useful
|
||||
@ -223,6 +238,30 @@ use the [default function](https://go-task.github.io/slim-sprig/defaults.html):
|
||||
|
||||
:::
|
||||
|
||||
## Internal Tasks
|
||||
|
||||
Internal tasks are tasks that cannot be called directly by the user. They will
|
||||
not appear in the output when running `task --list|--list-all`. Other tasks may
|
||||
call internal tasks in the usual way. This is useful for creating reusable,
|
||||
function-like tasks that have no useful purpose on the command line.
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
|
||||
build-image-1:
|
||||
cmds:
|
||||
- task: build-image
|
||||
vars:
|
||||
DOCKER_IMAGE: image-1
|
||||
|
||||
build-image:
|
||||
internal: true
|
||||
cmds:
|
||||
- docker build -t {{.DOCKER_IMAGE}} .
|
||||
```
|
||||
|
||||
## Task directory
|
||||
|
||||
By default, tasks will be executed in the directory where the Taskfile is
|
||||
|
@ -20,6 +20,14 @@ func (err *taskNotFoundError) Error() string {
|
||||
return fmt.Sprintf(`task: Task %q not found`, err.taskName)
|
||||
}
|
||||
|
||||
type taskInternalError struct {
|
||||
taskName string
|
||||
}
|
||||
|
||||
func (err *taskInternalError) Error() string {
|
||||
return fmt.Sprintf(`task: Task "%s" is internal`, err.taskName)
|
||||
}
|
||||
|
||||
type TaskRunError struct {
|
||||
taskName string
|
||||
err error
|
||||
|
8
help.go
8
help.go
@ -52,7 +52,9 @@ func (e *Executor) printTasks(listAll bool) {
|
||||
func (e *Executor) allTaskNames() (tasks []*taskfile.Task) {
|
||||
tasks = make([]*taskfile.Task, 0, len(e.Taskfile.Tasks))
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
tasks = append(tasks, task)
|
||||
if !task.Internal {
|
||||
tasks = append(tasks, task)
|
||||
}
|
||||
}
|
||||
sort.Slice(tasks, func(i, j int) bool { return tasks[i].Task < tasks[j].Task })
|
||||
return
|
||||
@ -61,7 +63,7 @@ func (e *Executor) allTaskNames() (tasks []*taskfile.Task) {
|
||||
func (e *Executor) tasksWithDesc() (tasks []*taskfile.Task) {
|
||||
tasks = make([]*taskfile.Task, 0, len(e.Taskfile.Tasks))
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.Desc != "" {
|
||||
if !task.Internal && task.Desc != "" {
|
||||
compiledTask, err := e.FastCompiledTask(taskfile.Call{Task: task.Task})
|
||||
if err == nil {
|
||||
task = compiledTask
|
||||
@ -92,7 +94,7 @@ func (e *Executor) ListTaskNames(allTasks bool) {
|
||||
// create a string slice from all map values (*taskfile.Task)
|
||||
s := make([]string, 0, len(e.Taskfile.Tasks))
|
||||
for _, t := range e.Taskfile.Tasks {
|
||||
if allTasks || t.Desc != "" {
|
||||
if (allTasks || t.Desc != "") && !t.Internal {
|
||||
s = append(s, strings.TrimRight(t.Task, ":"))
|
||||
}
|
||||
}
|
||||
|
7
task.go
7
task.go
@ -64,11 +64,16 @@ type Executor struct {
|
||||
func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
||||
// check if given tasks exist
|
||||
for _, c := range calls {
|
||||
if _, ok := e.Taskfile.Tasks[c.Task]; !ok {
|
||||
t, ok := e.Taskfile.Tasks[c.Task]
|
||||
if !ok {
|
||||
// FIXME: move to the main package
|
||||
e.ListTasksWithDesc()
|
||||
return &taskNotFoundError{taskName: c.Task}
|
||||
}
|
||||
if t.Internal {
|
||||
e.ListTasksWithDesc()
|
||||
return &taskInternalError{taskName: c.Task}
|
||||
}
|
||||
}
|
||||
|
||||
if e.Summary {
|
||||
|
80
task_test.go
80
task_test.go
@ -958,6 +958,86 @@ func TestIncludesRelativePath(t *testing.T) {
|
||||
assert.Contains(t, buff.String(), "testdata/includes_rel_path/common")
|
||||
}
|
||||
|
||||
func TestIncludesInternal(t *testing.T) {
|
||||
const dir = "testdata/internal_task"
|
||||
tests := []struct {
|
||||
name string
|
||||
task string
|
||||
expectedErr bool
|
||||
expectedOutput string
|
||||
}{
|
||||
{"included internal task via task", "task-1", false, "Hello, World!\n"},
|
||||
{"included internal task via dep", "task-2", false, "Hello, World!\n"},
|
||||
{
|
||||
"included internal direct",
|
||||
"included:task-3",
|
||||
true,
|
||||
"task: No tasks with description available. Try --list-all to list all tasks\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
|
||||
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
||||
if test.expectedErr {
|
||||
assert.Error(t, err, test.expectedErr)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, test.expectedOutput, buff.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInternalTask(t *testing.T) {
|
||||
const dir = "testdata/internal_task"
|
||||
tests := []struct {
|
||||
name string
|
||||
task string
|
||||
expectedErr bool
|
||||
expectedOutput string
|
||||
}{
|
||||
{"internal task via task", "task-1", false, "Hello, World!\n"},
|
||||
{"internal task via dep", "task-2", false, "Hello, World!\n"},
|
||||
{
|
||||
"internal direct",
|
||||
"task-3",
|
||||
true,
|
||||
"task: No tasks with description available. Try --list-all to list all tasks\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
|
||||
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
||||
if test.expectedErr {
|
||||
assert.Error(t, err, test.expectedErr)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, test.expectedOutput, buff.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSupportedFileNames(t *testing.T) {
|
||||
fileNames := []string{
|
||||
"Taskfile.yml",
|
||||
|
@ -16,6 +16,7 @@ type IncludedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
Optional bool
|
||||
Internal bool
|
||||
AdvancedImport bool
|
||||
Vars *Vars
|
||||
BaseDir string // The directory from which the including taskfile was loaded; used to resolve relative paths
|
||||
@ -101,6 +102,7 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
Taskfile string
|
||||
Dir string
|
||||
Optional bool
|
||||
Internal bool
|
||||
Vars *Vars
|
||||
}
|
||||
if err := unmarshal(&includedTaskfile); err != nil {
|
||||
@ -109,6 +111,7 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
it.Taskfile = includedTaskfile.Taskfile
|
||||
it.Dir = includedTaskfile.Dir
|
||||
it.Optional = includedTaskfile.Optional
|
||||
it.Internal = includedTaskfile.Internal
|
||||
it.AdvancedImport = true
|
||||
it.Vars = includedTaskfile.Vars
|
||||
return nil
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
const NamespaceSeparator = ":"
|
||||
|
||||
// Merge merges the second Taskfile into the first
|
||||
func Merge(t1, t2 *Taskfile, namespaces ...string) error {
|
||||
func Merge(t1, t2 *Taskfile, internal bool, namespaces ...string) error {
|
||||
if t1.Version != t2.Version {
|
||||
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
|
||||
}
|
||||
@ -43,6 +43,8 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error {
|
||||
// have serious side-effects in the future, since we're editing
|
||||
// the original references instead of deep copying them.
|
||||
|
||||
v.Internal = v.Internal || internal
|
||||
|
||||
t1.Tasks[taskNameWithNamespace(k, namespaces...)] = v
|
||||
|
||||
for _, dep := range v.Deps {
|
||||
|
@ -78,6 +78,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
Taskfile: tr.Replace(includedTask.Taskfile),
|
||||
Dir: tr.Replace(includedTask.Dir),
|
||||
Optional: includedTask.Optional,
|
||||
Internal: includedTask.Internal,
|
||||
AdvancedImport: includedTask.AdvancedImport,
|
||||
Vars: includedTask.Vars,
|
||||
BaseDir: includedTask.BaseDir,
|
||||
@ -148,7 +149,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err = taskfile.Merge(t, includedTaskfile, namespace); err != nil {
|
||||
if err = taskfile.Merge(t, includedTaskfile, includedTask.Internal, namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -164,7 +165,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = taskfile.Merge(t, osTaskfile); err != nil {
|
||||
if err = taskfile.Merge(t, osTaskfile, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ type Task struct {
|
||||
Env *Vars
|
||||
Silent bool
|
||||
Interactive bool
|
||||
Internal bool
|
||||
Method string
|
||||
Prefix string
|
||||
IgnoreError bool
|
||||
@ -64,6 +65,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Env *Vars
|
||||
Silent bool
|
||||
Interactive bool
|
||||
Internal bool
|
||||
Method string
|
||||
Prefix string
|
||||
IgnoreError bool `yaml:"ignore_error"`
|
||||
@ -86,6 +88,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
t.Env = task.Env
|
||||
t.Silent = task.Silent
|
||||
t.Interactive = task.Interactive
|
||||
t.Internal = task.Internal
|
||||
t.Method = task.Method
|
||||
t.Prefix = task.Prefix
|
||||
t.IgnoreError = task.IgnoreError
|
||||
|
16
testdata/includes_internal/Taskfile.yml
vendored
Normal file
16
testdata/includes_internal/Taskfile.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included:
|
||||
taskfile: Taskfile2.yml
|
||||
internal: true
|
||||
|
||||
tasks:
|
||||
|
||||
task-1:
|
||||
cmds:
|
||||
- task: included:default
|
||||
|
||||
task-2:
|
||||
deps:
|
||||
- included:default
|
7
testdata/includes_internal/Taskfile2.yml
vendored
Normal file
7
testdata/includes_internal/Taskfile2.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
|
||||
task-3:
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
16
testdata/internal_task/Taskfile.yml
vendored
Normal file
16
testdata/internal_task/Taskfile.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
|
||||
task-1:
|
||||
cmds:
|
||||
- task: task-3
|
||||
|
||||
task-2:
|
||||
deps:
|
||||
- task-3
|
||||
|
||||
task-3:
|
||||
internal: true
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
@ -57,6 +57,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
||||
Env: nil,
|
||||
Silent: origTask.Silent,
|
||||
Interactive: origTask.Interactive,
|
||||
Internal: origTask.Internal,
|
||||
Method: r.Replace(origTask.Method),
|
||||
Prefix: r.Replace(origTask.Prefix),
|
||||
IgnoreError: origTask.IgnoreError,
|
||||
|
Loading…
x
Reference in New Issue
Block a user