mirror of
https://github.com/go-task/task.git
synced 2026-05-18 13:15:41 +02:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df4e3aea79 | ||
|
|
290d45fd05 | ||
|
|
168e8c925c | ||
|
|
d9859b18fe | ||
|
|
784847f35b | ||
|
|
97287377d1 | ||
|
|
a15b66e003 | ||
|
|
a441b4b90d | ||
|
|
0dcc1390a6 | ||
|
|
01c86636e9 | ||
|
|
846c27d579 | ||
|
|
db05059b42 | ||
|
|
b824328850 | ||
|
|
a8767a2b1a | ||
|
|
5e14e7fb70 | ||
|
|
fbaa7be52e | ||
|
|
b6016b244e | ||
|
|
e339a64261 | ||
|
|
17e18442ab | ||
|
|
e8aa3a17a6 | ||
|
|
bdb97eab86 | ||
|
|
690000254c | ||
|
|
6a0b778978 | ||
|
|
549d141053 | ||
|
|
c31ecdb8de | ||
|
|
8a09d044c7 | ||
|
|
a3b5b89930 | ||
|
|
ad6f100f6a | ||
|
|
3cfe21af58 | ||
|
|
b70a660975 | ||
|
|
04c1d1389f | ||
|
|
f12156bf81 | ||
|
|
0177ac660b | ||
|
|
361b9b4ce4 | ||
|
|
78792bd11c | ||
|
|
8b38ddfcd9 | ||
|
|
78ddf50d2d | ||
|
|
41a71e1dee | ||
|
|
a5ed8ad58c | ||
|
|
e45ed85b55 | ||
|
|
52474f9103 | ||
|
|
c2587da27d | ||
|
|
26036877b2 | ||
|
|
906cdd9050 | ||
|
|
762662d056 | ||
|
|
1de4b38766 | ||
|
|
6c73ab823b | ||
|
|
5ef1651151 | ||
|
|
8d695bc8d7 | ||
|
|
c892d055ed | ||
|
|
b327e54be1 | ||
|
|
989045489c | ||
|
|
888338c60e | ||
|
|
e6c6cc7811 | ||
|
|
fa0e72bd69 | ||
|
|
18decac44d | ||
|
|
1012a0cf2b | ||
|
|
7e4de945cf | ||
|
|
a468272726 | ||
|
|
039d8f000d | ||
|
|
2dc181c75e | ||
|
|
d35f960a8a | ||
|
|
634f8ed574 | ||
|
|
d369451308 | ||
|
|
8f1202424d | ||
|
|
0a6833e9d8 | ||
|
|
8f80fc4e2c | ||
|
|
50e5813222 | ||
|
|
7bc268aeaa | ||
|
|
537b5b1e25 | ||
|
|
aae38f8ce7 | ||
|
|
ad05432bcf | ||
|
|
8aa983257d | ||
|
|
046a97d1e5 | ||
|
|
d28649b13d | ||
|
|
3e16ca37bc | ||
|
|
2da38a5bdc | ||
|
|
bbe1d8b52e | ||
|
|
97c85e39c3 | ||
|
|
a7b59e5b12 | ||
|
|
9eb1252ce9 | ||
|
|
0e01e13670 | ||
|
|
239e61e718 | ||
|
|
22549e9fd8 | ||
|
|
1f9fd24064 | ||
|
|
a7594740e3 | ||
|
|
945c72cf6c | ||
|
|
824b0c0132 | ||
|
|
51e9f2f579 | ||
|
|
e8ec33d9d0 | ||
|
|
3bbbaf12fd | ||
|
|
30ffacd879 | ||
|
|
75e9b7791c | ||
|
|
4b665ab19a | ||
|
|
08265ed1d7 | ||
|
|
cded9af90f | ||
|
|
4e1f2ad017 | ||
|
|
7f92b7072d | ||
|
|
4a589ba6a4 | ||
|
|
7f16325fcc | ||
|
|
b62e5bf34c | ||
|
|
bd6b348cc7 | ||
|
|
62f35fe8c8 | ||
|
|
cb2cb4659c | ||
|
|
a2c58415cf | ||
|
|
2cb9987c99 | ||
|
|
36584cfb7c | ||
|
|
b825ad6a12 | ||
|
|
58c69e36a1 |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +1,2 @@
|
||||
open_collective: task
|
||||
patreon: andreynering
|
||||
custom: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=BRL&source=url'
|
||||
custom: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=USD&source=url'
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Use the template to report bugs and issues
|
||||
labels: bug
|
||||
---
|
||||
|
||||
- Task version:
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Use the template to make feature requests
|
||||
labels: feature
|
||||
---
|
||||
|
||||
Describe in detail what feature do you want to see in Task.
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -15,12 +15,12 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.15.x
|
||||
go-version: 1.17.x
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v1
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
GITHUB_TOKEN: ${{secrets.GH_PAT}}
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -5,7 +5,7 @@ jobs:
|
||||
name: Test
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.14.x, 1.15.x]
|
||||
go-version: [1.16.x, 1.17.x]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{matrix.platform}}
|
||||
steps:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
build:
|
||||
binary: task
|
||||
main: cmd/task
|
||||
main: ./cmd/task
|
||||
goos:
|
||||
- windows
|
||||
- darwin
|
||||
@@ -25,6 +25,10 @@ gomod:
|
||||
|
||||
archives:
|
||||
- name_template: "{{.Binary}}_{{.Os}}_{{.Arch}}"
|
||||
files:
|
||||
- README.md
|
||||
- LICENSE
|
||||
- completion/**/*
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
@@ -50,3 +54,20 @@ nfpms:
|
||||
- deb
|
||||
- rpm
|
||||
file_name_template: "{{.ProjectName}}_{{.Os}}_{{.Arch}}"
|
||||
|
||||
brews:
|
||||
- name: go-task
|
||||
description: Task runner / simpler Make alternative written in Go
|
||||
license: MIT
|
||||
homepage: https://taskfile.dev
|
||||
folder: Formula
|
||||
tap:
|
||||
owner: go-task
|
||||
name: homebrew-tap
|
||||
test:
|
||||
system "#{bin}/task", "--help"
|
||||
install: |-
|
||||
bin.install "task"
|
||||
bash_completion.install "completion/bash/task.bash" => "task"
|
||||
zsh_completion.install "completion/zsh/_task" => "_task"
|
||||
fish_completion.install "completion/fish/task.fish"
|
||||
|
||||
85
CHANGELOG.md
85
CHANGELOG.md
@@ -1,5 +1,90 @@
|
||||
# Changelog
|
||||
|
||||
## v3.9.2 - 2021-12-02
|
||||
|
||||
- Upgrade [mvdan/sh](https://github.com/mvdan/sh) which contains a fix a for
|
||||
a important regression on Windows
|
||||
([#619](https://github.com/go-task/task/issues/619), [mvdan/sh#768](https://github.com/mvdan/sh/issues/768), [mvdan/sh#769](https://github.com/mvdan/sh/pull/769)).
|
||||
|
||||
## v3.9.1 - 2021-11-28
|
||||
|
||||
- Add logging in verbose mode for when a task starts and finishes
|
||||
([#533](https://github.com/go-task/task/issues/533), [#588](https://github.com/go-task/task/pull/588)).
|
||||
- Fix an issue with preconditions and context errors
|
||||
([#597](https://github.com/go-task/task/issues/597), [#598](https://github.com/go-task/task/pull/598)).
|
||||
- Quote each `{{.CLI_ARGS}}` argument to prevent one with spaces to become many
|
||||
([#613](https://github.com/go-task/task/pull/613)).
|
||||
- Fix nil pointer when `cmd:` was left empty
|
||||
([#612](https://github.com/go-task/task/issues/612), [#614](https://github.com/go-task/task/pull/614)).
|
||||
- Upgrade [mvdan/sh](https://github.com/mvdan/sh) which contains two
|
||||
relevant fixes:
|
||||
- Fix quote of empty strings in `shellQuote`
|
||||
([#609](https://github.com/go-task/task/issues/609), [mvdan/sh#763](https://github.com/mvdan/sh/issues/763)).
|
||||
- Fix issue of wrong environment variable being picked when there's another
|
||||
very similar one
|
||||
([#586](https://github.com/go-task/task/issues/586), [mvdan/sh#745](https://github.com/mvdan/sh/pull/745)).
|
||||
- Install shell completions automatically when installing via Homebrew
|
||||
([#264](https://github.com/go-task/task/issues/264), [#592](https://github.com/go-task/task/pull/592), [go-task/homebrew-tap#2](https://github.com/go-task/homebrew-tap/pull/2)).
|
||||
|
||||
## v3.9.0 - 2021-10-02
|
||||
|
||||
- A new `shellQuote` function was added to the template system
|
||||
(`{{shellQuote "a string"}}`) to ensure a string is safe for use in shell
|
||||
([mvdan/sh#727](https://github.com/mvdan/sh/pull/727), [mvdan/sh#737](https://github.com/mvdan/sh/pull/737), [Documentation](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/syntax#Quote))
|
||||
- In this version [mvdan.cc/sh](https://github.com/mvdan/sh) was upgraded
|
||||
with some small fixes and features
|
||||
- The `read -p` flag is now supported
|
||||
([#314](https://github.com/go-task/task/issues/314), [mvdan/sh#551](https://github.com/mvdan/sh/issues/551), [mvdan/sh#772](https://github.com/mvdan/sh/pull/722))
|
||||
- The `pwd -P` and `pwd -L` flags are now supported
|
||||
([#553](https://github.com/go-task/task/issues/553), [mvdan/sh#724](https://github.com/mvdan/sh/issues/724), [mvdan/sh#728](https://github.com/mvdan/sh/pull/728))
|
||||
- The `$GID` environment variable is now correctly being set
|
||||
([#561](https://github.com/go-task/task/issues/561), [mvdan/sh#723](https://github.com/mvdan/sh/pull/723))
|
||||
|
||||
## v3.8.0 - 2021-09-26
|
||||
|
||||
- Add `interactive: true` setting to improve support for interactive CLI apps
|
||||
([#217](https://github.com/go-task/task/issues/217), [#563](https://github.com/go-task/task/pull/563)).
|
||||
- Fix some `nil` errors
|
||||
([#534](https://github.com/go-task/task/issues/534), [#573](https://github.com/go-task/task/pull/573)).
|
||||
- Add ability to declare an included Taskfile as optional
|
||||
([#519](https://github.com/go-task/task/issues/519), [#552](https://github.com/go-task/task/pull/552)).
|
||||
- Add support for including Taskfiles in the home directory by using `~`
|
||||
([#539](https://github.com/go-task/task/issues/539), [#557](https://github.com/go-task/task/pull/557)).
|
||||
|
||||
## v3.7.3 - 2021-09-04
|
||||
|
||||
- Add official support to Apple M1 ([#564](https://github.com/go-task/task/pull/564), [#567](https://github.com/go-task/task/pull/567)).
|
||||
- Our [official Homebrew tap](https://github.com/go-task/homebrew-tap) will
|
||||
support more platforms, including Apple M1
|
||||
|
||||
## v3.7.0 - 2021-07-31
|
||||
|
||||
- Add `run:` setting to control if tasks should run multiple times or not.
|
||||
Available options are `always` (the default), `when_changed` (if a variable
|
||||
modified the task) and `once` (run only once no matter what).
|
||||
This is a long time requested feature. Enjoy!
|
||||
([#53](https://github.com/go-task/task/issues/53), [#359](https://github.com/go-task/task/pull/359)).
|
||||
|
||||
## v3.6.0 - 2021-07-10
|
||||
|
||||
- Allow using both `sources:` and `status:` in the same task
|
||||
([#411](https://github.com/go-task/task/issues/411), [#427](https://github.com/go-task/task/issues/427), [#477](https://github.com/go-task/task/pull/477)).
|
||||
- Small optimization and bug fix: don't compute variables if not needed for
|
||||
`dotenv:` ([#517](https://github.com/go-task/task/issues/517)).
|
||||
|
||||
## v3.5.0 - 2021-07-04
|
||||
|
||||
- Add support for interpolation in `dotenv:`
|
||||
([#433](https://github.com/go-task/task/discussions/433), [#434](https://github.com/go-task/task/issues/434), [#453](https://github.com/go-task/task/pull/453)).
|
||||
|
||||
## v3.4.3 - 2021-05-30
|
||||
|
||||
- Add support for the `NO_COLOR` environment variable.
|
||||
([#459](https://github.com/go-task/task/issues/459), [fatih/color#137](https://github.com/fatih/color/pull/137)).
|
||||
- Fix bug where sources were not considering the right directory
|
||||
in `--watch` mode
|
||||
([#484](https://github.com/go-task/task/issues/484), [#485](https://github.com/go-task/task/pull/485)).
|
||||
|
||||
## v3.4.2 - 2021-04-23
|
||||
|
||||
- On watch, report which file failed to read
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
|
||||
"github.com/go-task/task/v3"
|
||||
"github.com/go-task/task/v3/args"
|
||||
@@ -89,7 +90,7 @@ func main() {
|
||||
pflag.StringVarP(&dir, "dir", "d", "", "sets directory of execution")
|
||||
pflag.StringVarP(&entrypoint, "taskfile", "t", "", `choose which Taskfile to run. Defaults to "Taskfile.yml"`)
|
||||
pflag.StringVarP(&output, "output", "o", "", "sets output style: [interleaved|group|prefixed]")
|
||||
pflag.BoolVarP(&color, "color", "c", true, "colored output")
|
||||
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.Parse()
|
||||
|
||||
@@ -159,18 +160,22 @@ func main() {
|
||||
}
|
||||
|
||||
var (
|
||||
calls []taskfile.Call
|
||||
globals *taskfile.Vars
|
||||
tasksAndVars, cliArgs = getArgs()
|
||||
calls []taskfile.Call
|
||||
globals *taskfile.Vars
|
||||
)
|
||||
|
||||
tasksAndVars, cliArgs, err := getArgs()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if v >= 3.0 {
|
||||
calls, globals = args.ParseV3(tasksAndVars...)
|
||||
} else {
|
||||
calls, globals = args.ParseV2(tasksAndVars...)
|
||||
}
|
||||
|
||||
globals.Set("CLI_ARGS", taskfile.Var{Static: strings.Join(cliArgs, " ")})
|
||||
globals.Set("CLI_ARGS", taskfile.Var{Static: cliArgs})
|
||||
e.Taskfile.Vars.Merge(globals)
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -191,20 +196,25 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func getArgs() (tasksAndVars, cliArgs []string) {
|
||||
func getArgs() ([]string, string, error) {
|
||||
var (
|
||||
args = pflag.Args()
|
||||
doubleDashPos = pflag.CommandLine.ArgsLenAtDash()
|
||||
)
|
||||
|
||||
if doubleDashPos != -1 {
|
||||
tasksAndVars = args[:doubleDashPos]
|
||||
cliArgs = args[doubleDashPos:]
|
||||
} else {
|
||||
tasksAndVars = args
|
||||
if doubleDashPos == -1 {
|
||||
return args, "", nil
|
||||
}
|
||||
|
||||
return
|
||||
var quotedCliArgs []string
|
||||
for _, arg := range args[doubleDashPos:] {
|
||||
quotedCliArg, err := syntax.Quote(arg, syntax.LangBash)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
quotedCliArgs = append(quotedCliArgs, quotedCliArg)
|
||||
}
|
||||
return args[:doubleDashPos], strings.Join(quotedCliArgs, " "), nil
|
||||
}
|
||||
|
||||
func getSignalContext() context.Context {
|
||||
|
||||
@@ -15,7 +15,7 @@ _task_completion()
|
||||
return
|
||||
fi
|
||||
|
||||
COMPREPLY=($(compgen -c | echo "$scripts" | grep $curr_arg));
|
||||
COMPREPLY=($(compgen -c | echo "$scripts" | grep -- $curr_arg));
|
||||
}
|
||||
|
||||
complete -F _task_completion task
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
function __task_get_tasks --description "Prints all available tasks with their description"
|
||||
task -l | sed '1d' | awk '{ $1=""; print $0 }' | tr ': ', '\t' | string trim
|
||||
task -l | sed '1d' | awk '{ $1=""; print $0 }' | sed 's/:\ /\t/g' | string trim
|
||||
end
|
||||
|
||||
complete -c task -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
|
||||
|
||||
@@ -23,11 +23,17 @@ Additionally, there's also some work done by
|
||||
extension, which has its code [here](https://github.com/paulvarache/vscode-taskfile)
|
||||
and is published [here](https://marketplace.visualstudio.com/items?itemName=paulvarache.vscode-taskfile).
|
||||
|
||||
### Sublime Text 4 package
|
||||
|
||||
There is a convenience wrapper for initializing and running tasks from Sublime Text's command palette. The package is
|
||||
developed by [@biozz](https://github.com/biozz), the source code is available [here](https://github.com/biozz/sublime-taskfile)
|
||||
and it is published on Package Control [here](https://packagecontrol.io/packages/Taskfile).
|
||||
|
||||
## Installation methods
|
||||
|
||||
Some installation methods are maintained by third party:
|
||||
|
||||
- [GitHub Actions](https://github.com/arduino/actions/tree/master/setup-taskfile)
|
||||
- [GitHub Actions](https://github.com/arduino/setup-task)
|
||||
by [@arduino](https://github.com/arduino)
|
||||
- [AUR](https://aur.archlinux.org/packages/taskfile-git)
|
||||
by [@kovetskiy](https://github.com/kovetskiy)
|
||||
|
||||
@@ -14,22 +14,14 @@ these options to donate:
|
||||
- [$2 per month](https://opencollective.com/task/contribute/backer-4034/checkout)
|
||||
- [$5 per month](https://opencollective.com/task/contribute/supporter-8404/checkout)
|
||||
- [$20 per month](https://opencollective.com/task/contribute/sponsor-4035/checkout)
|
||||
- [$50 per month](https://opencollective.com/task/contribute/sponsor-28775/checkout)
|
||||
- [Custom value - One-time donation option supported](https://opencollective.com/task/donate)
|
||||
|
||||
## Patreon
|
||||
|
||||
I'm also on [Patreon](https://www.patreon.com/andreynering) if
|
||||
you prefer:
|
||||
|
||||
- [$5 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229277)
|
||||
- [$10 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229276)
|
||||
- [$15 per month](https://www.patreon.com/join/andreynering/checkout?rid=4229275)
|
||||
|
||||
You can choose a custom value on any of the links above.
|
||||
|
||||
Patreon does not support one-time donation. As a workaround you can fire a
|
||||
subscription and cancel it once the donation was succeded.
|
||||
|
||||
## PayPal
|
||||
|
||||
- [Any value - One-time donation](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=BRL&source=url)
|
||||
- [Any value - One-time donation](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=USD&source=url)
|
||||
|
||||
## PIX (Brazil only)
|
||||
|
||||
If you're Brazilian, you can donate any value by
|
||||
<a href="/pix.png" target="_blank">using this QR Code</a>.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="A task runner / simpler Make alternative written in Go">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple-dark.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple.css">
|
||||
<meta name="google-site-verification" content="VGAYkbdmuaciIDGkBe-eAg9yfZg0C6ostgonbGxxOa0" />
|
||||
<style>
|
||||
#logo {
|
||||
@@ -43,6 +43,7 @@
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-themeable/dist/js/docsify-themeable.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-tabs"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-yaml.min.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -87,12 +87,12 @@ sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/b
|
||||
#### **GitHub Actions**
|
||||
|
||||
If you want to install Task in GitHub Actions you can try using
|
||||
[this action](https://github.com/arduino/actions/tree/master/setup-taskfile)
|
||||
[this action](https://github.com/arduino/setup-task)
|
||||
by the Arduino team:
|
||||
|
||||
```yaml
|
||||
- name: Install Task
|
||||
uses: Arduino/actions/setup-taskfile@master
|
||||
uses: arduino/setup-task@v1
|
||||
```
|
||||
|
||||
This installation method is community owned.
|
||||
|
||||
BIN
docs/pix.png
Normal file
BIN
docs/pix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -28,7 +28,7 @@ officially supported. On Linux, only `Taskfile.yml` will work, though.
|
||||
|
||||
- `version:`
|
||||
- `includes:`
|
||||
- Configuration ones, like `output:`, `expansions:` or `silent:`
|
||||
- Configuration ones, like `output:` or `silent:`
|
||||
- `vars:`
|
||||
- `env:`
|
||||
- `tasks:`
|
||||
@@ -60,7 +60,6 @@ version: '3'
|
||||
includes:
|
||||
docker: ./docker/Taskfile.yml
|
||||
output: prefixed
|
||||
expansions: 3
|
||||
vars:
|
||||
FOO: bar
|
||||
env:
|
||||
@@ -76,7 +75,6 @@ includes:
|
||||
docker: ./docker/Taskfile.yml
|
||||
|
||||
output: prefixed
|
||||
expansions: 3
|
||||
|
||||
vars:
|
||||
FOO: bar
|
||||
|
||||
100
docs/usage.md
100
docs/usage.md
@@ -78,18 +78,25 @@ setting:
|
||||
KEYNAME=VALUE
|
||||
```
|
||||
|
||||
```
|
||||
# testing/.env
|
||||
ENDPOINT=testing.com
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Taskfile.yml
|
||||
|
||||
version: '3'
|
||||
|
||||
dotenv: ['.env']
|
||||
env:
|
||||
ENV: testing
|
||||
|
||||
dotenv: ['.env', '{{.ENV}}/.env.', '{{.HOME}}/.env']
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
cmds:
|
||||
- echo "Using $KEYNAME"
|
||||
- echo "Using $KEYNAME and endpoint $ENDPOINT"
|
||||
```
|
||||
|
||||
## Including other Taskfiles
|
||||
@@ -147,6 +154,25 @@ includes:
|
||||
> This was a deliberate decision to keep use and implementation simple.
|
||||
> If you disagree, open an GitHub issue and explain your use case. =)
|
||||
|
||||
### Optional includes
|
||||
|
||||
Includes marked as optional will allow Task to continue execution as normal if
|
||||
the included file is missing.
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
tests:
|
||||
taskfile: ./tests/Taskfile.yml
|
||||
optional: true
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
cmds:
|
||||
- echo "This command can still be successfully executed if ./tests/Taskfile.yml does not exist"
|
||||
```
|
||||
|
||||
## Task directory
|
||||
|
||||
By default, tasks will be executed in the directory where the Taskfile is
|
||||
@@ -446,6 +472,47 @@ tasks:
|
||||
- echo "I will not run"
|
||||
```
|
||||
|
||||
### Limiting when tasks run
|
||||
|
||||
If a task executed by multiple `cmds` or multiple `deps` you can control
|
||||
when it is executed using `run`. `run` can also be set at the root
|
||||
of the Taskfile to change the behavior of all the tasks unless explicitly
|
||||
overridden.
|
||||
|
||||
Supported values for `run`:
|
||||
|
||||
* `always` (default) always attempt to invoke the task regardless of the
|
||||
number of previous executions
|
||||
* `once` only invoke this task once regardless of the number of references
|
||||
* `when_changed` only invokes the task once for each unique set of variables
|
||||
passed into the task
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- task: generate-file
|
||||
vars: { CONTENT: '1' }
|
||||
- task: generate-file
|
||||
vars: { CONTENT: '2' }
|
||||
- task: generate-file
|
||||
vars: { CONTENT: '2' }
|
||||
|
||||
generate-file:
|
||||
run: when_changed
|
||||
deps:
|
||||
- install-deps
|
||||
cmds:
|
||||
- echo {{.CONTENT}}
|
||||
|
||||
install-deps:
|
||||
run: once
|
||||
cmds:
|
||||
- sleep 5 # long operation like installing packages
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
When doing interpolation of variables, Task will look for the below.
|
||||
@@ -522,7 +589,7 @@ This works for all types of variables.
|
||||
|
||||
## Forwarding CLI arguments to commands
|
||||
|
||||
If `--` is given in the CLI, all following paramaters are added to a
|
||||
If `--` is given in the CLI, all following parameters are added to a
|
||||
special `.CLI_ARGS` variable. This is useful to forward arguments to another
|
||||
command.
|
||||
|
||||
@@ -569,9 +636,12 @@ Task also adds the following functions:
|
||||
- `toSlash`: Does nothing on Unix, but on Windows converts a string from `\`
|
||||
path format to `/`.
|
||||
- `fromSlash`: Opposite of `toSlash`. Does nothing on Unix, but on Windows
|
||||
converts a string from `\` path format to `/`.
|
||||
converts a string from `/` path format to `\`.
|
||||
- `exeExt`: Returns the right executable extension for the current OS
|
||||
(`".exe"` for Windows, `""` for others).
|
||||
- `shellQuote`: Quotes a string to make it safe for use in shell scripts.
|
||||
Task uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/syntax#Quote)
|
||||
for this. The Bash dialect is assumed.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -883,6 +953,28 @@ $ task default
|
||||
|
||||
> The `output` option can also be specified by the `--output` or `-o` flags.
|
||||
|
||||
## Interactive CLI application
|
||||
|
||||
When running interactive CLI applications inside Task they can sometimes behave
|
||||
weirdly, specially when the [output mode](#output-syntax) is set to something
|
||||
other than `interleaved` (the default), or when interactive apps are ran in
|
||||
parallel with other tasks.
|
||||
|
||||
The `interactive: true` tells Task this is an interactive application, and Task
|
||||
will try to optimize for it:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
cmds:
|
||||
- vim my-file.txt
|
||||
interactive: true
|
||||
```
|
||||
|
||||
If you still have problem running an interactive app through Task, please open
|
||||
an issue about it.
|
||||
|
||||
## Short task syntax
|
||||
|
||||
Starting on Task v3, you can now write tasks with a shorter syntax if they
|
||||
|
||||
11
go.mod
11
go.mod
@@ -1,16 +1,17 @@
|
||||
module github.com/go-task/task/v3
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/mattn/go-zglob v0.0.3
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/radovskyb/watcher v1.0.7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
mvdan.cc/sh/v3 v3.2.4
|
||||
mvdan.cc/sh/v3 v3.4.2-0.20211202103622-5ae9d64e1402
|
||||
)
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
66
go.sum
66
go.sum
@@ -1,53 +1,65 @@
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
|
||||
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/frankban/quicktest v1.13.1 h1:xVm/f9seEhZFL9+n5kv5XLrGwy6elc4V9v/XFY2vmd8=
|
||||
github.com/frankban/quicktest v1.13.1/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-zglob v0.0.3 h1:6Ry4EYsScDyt5di4OI6xw1bYhOqfE5S33Z1OPy+d+To=
|
||||
github.com/mattn/go-zglob v0.0.3/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE=
|
||||
github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
|
||||
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I=
|
||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
|
||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407 h1:5zh5atpUEdIc478E/ebrIaHLKcfVvG6dL/fGv7BcMoM=
|
||||
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210925032602-92d5a993a665 h1:QOQNt6vCjMpXE7JSK5VvAzJC1byuN3FgTNSBwf+CJgI=
|
||||
golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=
|
||||
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -55,6 +67,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
mvdan.cc/editorconfig v0.1.1-0.20200121172147-e40951bde157/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
|
||||
mvdan.cc/sh/v3 v3.2.4 h1:+fZaWcXWRjYAvqzEKoDhDM3DkxdDUykU2iw0VMKFe9s=
|
||||
mvdan.cc/sh/v3 v3.2.4/go.mod h1:fPQmabBpREM/XQ9YXSU5ZFZ/Sm+PmKP9/vkFHgYKJEI=
|
||||
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
|
||||
mvdan.cc/sh/v3 v3.4.2-0.20211202103622-5ae9d64e1402 h1:IhYcaLRZjSJqGoLrn+sXXFq3Xhd40I0wBkoIyg6cSZs=
|
||||
mvdan.cc/sh/v3 v3.4.2-0.20211202103622-5ae9d64e1402/go.mod h1:p/tqPPI4Epfk2rICAe2RoaNd8HBSJ8t9Y2DA9yQlbzY=
|
||||
|
||||
28
hash.go
Normal file
28
hash.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-task/task/v3/internal/hash"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
func (e *Executor) GetHash(t *taskfile.Task) (string, error) {
|
||||
r := t.Run
|
||||
if r == "" {
|
||||
r = e.Taskfile.Run
|
||||
}
|
||||
|
||||
var h hash.HashFunc
|
||||
switch r {
|
||||
case "always":
|
||||
h = hash.Empty
|
||||
case "once":
|
||||
h = hash.Name
|
||||
case "when_changed":
|
||||
h = hash.Hash
|
||||
default:
|
||||
return "", fmt.Errorf(`task: invalid run "%s"`, r)
|
||||
}
|
||||
return h(t)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
// Compiler handles compilation of a task before its execution.
|
||||
// E.g. variable merger, template processing, etc.
|
||||
type Compiler interface {
|
||||
GetTaskfileVariables() (*taskfile.Vars, error)
|
||||
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
|
||||
FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
|
||||
HandleDynamicVar(v taskfile.Var, dir string) (string, error)
|
||||
|
||||
@@ -30,6 +30,10 @@ type CompilerV2 struct {
|
||||
muDynamicCache sync.Mutex
|
||||
}
|
||||
|
||||
func (c *CompilerV2) GetTaskfileVariables() (*taskfile.Vars, error) {
|
||||
return &taskfile.Vars{}, nil
|
||||
}
|
||||
|
||||
// FastGetVariables is a no-op on v2
|
||||
func (c *CompilerV2) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
||||
return c.GetVariables(t, call)
|
||||
@@ -105,7 +109,7 @@ func (c *CompilerV2) HandleDynamicVar(v taskfile.Var, _ string) (string, error)
|
||||
Stderr: c.Logger.Stderr,
|
||||
}
|
||||
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
||||
return "", fmt.Errorf(`task: Command "%s" in taskvars file failed: %s`, opts.Command, err)
|
||||
return "", fmt.Errorf(`task: Command "%s" failed: %s`, opts.Command, err)
|
||||
}
|
||||
|
||||
// Trim a single trailing newline from the result to make most command
|
||||
|
||||
@@ -29,17 +29,23 @@ type CompilerV3 struct {
|
||||
muDynamicCache sync.Mutex
|
||||
}
|
||||
|
||||
func (c *CompilerV3) GetTaskfileVariables() (*taskfile.Vars, error) {
|
||||
return c.getVariables(nil, nil, true)
|
||||
}
|
||||
|
||||
func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
||||
return c.getVariables(t, call, true)
|
||||
return c.getVariables(t, &call, true)
|
||||
}
|
||||
|
||||
func (c *CompilerV3) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
||||
return c.getVariables(t, call, false)
|
||||
return c.getVariables(t, &call, false)
|
||||
}
|
||||
|
||||
func (c *CompilerV3) getVariables(t *taskfile.Task, call taskfile.Call, evaluateShVars bool) (*taskfile.Vars, error) {
|
||||
func (c *CompilerV3) getVariables(t *taskfile.Task, call *taskfile.Call, evaluateShVars bool) (*taskfile.Vars, error) {
|
||||
result := compiler.GetEnviron()
|
||||
result.Set("TASK", taskfile.Var{Static: t.Task})
|
||||
if t != nil {
|
||||
result.Set("TASK", taskfile.Var{Static: t.Task})
|
||||
}
|
||||
|
||||
getRangeFunc := func(dir string) func(k string, v taskfile.Var) error {
|
||||
return func(k string, v taskfile.Var) error {
|
||||
@@ -74,6 +80,11 @@ func (c *CompilerV3) getVariables(t *taskfile.Task, call taskfile.Call, evaluate
|
||||
if err := c.TaskfileVars.Range(rangeFunc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t == nil || call == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if err := call.Vars.Range(rangeFunc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,7 +136,7 @@ func (c *CompilerV3) HandleDynamicVar(v taskfile.Var, dir string) (string, error
|
||||
Stderr: c.Logger.Stderr,
|
||||
}
|
||||
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
||||
return "", fmt.Errorf(`task: Command "%s" in taskvars file failed: %s`, opts.Command, err)
|
||||
return "", fmt.Errorf(`task: Command "%s" failed: %s`, opts.Command, err)
|
||||
}
|
||||
|
||||
// Trim a single trailing newline from the result to make most command
|
||||
|
||||
24
internal/hash/hash.go
Normal file
24
internal/hash/hash.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package hash
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/hashstructure/v2"
|
||||
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
type HashFunc func(*taskfile.Task) (string, error)
|
||||
|
||||
func Empty(*taskfile.Task) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func Name(t *taskfile.Task) (string, error) {
|
||||
return t.Task, nil
|
||||
}
|
||||
|
||||
func Hash(t *taskfile.Task) (string, error) {
|
||||
h, err := hashstructure.Hash(t, hashstructure.FormatV2, nil)
|
||||
return fmt.Sprintf("%s:%d", t.Task, h), err
|
||||
}
|
||||
@@ -6,17 +6,16 @@ import (
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
type Color func() PrintFunc
|
||||
type PrintFunc func(io.Writer, string, ...interface{})
|
||||
|
||||
var (
|
||||
Default PrintFunc = color.New(color.Reset).FprintfFunc()
|
||||
Blue PrintFunc = color.New(color.FgBlue).FprintfFunc()
|
||||
Green PrintFunc = color.New(color.FgGreen).FprintfFunc()
|
||||
Cyan PrintFunc = color.New(color.FgCyan).FprintfFunc()
|
||||
Yellow PrintFunc = color.New(color.FgYellow).FprintfFunc()
|
||||
Magenta PrintFunc = color.New(color.FgMagenta).FprintfFunc()
|
||||
Red PrintFunc = color.New(color.FgRed).FprintfFunc()
|
||||
)
|
||||
func Default() PrintFunc { return color.New(color.Reset).FprintfFunc() }
|
||||
func Blue() PrintFunc { return color.New(color.FgBlue).FprintfFunc() }
|
||||
func Green() PrintFunc { return color.New(color.FgGreen).FprintfFunc() }
|
||||
func Cyan() PrintFunc { return color.New(color.FgCyan).FprintfFunc() }
|
||||
func Yellow() PrintFunc { return color.New(color.FgYellow).FprintfFunc() }
|
||||
func Magenta() PrintFunc { return color.New(color.FgMagenta).FprintfFunc() }
|
||||
func Red() PrintFunc { return color.New(color.FgRed).FprintfFunc() }
|
||||
|
||||
// Logger is just a wrapper that prints stuff to STDOUT or STDERR,
|
||||
// with optional color.
|
||||
@@ -28,37 +27,39 @@ type Logger struct {
|
||||
}
|
||||
|
||||
// Outf prints stuff to STDOUT.
|
||||
func (l *Logger) Outf(print PrintFunc, s string, args ...interface{}) {
|
||||
func (l *Logger) Outf(color Color, s string, args ...interface{}) {
|
||||
if len(args) == 0 {
|
||||
s, args = "%s", []interface{}{s}
|
||||
}
|
||||
if !l.Color {
|
||||
print = Default
|
||||
color = Default
|
||||
}
|
||||
print := color()
|
||||
print(l.Stdout, s+"\n", args...)
|
||||
}
|
||||
|
||||
// VerboseOutf prints stuff to STDOUT if verbose mode is enabled.
|
||||
func (l *Logger) VerboseOutf(print PrintFunc, s string, args ...interface{}) {
|
||||
func (l *Logger) VerboseOutf(color Color, s string, args ...interface{}) {
|
||||
if l.Verbose {
|
||||
l.Outf(print, s, args...)
|
||||
l.Outf(color, s, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Errf prints stuff to STDERR.
|
||||
func (l *Logger) Errf(print PrintFunc, s string, args ...interface{}) {
|
||||
func (l *Logger) Errf(color Color, s string, args ...interface{}) {
|
||||
if len(args) == 0 {
|
||||
s, args = "%s", []interface{}{s}
|
||||
}
|
||||
if !l.Color {
|
||||
print = Default
|
||||
color = Default
|
||||
}
|
||||
print := color()
|
||||
print(l.Stderr, s+"\n", args...)
|
||||
}
|
||||
|
||||
// VerboseErrf prints stuff to STDERR if verbose mode is enabled.
|
||||
func (l *Logger) VerboseErrf(print PrintFunc, s string, args ...interface{}) {
|
||||
func (l *Logger) VerboseErrf(color Color, s string, args ...interface{}) {
|
||||
if l.Verbose {
|
||||
l.Errf(print, s, args...)
|
||||
l.Errf(color, s, args...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (c *Checksum) IsUpToDate() (bool, error) {
|
||||
if len(c.Generates) > 0 {
|
||||
// For each specified 'generates' field, check whether the files actually exist
|
||||
for _, g := range c.Generates {
|
||||
generates, err := glob(c.TaskDir, g)
|
||||
generates, err := Glob(c.TaskDir, g)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func globs(dir string, globs []string) ([]string, error) {
|
||||
files := make([]string, 0)
|
||||
for _, g := range globs {
|
||||
f, err := glob(dir, g)
|
||||
f, err := Glob(dir, g)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func globs(dir string, globs []string) ([]string, error) {
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func glob(dir string, g string) ([]string, error) {
|
||||
func Glob(dir string, g string) ([]string, error) {
|
||||
files := make([]string, 0)
|
||||
if !filepath.IsAbs(g) {
|
||||
g = filepath.Join(dir, g)
|
||||
|
||||
@@ -6,7 +6,8 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/go-task/slim-sprig"
|
||||
sprig "github.com/go-task/slim-sprig"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -37,6 +38,9 @@ func init() {
|
||||
}
|
||||
return ""
|
||||
},
|
||||
"shellQuote": func(str string) (string, error) {
|
||||
return syntax.Quote(str, syntax.LangBash)
|
||||
},
|
||||
// IsSH is deprecated.
|
||||
"IsSH": func() bool { return true },
|
||||
}
|
||||
|
||||
29
status.go
29
status.go
@@ -29,16 +29,35 @@ func (e *Executor) Status(ctx context.Context, calls ...taskfile.Call) error {
|
||||
}
|
||||
|
||||
func (e *Executor) isTaskUpToDate(ctx context.Context, t *taskfile.Task) (bool, error) {
|
||||
if len(t.Status) == 0 && len(t.Sources) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if len(t.Status) > 0 {
|
||||
return e.isTaskUpToDateStatus(ctx, t)
|
||||
isUpToDate, err := e.isTaskUpToDateStatus(ctx, t)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !isUpToDate {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
checker, err := e.getStatusChecker(t)
|
||||
if err != nil {
|
||||
return false, err
|
||||
if len(t.Sources) > 0 {
|
||||
checker, err := e.getStatusChecker(t)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isUpToDate, err := checker.IsUpToDate()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !isUpToDate {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return checker.IsUpToDate()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (e *Executor) statusOnError(t *taskfile.Task) error {
|
||||
|
||||
158
task.go
158
task.go
@@ -58,6 +58,8 @@ type Executor struct {
|
||||
concurrencySemaphore chan struct{}
|
||||
taskCallCount map[string]*int32
|
||||
mkdirMutexMap map[string]*sync.Mutex
|
||||
executionHashes map[string]context.Context
|
||||
executionHashesMutex sync.Mutex
|
||||
}
|
||||
|
||||
// Run runs Task
|
||||
@@ -149,9 +151,12 @@ func (e *Executor) Setup() error {
|
||||
if v == 2.0 {
|
||||
v = 2.6
|
||||
}
|
||||
if v == 3.0 {
|
||||
v = 3.7
|
||||
}
|
||||
|
||||
if v > 3.0 {
|
||||
return fmt.Errorf(`task: Taskfile versions greater than v3.0 not implemented in the version of Task`)
|
||||
if v > 3.7 {
|
||||
return fmt.Errorf(`task: Taskfile versions greater than v3.7 not implemented in the version of Task`)
|
||||
}
|
||||
|
||||
// Color available only on v3
|
||||
@@ -176,6 +181,23 @@ func (e *Executor) Setup() error {
|
||||
}
|
||||
}
|
||||
|
||||
if v >= 3.0 {
|
||||
env, err := read.Dotenv(e.Compiler, e.Taskfile, e.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = env.Range(func(key string, value taskfile.Var) error {
|
||||
if _, ok := e.Taskfile.Env.Mapping[key]; !ok {
|
||||
e.Taskfile.Env.Set(key, value)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v < 2.1 && e.Taskfile.Output != "" {
|
||||
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
|
||||
}
|
||||
@@ -243,6 +265,24 @@ func (e *Executor) Setup() error {
|
||||
}
|
||||
}
|
||||
|
||||
if v < 3.7 {
|
||||
if e.Taskfile.Run != "" {
|
||||
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
|
||||
}
|
||||
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.Run != "" {
|
||||
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if e.Taskfile.Run == "" {
|
||||
e.Taskfile.Run = "always"
|
||||
}
|
||||
|
||||
e.executionHashes = make(map[string]context.Context)
|
||||
|
||||
e.taskCallCount = make(map[string]*int32, len(e.Taskfile.Tasks))
|
||||
e.mkdirMutexMap = make(map[string]*sync.Mutex, len(e.Taskfile.Tasks))
|
||||
for k := range e.Taskfile.Tasks {
|
||||
@@ -269,48 +309,56 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
|
||||
release := e.acquireConcurrencyLimit()
|
||||
defer release()
|
||||
|
||||
if err := e.runDeps(ctx, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !e.Force {
|
||||
preCondMet, err := e.areTaskPreconditionsMet(ctx, t)
|
||||
if err != nil {
|
||||
return e.startExecution(ctx, t, func(ctx context.Context) error {
|
||||
e.Logger.VerboseErrf(logger.Magenta, `task: "%s" started`, call.Task)
|
||||
if err := e.runDeps(ctx, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
upToDate, err := e.isTaskUpToDate(ctx, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if upToDate && preCondMet {
|
||||
if !e.Silent {
|
||||
e.Logger.Errf(logger.Magenta, `task: Task "%s" is up to date`, t.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := e.mkdir(t); err != nil {
|
||||
e.Logger.Errf(logger.Red, "task: cannot make directory %q: %v", t.Dir, err)
|
||||
}
|
||||
|
||||
for i := range t.Cmds {
|
||||
if err := e.runCommand(ctx, t, call, i); err != nil {
|
||||
if err2 := e.statusOnError(t); err2 != nil {
|
||||
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v", err2)
|
||||
if !e.Force {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if execext.IsExitError(err) && t.IgnoreError {
|
||||
e.Logger.VerboseErrf(logger.Yellow, "task: task error ignored: %v", err)
|
||||
continue
|
||||
preCondMet, err := e.areTaskPreconditionsMet(ctx, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return &taskRunError{t.Task, err}
|
||||
upToDate, err := e.isTaskUpToDate(ctx, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if upToDate && preCondMet {
|
||||
if !e.Silent {
|
||||
e.Logger.Errf(logger.Magenta, `task: Task "%s" is up to date`, t.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
if err := e.mkdir(t); err != nil {
|
||||
e.Logger.Errf(logger.Red, "task: cannot make directory %q: %v", t.Dir, err)
|
||||
}
|
||||
|
||||
for i := range t.Cmds {
|
||||
if err := e.runCommand(ctx, t, call, i); err != nil {
|
||||
if err2 := e.statusOnError(t); err2 != nil {
|
||||
e.Logger.VerboseErrf(logger.Yellow, "task: error cleaning status on error: %v", err2)
|
||||
}
|
||||
|
||||
if execext.IsExitError(err) && t.IgnoreError {
|
||||
e.Logger.VerboseErrf(logger.Yellow, "task: task error ignored: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
return &taskRunError{t.Task, err}
|
||||
}
|
||||
}
|
||||
e.Logger.VerboseErrf(logger.Magenta, `task: "%s" finished`, call.Task)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (e *Executor) mkdir(t *taskfile.Task) error {
|
||||
@@ -373,8 +421,13 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi
|
||||
return nil
|
||||
}
|
||||
|
||||
stdOut := e.Output.WrapWriter(e.Stdout, t.Prefix)
|
||||
stdErr := e.Output.WrapWriter(e.Stderr, t.Prefix)
|
||||
outputWrapper := e.Output
|
||||
if t.Interactive {
|
||||
outputWrapper = output.Interleaved{}
|
||||
}
|
||||
stdOut := outputWrapper.WrapWriter(e.Stdout, t.Prefix)
|
||||
stdErr := outputWrapper.WrapWriter(e.Stderr, t.Prefix)
|
||||
|
||||
defer func() {
|
||||
if _, ok := stdOut.(*os.File); !ok {
|
||||
if closer, ok := stdOut.(io.Closer); ok {
|
||||
@@ -428,3 +481,32 @@ func getEnviron(t *taskfile.Task) []string {
|
||||
|
||||
return environ
|
||||
}
|
||||
|
||||
func (e *Executor) startExecution(ctx context.Context, t *taskfile.Task, execute func(ctx context.Context) error) error {
|
||||
h, err := e.GetHash(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if h == "" {
|
||||
return execute(ctx)
|
||||
}
|
||||
|
||||
e.executionHashesMutex.Lock()
|
||||
otherExecutionCtx, ok := e.executionHashes[h]
|
||||
|
||||
if ok {
|
||||
e.executionHashesMutex.Unlock()
|
||||
e.Logger.VerboseErrf(logger.Magenta, "task: skipping execution of task: %s", h)
|
||||
<-otherExecutionCtx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
e.executionHashes[h] = ctx
|
||||
e.executionHashesMutex.Unlock()
|
||||
|
||||
return execute(ctx)
|
||||
}
|
||||
|
||||
157
task_test.go
157
task_test.go
@@ -17,6 +17,10 @@ import (
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = os.Setenv("NO_COLOR", "1")
|
||||
}
|
||||
|
||||
// fileContentTest provides a basic reusable test-case for running a Taskfile
|
||||
// and inspect generated files.
|
||||
type fileContentTest struct {
|
||||
@@ -248,12 +252,18 @@ func TestDeps(t *testing.T) {
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
const dir = "testdata/status"
|
||||
var file = filepath.Join(dir, "foo.txt")
|
||||
|
||||
_ = os.Remove(file)
|
||||
files := []string{
|
||||
"foo.txt",
|
||||
"bar.txt",
|
||||
}
|
||||
|
||||
if _, err := os.Stat(file); err == nil {
|
||||
t.Errorf("File should not exist: %v", err)
|
||||
for _, f := range files {
|
||||
path := filepath.Join(dir, f)
|
||||
_ = os.Remove(path)
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
t.Errorf("File should not exist: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
@@ -265,17 +275,33 @@ func TestStatus(t *testing.T) {
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||
|
||||
if _, err := os.Stat(file); err != nil {
|
||||
t.Errorf("File should exist: %v", err)
|
||||
for _, f := range files {
|
||||
if _, err := os.Stat(filepath.Join(dir, f)); err != nil {
|
||||
t.Errorf("File should exist: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
e.Silent = false
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||
|
||||
if buff.String() != `task: Task "gen-foo" is up to date`+"\n" {
|
||||
t.Errorf("Wrong output message: %s", buff.String())
|
||||
}
|
||||
// all: not up-to-date
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||
assert.Equal(t, "task: [gen-foo] touch foo.txt", strings.TrimSpace(buff.String()))
|
||||
buff.Reset()
|
||||
// status: not up-to-date
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||
assert.Equal(t, "task: [gen-foo] touch foo.txt", strings.TrimSpace(buff.String()))
|
||||
buff.Reset()
|
||||
|
||||
// sources: not up-to-date
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||
assert.Equal(t, "task: [gen-bar] touch bar.txt", strings.TrimSpace(buff.String()))
|
||||
buff.Reset()
|
||||
// all: up-to-date
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-bar"}))
|
||||
assert.Equal(t, `task: Task "gen-bar" is up to date`, strings.TrimSpace(buff.String()))
|
||||
buff.Reset()
|
||||
}
|
||||
|
||||
func TestPrecondition(t *testing.T) {
|
||||
@@ -729,6 +755,41 @@ func TestIncludesCallingRoot(t *testing.T) {
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestIncludesOptional(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/includes_optional",
|
||||
Target: "default",
|
||||
TrimSpace: true,
|
||||
Files: map[string]string{
|
||||
"called_dep.txt": "called_dep",
|
||||
}}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestIncludesOptionalImplicitFalse(t *testing.T) {
|
||||
e := task.Executor{
|
||||
Dir: "testdata/includes_optional_implicit_false",
|
||||
Stdout: ioutil.Discard,
|
||||
Stderr: ioutil.Discard,
|
||||
}
|
||||
|
||||
err := e.Setup()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "stat testdata/includes_optional_implicit_false/TaskfileOptional.yml: no such file or directory", err.Error())
|
||||
}
|
||||
|
||||
func TestIncludesOptionalExplicitFalse(t *testing.T) {
|
||||
e := task.Executor{
|
||||
Dir: "testdata/includes_optional_explicit_false",
|
||||
Stdout: ioutil.Discard,
|
||||
Stderr: ioutil.Discard,
|
||||
}
|
||||
|
||||
err := e.Setup()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "stat testdata/includes_optional_explicit_false/TaskfileOptional.yml: no such file or directory", err.Error())
|
||||
}
|
||||
|
||||
func TestSummary(t *testing.T) {
|
||||
const dir = "testdata/summary"
|
||||
|
||||
@@ -900,6 +961,44 @@ func TestDotenvShouldAllowMissingEnv(t *testing.T) {
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestDotenvHasLocalEnvInPath(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/dotenv/local_env_in_path",
|
||||
Target: "default",
|
||||
TrimSpace: false,
|
||||
Files: map[string]string{
|
||||
"var.txt": "VAR='var_in_dot_env_1'\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestDotenvHasLocalVarInPath(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/dotenv/local_var_in_path",
|
||||
Target: "default",
|
||||
TrimSpace: false,
|
||||
Files: map[string]string{
|
||||
"var.txt": "VAR='var_in_dot_env_3'\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestDotenvHasEnvVarInPath(t *testing.T) {
|
||||
os.Setenv("ENV_VAR", "testing")
|
||||
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/dotenv/env_var_in_path",
|
||||
Target: "default",
|
||||
TrimSpace: false,
|
||||
Files: map[string]string{
|
||||
"var.txt": "VAR='var_in_dot_env_2'\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestExitImmediately(t *testing.T) {
|
||||
const dir = "testdata/exit_immediately"
|
||||
|
||||
@@ -915,3 +1014,41 @@ func TestExitImmediately(t *testing.T) {
|
||||
assert.Error(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
||||
assert.Contains(t, buff.String(), `"this_should_fail": executable file not found in $PATH`)
|
||||
}
|
||||
|
||||
func TestRunOnlyRunsJobsHashOnce(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/run",
|
||||
Target: "generate-hash",
|
||||
Files: map[string]string{
|
||||
"hash.txt": "starting 1\n1\n2\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestIgnoreNilElements(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
dir string
|
||||
}{
|
||||
{"nil cmd", "testdata/ignore_nil_elements/cmds"},
|
||||
{"nil dep", "testdata/ignore_nil_elements/deps"},
|
||||
{"nil include", "testdata/ignore_nil_elements/includes"},
|
||||
{"nil precondition", "testdata/ignore_nil_elements/preconditions"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: test.dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
||||
assert.Equal(t, "string-slice-1\n", buff.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
type IncludedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
Optional bool
|
||||
AdvancedImport bool
|
||||
}
|
||||
|
||||
@@ -92,12 +93,14 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
var includedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
Optional bool
|
||||
}
|
||||
if err := unmarshal(&includedTaskfile); err != nil {
|
||||
return err
|
||||
}
|
||||
it.Dir = includedTaskfile.Dir
|
||||
it.Taskfile = includedTaskfile.Taskfile
|
||||
it.Dir = includedTaskfile.Dir
|
||||
it.Optional = includedTaskfile.Optional
|
||||
it.AdvancedImport = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error {
|
||||
dep.Task = taskNameWithNamespace(dep.Task, namespaces...)
|
||||
}
|
||||
for _, cmd := range v.Cmds {
|
||||
if cmd.Task != "" {
|
||||
if cmd != nil && cmd.Task != "" {
|
||||
cmd.Task = taskNameWithNamespace(cmd.Task, namespaces...)
|
||||
}
|
||||
}
|
||||
|
||||
50
taskfile/read/dotenv.go
Normal file
50
taskfile/read/dotenv.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package read
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"github.com/go-task/task/v3/internal/compiler"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
func Dotenv(c compiler.Compiler, tf *taskfile.Taskfile, dir string) (*taskfile.Vars, error) {
|
||||
if len(tf.Dotenv) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
vars, err := c.GetTaskfileVariables()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
env := &taskfile.Vars{}
|
||||
|
||||
tr := templater.Templater{Vars: vars, RemoveNoValue: true}
|
||||
|
||||
for _, dotEnvPath := range tf.Dotenv {
|
||||
dotEnvPath = tr.Replace(dotEnvPath)
|
||||
|
||||
if !filepath.IsAbs(dotEnvPath) {
|
||||
dotEnvPath = filepath.Join(dir, dotEnvPath)
|
||||
}
|
||||
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
envs, err := godotenv.Read(dotEnvPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for key, value := range envs {
|
||||
if _, ok := env.Mapping[key]; !ok {
|
||||
env.Set(key, taskfile.Var{Static: value})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return env, nil
|
||||
}
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
@@ -37,33 +37,13 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if v >= 3.0 {
|
||||
for _, dotEnvPath := range t.Dotenv {
|
||||
if !filepath.IsAbs(dotEnvPath) {
|
||||
dotEnvPath = filepath.Join(dir, dotEnvPath)
|
||||
}
|
||||
if _, err := os.Stat(dotEnvPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
envs, err := godotenv.Read(dotEnvPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for key, value := range envs {
|
||||
if _, ok := t.Env.Mapping[key]; !ok {
|
||||
t.Env.Set(key, taskfile.Var{Static: value})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
|
||||
if v >= 3.0 {
|
||||
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}
|
||||
includedTask = taskfile.IncludedTaskfile{
|
||||
Taskfile: tr.Replace(includedTask.Taskfile),
|
||||
Dir: tr.Replace(includedTask.Dir),
|
||||
Optional: includedTask.Optional,
|
||||
AdvancedImport: includedTask.AdvancedImport,
|
||||
}
|
||||
if err := tr.Err(); err != nil {
|
||||
@@ -71,14 +51,19 @@ func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if filepath.IsAbs(includedTask.Taskfile) {
|
||||
path = includedTask.Taskfile
|
||||
} else {
|
||||
path = filepath.Join(dir, includedTask.Taskfile)
|
||||
path, err := execext.Expand(includedTask.Taskfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join(dir, path)
|
||||
}
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if includedTask.Optional {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
|
||||
@@ -19,9 +19,11 @@ type Task struct {
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Silent bool
|
||||
Interactive bool
|
||||
Method string
|
||||
Prefix string
|
||||
IgnoreError bool
|
||||
Run string
|
||||
}
|
||||
|
||||
func (t *Task) Name() string {
|
||||
@@ -58,9 +60,11 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Silent bool
|
||||
Interactive bool
|
||||
Method string
|
||||
Prefix string
|
||||
IgnoreError bool `yaml:"ignore_error"`
|
||||
Run string
|
||||
}
|
||||
if err := unmarshal(&task); err != nil {
|
||||
return err
|
||||
@@ -78,8 +82,10 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
t.Vars = task.Vars
|
||||
t.Env = task.Env
|
||||
t.Silent = task.Silent
|
||||
t.Interactive = task.Interactive
|
||||
t.Method = task.Method
|
||||
t.Prefix = task.Prefix
|
||||
t.IgnoreError = task.IgnoreError
|
||||
t.Run = task.Run
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type Taskfile struct {
|
||||
Tasks Tasks
|
||||
Silent bool
|
||||
Dotenv []string
|
||||
Run string
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
@@ -32,6 +33,7 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Tasks Tasks
|
||||
Silent bool
|
||||
Dotenv []string
|
||||
Run string
|
||||
}
|
||||
if err := unmarshal(&taskfile); err != nil {
|
||||
return err
|
||||
@@ -46,6 +48,7 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
tf.Tasks = taskfile.Tasks
|
||||
tf.Silent = taskfile.Silent
|
||||
tf.Dotenv = taskfile.Dotenv
|
||||
tf.Run = taskfile.Run
|
||||
if tf.Expansions <= 0 {
|
||||
tf.Expansions = 2
|
||||
}
|
||||
|
||||
1
testdata/dotenv/env_var_in_path/.env.testing
vendored
Normal file
1
testdata/dotenv/env_var_in_path/.env.testing
vendored
Normal file
@@ -0,0 +1 @@
|
||||
VAR_IN_DOTENV=var_in_dot_env_2
|
||||
8
testdata/dotenv/env_var_in_path/Taskfile.yml
vendored
Normal file
8
testdata/dotenv/env_var_in_path/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: "3"
|
||||
|
||||
dotenv: [".env.{{.ENV_VAR}}"]
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "VAR='$VAR_IN_DOTENV'" > var.txt
|
||||
1
testdata/dotenv/local_env_in_path/.env.testing
vendored
Normal file
1
testdata/dotenv/local_env_in_path/.env.testing
vendored
Normal file
@@ -0,0 +1 @@
|
||||
VAR_IN_DOTENV=var_in_dot_env_1
|
||||
11
testdata/dotenv/local_env_in_path/Taskfile.yml
vendored
Normal file
11
testdata/dotenv/local_env_in_path/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: "3"
|
||||
|
||||
env:
|
||||
LOCAL_ENV: testing
|
||||
|
||||
dotenv: [".env.{{.LOCAL_ENV}}"]
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "VAR='$VAR_IN_DOTENV'" > var.txt
|
||||
1
testdata/dotenv/local_var_in_path/.env.testing
vendored
Normal file
1
testdata/dotenv/local_var_in_path/.env.testing
vendored
Normal file
@@ -0,0 +1 @@
|
||||
VAR_IN_DOTENV=var_in_dot_env_3
|
||||
13
testdata/dotenv/local_var_in_path/Taskfile.yml
vendored
Normal file
13
testdata/dotenv/local_var_in_path/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
version: "3"
|
||||
|
||||
vars:
|
||||
PART_1: test
|
||||
PART_2: ing
|
||||
LOCAL_VAR: "{{.PART_1}}{{.PART_2}}"
|
||||
|
||||
dotenv: [".env.{{.LOCAL_VAR}}"]
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "VAR='$VAR_IN_DOTENV'" > var.txt
|
||||
7
testdata/ignore_nil_elements/cmds/Taskfile.yml
vendored
Normal file
7
testdata/ignore_nil_elements/cmds/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "string-slice-1"
|
||||
-
|
||||
11
testdata/ignore_nil_elements/deps/Taskfile.yml
vendored
Normal file
11
testdata/ignore_nil_elements/deps/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
deps:
|
||||
-
|
||||
- task: dep
|
||||
|
||||
dep:
|
||||
cmds:
|
||||
- echo "string-slice-1"
|
||||
9
testdata/ignore_nil_elements/includes/Taskfile.yml
vendored
Normal file
9
testdata/ignore_nil_elements/includes/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
inc: inc.yml
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- task: inc:default
|
||||
7
testdata/ignore_nil_elements/includes/inc.yml
vendored
Normal file
7
testdata/ignore_nil_elements/includes/inc.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
-
|
||||
- echo "string-slice-1"
|
||||
9
testdata/ignore_nil_elements/preconditions/Taskfile.yml
vendored
Normal file
9
testdata/ignore_nil_elements/preconditions/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
preconditions:
|
||||
-
|
||||
- sh: "[ 1 = 1 ]"
|
||||
cmds:
|
||||
- echo "string-slice-1"
|
||||
1
testdata/includes_optional/.gitignore
vendored
Normal file
1
testdata/includes_optional/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.txt
|
||||
11
testdata/includes_optional/Taskfile.yml
vendored
Normal file
11
testdata/includes_optional/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included:
|
||||
taskfile: TaskfileOptional.yml
|
||||
optional: true
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "called_dep" > called_dep.txt
|
||||
11
testdata/includes_optional_explicit_false/Taskfile.yml
vendored
Normal file
11
testdata/includes_optional_explicit_false/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included:
|
||||
taskfile: TaskfileOptional.yml
|
||||
optional: false
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "Hello, world!"
|
||||
9
testdata/includes_optional_implicit_false/Taskfile.yml
vendored
Normal file
9
testdata/includes_optional_implicit_false/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included: TaskfileOptional.yml
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "Hello, world!"
|
||||
1
testdata/run/.gitignore
vendored
Normal file
1
testdata/run/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.txt
|
||||
24
testdata/run/Taskfile.yml
vendored
Normal file
24
testdata/run/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
version: '3.7'
|
||||
run: when_changed
|
||||
|
||||
tasks:
|
||||
generate-hash:
|
||||
- rm -f hash.txt
|
||||
- task: input-content
|
||||
vars: { CONTENT: '1' }
|
||||
- task: input-content
|
||||
vars: { CONTENT: '2' }
|
||||
- task: input-content
|
||||
vars: { CONTENT: '2' }
|
||||
|
||||
input-content:
|
||||
deps:
|
||||
- task: create-output
|
||||
vars: { CONTENT: '1' }
|
||||
cmds:
|
||||
- echo {{.CONTENT}} >> hash.txt
|
||||
|
||||
create-output:
|
||||
run: once
|
||||
cmds:
|
||||
- echo starting {{.CONTENT}} >> hash.txt
|
||||
12
testdata/status/Taskfile.yml
vendored
12
testdata/status/Taskfile.yml
vendored
@@ -4,5 +4,15 @@ tasks:
|
||||
gen-foo:
|
||||
cmds:
|
||||
- touch foo.txt
|
||||
sources:
|
||||
- ./foo.txt
|
||||
status:
|
||||
- test -f foo.txt
|
||||
- test 1 = 0
|
||||
|
||||
gen-bar:
|
||||
cmds:
|
||||
- touch bar.txt
|
||||
sources:
|
||||
- ./bar.txt
|
||||
status:
|
||||
- test 1 = 1
|
||||
|
||||
35
variables.go
35
variables.go
@@ -56,9 +56,11 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
||||
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),
|
||||
}
|
||||
new.Dir, err = execext.Expand(new.Dir)
|
||||
if err != nil {
|
||||
@@ -89,34 +91,43 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
||||
}
|
||||
|
||||
if len(origTask.Cmds) > 0 {
|
||||
new.Cmds = make([]*taskfile.Cmd, len(origTask.Cmds))
|
||||
for i, cmd := range origTask.Cmds {
|
||||
new.Cmds[i] = &taskfile.Cmd{
|
||||
new.Cmds = make([]*taskfile.Cmd, 0, len(origTask.Cmds))
|
||||
for _, cmd := range origTask.Cmds {
|
||||
if cmd == nil {
|
||||
continue
|
||||
}
|
||||
new.Cmds = append(new.Cmds, &taskfile.Cmd{
|
||||
Task: r.Replace(cmd.Task),
|
||||
Silent: cmd.Silent,
|
||||
Cmd: r.Replace(cmd.Cmd),
|
||||
Vars: r.ReplaceVars(cmd.Vars),
|
||||
IgnoreError: cmd.IgnoreError,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(origTask.Deps) > 0 {
|
||||
new.Deps = make([]*taskfile.Dep, len(origTask.Deps))
|
||||
for i, dep := range origTask.Deps {
|
||||
new.Deps[i] = &taskfile.Dep{
|
||||
new.Deps = make([]*taskfile.Dep, 0, len(origTask.Deps))
|
||||
for _, dep := range origTask.Deps {
|
||||
if dep == nil {
|
||||
continue
|
||||
}
|
||||
new.Deps = append(new.Deps, &taskfile.Dep{
|
||||
Task: r.Replace(dep.Task),
|
||||
Vars: r.ReplaceVars(dep.Vars),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(origTask.Preconditions) > 0 {
|
||||
new.Preconditions = make([]*taskfile.Precondition, len(origTask.Preconditions))
|
||||
for i, precond := range origTask.Preconditions {
|
||||
new.Preconditions[i] = &taskfile.Precondition{
|
||||
new.Preconditions = make([]*taskfile.Precondition, 0, len(origTask.Preconditions))
|
||||
for _, precond := range origTask.Preconditions {
|
||||
if precond == nil {
|
||||
continue
|
||||
}
|
||||
new.Preconditions = append(new.Preconditions, &taskfile.Precondition{
|
||||
Sh: r.Replace(precond.Sh),
|
||||
Msg: r.Replace(precond.Msg),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
watch.go
4
watch.go
@@ -11,8 +11,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/status"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/mattn/go-zglob"
|
||||
"github.com/radovskyb/watcher"
|
||||
)
|
||||
|
||||
@@ -128,7 +128,7 @@ func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...taskfile.Ca
|
||||
}
|
||||
|
||||
for _, s := range task.Sources {
|
||||
files, err := zglob.Glob(s)
|
||||
files, err := status.Glob(task.Dir, s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("task: %s: %w", s, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user