mirror of
https://github.com/go-task/task.git
synced 2025-05-27 23:08:16 +02:00
Merge branch 'master' into aliases
This commit is contained in:
commit
d2f2cba6d8
@ -8,6 +8,6 @@ charset = utf-8
|
|||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|
||||||
[*.{md,yml,yaml,json,toml,htm,html,js,css,svg,sh,bash}]
|
[*.{md,yml,yaml,json,toml,htm,html,js,css,svg,sh,bash,fish}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,6 +22,7 @@ dist/
|
|||||||
# editors
|
# editors
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.fleet/
|
||||||
|
|
||||||
# exuberant ctags
|
# exuberant ctags
|
||||||
tags
|
tags
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
- Add ability to set `aliases` for tasks and namespaces ([#268](https://github.com/go-task/task/pull/268), [#340](https://github.com/go-task/task/pull/340), [#879](https://github.com/go-task/task/pull/879)).
|
- Add ability to set `aliases` for tasks and namespaces ([#268](https://github.com/go-task/task/pull/268), [#340](https://github.com/go-task/task/pull/340), [#879](https://github.com/go-task/task/pull/879)).
|
||||||
|
- Improvements to Fish shell completion
|
||||||
|
([#897](https://github.com/go-task/task/pull/897)).
|
||||||
|
- Added ability to set a different watch interval by setting
|
||||||
|
`interval: '500ms'` or using the `--interval=500ms` flag
|
||||||
|
([#813](https://github.com/go-task/task/issues/813), [#865](https://github.com/go-task/task/pull/865)).
|
||||||
- Add colored output to `--list`, `--list-all` and `--summary` flags ([#845](https://github.com/go-task/task/pull/845), [#874](https://github.com/go-task/task/pull/874)).
|
- Add colored output to `--list`, `--list-all` and `--summary` flags ([#845](https://github.com/go-task/task/pull/845), [#874](https://github.com/go-task/task/pull/874)).
|
||||||
- Fix unexpected behavior where `label:` was being shown instead of the task
|
- Fix unexpected behavior where `label:` was being shown instead of the task
|
||||||
name on `--list`
|
name on `--list`
|
||||||
|
@ -73,6 +73,7 @@ func main() {
|
|||||||
entrypoint string
|
entrypoint string
|
||||||
output taskfile.Output
|
output taskfile.Output
|
||||||
color bool
|
color bool
|
||||||
|
interval string
|
||||||
)
|
)
|
||||||
|
|
||||||
pflag.BoolVar(&versionFlag, "version", false, "show Task version")
|
pflag.BoolVar(&versionFlag, "version", false, "show Task version")
|
||||||
@ -96,6 +97,7 @@ func main() {
|
|||||||
pflag.StringVar(&output.Group.End, "output-group-end", "", "message template to print after a task's grouped output")
|
pflag.StringVar(&output.Group.End, "output-group-end", "", "message template to print after a task's grouped output")
|
||||||
pflag.BoolVarP(&color, "color", "c", true, "colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable")
|
pflag.BoolVarP(&color, "color", "c", true, "colored output. Enabled by default. Set flag to false or use NO_COLOR=1 to disable")
|
||||||
pflag.IntVarP(&concurrency, "concurrency", "C", 0, "limit number tasks to run concurrently")
|
pflag.IntVarP(&concurrency, "concurrency", "C", 0, "limit number tasks to run concurrently")
|
||||||
|
pflag.StringVarP(&interval, "interval", "I", "5s", "interval to watch for changes")
|
||||||
pflag.Parse()
|
pflag.Parse()
|
||||||
|
|
||||||
if versionFlag {
|
if versionFlag {
|
||||||
@ -151,6 +153,7 @@ func main() {
|
|||||||
Parallel: parallel,
|
Parallel: parallel,
|
||||||
Color: color,
|
Color: color,
|
||||||
Concurrency: concurrency,
|
Concurrency: concurrency,
|
||||||
|
Interval: interval,
|
||||||
|
|
||||||
Stdin: os.Stdin,
|
Stdin: os.Stdin,
|
||||||
Stdout: os.Stdout,
|
Stdout: os.Stdout,
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
set GO_TASK_PROGNAME task
|
set GO_TASK_PROGNAME task
|
||||||
|
|
||||||
function __task_get_tasks --description "Prints all available tasks with their description"
|
function __task_get_tasks --description "Prints all available tasks with their description"
|
||||||
set -l output ($GO_TASK_PROGNAME --list-all | sed '1d; s/\* \(.*\):\s*\(.*\)/\1\t\2/' | string split0)
|
# Read the list of tasks (and potential errors)
|
||||||
|
$GO_TASK_PROGNAME --list-all 2>&1 | read -lz rawOutput
|
||||||
|
|
||||||
|
# Return on non-zero exit code (for cases when there is no Taskfile found or etc.)
|
||||||
|
if test $status -ne 0
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Grab names and descriptions (if any) of the tasks
|
||||||
|
set -l output (echo $rawOutput | sed '1d; s/\* \(.*\):\s*\(.*\)/\1\t\2/' | string split0)
|
||||||
if test $output
|
if test $output
|
||||||
echo $output
|
echo $output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
complete -c $GO_TASK_PROGNAME -d 'Runs the specified task(s). Falls back to the "default" task if no task name was specified, or lists all tasks if an unknown task name was
|
complete -c $GO_TASK_PROGNAME -d 'Runs the specified task(s). Falls back to the "default" task if no task name was specified, or lists all tasks if an unknown task name was
|
||||||
specified.' -xa "(__task_get_tasks)"
|
specified.' -xa "(__task_get_tasks)"
|
||||||
|
|
||||||
|
|
||||||
complete -c $GO_TASK_PROGNAME -s c -l color -d 'colored output (default true)'
|
complete -c $GO_TASK_PROGNAME -s c -l color -d 'colored output (default true)'
|
||||||
complete -c $GO_TASK_PROGNAME -s d -l dir -d 'sets directory of execution'
|
complete -c $GO_TASK_PROGNAME -s d -l dir -d 'sets directory of execution'
|
||||||
complete -c $GO_TASK_PROGNAME -l dry -d 'compiles and prints tasks in the order that they would be run, without executing them'
|
complete -c $GO_TASK_PROGNAME -l dry -d 'compiles and prints tasks in the order that they would be run, without executing them'
|
||||||
|
@ -30,6 +30,7 @@ variable
|
|||||||
| `-f` | `--force` | `bool` | `false` | Forces execution even when the task is up-to-date. |
|
| `-f` | `--force` | `bool` | `false` | Forces execution even when the task is up-to-date. |
|
||||||
| `-h` | `--help` | `bool` | `false` | Shows Task usage. |
|
| `-h` | `--help` | `bool` | `false` | Shows Task usage. |
|
||||||
| `-i` | `--init` | `bool` | `false` | Creates a new Taskfile.yaml in the current folder. |
|
| `-i` | `--init` | `bool` | `false` | Creates a new Taskfile.yaml in the current folder. |
|
||||||
|
| `-I` | `--interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
|
||||||
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
|
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
|
||||||
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
|
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
|
||||||
| `-o` | `--output` | `string` | Default set in the Taskfile or `intervealed` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
|
| `-o` | `--output` | `string` | Default set in the Taskfile or `intervealed` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
|
||||||
@ -84,6 +85,7 @@ Some environment variables can be overriden to adjust Task behavior.
|
|||||||
| `method` | `string` | `checksum` | Default method in this Taskfile. Can be overriden in a task by task basis. Available options: `checksum`, `timestamp` and `none`. |
|
| `method` | `string` | `checksum` | Default method in this Taskfile. Can be overriden in a task by task basis. Available options: `checksum`, `timestamp` and `none`. |
|
||||||
| `silent` | `bool` | `false` | Default "silent" options for this Taskfile. If `false`, can be overidden with `true` in a task by task basis. |
|
| `silent` | `bool` | `false` | Default "silent" options for this Taskfile. If `false`, can be overidden with `true` in a task by task basis. |
|
||||||
| `run` | `string` | `always` | Default "run" option for this Taskfile. Available options: `always`, `once` and `when_changed`. |
|
| `run` | `string` | `always` | Default "run" option for this Taskfile. Available options: `always`, `once` and `when_changed`. |
|
||||||
|
| `interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
|
||||||
| `vars` | [`map[string]Variable`](#variable) | | Global variables. |
|
| `vars` | [`map[string]Variable`](#variable) | | Global variables. |
|
||||||
| `env` | [`map[string]Variable`](#variable) | | Global environment. |
|
| `env` | [`map[string]Variable`](#variable) | | Global environment. |
|
||||||
| `dotenv` | `[]string` | | A list of `.env` file paths to be parsed. |
|
| `dotenv` | `[]string` | | A list of `.env` file paths to be parsed. |
|
||||||
|
@ -232,7 +232,9 @@ includes:
|
|||||||
|
|
||||||
### Namespace aliases
|
### Namespace aliases
|
||||||
|
|
||||||
When including a taskfile, you can give the namespace a list of `aliases`. This works in the same way as [task aliases](#task-aliases) and can be used together to create shorter and easier-to-type commands.
|
When including a Taskfile, you can give the namespace a list of `aliases`.
|
||||||
|
This works in the same way as [task aliases](#task-aliases) and can be used
|
||||||
|
together to create shorter and easier-to-type commands.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: '3'
|
version: '3'
|
||||||
@ -1284,5 +1286,9 @@ With the flags `--watch` or `-w` task will watch for file changes
|
|||||||
and run the task again. This requires the `sources` attribute to be given,
|
and run the task again. This requires the `sources` attribute to be given,
|
||||||
so task knows which files to watch.
|
so task knows which files to watch.
|
||||||
|
|
||||||
|
The default watch interval is 5 seconds, but it's possible to change it by
|
||||||
|
either setting `interval: '500ms'` in the root of the Taskfile passing it
|
||||||
|
as an argument like `--interval=500ms`.
|
||||||
|
|
||||||
[gotemplate]: https://golang.org/pkg/text/template/
|
[gotemplate]: https://golang.org/pkg/text/template/
|
||||||
[minify]: https://github.com/tdewolff/minify/tree/master/cmd/minify
|
[minify]: https://github.com/tdewolff/minify/tree/master/cmd/minify
|
||||||
|
1
task.go
1
task.go
@ -42,6 +42,7 @@ type Executor struct {
|
|||||||
Parallel bool
|
Parallel bool
|
||||||
Color bool
|
Color bool
|
||||||
Concurrency int
|
Concurrency int
|
||||||
|
Interval string
|
||||||
|
|
||||||
Stdin io.Reader
|
Stdin io.Reader
|
||||||
Stdout io.Writer
|
Stdout io.Writer
|
||||||
|
62
task_test.go
62
task_test.go
@ -10,6 +10,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@ -1532,3 +1533,64 @@ func TestEvaluateSymlinksInPaths(t *testing.T) {
|
|||||||
err = os.RemoveAll(dir + "/.task")
|
err = os.RemoveAll(dir + "/.task")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileWatcherInterval(t *testing.T) {
|
||||||
|
const dir = "testdata/watcher_interval"
|
||||||
|
expectedOutput := strings.TrimSpace(`
|
||||||
|
task: Started watching for tasks: default
|
||||||
|
task: [default] echo "Hello, World!"
|
||||||
|
Hello, World!
|
||||||
|
task: [default] echo "Hello, World!"
|
||||||
|
Hello, World!
|
||||||
|
`)
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := &task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
Watch: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
buff.Reset()
|
||||||
|
|
||||||
|
err := os.MkdirAll(filepathext.SmartJoin(dir, "src"), 0755)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.WriteFile(filepathext.SmartJoin(dir, "src/a"), []byte("test"), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
|
go func(ctx context.Context) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
err := e.Run(ctx, taskfile.Call{Task: "default"})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(ctx)
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
err = os.WriteFile(filepathext.SmartJoin(dir, "src/a"), []byte("test updated"), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(700 * time.Millisecond)
|
||||||
|
cancel()
|
||||||
|
assert.Equal(t, expectedOutput, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
err = os.RemoveAll(filepathext.SmartJoin(dir, ".task"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.RemoveAll(filepathext.SmartJoin(dir, "src"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
|
|
||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ type Taskfile struct {
|
|||||||
Silent bool
|
Silent bool
|
||||||
Dotenv []string
|
Dotenv []string
|
||||||
Run string
|
Run string
|
||||||
|
Interval string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||||
@ -34,10 +35,13 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
Silent bool
|
Silent bool
|
||||||
Dotenv []string
|
Dotenv []string
|
||||||
Run string
|
Run string
|
||||||
|
Interval string
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := unmarshal(&taskfile); err != nil {
|
if err := unmarshal(&taskfile); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tf.Version = taskfile.Version
|
tf.Version = taskfile.Version
|
||||||
tf.Expansions = taskfile.Expansions
|
tf.Expansions = taskfile.Expansions
|
||||||
tf.Output = taskfile.Output
|
tf.Output = taskfile.Output
|
||||||
@ -49,6 +53,8 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
tf.Silent = taskfile.Silent
|
tf.Silent = taskfile.Silent
|
||||||
tf.Dotenv = taskfile.Dotenv
|
tf.Dotenv = taskfile.Dotenv
|
||||||
tf.Run = taskfile.Run
|
tf.Run = taskfile.Run
|
||||||
|
tf.Interval = taskfile.Interval
|
||||||
|
|
||||||
if tf.Expansions <= 0 {
|
if tf.Expansions <= 0 {
|
||||||
tf.Expansions = 2
|
tf.Expansions = 2
|
||||||
}
|
}
|
||||||
|
1
testdata/watcher_interval/.gitignore
vendored
Normal file
1
testdata/watcher_interval/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
src/*
|
16
testdata/watcher_interval/Taskfile.yaml
vendored
Normal file
16
testdata/watcher_interval/Taskfile.yaml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# https://taskfile.dev
|
||||||
|
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
GREETING: Hello, World!
|
||||||
|
|
||||||
|
interval: "500ms"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
sources:
|
||||||
|
- "src/*"
|
||||||
|
cmds:
|
||||||
|
- echo "{{.GREETING}}"
|
||||||
|
silent: false
|
32
watch.go
32
watch.go
@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/radovskyb/watcher"
|
"github.com/radovskyb/watcher"
|
||||||
)
|
)
|
||||||
|
|
||||||
const watchInterval = 5 * time.Second
|
const defaultWatchInterval = 5 * time.Second
|
||||||
|
|
||||||
// watchTasks start watching the given tasks
|
// watchTasks start watching the given tasks
|
||||||
func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
||||||
@ -24,6 +24,7 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
for i, c := range calls {
|
for i, c := range calls {
|
||||||
tasks[i] = c.Task
|
tasks[i] = c.Task
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Logger.Errf(logger.Green, "task: Started watching for tasks: %s", strings.Join(tasks, ", "))
|
e.Logger.Errf(logger.Green, "task: Started watching for tasks: %s", strings.Join(tasks, ", "))
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@ -36,6 +37,27 @@ func (e *Executor) watchTasks(calls ...taskfile.Call) error {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var watchIntervalString string
|
||||||
|
|
||||||
|
if e.Interval != "" {
|
||||||
|
watchIntervalString = e.Interval
|
||||||
|
} else if e.Taskfile.Interval != "" {
|
||||||
|
watchIntervalString = e.Taskfile.Interval
|
||||||
|
}
|
||||||
|
|
||||||
|
watchInterval := defaultWatchInterval
|
||||||
|
|
||||||
|
if watchIntervalString != "" {
|
||||||
|
var err error
|
||||||
|
watchInterval, err = parseWatchInterval(watchIntervalString)
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Logger.VerboseOutf(logger.Green, "task: Watching for changes every %v", watchInterval)
|
||||||
|
|
||||||
w := watcher.New()
|
w := watcher.New()
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
w.SetMaxEvents(1)
|
w.SetMaxEvents(1)
|
||||||
@ -163,3 +185,11 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Ca
|
|||||||
func shouldIgnoreFile(path string) bool {
|
func shouldIgnoreFile(path string) bool {
|
||||||
return strings.Contains(path, "/.git") || strings.Contains(path, "/.task") || strings.Contains(path, "/node_modules")
|
return strings.Contains(path, "/.git") || strings.Contains(path, "/.task") || strings.Contains(path, "/node_modules")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseWatchInterval(watchInterval string) (time.Duration, error) {
|
||||||
|
v, err := time.ParseDuration(watchInterval)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf(`task: Could not parse watch interval "%s": %v`, watchInterval, err)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user