mirror of
https://github.com/go-task/task.git
synced 2026-05-18 13:15:41 +02:00
Compare commits
104 Commits
v3.0.0-pre
...
v3.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b2e25735b | ||
|
|
e09e75b0ba | ||
|
|
6630113fef | ||
|
|
b2f08c9c20 | ||
|
|
6a4315b7e7 | ||
|
|
8b3e62ff6d | ||
|
|
f1d3f6740d | ||
|
|
9ccd1d920c | ||
|
|
9674d75ff6 | ||
|
|
22fd74846d | ||
|
|
777645888a | ||
|
|
ac8e344173 | ||
|
|
16fad60833 | ||
|
|
cb96a39b46 | ||
|
|
a540634b5b | ||
|
|
e15576bc47 | ||
|
|
95359760ae | ||
|
|
be209cb7b6 | ||
|
|
f5eb80759b | ||
|
|
9f125502f8 | ||
|
|
3f856c4b1c | ||
|
|
f55fb1e3a5 | ||
|
|
bf88bd5da5 | ||
|
|
b7112e02db | ||
|
|
b136166fc9 | ||
|
|
75727c3d68 | ||
|
|
6c625b3359 | ||
|
|
60759a4e3b | ||
|
|
582a66bb2f | ||
|
|
d78f78bb5c | ||
|
|
71b7d062d5 | ||
|
|
c6138a0660 | ||
|
|
ce4ac97269 | ||
|
|
2088a86512 | ||
|
|
e296fe2b98 | ||
|
|
96b8890ecc | ||
|
|
db6fae2f5b | ||
|
|
6743cdbb65 | ||
|
|
71466c9a27 | ||
|
|
1bdf7e3192 | ||
|
|
7285f3c844 | ||
|
|
eb257d3aa7 | ||
|
|
87f11491d9 | ||
|
|
5735a02473 | ||
|
|
47dd9b5a03 | ||
|
|
7652d7889b | ||
|
|
dd2116c897 | ||
|
|
c5566b3e94 | ||
|
|
30cbf02bff | ||
|
|
9e4e9b4f1a | ||
|
|
6f290f28b6 | ||
|
|
6ff3c9015b | ||
|
|
e28b82b2b7 | ||
|
|
3edf124f96 | ||
|
|
fb72b46a3c | ||
|
|
49bf395f61 | ||
|
|
eab14b6c49 | ||
|
|
8b962fb8e8 | ||
|
|
e5a3c861cb | ||
|
|
c7bb3d63b0 | ||
|
|
e6b543c15e | ||
|
|
8137517d93 | ||
|
|
572f6a7fab | ||
|
|
c6d9201680 | ||
|
|
7dcb3af944 | ||
|
|
4bc183a8a1 | ||
|
|
9f83311931 | ||
|
|
10986d3a7c | ||
|
|
f4f6efa547 | ||
|
|
bf64259af3 | ||
|
|
6141ba84ce | ||
|
|
329902f0db | ||
|
|
bfcaa7a443 | ||
|
|
45915bf0ed | ||
|
|
ee7f2a541f | ||
|
|
59a00eae98 | ||
|
|
df8293bee6 | ||
|
|
935216f179 | ||
|
|
f56bbd46fd | ||
|
|
9f0f18c5c4 | ||
|
|
191c34c9c4 | ||
|
|
6a604b3002 | ||
|
|
5a435b533e | ||
|
|
4b027722b1 | ||
|
|
68ce8642b1 | ||
|
|
4913b6a0f1 | ||
|
|
aee0ab05f4 | ||
|
|
b44432f24a | ||
|
|
86be13ff1f | ||
|
|
ee95df0e57 | ||
|
|
442c29f020 | ||
|
|
739037fc37 | ||
|
|
f8252020aa | ||
|
|
38b87439fe | ||
|
|
116879f7ea | ||
|
|
2eafb2f067 | ||
|
|
c36f0f6f7f | ||
|
|
bfc033959b | ||
|
|
814f350b6d | ||
|
|
05db8ce582 | ||
|
|
3fd36a0c72 | ||
|
|
cbb12b29bd | ||
|
|
6ed30f1add | ||
|
|
a044c41c66 |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1,2 +1,3 @@
|
||||
open_collective: task
|
||||
patreon: andreynering
|
||||
custom: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GSVDU63RKG45A¤cy_code=BRL&source=url'
|
||||
|
||||
6
.github/ISSUE_TEMPLATE.md
vendored
6
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,6 +0,0 @@
|
||||
<!--
|
||||
If relevant, include the following information:
|
||||
- Task version
|
||||
- OS
|
||||
- Example Taskfile showing the issue
|
||||
-->
|
||||
14
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Use the template to report bugs and issues
|
||||
labels: bug
|
||||
---
|
||||
|
||||
- Task version:
|
||||
- Operating System:
|
||||
|
||||
### Example Taskfile showing the issue
|
||||
|
||||
```yaml
|
||||
|
||||
```
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions, Ideas and General Discussions
|
||||
url: https://github.com/go-task/task/discussions
|
||||
about: Ask questions and discuss general ideas with the community
|
||||
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
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.
|
||||
Give examples if possible.
|
||||
|
||||
Please, search if this wasn't proposed before, and if this is more like an idea
|
||||
than a strong feature request, consider opening a
|
||||
[discussion](https://github.com/go-task/task/discussions) instead.
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.14.x
|
||||
go-version: 1.15.x
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v1
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -5,7 +5,7 @@ jobs:
|
||||
name: Test
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.13.x, 1.14.x]
|
||||
go-version: [1.14.x, 1.15.x]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{matrix.platform}}
|
||||
steps:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ tags
|
||||
|
||||
/bin
|
||||
/testdata/vars/v1
|
||||
/tmp
|
||||
|
||||
@@ -8,6 +8,10 @@ build:
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
goarm:
|
||||
- 6
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: 386
|
||||
@@ -40,4 +44,4 @@ nfpms:
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
name_template: "{{.ProjectName}}_{{.Os}}_{{.Arch}}"
|
||||
file_name_template: "{{.ProjectName}}_{{.Os}}_{{.Arch}}"
|
||||
|
||||
58
CHANGELOG.md
58
CHANGELOG.md
@@ -1,16 +1,52 @@
|
||||
# Changelog
|
||||
|
||||
# v3.0.0 - Preview 3
|
||||
## v3.1.0
|
||||
|
||||
- Fix a bug when the checksum up-to-date resolution is used by a task
|
||||
with a custom `label:` attribute
|
||||
([#412](https://github.com/go-task/task/issues/412)).
|
||||
- Starting from this release, we're releasing official ARMv6 and ARM64 binaries
|
||||
for Linux
|
||||
([#375](https://github.com/go-task/task/issues/375), [#418](https://github.com/go-task/task/issues/418)).
|
||||
- Task now respects the order of declaration of included Taskfiles when
|
||||
evaluating variables declaring by them
|
||||
([#393](https://github.com/go-task/task/issues/393)).
|
||||
- `set -e` is now automatically set on every command. This was done to fix an
|
||||
issue where multiline string commands wouldn't really fail unless the
|
||||
sentence was in the last line
|
||||
([#403](https://github.com/go-task/task/issues/403)).
|
||||
|
||||
## v3.0.1
|
||||
|
||||
- Allow use as a library by moving the required packages out of the `internal`
|
||||
directory
|
||||
([#358](https://github.com/go-task/task/pull/358)).
|
||||
- Do not error if a specified dotenv file does not exist
|
||||
([#378](https://github.com/go-task/task/issues/378), [#385](https://github.com/go-task/task/pull/385)).
|
||||
- Fix panic when you have empty tasks in your Taskfile
|
||||
([#338](https://github.com/go-task/task/issues/338), [#362](https://github.com/go-task/task/pull/362)).
|
||||
|
||||
## v3.0.0
|
||||
|
||||
- On `v3`, all CLI variables will be considered global variables
|
||||
([#336](https://github.com/go-task/task/issues/336), [#341](https://github.com/go-task/task/pull/341))
|
||||
- Add support to `.env` like files
|
||||
([#324](https://github.com/go-task/task/issues/324), [#356](https://github.com/go-task/task/pull/356)).
|
||||
- Add `label:` to task so you can override the task name in the logs
|
||||
([#321](https://github.com/go-task/task/issues/321]), [#337](https://github.com/go-task/task/pull/337)).
|
||||
- Refactor how variables work on version 3
|
||||
([#311](https://github.com/go-task/task/pull/311)).
|
||||
- Disallow `expansions` on v3 since it has no effect.
|
||||
- `Taskvars.yml` is not automatically included anymore.
|
||||
- `Taskfile_{{OS}}.yml` is not automatically included anymore.
|
||||
- Allow interpolation on `includes`, so you can manually include a Taskfile
|
||||
based on operation system, for example.
|
||||
- Expose `.TASK` variable in templates with the task name
|
||||
([#252](https://github.com/go-task/task/issues/252)).
|
||||
- Implement short task syntax
|
||||
([#194](https://github.com/go-task/task/issues/194), [#240](https://github.com/go-task/task/pull/240)).
|
||||
- Added option to make included Taskfile run commands on its own directory
|
||||
([#260](https://github.com/go-task/task/issues/260), [#144](https://github.com/go-task/task/issues/144))
|
||||
|
||||
# v3.0.0 - Preview 2
|
||||
|
||||
- Taskfiles in version 1 are not supported anymore
|
||||
([#237](https://github.com/go-task/task/pull/237)).
|
||||
- Added global `method:` option. With this option, you can set a default
|
||||
@@ -25,9 +61,6 @@
|
||||
This is useful for manual checking when using external, or even remote,
|
||||
artifacts when using `status:`
|
||||
([#216](https://github.com/go-task/task/pull/216)).
|
||||
|
||||
## v3.0.0 - Preview 1
|
||||
|
||||
- We're now using [slim-sprig](https://github.com/go-task/slim-sprig) instead of
|
||||
[sprig](https://github.com/Masterminds/sprig), which allowed a file size
|
||||
reduction of about 22%
|
||||
@@ -36,6 +69,17 @@
|
||||
commands are green, errors are red, etc
|
||||
([#207](https://github.com/go-task/task/pull/207)).
|
||||
|
||||
## v2.8.1 - 2019-05-20
|
||||
|
||||
- Fix error code for the `--help` flag
|
||||
([#300](https://github.com/go-task/task/issues/300), [#330](https://github.com/go-task/task/pull/330)).
|
||||
- Print version to stdout instead of stderr
|
||||
([#299](https://github.com/go-task/task/issues/299), [#329](https://github.com/go-task/task/pull/329)).
|
||||
- Supress `context` errors when using the `--watch` flag
|
||||
([#313](https://github.com/go-task/task/issues/313), [#317](https://github.com/go-task/task/pull/317)).
|
||||
- Support templating on description
|
||||
([#276](https://github.com/go-task/task/issues/276), [#283](https://github.com/go-task/task/pull/283)).
|
||||
|
||||
## v2.8.0 - 2019-12-07
|
||||
|
||||
- Add `--parallel` flag (alias `-p`) to run tasks given by the command line in
|
||||
|
||||
31
README.md
31
README.md
@@ -1,22 +1,15 @@
|
||||
[](https://travis-ci.org/go-task/task)
|
||||
<div align="center">
|
||||
<a href="https://taskfile.dev">
|
||||
<img src="docs/Logo.png" width="200px" height="200px" />
|
||||
</a>
|
||||
|
||||
# Task
|
||||
<h1>Task</h1>
|
||||
|
||||
Task is a task runner / build tool that aims to be simpler and easier to use
|
||||
than, for example, [GNU Make](https://www.gnu.org/software/make/).
|
||||
<p>
|
||||
Task is a task runner / build tool that aims to be simpler and easier to use than, for example, <a href="https://www.gnu.org/software/make/">GNU Make<a>.
|
||||
</p>
|
||||
|
||||
See [taskfile.dev](https://taskfile.dev) for documentation.
|
||||
|
||||
---
|
||||
|
||||
## Sponsors
|
||||
|
||||
[](https://opencollective.com/task)
|
||||
|
||||
## Backers
|
||||
|
||||
[](https://opencollective.com/task)
|
||||
|
||||
## Contributors
|
||||
|
||||
[](https://github.com/go-task/task/graphs/contributors)
|
||||
<p>
|
||||
See <a href="https://taskfile.dev">taskfile.dev</a> for the documentation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
23
Taskfile.yml
23
Taskfile.yml
@@ -24,8 +24,14 @@ tasks:
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
|
||||
dl-deps:
|
||||
desc: Downloads cli dependencies
|
||||
mod:
|
||||
desc: Downloads and tidy Go modules
|
||||
cmds:
|
||||
- go mod download
|
||||
- go mod tidy
|
||||
|
||||
cli-deps:
|
||||
desc: Downloads CLI dependencies
|
||||
cmds:
|
||||
- task: go-get
|
||||
vars: {REPO: golang.org/x/lint/golint}
|
||||
@@ -34,17 +40,6 @@ tasks:
|
||||
- task: go-get
|
||||
vars: {REPO: github.com/goreleaser/godownloader}
|
||||
|
||||
vendor:
|
||||
desc: Sync vendor/ directory according to go.mod file
|
||||
cmds:
|
||||
- go mod vendor
|
||||
|
||||
update-deps:
|
||||
desc: Updates dependencies
|
||||
cmds:
|
||||
- dep ensure
|
||||
- dep ensure -update
|
||||
|
||||
clean:
|
||||
desc: Cleans temp files and folders
|
||||
cmds:
|
||||
@@ -67,7 +62,7 @@ tasks:
|
||||
cmds:
|
||||
- goreleaser --snapshot --rm-dist
|
||||
|
||||
generate-install-script:
|
||||
gen-install-script:
|
||||
desc: Generate install script using https://github.com/goreleaser/godownloader
|
||||
cmds:
|
||||
- godownloader --repo go-task/task -o install-task.sh
|
||||
|
||||
70
args/args.go
Normal file
70
args/args.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package args
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
// ParseV3 parses command line argument: tasks and global variables
|
||||
func ParseV3(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
||||
var calls []taskfile.Call
|
||||
var globals *taskfile.Vars
|
||||
|
||||
for _, arg := range args {
|
||||
if !strings.Contains(arg, "=") {
|
||||
calls = append(calls, taskfile.Call{Task: arg})
|
||||
continue
|
||||
}
|
||||
|
||||
if globals == nil {
|
||||
globals = &taskfile.Vars{}
|
||||
}
|
||||
name, value := splitVar(arg)
|
||||
globals.Set(name, taskfile.Var{Static: value})
|
||||
}
|
||||
|
||||
if len(calls) == 0 {
|
||||
calls = append(calls, taskfile.Call{Task: "default"})
|
||||
}
|
||||
|
||||
return calls, globals
|
||||
}
|
||||
|
||||
// ParseV2 parses command line argument: tasks and vars of each task
|
||||
func ParseV2(args ...string) ([]taskfile.Call, *taskfile.Vars) {
|
||||
var calls []taskfile.Call
|
||||
var globals *taskfile.Vars
|
||||
|
||||
for _, arg := range args {
|
||||
if !strings.Contains(arg, "=") {
|
||||
calls = append(calls, taskfile.Call{Task: arg})
|
||||
continue
|
||||
}
|
||||
|
||||
if len(calls) < 1 {
|
||||
if globals == nil {
|
||||
globals = &taskfile.Vars{}
|
||||
}
|
||||
name, value := splitVar(arg)
|
||||
globals.Set(name, taskfile.Var{Static: value})
|
||||
} else {
|
||||
if calls[len(calls)-1].Vars == nil {
|
||||
calls[len(calls)-1].Vars = &taskfile.Vars{}
|
||||
}
|
||||
name, value := splitVar(arg)
|
||||
calls[len(calls)-1].Vars.Set(name, taskfile.Var{Static: value})
|
||||
}
|
||||
}
|
||||
|
||||
if len(calls) == 0 {
|
||||
calls = append(calls, taskfile.Call{Task: "default"})
|
||||
}
|
||||
|
||||
return calls, globals
|
||||
}
|
||||
|
||||
func splitVar(s string) (string, string) {
|
||||
pair := strings.SplitN(s, "=", 2)
|
||||
return pair[0], pair[1]
|
||||
}
|
||||
204
args/args_test.go
Normal file
204
args/args_test.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package args_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v3/args"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestArgsV3(t *testing.T) {
|
||||
tests := []struct {
|
||||
Args []string
|
||||
ExpectedCalls []taskfile.Call
|
||||
ExpectedGlobals *taskfile.Vars
|
||||
}{
|
||||
{
|
||||
Args: []string{"task-a", "task-b", "task-c"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
{Task: "task-c"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"task-a", "FOO=bar", "task-b", "task-c", "BAR=baz", "BAZ=foo"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
{Task: "task-c"},
|
||||
},
|
||||
ExpectedGlobals: &taskfile.Vars{
|
||||
Keys: []string{"FOO", "BAR", "BAZ"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"FOO": taskfile.Var{Static: "bar"},
|
||||
"BAR": taskfile.Var{Static: "baz"},
|
||||
"BAZ": taskfile.Var{Static: "foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"task-a", "CONTENT=with some spaces"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
},
|
||||
ExpectedGlobals: &taskfile.Vars{
|
||||
Keys: []string{"CONTENT"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"CONTENT": taskfile.Var{Static: "with some spaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"FOO=bar", "task-a", "task-b"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
},
|
||||
ExpectedGlobals: &taskfile.Vars{
|
||||
Keys: []string{"FOO"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"FOO": {Static: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: nil,
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"FOO=bar", "BAR=baz"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
ExpectedGlobals: &taskfile.Vars{
|
||||
Keys: []string{"FOO", "BAR"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"FOO": {Static: "bar"},
|
||||
"BAR": {Static: "baz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
||||
calls, globals := args.ParseV3(test.Args...)
|
||||
assert.Equal(t, test.ExpectedCalls, calls)
|
||||
assert.Equal(t, test.ExpectedGlobals, globals)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestArgsV2(t *testing.T) {
|
||||
tests := []struct {
|
||||
Args []string
|
||||
ExpectedCalls []taskfile.Call
|
||||
ExpectedGlobals *taskfile.Vars
|
||||
}{
|
||||
{
|
||||
Args: []string{"task-a", "task-b", "task-c"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
{Task: "task-c"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"task-a", "FOO=bar", "task-b", "task-c", "BAR=baz", "BAZ=foo"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{
|
||||
Task: "task-a",
|
||||
Vars: &taskfile.Vars{
|
||||
Keys: []string{"FOO"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"FOO": taskfile.Var{Static: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Task: "task-b"},
|
||||
{
|
||||
Task: "task-c",
|
||||
Vars: &taskfile.Vars{
|
||||
Keys: []string{"BAR", "BAZ"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"BAR": taskfile.Var{Static: "baz"},
|
||||
"BAZ": taskfile.Var{Static: "foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"task-a", "CONTENT=with some spaces"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{
|
||||
Task: "task-a",
|
||||
Vars: &taskfile.Vars{
|
||||
Keys: []string{"CONTENT"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"CONTENT": taskfile.Var{Static: "with some spaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"FOO=bar", "task-a", "task-b"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
},
|
||||
ExpectedGlobals: &taskfile.Vars{
|
||||
Keys: []string{"FOO"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"FOO": {Static: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: nil,
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"FOO=bar", "BAR=baz"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
ExpectedGlobals: &taskfile.Vars{
|
||||
Keys: []string{"FOO", "BAR"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"FOO": {Static: "bar"},
|
||||
"BAR": {Static: "baz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
||||
calls, globals := args.ParseV2(test.Args...)
|
||||
assert.Equal(t, test.ExpectedCalls, calls)
|
||||
assert.Equal(t, test.ExpectedGlobals, globals)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,17 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-task/task/v2"
|
||||
"github.com/go-task/task/v2/internal/args"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v3"
|
||||
"github.com/go-task/task/v3/args"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
@@ -52,6 +54,7 @@ func main() {
|
||||
|
||||
var (
|
||||
versionFlag bool
|
||||
helpFlag bool
|
||||
init bool
|
||||
list bool
|
||||
status bool
|
||||
@@ -69,6 +72,7 @@ func main() {
|
||||
)
|
||||
|
||||
pflag.BoolVar(&versionFlag, "version", false, "show Task version")
|
||||
pflag.BoolVarP(&helpFlag, "help", "h", false, "shows Task usage")
|
||||
pflag.BoolVarP(&init, "init", "i", false, "creates a new Taskfile.yml in the current folder")
|
||||
pflag.BoolVarP(&list, "list", "l", false, "lists tasks with description of current Taskfile")
|
||||
pflag.BoolVar(&status, "status", false, "exits with non-zero exit code if any of the given tasks is not up-to-date")
|
||||
@@ -86,7 +90,12 @@ func main() {
|
||||
pflag.Parse()
|
||||
|
||||
if versionFlag {
|
||||
log.Printf("Task version: %s\n", version)
|
||||
fmt.Printf("Task version: %s\n", version)
|
||||
return
|
||||
}
|
||||
|
||||
if helpFlag {
|
||||
pflag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -133,16 +142,27 @@ func main() {
|
||||
if err := e.Setup(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
v, err := e.Taskfile.ParsedVersion()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
if list {
|
||||
e.PrintTasksHelp()
|
||||
return
|
||||
}
|
||||
|
||||
calls, globals := args.Parse(pflag.Args()...)
|
||||
for name, value := range globals {
|
||||
e.Taskfile.Vars[name] = value
|
||||
var (
|
||||
calls []taskfile.Call
|
||||
globals *taskfile.Vars
|
||||
)
|
||||
if v >= 3.0 {
|
||||
calls, globals = args.ParseV3(pflag.Args()...)
|
||||
} else {
|
||||
calls, globals = args.ParseV2(pflag.Args()...)
|
||||
}
|
||||
e.Taskfile.Vars.Merge(globals)
|
||||
|
||||
ctx := context.Background()
|
||||
if !watch {
|
||||
|
||||
24
completion/fish/task.fish
Normal file
24
completion/fish/task.fish
Normal file
@@ -0,0 +1,24 @@
|
||||
function __task_get_tasks --description "Prints all available tasks with their description"
|
||||
task -l | sed '1d' | awk '{ $1=""; print $0 }' | tr ': ', '\t' | 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
|
||||
specified.' -xa "(__task_get_tasks)"
|
||||
|
||||
|
||||
complete -c task -s c -l color -d 'colored output (default true)'
|
||||
complete -c task -s d -l dir -d 'sets directory of execution'
|
||||
complete -c task -l dry -d 'compiles and prints tasks in the order that they would be run, without executing them'
|
||||
complete -c task -s f -l force -d 'forces execution even when the task is up-to-date'
|
||||
complete -c task -s h -l help -d 'shows Task usage'
|
||||
complete -c task -s i -l init -d 'creates a new Taskfile.yml in the current folder'
|
||||
complete -c task -s l -l list -d 'lists tasks with description of current Taskfile'
|
||||
complete -c task -s o -l output -d 'sets output style: [interleaved|group|prefixed]' -xa "interleaved group prefixed"
|
||||
complete -c task -s p -l parallel -d 'executes tasks provided on command line in parallel'
|
||||
complete -c task -s s -l silent -d 'disables echoing'
|
||||
complete -c task -l status -d 'exits with non-zero exit code if any of the given tasks is not up-to-date'
|
||||
complete -c task -l summary -d 'show summary about a task'
|
||||
complete -c task -s t -l taskfile -d 'choose which Taskfile to run. Defaults to "Taskfile.yml"'
|
||||
complete -c task -s v -l verbose -d 'enables verbose mode'
|
||||
complete -c task -l version -d 'show Task version'
|
||||
complete -c task -s w -l watch -d 'enables watch of the given task'
|
||||
@@ -5,7 +5,7 @@ function __list() {
|
||||
local -a scripts
|
||||
|
||||
if [ -f Taskfile.yml ]; then
|
||||
scripts=($(task -l | sed '1d' | sed 's/^\* //' | awk '{ print $1 }' | sed 's/:$//' | sed 's/:/\\:/'))
|
||||
scripts=($(task -l | sed '1d' | sed 's/^\* //' | awk '{ print $1 }' | sed 's/:$//' | sed 's/:/\\:/g'))
|
||||
_describe 'script' scripts
|
||||
fi
|
||||
}
|
||||
|
||||
BIN
docs/Logo.png
Normal file
BIN
docs/Logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -1,5 +1,9 @@
|
||||
# Task
|
||||
|
||||
<div align="center">
|
||||
<img id="logo" src="/Logo.png" height="250px" width="250px" />
|
||||
</div>
|
||||
|
||||
Task is a task runner / build tool that aims to be simpler and easier to use
|
||||
than, for example, [GNU Make][make].
|
||||
|
||||
@@ -11,7 +15,7 @@ Once [installed](installation.md), you just need to describe your build tasks
|
||||
using a simple [YAML][yaml] schema in a file called `Taskfile.yml`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
hello:
|
||||
@@ -38,18 +42,6 @@ guide to check the full schema documentation and Task features.
|
||||
if a given set of files haven't changed since last run (based either on its
|
||||
timestamp or content).
|
||||
|
||||
## Sponsors
|
||||
|
||||
[](https://opencollective.com/task)
|
||||
|
||||
## Backers
|
||||
|
||||
[](https://opencollective.com/task)
|
||||
|
||||
## Contributors
|
||||
|
||||
[](https://github.com/go-task/task/graphs/contributors)
|
||||
|
||||
[make]: https://www.gnu.org/software/make/
|
||||
[go]: https://golang.org/
|
||||
[yaml]: http://yaml.org/
|
||||
|
||||
@@ -10,3 +10,8 @@ tasks:
|
||||
desc: Serves the documentation site locally
|
||||
cmds:
|
||||
- docsify serve .
|
||||
|
||||
ico:
|
||||
desc: Generate favicon.ico from Logo.png
|
||||
cmds:
|
||||
- convert -background transparent "Logo.png" -define icon:auto-resize=16,24,32,48,64,72,96,128,256 "favicon.ico"
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
- [Taskfile Versions](taskfile_versions.md)
|
||||
- [Examples](examples.md)
|
||||
- [Releasing Task](releasing_task.md)
|
||||
- [Alternative Task Runners](alternative_task_runners.md)
|
||||
- [Github](https://github.com/go-task/task)
|
||||
- [Donate](donate.md)
|
||||
- [GitHub](https://github.com/go-task/task)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Alternative task runners
|
||||
|
||||
## YAML based
|
||||
|
||||
- [rliebz/tusk][tusk]
|
||||
|
||||
## Go based
|
||||
|
||||
- [magefile/mage][mage]
|
||||
|
||||
## Make similar
|
||||
|
||||
- [casey/just][just]
|
||||
|
||||
[tusk]: https://github.com/rliebz/tusk
|
||||
[mage]: https://github.com/magefile/mage
|
||||
[just]: https://github.com/casey/just
|
||||
35
docs/donate.md
Normal file
35
docs/donate.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Donate
|
||||
|
||||
If you find this project useful, you can consider donating by using one of the
|
||||
channels listed below.
|
||||
|
||||
This is just a way of saying "thank you", it won't give you any benefits like
|
||||
higher priority on issues or something similar.
|
||||
|
||||
## Open Collective
|
||||
|
||||
Task is on [Open Collective](https://opencollective.com/task) and you have
|
||||
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)
|
||||
- [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)
|
||||
BIN
docs/favicon.ico
BIN
docs/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 170 KiB |
@@ -6,25 +6,21 @@
|
||||
<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="//unpkg.com/docsify-themeable/dist/css/theme-simple.css">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify-themeable/dist/css/theme-simple.css">
|
||||
<meta name="google-site-verification" content="VGAYkbdmuaciIDGkBe-eAg9yfZg0C6ostgonbGxxOa0" />
|
||||
<script>
|
||||
var SeedAndDewConfig = {};
|
||||
(function() {
|
||||
SeedAndDewConfig['adClass'] = "snd-ad";
|
||||
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||
SeedAndDewConfig['projectId'] = '16e0aed0-b265-48c9-9eae-0aad56147553';
|
||||
SeedAndDewConfig['loadStartTime'] = performance.now();
|
||||
SeedAndDewConfig['apiVersion'] = '2018-05-28'
|
||||
SeedAndDewConfig['sessionId'] = Math.random().toString(36).substring(2, 15);
|
||||
var snd = document.createElement('script');
|
||||
snd.type = 'text/javascript';
|
||||
snd.async = true;
|
||||
snd.src = 'https://www.seedanddew.com/static/embed.min.js';
|
||||
(document.getElementsByTagName('head')[0] ||
|
||||
document.getElementsByTagName('body')[0]).appendChild(snd);
|
||||
})();
|
||||
</script>
|
||||
<style>
|
||||
#logo {
|
||||
transition: all 0.7s ease;
|
||||
}
|
||||
#logo:hover {
|
||||
-webkit-transform: rotateZ(360deg);
|
||||
-ms-transform: rotateZ(360deg);
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
.app-name-link img {
|
||||
width: 125px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
@@ -32,18 +28,18 @@
|
||||
window.$docsify = {
|
||||
name: 'Task',
|
||||
repo: 'go-task/task',
|
||||
ga: 'UA-126286662-1',
|
||||
themeColor: '#00add8',
|
||||
logo: 'Logo.png',
|
||||
themeColor: '#29beb0',
|
||||
loadSidebar: true,
|
||||
auto2top: true,
|
||||
maxLevel: 3,
|
||||
subMaxLevel: 3
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-themeable"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-yaml.min.js"></script>
|
||||
<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/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-yaml.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Installation
|
||||
|
||||
## Binary
|
||||
Task offers many installation methods. Check out the available methods below.
|
||||
|
||||
Or you can download the binary from the [releases][releases] page and add to
|
||||
your $PATH. DEB and RPM packages are also available.
|
||||
The `task_checksums.txt` file contains the sha256 checksum for each file.
|
||||
## Package Managers
|
||||
|
||||
## Homebrew
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **Homebrew**
|
||||
|
||||
If you're on macOS or Linux and have [Homebrew][homebrew] installed, getting
|
||||
Task is as simple as running:
|
||||
@@ -15,19 +15,17 @@ Task is as simple as running:
|
||||
brew install go-task/tap/go-task
|
||||
```
|
||||
|
||||
> This installation method is only currently supported on amd64 architectures.
|
||||
#### **Snap**
|
||||
|
||||
## Snap
|
||||
|
||||
Task is available for [Snapcraft][snapcraft], but keep in mind that your
|
||||
Task is available in [Snapcraft][snapcraft], but keep in mind that your
|
||||
Linux distribution should allow classic confinement for Snaps to Task work
|
||||
right:
|
||||
|
||||
```bash
|
||||
sudo snap install task
|
||||
sudo snap install task --classic
|
||||
```
|
||||
|
||||
## Scoop
|
||||
#### **Scoop**
|
||||
|
||||
If you're on Windows and have [Scoop][scoop] installed, use `extras` bucket
|
||||
to install Task like:
|
||||
@@ -40,7 +38,7 @@ scoop install task
|
||||
This installation method is community owned. After a new release of Task, it
|
||||
may take some time until it's available on Scoop.
|
||||
|
||||
## Arch Linux
|
||||
#### **AUR**
|
||||
|
||||
If you're on Arch Linux you can install Task from
|
||||
[AUR](https://aur.archlinux.org/packages/taskfile-git) using your favorite
|
||||
@@ -53,45 +51,40 @@ yay -S taskfile-git
|
||||
This installation method is community owned, but since it's `-git` version of
|
||||
the package, it's always latest available version based on the Git repository.
|
||||
|
||||
## Go
|
||||
<!-- tabs:end -->
|
||||
|
||||
Task now uses [Go Modules](https://github.com/golang/go/wiki/Modules), which
|
||||
means you may have trouble compiling it on older Go versions or using
|
||||
`$GOPATH`.
|
||||
## Get The Binary
|
||||
|
||||
For CI environments we recommend using the [Install Script](#install-script)
|
||||
instead, which is faster and more stable, since it'll just download the latest
|
||||
released binary, instead of compiling the edge (master branch) version.
|
||||
<!-- tabs:start -->
|
||||
|
||||
Installing in another directory:
|
||||
#### **Binary**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/go-task/task
|
||||
cd task
|
||||
You can download the binary from the [releases page on GitHub][releases] and
|
||||
add to your `$PATH`.
|
||||
|
||||
# compiling binary to $GOPATH/bin
|
||||
go install -v ./cmd/task
|
||||
DEB and RPM packages are also available.
|
||||
|
||||
# compiling it to another location
|
||||
# use -o ./task.exe on Windows
|
||||
go build -v -o ./task ./cmd/task
|
||||
```
|
||||
The `task_checksums.txt` file contains the SHA-256 checksum for each file.
|
||||
|
||||
Both methods requires having the [Go][go] environment properly setup locally.
|
||||
|
||||
## Install script
|
||||
#### **Install Script**
|
||||
|
||||
We also have a [install script][installscript], which is very useful on
|
||||
scenarios like CIs. Many thanks to [godownloader][godownloader] for allowing
|
||||
scenarios like CIs. Many thanks to [GoDownloader][godownloader] for allowing
|
||||
easily generating this script.
|
||||
|
||||
```bash
|
||||
curl -sL https://taskfile.dev/install.sh | sh
|
||||
# For Default Installion to ./bin with debug logging
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d
|
||||
|
||||
# For Installation To /usr/local/bin for userwide access with debug logging
|
||||
# May require sudo sh
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
|
||||
|
||||
```
|
||||
|
||||
> This method will download the binary on the local `./bin` directory by default.
|
||||
|
||||
## GitHub Actions
|
||||
#### **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)
|
||||
@@ -104,8 +97,44 @@ by the Arduino team:
|
||||
|
||||
This installation method is community owned.
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
## Build From Source
|
||||
|
||||
<!-- tabs:start -->
|
||||
|
||||
#### **Go Modules**
|
||||
|
||||
First, make sure you have [Go][go] properly installed and setup.
|
||||
|
||||
You can easily install it globally by running:
|
||||
|
||||
```bash
|
||||
go get -u github.com/go-task/task/v3/cmd/task
|
||||
```
|
||||
|
||||
Or you can install into another directory:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/go-task/task
|
||||
cd task
|
||||
|
||||
# Compiling binary to $GOPATH/bin
|
||||
go install -v ./cmd/task
|
||||
|
||||
# Compiling it to another location.
|
||||
# Use -o ./task.exe on Windows.
|
||||
go build -v -o ./task ./cmd/task
|
||||
```
|
||||
|
||||
> For CI environments we recommend using the [Install Script](#get-the-binary)
|
||||
> instead, which is faster and more stable, since it'll just download the latest
|
||||
> released binary, instead of compiling the edge (master branch) version.
|
||||
|
||||
<!-- tabs:end -->
|
||||
|
||||
[go]: https://golang.org/
|
||||
[snapcraft]: https://snapcraft.io/
|
||||
[snapcraft]: https://snapcraft.io/task
|
||||
[homebrew]: https://brew.sh/
|
||||
[installscript]: https://github.com/go-task/task/blob/master/install-task.sh
|
||||
[releases]: https://github.com/go-task/task/releases
|
||||
|
||||
@@ -4,9 +4,9 @@ The release process of Task is done with the help of
|
||||
[GoReleaser][goreleaser]. You can test the release process locally by calling
|
||||
the `test-release` task of the Taskfile.
|
||||
|
||||
The Travis CI should release automatically when a new
|
||||
Git tag is pushed to master, either for the artifact uploading (raw executables
|
||||
and DEB and RPM packages)
|
||||
[GitHub Actions](https://github.com/go-task/task/actions) should release
|
||||
artifacts automatically when a new Git tag is pushed to master
|
||||
(raw executables and DEB and RPM packages).
|
||||
|
||||
# Homebrew
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ tasks:
|
||||
|
||||
```yaml
|
||||
# bad
|
||||
version: 2
|
||||
version: '3'
|
||||
includes:
|
||||
docker: ./docker/Taskfile.yml
|
||||
output: prefixed
|
||||
@@ -70,7 +70,7 @@ tasks:
|
||||
|
||||
|
||||
# good
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
docker: ./docker/Taskfile.yml
|
||||
@@ -92,7 +92,7 @@ tasks:
|
||||
|
||||
```yaml
|
||||
# bad
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
@@ -107,7 +107,7 @@ tasks:
|
||||
|
||||
|
||||
# good
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
@@ -127,7 +127,7 @@ tasks:
|
||||
|
||||
```yaml
|
||||
# bad
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
binary_name: myapp
|
||||
@@ -139,7 +139,7 @@ tasks:
|
||||
|
||||
|
||||
# good
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
BINARY_NAME: myapp
|
||||
@@ -154,7 +154,7 @@ tasks:
|
||||
|
||||
```yaml
|
||||
# bad
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
@@ -163,7 +163,7 @@ tasks:
|
||||
|
||||
|
||||
# good
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
@@ -177,7 +177,7 @@ This convention is also used by most people for any Go templating.
|
||||
|
||||
```yaml
|
||||
# bad
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
do_something_fancy:
|
||||
@@ -186,7 +186,7 @@ tasks:
|
||||
|
||||
|
||||
# good
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
do-something-fancy:
|
||||
@@ -198,7 +198,7 @@ tasks:
|
||||
|
||||
```yaml
|
||||
# good
|
||||
version: 2
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
docker:build:
|
||||
|
||||
@@ -9,8 +9,8 @@ The Taskfile version follows the Task version. E.g. the change to Taskfile
|
||||
version `2` means that Task `v2.0.0` should be release to support it.
|
||||
|
||||
The `version:` key on Taskfile accepts a semver string, so either `2`, `2.0` or
|
||||
`2.0.0` is accepted. You you choose to use `2.0` Task will not enable future
|
||||
`2.1` features, but if you choose to use `2`, than any `2.x.x` features will be
|
||||
`2.0.0` is accepted. If you choose to use `2.0` Task will not enable future
|
||||
`2.1` features, but if you choose to use `2`, then any `2.x.x` features will be
|
||||
available, but not `3.0.0+`.
|
||||
|
||||
## Version 1
|
||||
@@ -35,7 +35,7 @@ The variable priority order was also different:
|
||||
|
||||
## Version 2.0
|
||||
|
||||
At version 2, we introduced the `version:` key, to allow us to envolve Task
|
||||
At version 2, we introduced the `version:` key, to allow us to evolve Task
|
||||
with new features without breaking existing Taskfiles. The new syntax is as
|
||||
follows:
|
||||
|
||||
@@ -110,7 +110,7 @@ tasks:
|
||||
prefix: server
|
||||
```
|
||||
|
||||
From this version it's not also possible to ignore errors of a command or task
|
||||
From this version it's also possible to ignore errors of a command or task
|
||||
(check documentation [here][ignore_errors]):
|
||||
|
||||
```yaml
|
||||
@@ -163,3 +163,63 @@ Please check the [documentation][includes]
|
||||
[output]: usage.md#output-syntax
|
||||
[ignore_errors]: usage.md#ignore-errors
|
||||
[includes]: usage.md#including-other-taskfiles
|
||||
|
||||
## Version 3
|
||||
|
||||
These are some major changes done on `v3`:
|
||||
|
||||
- Task's output will now be colored
|
||||
- Added support for `.env` like files
|
||||
- Added `label:` setting to task so one can override how the task name
|
||||
appear in the logs
|
||||
- A global `method:` was added to allow setting the default method,
|
||||
and Task's default changed to `checksum`
|
||||
- Two magic variables were added when using `status:`: `CHECKSUM` and
|
||||
`TIMESTAMP` which contains, respectively, the md5 checksum and greatest
|
||||
modification timestamp of the files listed on `sources:`
|
||||
- Also, the `TASK` variable is always available with the current task name
|
||||
- CLI variables are always treated as global variables
|
||||
- Added `dir:` option to `includes` to allow choosing on which directory an
|
||||
included Taskfile will run:
|
||||
|
||||
```yaml
|
||||
includes:
|
||||
docs:
|
||||
taskfile: ./docs
|
||||
dir: ./docs
|
||||
```
|
||||
|
||||
- Implemented short task syntax. All below syntaxes are equivalent:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print:
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
```
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print:
|
||||
- echo "Hello, World!"
|
||||
```
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print: echo "Hello, World!"
|
||||
```
|
||||
|
||||
- There was a major refactor on how variables are handled. They're now easier
|
||||
to understand. The `expansions:` setting was removed as it became unncessary.
|
||||
This is the order in which Task will process variables, each level can see
|
||||
the variables set by the previous one and override those.
|
||||
- Environment variables
|
||||
- Global + CLI variables
|
||||
- Call variables
|
||||
- Task variables
|
||||
|
||||
252
docs/usage.md
252
docs/usage.md
@@ -8,7 +8,7 @@ The example below allows compiling a Go app and uses [Minify][minify] to concat
|
||||
and minify multiple CSS files into a single one.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
@@ -33,12 +33,14 @@ executable called must be available by the OS or in PATH.
|
||||
|
||||
If you omit a task name, "default" will be assumed.
|
||||
|
||||
## Environment
|
||||
## Environment variables
|
||||
|
||||
### Task
|
||||
|
||||
You can use `env` to set custom environment variables for a specific task:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
@@ -52,7 +54,7 @@ Additionally, you can set globally environment variables, that'll be available
|
||||
to all tasks:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
env:
|
||||
GREETING: Hey, there!
|
||||
@@ -66,53 +68,37 @@ tasks:
|
||||
> NOTE: `env` supports expansion and retrieving output from a shell command
|
||||
> just like variables, as you can see on the [Variables](#variables) section.
|
||||
|
||||
## Operating System specific tasks
|
||||
### .env files
|
||||
|
||||
If you add a `Taskfile_{{GOOS}}.yml` you can override or amend your Taskfile
|
||||
based on the operating system.
|
||||
You can also ask Task to include `.env` like files by using the `dotenv:`
|
||||
setting:
|
||||
|
||||
Example:
|
||||
|
||||
Taskfile.yml:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
cmds:
|
||||
- echo "default"
|
||||
```
|
||||
# .env
|
||||
KEYNAME=VALUE
|
||||
```
|
||||
|
||||
Taskfile_linux.yml:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
# Taskfile.yml
|
||||
|
||||
version: '3'
|
||||
|
||||
dotenv: ['.env']
|
||||
|
||||
tasks:
|
||||
build:
|
||||
greet:
|
||||
cmds:
|
||||
- echo "linux"
|
||||
- echo "Using $KEYNAME"
|
||||
```
|
||||
|
||||
Will print out `linux` and not `default`.
|
||||
|
||||
Keep in mind that the version of the files should match. Also, when redefining
|
||||
a task the whole task is replaced, properties of the task are not merged.
|
||||
|
||||
It's also possible to have an OS specific `Taskvars.yml` file, like
|
||||
`Taskvars_windows.yml`, `Taskvars_linux.yml`, or `Taskvars_darwin.yml`. See the
|
||||
[variables section](#variables) below.
|
||||
|
||||
## Including other Taskfiles
|
||||
|
||||
> This feature is still experimental and may have bugs.
|
||||
|
||||
If you want to share tasks between different projects (Taskfiles), you can use
|
||||
the importing mechanism to include other Taskfiles using the `includes` keyword:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
docs: ./documentation # will look for ./documentation/Taskfile.yml
|
||||
@@ -124,6 +110,21 @@ namespace. So, you'd call `task docs:serve` to run the `serve` task from
|
||||
`documentation/Taskfile.yml` or `task docker:build` to run the `build` task
|
||||
from the `DockerTasks.yml` file.
|
||||
|
||||
### OS-specific Taskfiles
|
||||
|
||||
With `version: '2'`, task automatically includes any `Taskfile_{{OS}}.yml`
|
||||
if it exists (for example: `Taskfile_windows.yml`, `Taskfile_linux.yml` or
|
||||
`Taskfile_darwin.yml`). Since this behavior was a bit too implicit, it
|
||||
was removed on version 3, but you still can have a similar behavior by
|
||||
explicitly importing these files:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
build: ./Taskfile_{{OS}}.yml
|
||||
```
|
||||
|
||||
### Directory of included Taskfile
|
||||
|
||||
By default, included Taskfile's tasks are ran in the current directory, even
|
||||
@@ -153,7 +154,7 @@ located. But you can easily make the task run in another folder informing
|
||||
`dir`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
serve:
|
||||
@@ -167,11 +168,15 @@ If the directory doesn't exist, `task` creates it.
|
||||
|
||||
## Task dependencies
|
||||
|
||||
> Dependencies run in parallel, so dependencies of a task shouldn't depend one
|
||||
> another. If you want to force tasks to run serially take a look at the
|
||||
> [Calling Another Task](#calling-another-task) section below.
|
||||
|
||||
You may have tasks that depend on others. Just pointing them on `deps` will
|
||||
make them run automatically before running the parent task:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
@@ -190,7 +195,7 @@ In the above example, `assets` will always run right before `build` if you run
|
||||
A task can have only dependencies and no commands to group tasks together:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
assets:
|
||||
@@ -215,7 +220,7 @@ If you want to pass information to dependencies, you can do that the same
|
||||
manner as you would to [call another task](#calling-another-task):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
@@ -239,7 +244,7 @@ often result in a faster build pipeline. But in some situations you may need
|
||||
to call other tasks serially. In this case, just use the following syntax:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
main-task:
|
||||
@@ -261,19 +266,19 @@ Overriding variables in the called task is as simple as informing `vars`
|
||||
attribute:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
main-task:
|
||||
greet:
|
||||
vars:
|
||||
RECIPIENT: '{{default "World" .RECIPIENT}}'
|
||||
cmds:
|
||||
- task: write-file
|
||||
vars: {FILE: "hello.txt", CONTENT: "Hello!"}
|
||||
- task: write-file
|
||||
vars: {FILE: "world.txt", CONTENT: "World!"}
|
||||
- echo "Hello, {{.RECIPIENT}}!"
|
||||
|
||||
write-file:
|
||||
greet-pessimistically:
|
||||
cmds:
|
||||
- echo "{{.CONTENT}}" > {{.FILE}}
|
||||
- task: greet
|
||||
vars: {RECIPIENT: "Cruel World"}
|
||||
```
|
||||
|
||||
The above syntax is also supported in `deps`.
|
||||
@@ -290,7 +295,7 @@ If a task generates something, you can inform Task the source and generated
|
||||
files, so Task will prevent to run them if not necessary.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
@@ -315,18 +320,18 @@ tasks:
|
||||
- public/style.css
|
||||
```
|
||||
|
||||
`sources` and `generates` can be files or file patterns. When both are given,
|
||||
Task will compare the modification date/time of the files to determine if it's
|
||||
`sources` and `generates` can be files or file patterns. When given,
|
||||
Task will compare the checksum of the source files to determine if it's
|
||||
necessary to run the task. If not, it will just print a message like
|
||||
`Task "js" is up to date`.
|
||||
|
||||
If you prefer this check to be made by the content of the files, instead of
|
||||
its timestamp, just set the `method` property to `checksum`.
|
||||
You will probably want to ignore the `.task` folder in your `.gitignore` file
|
||||
(It's there that Task stores the last checksum).
|
||||
|
||||
If you prefer this check to be made by the modification timestamp of the files,
|
||||
instead of its checksum (content), just set the `method` property to `timestamp`.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
@@ -341,13 +346,17 @@ tasks:
|
||||
|
||||
> TIP: method `none` skips any validation and always run the task.
|
||||
|
||||
> NOTE: for the `checksum` (default) method to work, it's only necessary to
|
||||
> inform the source files, but if you want to use the `timestamp` method, you
|
||||
> also need to inform the generated files with `generates`.
|
||||
|
||||
### Using programmatic checks to indicate a task is up to date.
|
||||
|
||||
Alternatively, you can inform a sequence of tests as `status`. If no error
|
||||
is returned (exit status 0), the task is considered up-to-date:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
generate-files:
|
||||
@@ -392,7 +401,7 @@ conditions to be _true_ you can use the `preconditions` stanza.
|
||||
expansion and they SHOULD all return 0.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
generate-files:
|
||||
@@ -420,19 +429,20 @@ executing tasks that depend on it, a `precondition` will fail a task, along
|
||||
with any other tasks that depend on it.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
task_will_fail:
|
||||
task-will-fail:
|
||||
preconditions:
|
||||
- sh: "exit 1"
|
||||
|
||||
task_will_also_fail:
|
||||
task-will-also-fail:
|
||||
deps:
|
||||
- task_will_fail
|
||||
- task-will-fail
|
||||
|
||||
task_will_still_fail:
|
||||
task-will-still-fail:
|
||||
cmds:
|
||||
- task: task_will_fail
|
||||
- task: task-will-fail
|
||||
- echo "I will not run"
|
||||
```
|
||||
|
||||
@@ -442,10 +452,9 @@ When doing interpolation of variables, Task will look for the below.
|
||||
They are listed below in order of importance (e.g. most important first):
|
||||
|
||||
- Variables declared in the task definition
|
||||
- Variables given while calling a task from another.
|
||||
- Variables given while calling a task from another
|
||||
(See [Calling another task](#calling-another-task) above)
|
||||
- Variables declared in the `vars:` option in the `Taskfile`
|
||||
- Variables available in the `Taskvars.yml` file
|
||||
- Global variables (those declared in the `vars:` option in the Taskfile)
|
||||
- Environment variables
|
||||
|
||||
Example of sending parameters with environment variables:
|
||||
@@ -454,27 +463,20 @@ Example of sending parameters with environment variables:
|
||||
$ TASK_VARIABLE=a-value task do-something
|
||||
```
|
||||
|
||||
> TIP: A special variable `.TASK` is always available containg the task name.
|
||||
> TIP: A special variable `.TASK` is always available containing the task name.
|
||||
|
||||
Since some shells don't support above syntax to set environment variables
|
||||
(Windows) tasks also accepts a similar style when not in the beginning of
|
||||
the command. Variables given in this form are only visible to the task called
|
||||
right before.
|
||||
the command.
|
||||
|
||||
```bash
|
||||
$ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!"
|
||||
```
|
||||
|
||||
If you want to set global variables using this syntax, give it before any task:
|
||||
|
||||
```bash
|
||||
$ task OUTPUT=file.txt generate-file
|
||||
```
|
||||
|
||||
Example of locally declared vars:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print-var:
|
||||
@@ -487,7 +489,7 @@ tasks:
|
||||
Example of global vars in a `Taskfile.yml`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
GREETING: Hello from Taskfile!
|
||||
@@ -498,38 +500,6 @@ tasks:
|
||||
- echo "{{.GREETING}}"
|
||||
```
|
||||
|
||||
Example of `Taskvars.yml` file:
|
||||
|
||||
```yaml
|
||||
PROJECT_NAME: My Project
|
||||
DEV_MODE: production
|
||||
GIT_COMMIT: {sh: git log -n 1 --format=%h}
|
||||
```
|
||||
|
||||
### Variables expansion
|
||||
|
||||
Variables are expanded 2 times by default. You can change that by setting the
|
||||
`expansions:` option. Change that will be necessary if you compose many
|
||||
variables together:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
expansions: 3
|
||||
|
||||
vars:
|
||||
FOO: foo
|
||||
BAR: bar
|
||||
BAZ: baz
|
||||
FOOBAR: "{{.FOO}}{{.BAR}}"
|
||||
FOOBARBAZ: "{{.FOOBAR}}{{.BAZ}}"
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "{{.FOOBARBAZ}}"
|
||||
```
|
||||
|
||||
### Dynamic variables
|
||||
|
||||
The below syntax (`sh:` prop in a variable) is considered a dynamic variable.
|
||||
@@ -537,7 +507,7 @@ The value will be treated as a command and the output assigned. If there is one
|
||||
or more trailing newlines, the last newline will be trimmed.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
@@ -559,7 +529,7 @@ All functions by the Go's [slim-sprig lib](https://go-task.github.io/slim-sprig/
|
||||
are available. The following example gets the current date in a given format:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print-date:
|
||||
@@ -585,7 +555,7 @@ Task also adds the following functions:
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print-os:
|
||||
@@ -613,7 +583,7 @@ Running `task --list` (or `task -l`) lists all tasks with a description.
|
||||
The following Taskfile:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
@@ -644,11 +614,11 @@ would print the following output:
|
||||
|
||||
## Display summary of task
|
||||
|
||||
Running `task --summary task-name` will show a summary of a task
|
||||
Running `task --summary task-name` will show a summary of a task.
|
||||
The following Taskfile:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
release:
|
||||
@@ -656,7 +626,7 @@ tasks:
|
||||
summary: |
|
||||
Release your project to github
|
||||
|
||||
It will build your project before starting the release it.
|
||||
It will build your project before starting the release.
|
||||
Please make sure that you have set GITHUB_TOKEN before starting.
|
||||
cmds:
|
||||
- your-release-tool
|
||||
@@ -673,7 +643,7 @@ task: release
|
||||
|
||||
Release your project to github
|
||||
|
||||
It will build your project before starting the release it.
|
||||
It will build your project before starting the release.
|
||||
Please make sure that you have set GITHUB_TOKEN before starting.
|
||||
|
||||
dependencies:
|
||||
@@ -687,13 +657,37 @@ If the task does not have a summary or a description, a warning is printed.
|
||||
|
||||
Please note: *showing the summary will not execute the command*.
|
||||
|
||||
## Overriding task name
|
||||
|
||||
Sometimes you may want to override the task name print on summary, up-to-date
|
||||
messages to STDOUT, etc. In this case you can just set `label:`, which can also
|
||||
be interpolated with variables:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
- task: print
|
||||
vars:
|
||||
MESSAGE: hello
|
||||
- task: print
|
||||
vars:
|
||||
MESSAGE: world
|
||||
|
||||
print:
|
||||
label: 'print-{{.MESSAGE}}'
|
||||
cmds:
|
||||
- echo "{{.MESSAGE}}"
|
||||
```
|
||||
|
||||
## Silent mode
|
||||
|
||||
Silent mode disables echoing of commands before Task runs it.
|
||||
For the following Taskfile:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
@@ -719,7 +713,7 @@ There are four ways to enable silent mode:
|
||||
* At command level:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
@@ -731,7 +725,7 @@ tasks:
|
||||
* At task level:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
@@ -743,7 +737,7 @@ tasks:
|
||||
* Globally at Taskfile level:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
silent: true
|
||||
|
||||
@@ -758,7 +752,7 @@ tasks:
|
||||
If you want to suppress STDOUT instead, just redirect a command to `/dev/null`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
@@ -777,7 +771,7 @@ You have the option to ignore errors during command execution.
|
||||
Given the following Taskfile:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
@@ -790,7 +784,7 @@ Task will abort the execution after running `exit 1` because the status code `1`
|
||||
However it is possible to continue with execution using `ignore_error`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
@@ -821,7 +815,7 @@ options you can choose:
|
||||
To choose another one, just set it to root in the Taskfile:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
output: 'group'
|
||||
|
||||
@@ -838,7 +832,7 @@ tasks:
|
||||
with the `prefix:` attribute:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
output: prefixed
|
||||
|
||||
@@ -871,7 +865,7 @@ $ task default
|
||||
## Short task syntax
|
||||
|
||||
Starting on Task v3, you can now write tasks with a shorter syntax if they
|
||||
have the default settings (e.g. no custom `env:`, `vars:`, `silent:` , etc):
|
||||
have the default settings (e.g. no custom `env:`, `vars:`, `desc:`, `silent:` , etc):
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
@@ -879,16 +873,16 @@ version: '3'
|
||||
tasks:
|
||||
build: go build -v -o ./app{{exeExt}} .
|
||||
|
||||
build:
|
||||
run:
|
||||
- task: build
|
||||
- ./app{{exeExt}} -h localhost -p 8080
|
||||
```
|
||||
|
||||
## Watch tasks
|
||||
|
||||
If you give a `--watch` or `-w` argument, task will watch for file changes
|
||||
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,
|
||||
so task know which files to watch.
|
||||
so task knows which files to watch.
|
||||
|
||||
[gotemplate]: https://golang.org/pkg/text/template/
|
||||
[minify]: https://github.com/tdewolff/minify/tree/master/cmd/minify
|
||||
|
||||
13
go.mod
13
go.mod
@@ -1,16 +1,17 @@
|
||||
module github.com/go-task/task/v2
|
||||
module github.com/go-task/task/v3
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/go-task/slim-sprig v0.0.0-20191103011349-ba7d6a531428
|
||||
github.com/go-task/slim-sprig v0.0.0-20200516131648-f9bac4e523eb
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-zglob v0.0.1
|
||||
github.com/radovskyb/watcher v1.0.5
|
||||
github.com/spf13/pflag v1.0.3
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
mvdan.cc/sh/v3 v3.0.2
|
||||
github.com/stretchr/testify v1.5.1
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
mvdan.cc/sh/v3 v3.2.1
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
||||
51
go.sum
51
go.sum
@@ -1,12 +1,22 @@
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20191103011349-ba7d6a531428 h1:62JQa/NJVTX0I2G7GlVBbDl/8f6kmUQCoVf8R3fHvqE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20191103011349-ba7d6a531428/go.mod h1:BU9jUCGL9r2yojTEkwli1J2X4GmnOJPAsUXFtPud7Mg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20200516131648-f9bac4e523eb h1:/qbv1F67s6ehqX9mG23cJOeca3FWpOVKgtPfPUMAi0k=
|
||||
github.com/go-task/slim-sprig v0.0.0-20200516131648-f9bac4e523eb/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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
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/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=
|
||||
@@ -16,42 +26,37 @@ github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-zglob v0.0.1 h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY=
|
||||
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
||||
github.com/pkg/diff v0.0.0-20190930165518-531926345625/go.mod h1:kFj35MyHn14a6pIgWhm46KVjJr5CHys3eEYxkuKD1EI=
|
||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
|
||||
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.5 h1:wqt7gb+HjGacvFoLTKeT44C+XVPxu7bvHvKT1IvZ7rw=
|
||||
github.com/radovskyb/watcher v1.0.5/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
|
||||
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
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/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
mvdan.cc/editorconfig v0.1.1-0.20191109213504-890940e3f00e/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
|
||||
mvdan.cc/sh/v3 v3.0.2 h1:NU+UpTZHRdIZ9igRo8zi/7+5/NpetYlhlyDhz1/AdMM=
|
||||
mvdan.cc/sh/v3 v3.0.2/go.mod h1:rBIndNJFYPp8xSppiZcGIk6B5d1g3OEARxEaXjPxwVI=
|
||||
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.1 h1:uQBpiGM+rEuHse3Q+W7ajuJUeOtFVJUN/6GeX4/dUWE=
|
||||
mvdan.cc/sh/v3 v3.2.1/go.mod h1:fPQmabBpREM/XQ9YXSU5ZFZ/Sm+PmKP9/vkFHgYKJEI=
|
||||
|
||||
6
help.go
6
help.go
@@ -5,8 +5,8 @@ import (
|
||||
"sort"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
// PrintTasksHelp prints help os tasks that have a description
|
||||
@@ -21,7 +21,7 @@ func (e *Executor) PrintTasksHelp() {
|
||||
// Format in tab-separated columns with a tab stop of 8.
|
||||
w := tabwriter.NewWriter(e.Stdout, 0, 8, 0, '\t', 0)
|
||||
for _, task := range tasks {
|
||||
fmt.Fprintf(w, "* %s: \t%s\n", task.Task, task.Desc)
|
||||
fmt.Fprintf(w, "* %s: \t%s\n", task.Name(), task.Desc)
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package args
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
)
|
||||
|
||||
// Parse parses command line argument: tasks and vars of each task
|
||||
func Parse(args ...string) ([]taskfile.Call, taskfile.Vars) {
|
||||
var calls []taskfile.Call
|
||||
var globals taskfile.Vars
|
||||
|
||||
for _, arg := range args {
|
||||
if !strings.Contains(arg, "=") {
|
||||
calls = append(calls, taskfile.Call{Task: arg})
|
||||
continue
|
||||
}
|
||||
|
||||
if len(calls) < 1 {
|
||||
if globals == nil {
|
||||
globals = taskfile.Vars{}
|
||||
}
|
||||
|
||||
name, value := splitVar(arg)
|
||||
globals[name] = taskfile.Var{Static: value}
|
||||
} else {
|
||||
if calls[len(calls)-1].Vars == nil {
|
||||
calls[len(calls)-1].Vars = make(taskfile.Vars)
|
||||
}
|
||||
|
||||
name, value := splitVar((arg))
|
||||
calls[len(calls)-1].Vars[name] = taskfile.Var{Static: value}
|
||||
}
|
||||
}
|
||||
|
||||
if len(calls) == 0 {
|
||||
calls = append(calls, taskfile.Call{Task: "default"})
|
||||
}
|
||||
|
||||
return calls, globals
|
||||
}
|
||||
|
||||
func splitVar(s string) (string, string) {
|
||||
pair := strings.SplitN(s, "=", 2)
|
||||
return pair[0], pair[1]
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package args_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2/internal/args"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestArgs(t *testing.T) {
|
||||
tests := []struct {
|
||||
Args []string
|
||||
ExpectedCalls []taskfile.Call
|
||||
ExpectedGlobals taskfile.Vars
|
||||
}{
|
||||
{
|
||||
Args: []string{"task-a", "task-b", "task-c"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
{Task: "task-c"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"task-a", "FOO=bar", "task-b", "task-c", "BAR=baz", "BAZ=foo"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{
|
||||
Task: "task-a",
|
||||
Vars: taskfile.Vars{
|
||||
"FOO": taskfile.Var{Static: "bar"},
|
||||
},
|
||||
},
|
||||
{Task: "task-b"},
|
||||
{
|
||||
Task: "task-c",
|
||||
Vars: taskfile.Vars{
|
||||
"BAR": taskfile.Var{Static: "baz"},
|
||||
"BAZ": taskfile.Var{Static: "foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"task-a", "CONTENT=with some spaces"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{
|
||||
Task: "task-a",
|
||||
Vars: taskfile.Vars{
|
||||
"CONTENT": taskfile.Var{Static: "with some spaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"FOO=bar", "task-a", "task-b"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "task-a"},
|
||||
{Task: "task-b"},
|
||||
},
|
||||
ExpectedGlobals: taskfile.Vars{
|
||||
"FOO": {Static: "bar"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: nil,
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: []string{"FOO=bar", "BAR=baz"},
|
||||
ExpectedCalls: []taskfile.Call{
|
||||
{Task: "default"},
|
||||
},
|
||||
ExpectedGlobals: taskfile.Vars{
|
||||
"FOO": {Static: "bar"},
|
||||
"BAR": {Static: "baz"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("TestArgs%d", i+1), func(t *testing.T) {
|
||||
calls, globals := args.Parse(test.Args...)
|
||||
assert.Equal(t, test.ExpectedCalls, calls)
|
||||
assert.Equal(t, test.ExpectedGlobals, globals)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
// Compiler handles compilation of a task before its execution.
|
||||
// E.g. variable merger, template processing, etc.
|
||||
type Compiler interface {
|
||||
GetVariables(t *taskfile.Task, call taskfile.Call) (taskfile.Vars, error)
|
||||
GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error)
|
||||
HandleDynamicVar(v taskfile.Var) (string, error)
|
||||
}
|
||||
|
||||
@@ -4,21 +4,17 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
// GetEnviron the all return all environment variables encapsulated on a
|
||||
// taskfile.Vars
|
||||
func GetEnviron() taskfile.Vars {
|
||||
var (
|
||||
env = os.Environ()
|
||||
m = make(taskfile.Vars, len(env))
|
||||
)
|
||||
|
||||
for _, e := range env {
|
||||
func GetEnviron() *taskfile.Vars {
|
||||
m := &taskfile.Vars{}
|
||||
for _, e := range os.Environ() {
|
||||
keyVal := strings.SplitN(e, "=", 2)
|
||||
key, val := keyVal[0], keyVal[1]
|
||||
m[key] = taskfile.Var{Static: val}
|
||||
m.Set(key, taskfile.Var{Static: val})
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-task/task/v2/internal/compiler"
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v2/internal/templater"
|
||||
"github.com/go-task/task/v3/internal/compiler"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
var _ compiler.Compiler = &CompilerV2{}
|
||||
@@ -19,8 +19,8 @@ var _ compiler.Compiler = &CompilerV2{}
|
||||
type CompilerV2 struct {
|
||||
Dir string
|
||||
|
||||
Taskvars taskfile.Vars
|
||||
TaskfileVars taskfile.Vars
|
||||
Taskvars *taskfile.Vars
|
||||
TaskfileVars *taskfile.Vars
|
||||
|
||||
Expansions int
|
||||
|
||||
@@ -36,10 +36,10 @@ type CompilerV2 struct {
|
||||
// 3. Taskfile variables
|
||||
// 4. Taskvars file variables
|
||||
// 5. Environment variables
|
||||
func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (taskfile.Vars, error) {
|
||||
func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
||||
vr := varResolver{c: c, vars: compiler.GetEnviron()}
|
||||
vr.vars["TASK"] = taskfile.Var{Static: t.Task}
|
||||
for _, vars := range []taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} {
|
||||
vr.vars.Set("TASK", taskfile.Var{Static: t.Task})
|
||||
for _, vars := range []*taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} {
|
||||
for i := 0; i < c.Expansions; i++ {
|
||||
vr.merge(vars)
|
||||
}
|
||||
@@ -49,16 +49,16 @@ func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (taskfil
|
||||
|
||||
type varResolver struct {
|
||||
c *CompilerV2
|
||||
vars taskfile.Vars
|
||||
vars *taskfile.Vars
|
||||
err error
|
||||
}
|
||||
|
||||
func (vr *varResolver) merge(vars taskfile.Vars) {
|
||||
func (vr *varResolver) merge(vars *taskfile.Vars) {
|
||||
if vr.err != nil {
|
||||
return
|
||||
}
|
||||
tr := templater.Templater{Vars: vr.vars}
|
||||
for k, v := range vars {
|
||||
vars.Range(func(k string, v taskfile.Var) error {
|
||||
v = taskfile.Var{
|
||||
Static: tr.Replace(v.Static),
|
||||
Sh: tr.Replace(v.Sh),
|
||||
@@ -66,10 +66,11 @@ func (vr *varResolver) merge(vars taskfile.Vars) {
|
||||
static, err := vr.c.HandleDynamicVar(v)
|
||||
if err != nil {
|
||||
vr.err = err
|
||||
return
|
||||
return err
|
||||
}
|
||||
vr.vars[k] = taskfile.Var{Static: static}
|
||||
}
|
||||
vr.vars.Set(k, taskfile.Var{Static: static})
|
||||
return nil
|
||||
})
|
||||
vr.err = tr.Err()
|
||||
}
|
||||
|
||||
|
||||
98
internal/compiler/v3/compiler_v3.go
Normal file
98
internal/compiler/v3/compiler_v3.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-task/task/v3/internal/compiler"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
var _ compiler.Compiler = &CompilerV3{}
|
||||
|
||||
type CompilerV3 struct {
|
||||
Dir string
|
||||
|
||||
TaskfileVars *taskfile.Vars
|
||||
|
||||
Logger *logger.Logger
|
||||
|
||||
dynamicCache map[string]string
|
||||
muDynamicCache sync.Mutex
|
||||
}
|
||||
|
||||
func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
|
||||
result := compiler.GetEnviron()
|
||||
result.Set("TASK", taskfile.Var{Static: t.Task})
|
||||
|
||||
rangeFunc := func(k string, v taskfile.Var) error {
|
||||
tr := templater.Templater{Vars: result, RemoveNoValue: true}
|
||||
v = taskfile.Var{
|
||||
Static: tr.Replace(v.Static),
|
||||
Sh: tr.Replace(v.Sh),
|
||||
}
|
||||
if err := tr.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
static, err := c.HandleDynamicVar(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result.Set(k, taskfile.Var{Static: static})
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.TaskfileVars.Range(rangeFunc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := call.Vars.Range(rangeFunc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.Vars.Range(rangeFunc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) {
|
||||
if v.Static != "" || v.Sh == "" {
|
||||
return v.Static, nil
|
||||
}
|
||||
|
||||
c.muDynamicCache.Lock()
|
||||
defer c.muDynamicCache.Unlock()
|
||||
|
||||
if c.dynamicCache == nil {
|
||||
c.dynamicCache = make(map[string]string, 30)
|
||||
}
|
||||
if result, ok := c.dynamicCache[v.Sh]; ok {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var stdout bytes.Buffer
|
||||
opts := &execext.RunCommandOptions{
|
||||
Command: v.Sh,
|
||||
Dir: c.Dir,
|
||||
Stdout: &stdout,
|
||||
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)
|
||||
}
|
||||
|
||||
// Trim a single trailing newline from the result to make most command
|
||||
// output easier to use in shell commands.
|
||||
result := strings.TrimSuffix(stdout.String(), "\n")
|
||||
|
||||
c.dynamicCache[v.Sh] = result
|
||||
c.Logger.VerboseErrf(logger.Magenta, `task: dynamic variable: '%s' result: '%s'`, v.Sh, result)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -46,16 +46,10 @@ func RunCommand(ctx context.Context, opts *RunCommandOptions) error {
|
||||
}
|
||||
|
||||
r, err := interp.New(
|
||||
interp.Params("-e"),
|
||||
interp.Dir(opts.Dir),
|
||||
interp.Env(expand.ListEnviron(environ...)),
|
||||
|
||||
interp.OpenHandler(func(ctx context.Context, path string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
|
||||
if path == "/dev/null" {
|
||||
return devNull{}, nil
|
||||
}
|
||||
return interp.DefaultOpenHandler()(ctx, path, flag, perm)
|
||||
}),
|
||||
|
||||
interp.OpenHandler(openHandler),
|
||||
interp.StdIO(opts.Stdin, opts.Stdout, opts.Stderr),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -86,3 +80,10 @@ func Expand(s string) (string, error) {
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func openHandler(ctx context.Context, path string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
|
||||
if path == "/dev/null" {
|
||||
return devNull{}, nil
|
||||
}
|
||||
return interp.DefaultOpenHandler()(ctx, path, flag, perm)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2/internal/output"
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -95,6 +95,9 @@ func (c *Checksum) Value() (interface{}, error) {
|
||||
|
||||
// OnError implements the Checker interface
|
||||
func (c *Checksum) OnError() error {
|
||||
if len(c.Sources) == 0 {
|
||||
return nil
|
||||
}
|
||||
return os.Remove(c.checksumFilePath())
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
|
||||
"github.com/mattn/go-zglob"
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ package summary
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
func PrintTasks(l *logger.Logger, t *taskfile.Taskfile, c []taskfile.Call) {
|
||||
@@ -56,7 +56,7 @@ func printTaskSummary(l *logger.Logger, t *taskfile.Task) {
|
||||
}
|
||||
|
||||
func printTaskName(l *logger.Logger, t *taskfile.Task) {
|
||||
l.Outf(logger.Default, "task: %s", t.Task)
|
||||
l.Outf(logger.Default, "task: %s", t.Name())
|
||||
l.Outf(logger.Default, "")
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/summary"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/summary"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package taskfile
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrCantUnmarshalIncludedTaskfile is returned for invalid var YAML.
|
||||
ErrCantUnmarshalIncludedTaskfile = errors.New("task: can't unmarshal included value")
|
||||
)
|
||||
|
||||
// IncludedTaskfile represents information about included tasksfile
|
||||
type IncludedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
AdvancedImport bool
|
||||
}
|
||||
|
||||
// IncludedTaskfiles represents information about included tasksfiles
|
||||
type IncludedTaskfiles = map[string]IncludedTaskfile
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var str string
|
||||
if err := unmarshal(&str); err == nil {
|
||||
it.Taskfile = str
|
||||
return nil
|
||||
}
|
||||
|
||||
var includedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
}
|
||||
if err := unmarshal(&includedTaskfile); err == nil {
|
||||
it.Dir = includedTaskfile.Dir
|
||||
it.Taskfile = includedTaskfile.Taskfile
|
||||
it.AdvancedImport = true
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrCantUnmarshalIncludedTaskfile
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package read
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrIncludedTaskfilesCantHaveIncludes is returned when a included Taskfile contains includes
|
||||
ErrIncludedTaskfilesCantHaveIncludes = errors.New("task: Included Taskfiles can't have includes. Please, move the include to the main Taskfile")
|
||||
)
|
||||
|
||||
// Taskfile reads a Taskfile for a given directory
|
||||
func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
|
||||
path := filepath.Join(dir, entrypoint)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return nil, fmt.Errorf(`task: No Taskfile found on "%s". Use "task --init" to create a new one`, path)
|
||||
}
|
||||
t, err := readTaskfile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for namespace, includedTask := range t.Includes {
|
||||
if filepath.IsAbs(includedTask.Taskfile) {
|
||||
path = includedTask.Taskfile
|
||||
} else {
|
||||
path = filepath.Join(dir, includedTask.Taskfile)
|
||||
}
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info.IsDir() {
|
||||
path = filepath.Join(path, "Taskfile.yml")
|
||||
}
|
||||
includedTaskfile, err := readTaskfile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(includedTaskfile.Includes) > 0 {
|
||||
return nil, ErrIncludedTaskfilesCantHaveIncludes
|
||||
}
|
||||
|
||||
if includedTask.AdvancedImport {
|
||||
for _, task := range includedTaskfile.Tasks {
|
||||
if !filepath.IsAbs(task.Dir) {
|
||||
task.Dir = filepath.Join(includedTask.Dir, task.Dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = taskfile.Merge(t, includedTaskfile, namespace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
path = filepath.Join(dir, fmt.Sprintf("Taskfile_%s.yml", runtime.GOOS))
|
||||
if _, err = os.Stat(path); err == nil {
|
||||
osTaskfile, err := readTaskfile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = taskfile.Merge(t, osTaskfile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for name, task := range t.Tasks {
|
||||
task.Task = name
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func readTaskfile(file string) (*taskfile.Taskfile, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var t taskfile.Taskfile
|
||||
return &t, yaml.NewDecoder(f).Decode(&t)
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrCantUnmarshalVar is returned for invalid var YAML.
|
||||
ErrCantUnmarshalVar = errors.New("task: can't unmarshal var value")
|
||||
)
|
||||
|
||||
// Vars is a string[string] variables map.
|
||||
type Vars map[string]Var
|
||||
|
||||
// ToCacheMap converts Vars to a map containing only the static
|
||||
// variables
|
||||
func (vs Vars) ToCacheMap() (m map[string]interface{}) {
|
||||
m = make(map[string]interface{}, len(vs))
|
||||
for k, v := range vs {
|
||||
if v.Sh != "" {
|
||||
// Dynamic variable is not yet resolved; trigger
|
||||
// <no value> to be used in templates.
|
||||
continue
|
||||
}
|
||||
|
||||
if v.Live != nil {
|
||||
m[k] = v.Live
|
||||
} else {
|
||||
m[k] = v.Static
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Var represents either a static or dynamic variable.
|
||||
type Var struct {
|
||||
Static string
|
||||
Live interface{}
|
||||
Sh string
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface.
|
||||
func (v *Var) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var str string
|
||||
if err := unmarshal(&str); err == nil {
|
||||
if strings.HasPrefix(str, "$") {
|
||||
v.Sh = strings.TrimPrefix(str, "$")
|
||||
} else {
|
||||
v.Static = str
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var sh struct {
|
||||
Sh string
|
||||
}
|
||||
if err := unmarshal(&sh); err == nil {
|
||||
v.Sh = sh.Sh
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrCantUnmarshalVar
|
||||
}
|
||||
@@ -2,9 +2,10 @@ package templater
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
// Templater is a help struct that allow us to call "replaceX" funcs multiple
|
||||
@@ -12,7 +13,8 @@ import (
|
||||
// happen will be assigned to r.err, and consecutive calls to funcs will just
|
||||
// return the zero value.
|
||||
type Templater struct {
|
||||
Vars taskfile.Vars
|
||||
Vars *taskfile.Vars
|
||||
RemoveNoValue bool
|
||||
|
||||
cacheMap map[string]interface{}
|
||||
err error
|
||||
@@ -42,6 +44,9 @@ func (r *Templater) Replace(str string) string {
|
||||
r.err = err
|
||||
return ""
|
||||
}
|
||||
if r.RemoveNoValue {
|
||||
return strings.ReplaceAll(b.String(), "<no value>", "")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -57,20 +62,22 @@ func (r *Templater) ReplaceSlice(strs []string) []string {
|
||||
return new
|
||||
}
|
||||
|
||||
func (r *Templater) ReplaceVars(vars taskfile.Vars) taskfile.Vars {
|
||||
if r.err != nil || len(vars) == 0 {
|
||||
func (r *Templater) ReplaceVars(vars *taskfile.Vars) *taskfile.Vars {
|
||||
if r.err != nil || vars == nil || len(vars.Keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
new := make(taskfile.Vars, len(vars))
|
||||
for k, v := range vars {
|
||||
new[k] = taskfile.Var{
|
||||
var new taskfile.Vars
|
||||
vars.Range(func(k string, v taskfile.Var) error {
|
||||
new.Set(k, taskfile.Var{
|
||||
Static: r.Replace(v.Static),
|
||||
Live: v.Live,
|
||||
Sh: r.Replace(v.Sh),
|
||||
}
|
||||
}
|
||||
return new
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
return &new
|
||||
}
|
||||
|
||||
func (r *Templater) Err() error {
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
12
status.go
12
status.go
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/status"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/status"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
// Status returns an error if any the of given tasks is not up-to-date
|
||||
@@ -22,7 +22,7 @@ func (e *Executor) Status(ctx context.Context, calls ...taskfile.Call) error {
|
||||
return err
|
||||
}
|
||||
if !isUpToDate {
|
||||
return fmt.Errorf(`task: Task "%s" is not up-to-date`, t.Task)
|
||||
return fmt.Errorf(`task: Task "%s" is not up-to-date`, t.Name())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -77,7 +77,7 @@ func (e *Executor) timestampChecker(t *taskfile.Task) status.Checker {
|
||||
func (e *Executor) checksumChecker(t *taskfile.Task) status.Checker {
|
||||
return &status.Checksum{
|
||||
Dir: t.Dir,
|
||||
Task: t.Task,
|
||||
Task: t.Name(),
|
||||
Sources: t.Sources,
|
||||
Generates: t.Generates,
|
||||
Dry: e.Dry,
|
||||
|
||||
68
task.go
68
task.go
@@ -6,18 +6,18 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/go-task/task/v2/internal/compiler"
|
||||
compilerv2 "github.com/go-task/task/v2/internal/compiler/v2"
|
||||
"github.com/go-task/task/v2/internal/execext"
|
||||
"github.com/go-task/task/v2/internal/logger"
|
||||
"github.com/go-task/task/v2/internal/output"
|
||||
"github.com/go-task/task/v2/internal/summary"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v2/internal/taskfile/read"
|
||||
"github.com/go-task/task/v3/internal/compiler"
|
||||
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
|
||||
compilerv3 "github.com/go-task/task/v3/internal/compiler/v3"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
"github.com/go-task/task/v3/internal/summary"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/read"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -52,7 +52,7 @@ type Executor struct {
|
||||
Output output.Output
|
||||
OutputStyle string
|
||||
|
||||
taskvars taskfile.Vars
|
||||
taskvars *taskfile.Vars
|
||||
|
||||
taskCallCount map[string]*int32
|
||||
mkdirMutexMap map[string]*sync.Mutex
|
||||
@@ -110,11 +110,19 @@ func (e *Executor) Setup() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.taskvars, err = read.Taskvars(e.Dir)
|
||||
|
||||
v, err := e.Taskfile.ParsedVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v < 3.0 {
|
||||
e.taskvars, err = read.Taskvars(e.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if e.Stdin == nil {
|
||||
e.Stdin = os.Stdin
|
||||
}
|
||||
@@ -131,11 +139,6 @@ func (e *Executor) Setup() error {
|
||||
Color: e.Color,
|
||||
}
|
||||
|
||||
v, err := strconv.ParseFloat(e.Taskfile.Version, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf(`task: Could not parse taskfile version "%s": %v`, e.Taskfile.Version, err)
|
||||
}
|
||||
|
||||
if v < 2 {
|
||||
return fmt.Errorf(`task: Taskfile versions prior to v2 are not supported anymore`)
|
||||
}
|
||||
@@ -154,20 +157,31 @@ func (e *Executor) Setup() error {
|
||||
e.Logger.Color = false
|
||||
}
|
||||
|
||||
e.Compiler = &compilerv2.CompilerV2{
|
||||
Dir: e.Dir,
|
||||
Taskvars: e.taskvars,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Expansions: e.Taskfile.Expansions,
|
||||
Logger: e.Logger,
|
||||
if v < 3 {
|
||||
e.Compiler = &compilerv2.CompilerV2{
|
||||
Dir: e.Dir,
|
||||
Taskvars: e.taskvars,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Expansions: e.Taskfile.Expansions,
|
||||
Logger: e.Logger,
|
||||
}
|
||||
} else {
|
||||
e.Compiler = &compilerv3.CompilerV3{
|
||||
Dir: e.Dir,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Logger: e.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
if v < 2.1 && e.Taskfile.Output != "" {
|
||||
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
|
||||
}
|
||||
if v < 2.2 && len(e.Taskfile.Includes) > 0 {
|
||||
if v < 2.2 && e.Taskfile.Includes.Len() > 0 {
|
||||
return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`)
|
||||
}
|
||||
if v >= 3.0 && e.Taskfile.Expansions > 2 {
|
||||
return fmt.Errorf(`task: The "expansions" setting is not available anymore on v3.0`)
|
||||
}
|
||||
|
||||
if e.OutputStyle != "" {
|
||||
e.Taskfile.Output = e.OutputStyle
|
||||
@@ -215,10 +229,14 @@ func (e *Executor) Setup() error {
|
||||
}
|
||||
|
||||
if v < 3 {
|
||||
for _, taskfile := range e.Taskfile.Includes {
|
||||
err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error {
|
||||
if taskfile.AdvancedImport {
|
||||
return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +276,7 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
|
||||
|
||||
if upToDate && preCondMet {
|
||||
if !e.Silent {
|
||||
e.Logger.Errf(logger.Magenta, `task: Task "%s" is up to date`, t.Task)
|
||||
e.Logger.Errf(logger.Magenta, `task: Task "%s" is up to date`, t.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
171
task_test.go
171
task_test.go
@@ -11,8 +11,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2"
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -56,6 +56,16 @@ func (fct fileContentTest) Run(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyTask(t *testing.T) {
|
||||
e := &task.Executor{
|
||||
Dir: "testdata/empty_task",
|
||||
Stdout: ioutil.Discard,
|
||||
Stderr: ioutil.Discard,
|
||||
}
|
||||
assert.NoError(t, e.Setup(), "e.Setup()")
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/env",
|
||||
@@ -107,6 +117,20 @@ func TestVarsV2(t *testing.T) {
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestVarsV3(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/vars/v3",
|
||||
Target: "default",
|
||||
Files: map[string]string{
|
||||
"missing-var.txt": "\n",
|
||||
"var-order.txt": "ABCDEF\n",
|
||||
"dependent-sh.txt": "123456\n",
|
||||
"with-call.txt": "Hi, ABC123!\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestMultilineVars(t *testing.T) {
|
||||
for _, dir := range []string{"testdata/vars/v2/multiline"} {
|
||||
tt := fileContentTest{
|
||||
@@ -370,6 +394,90 @@ func TestStatusChecksum(t *testing.T) {
|
||||
assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String())
|
||||
}
|
||||
|
||||
func TestLabelUpToDate(t *testing.T) {
|
||||
const dir = "testdata/label_uptodate"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
|
||||
assert.Contains(t, buff.String(), "foobar")
|
||||
}
|
||||
|
||||
func TestLabelSummary(t *testing.T) {
|
||||
const dir = "testdata/label_summary"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Summary: true,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
|
||||
assert.Contains(t, buff.String(), "foobar")
|
||||
}
|
||||
|
||||
func TestLabelInStatus(t *testing.T) {
|
||||
const dir = "testdata/label_status"
|
||||
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
err := e.Status(context.Background(), taskfile.Call{Task: "foo"})
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "foobar")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelWithVariableExpansion(t *testing.T) {
|
||||
const dir = "testdata/label_var"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
|
||||
assert.Contains(t, buff.String(), "foobaz")
|
||||
}
|
||||
|
||||
func TestLabelInSummary(t *testing.T) {
|
||||
const dir = "testdata/label_summary"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "foo"}))
|
||||
assert.Contains(t, buff.String(), "foobar")
|
||||
}
|
||||
|
||||
func TestLabelInList(t *testing.T) {
|
||||
const dir = "testdata/label_list"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
e.PrintTasksHelp()
|
||||
assert.Contains(t, buff.String(), "foobar")
|
||||
}
|
||||
|
||||
func TestStatusVariables(t *testing.T) {
|
||||
const dir = "testdata/status_vars"
|
||||
|
||||
@@ -546,6 +654,7 @@ func TestIncludes(t *testing.T) {
|
||||
"included_taskfile_without_dir.txt": "included_taskfile_without_dir",
|
||||
"./module2/included_directory_with_dir.txt": "included_directory_with_dir",
|
||||
"./module2/included_taskfile_with_dir.txt": "included_taskfile_with_dir",
|
||||
"os_include.txt": "os",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
@@ -717,3 +826,61 @@ func TestShortTaskNotation(t *testing.T) {
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
||||
assert.Equal(t, "string-slice-1\nstring-slice-2\nstring\n", buff.String())
|
||||
}
|
||||
|
||||
func TestDotenvShouldIncludeAllEnvFiles(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/dotenv/default",
|
||||
Target: "default",
|
||||
TrimSpace: false,
|
||||
Files: map[string]string{
|
||||
"include.txt": "INCLUDE1='from_include1' INCLUDE2='from_include2'\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestDotenvShouldErrorWhenIncludingDependantDotenvs(t *testing.T) {
|
||||
const dir = "testdata/dotenv/error_included_envs"
|
||||
const entry = "Taskfile.yml"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Entrypoint: entry,
|
||||
Summary: true,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
|
||||
err := e.Setup()
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "move the dotenv")
|
||||
}
|
||||
|
||||
func TestDotenvShouldAllowMissingEnv(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/dotenv/missing_env",
|
||||
Target: "default",
|
||||
TrimSpace: false,
|
||||
Files: map[string]string{
|
||||
"include.txt": "INCLUDE1='' INCLUDE2=''\n",
|
||||
},
|
||||
}
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestExitImmediately(t *testing.T) {
|
||||
const dir = "testdata/exit_immediately"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
|
||||
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`)
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ package taskfile
|
||||
// Call is the parameters to a task call
|
||||
type Call struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
Vars *Vars
|
||||
}
|
||||
@@ -10,14 +10,14 @@ type Cmd struct {
|
||||
Cmd string
|
||||
Silent bool
|
||||
Task string
|
||||
Vars Vars
|
||||
Vars *Vars
|
||||
IgnoreError bool
|
||||
}
|
||||
|
||||
// Dep is a task dependency
|
||||
type Dep struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
Vars *Vars
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -51,7 +51,7 @@ func (c *Cmd) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
}
|
||||
var taskCall struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
Vars *Vars
|
||||
}
|
||||
if err := unmarshal(&taskCall); err == nil {
|
||||
c.Task = taskCall.Task
|
||||
@@ -70,7 +70,7 @@ func (d *Dep) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
}
|
||||
var taskCall struct {
|
||||
Task string
|
||||
Vars Vars
|
||||
Vars *Vars
|
||||
}
|
||||
if err := unmarshal(&taskCall); err == nil {
|
||||
d.Task = taskCall.Task
|
||||
109
taskfile/included_taskfile.go
Normal file
109
taskfile/included_taskfile.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrCantUnmarshalIncludedTaskfile is returned for invalid var YAML.
|
||||
ErrCantUnmarshalIncludedTaskfile = errors.New("task: can't unmarshal included value")
|
||||
)
|
||||
|
||||
// IncludedTaskfile represents information about included tasksfile
|
||||
type IncludedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
AdvancedImport bool
|
||||
}
|
||||
|
||||
// IncludedTaskfiles represents information about included tasksfiles
|
||||
type IncludedTaskfiles struct {
|
||||
Keys []string
|
||||
Mapping map[string]IncludedTaskfile
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (tfs *IncludedTaskfiles) UnmarshalYAML(node *yaml.Node) error {
|
||||
if node.Kind != yaml.MappingNode {
|
||||
return errors.New("task: includes is not a map")
|
||||
}
|
||||
|
||||
// NOTE(@andreynering): on this style of custom unmarsheling,
|
||||
// even number contains the keys, while odd numbers contains
|
||||
// the values.
|
||||
for i := 0; i < len(node.Content); i += 2 {
|
||||
keyNode := node.Content[i]
|
||||
valueNode := node.Content[i+1]
|
||||
|
||||
var v IncludedTaskfile
|
||||
if err := valueNode.Decode(&v); err != nil {
|
||||
return err
|
||||
}
|
||||
tfs.Set(keyNode.Value, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Len returns the length of the map
|
||||
func (tfs *IncludedTaskfiles) Len() int {
|
||||
if tfs == nil {
|
||||
return 0
|
||||
}
|
||||
return len(tfs.Keys)
|
||||
}
|
||||
|
||||
// Merge merges the given IncludedTaskfiles into the caller one
|
||||
func (tfs *IncludedTaskfiles) Merge(other *IncludedTaskfiles) {
|
||||
other.Range(func(key string, value IncludedTaskfile) error {
|
||||
tfs.Set(key, value)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Set sets a value to a given key
|
||||
func (tfs *IncludedTaskfiles) Set(key string, includedTaskfile IncludedTaskfile) {
|
||||
if tfs.Mapping == nil {
|
||||
tfs.Mapping = make(map[string]IncludedTaskfile, 1)
|
||||
}
|
||||
if !stringSliceContains(tfs.Keys, key) {
|
||||
tfs.Keys = append(tfs.Keys, key)
|
||||
}
|
||||
tfs.Mapping[key] = includedTaskfile
|
||||
}
|
||||
|
||||
// Range allows you to loop into the included taskfiles in its right order
|
||||
func (tfs *IncludedTaskfiles) Range(yield func(key string, includedTaskfile IncludedTaskfile) error) error {
|
||||
if tfs == nil {
|
||||
return nil
|
||||
}
|
||||
for _, k := range tfs.Keys {
|
||||
if err := yield(k, tfs.Mapping[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var str string
|
||||
if err := unmarshal(&str); err == nil {
|
||||
it.Taskfile = str
|
||||
return nil
|
||||
}
|
||||
|
||||
var includedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
}
|
||||
if err := unmarshal(&includedTaskfile); err == nil {
|
||||
it.Dir = includedTaskfile.Dir
|
||||
it.Taskfile = includedTaskfile.Taskfile
|
||||
it.AdvancedImport = true
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrCantUnmarshalIncludedTaskfile
|
||||
}
|
||||
@@ -22,25 +22,18 @@ func Merge(t1, t2 *Taskfile, namespaces ...string) error {
|
||||
}
|
||||
|
||||
if t1.Includes == nil {
|
||||
t1.Includes = make(IncludedTaskfiles)
|
||||
}
|
||||
for k, v := range t2.Includes {
|
||||
t1.Includes[k] = v
|
||||
t1.Includes = &IncludedTaskfiles{}
|
||||
}
|
||||
t1.Includes.Merge(t2.Includes)
|
||||
|
||||
if t1.Vars == nil {
|
||||
t1.Vars = make(Vars)
|
||||
t1.Vars = &Vars{}
|
||||
}
|
||||
for k, v := range t2.Vars {
|
||||
t1.Vars[k] = v
|
||||
}
|
||||
|
||||
if t1.Env == nil {
|
||||
t1.Env = make(Vars)
|
||||
}
|
||||
for k, v := range t2.Env {
|
||||
t1.Env[k] = v
|
||||
t1.Env = &Vars{}
|
||||
}
|
||||
t1.Vars.Merge(t2.Vars)
|
||||
t1.Env.Merge(t2.Env)
|
||||
|
||||
if t1.Tasks == nil {
|
||||
t1.Tasks = make(Tasks)
|
||||
@@ -3,10 +3,10 @@ package taskfile_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestPreconditionParse(t *testing.T) {
|
||||
147
taskfile/read/taskfile.go
Normal file
147
taskfile/read/taskfile.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package read
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrIncludedTaskfilesCantHaveIncludes is returned when a included Taskfile contains includes
|
||||
ErrIncludedTaskfilesCantHaveIncludes = errors.New("task: Included Taskfiles can't have includes. Please, move the include to the main Taskfile")
|
||||
// ErrIncludedTaskfilesCantHaveDotenvs is returned when a included Taskfile contains dotenvs
|
||||
ErrIncludedTaskfilesCantHaveDotenvs = errors.New("task: Included Taskfiles can't have dotenv declarations. Please, move the dotenv declaration to the main Taskfile")
|
||||
)
|
||||
|
||||
// Taskfile reads a Taskfile for a given directory
|
||||
func Taskfile(dir string, entrypoint string) (*taskfile.Taskfile, error) {
|
||||
path := filepath.Join(dir, entrypoint)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return nil, fmt.Errorf(`task: No Taskfile found on "%s". Use "task --init" to create a new one`, path)
|
||||
}
|
||||
t, err := readTaskfile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, err := t.ParsedVersion()
|
||||
if err != nil {
|
||||
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),
|
||||
AdvancedImport: includedTask.AdvancedImport,
|
||||
}
|
||||
if err := tr.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if filepath.IsAbs(includedTask.Taskfile) {
|
||||
path = includedTask.Taskfile
|
||||
} else {
|
||||
path = filepath.Join(dir, includedTask.Taskfile)
|
||||
}
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
path = filepath.Join(path, "Taskfile.yml")
|
||||
}
|
||||
includedTaskfile, err := readTaskfile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if includedTaskfile.Includes.Len() > 0 {
|
||||
return ErrIncludedTaskfilesCantHaveIncludes
|
||||
}
|
||||
|
||||
if v >= 3.0 && len(includedTaskfile.Dotenv) > 0 {
|
||||
return ErrIncludedTaskfilesCantHaveDotenvs
|
||||
}
|
||||
|
||||
if includedTask.AdvancedImport {
|
||||
for _, task := range includedTaskfile.Tasks {
|
||||
if !filepath.IsAbs(task.Dir) {
|
||||
task.Dir = filepath.Join(includedTask.Dir, task.Dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = taskfile.Merge(t, includedTaskfile, namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if v < 3.0 {
|
||||
path = filepath.Join(dir, fmt.Sprintf("Taskfile_%s.yml", runtime.GOOS))
|
||||
if _, err = os.Stat(path); err == nil {
|
||||
osTaskfile, err := readTaskfile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = taskfile.Merge(t, osTaskfile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for name, task := range t.Tasks {
|
||||
if task == nil {
|
||||
task = &taskfile.Task{}
|
||||
t.Tasks[name] = task
|
||||
}
|
||||
task.Task = name
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func readTaskfile(file string) (*taskfile.Taskfile, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var t taskfile.Taskfile
|
||||
return &t, yaml.NewDecoder(f).Decode(&t)
|
||||
}
|
||||
@@ -6,14 +6,14 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Taskvars reads a Taskvars for a given directory
|
||||
func Taskvars(dir string) (taskfile.Vars, error) {
|
||||
vars := make(taskfile.Vars)
|
||||
func Taskvars(dir string) (*taskfile.Vars, error) {
|
||||
vars := &taskfile.Vars{}
|
||||
|
||||
path := filepath.Join(dir, "Taskvars.yml")
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
@@ -29,24 +29,17 @@ func Taskvars(dir string) (taskfile.Vars, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vars == nil {
|
||||
vars = osVars
|
||||
} else {
|
||||
for k, v := range osVars {
|
||||
vars[k] = v
|
||||
}
|
||||
}
|
||||
vars.Merge(osVars)
|
||||
}
|
||||
|
||||
return vars, nil
|
||||
}
|
||||
|
||||
func readTaskvars(file string) (taskfile.Vars, error) {
|
||||
func readTaskvars(file string) (*taskfile.Vars, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var vars taskfile.Vars
|
||||
return vars, yaml.NewDecoder(f).Decode(&vars)
|
||||
return &vars, yaml.NewDecoder(f).Decode(&vars)
|
||||
}
|
||||
10
taskfile/slice.go
Normal file
10
taskfile/slice.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package taskfile
|
||||
|
||||
func stringSliceContains(s []string, str string) bool {
|
||||
for _, v := range s {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -12,6 +12,7 @@ type Task struct {
|
||||
Task string
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
Label string
|
||||
Desc string
|
||||
Summary string
|
||||
Sources []string
|
||||
@@ -19,8 +20,8 @@ type Task struct {
|
||||
Status []string
|
||||
Preconditions []*Precondition
|
||||
Dir string
|
||||
Vars Vars
|
||||
Env Vars
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Silent bool
|
||||
Method string
|
||||
Prefix string
|
||||
@@ -32,6 +33,13 @@ var (
|
||||
ErrCantUnmarshalTask = errors.New("task: can't unmarshal task value")
|
||||
)
|
||||
|
||||
func (t *Task) Name() string {
|
||||
if t.Label != "" {
|
||||
return t.Label
|
||||
}
|
||||
return t.Task
|
||||
}
|
||||
|
||||
func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var cmd Cmd
|
||||
if err := unmarshal(&cmd); err == nil && cmd.Cmd != "" {
|
||||
@@ -48,6 +56,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var task struct {
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
Label string
|
||||
Desc string
|
||||
Summary string
|
||||
Sources []string
|
||||
@@ -55,8 +64,8 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Status []string
|
||||
Preconditions []*Precondition
|
||||
Dir string
|
||||
Vars Vars
|
||||
Env Vars
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Silent bool
|
||||
Method string
|
||||
Prefix string
|
||||
@@ -65,6 +74,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
if err := unmarshal(&task); err == nil {
|
||||
t.Cmds = task.Cmds
|
||||
t.Deps = task.Deps
|
||||
t.Label = task.Label
|
||||
t.Desc = task.Desc
|
||||
t.Summary = task.Summary
|
||||
t.Sources = task.Sources
|
||||
@@ -1,16 +1,22 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Taskfile represents a Taskfile.yml
|
||||
type Taskfile struct {
|
||||
Version string
|
||||
Expansions int
|
||||
Output string
|
||||
Method string
|
||||
Includes IncludedTaskfiles
|
||||
Vars Vars
|
||||
Env Vars
|
||||
Includes *IncludedTaskfiles
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Tasks Tasks
|
||||
Silent bool
|
||||
Dotenv []string
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface
|
||||
@@ -20,11 +26,12 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
Expansions int
|
||||
Output string
|
||||
Method string
|
||||
Includes IncludedTaskfiles
|
||||
Vars Vars
|
||||
Env Vars
|
||||
Includes *IncludedTaskfiles
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Tasks Tasks
|
||||
Silent bool
|
||||
Dotenv []string
|
||||
}
|
||||
if err := unmarshal(&taskfile); err != nil {
|
||||
return err
|
||||
@@ -38,11 +45,24 @@ func (tf *Taskfile) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
tf.Env = taskfile.Env
|
||||
tf.Tasks = taskfile.Tasks
|
||||
tf.Silent = taskfile.Silent
|
||||
tf.Dotenv = taskfile.Dotenv
|
||||
if tf.Expansions <= 0 {
|
||||
tf.Expansions = 2
|
||||
}
|
||||
if tf.Vars == nil {
|
||||
tf.Vars = make(Vars)
|
||||
tf.Vars = &Vars{}
|
||||
}
|
||||
if tf.Env == nil {
|
||||
tf.Env = &Vars{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParsedVersion returns the version as a float64
|
||||
func (tf *Taskfile) ParsedVersion() (float64, error) {
|
||||
v, err := strconv.ParseFloat(tf.Version, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf(`task: Could not parse taskfile version "%s": %v`, tf.Version, err)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
@@ -3,10 +3,10 @@ package taskfile_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-task/task/v2/internal/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestCmdParse(t *testing.T) {
|
||||
@@ -33,9 +33,12 @@ vars:
|
||||
{
|
||||
yamlTaskCall,
|
||||
&taskfile.Cmd{},
|
||||
&taskfile.Cmd{Task: "another-task", Vars: taskfile.Vars{
|
||||
"PARAM1": taskfile.Var{Static: "VALUE1"},
|
||||
"PARAM2": taskfile.Var{Static: "VALUE2"},
|
||||
&taskfile.Cmd{Task: "another-task", Vars: &taskfile.Vars{
|
||||
Keys: []string{"PARAM1", "PARAM2"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"PARAM1": taskfile.Var{Static: "VALUE1"},
|
||||
"PARAM2": taskfile.Var{Static: "VALUE2"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
@@ -46,9 +49,12 @@ vars:
|
||||
{
|
||||
yamlTaskCall,
|
||||
&taskfile.Dep{},
|
||||
&taskfile.Dep{Task: "another-task", Vars: taskfile.Vars{
|
||||
"PARAM1": taskfile.Var{Static: "VALUE1"},
|
||||
"PARAM2": taskfile.Var{Static: "VALUE2"},
|
||||
&taskfile.Dep{Task: "another-task", Vars: &taskfile.Vars{
|
||||
Keys: []string{"PARAM1", "PARAM2"},
|
||||
Mapping: map[string]taskfile.Var{
|
||||
"PARAM1": taskfile.Var{Static: "VALUE1"},
|
||||
"PARAM2": taskfile.Var{Static: "VALUE2"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
124
taskfile/var.go
Normal file
124
taskfile/var.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrCantUnmarshalVar is returned for invalid var YAML.
|
||||
ErrCantUnmarshalVar = errors.New("task: can't unmarshal var value")
|
||||
)
|
||||
|
||||
// Vars is a string[string] variables map.
|
||||
type Vars struct {
|
||||
Keys []string
|
||||
Mapping map[string]Var
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
|
||||
if node.Kind != yaml.MappingNode {
|
||||
return errors.New("task: vars is not a map")
|
||||
}
|
||||
|
||||
// NOTE(@andreynering): on this style of custom unmarsheling,
|
||||
// even number contains the keys, while odd numbers contains
|
||||
// the values.
|
||||
for i := 0; i < len(node.Content); i += 2 {
|
||||
keyNode := node.Content[i]
|
||||
valueNode := node.Content[i+1]
|
||||
|
||||
var v Var
|
||||
if err := valueNode.Decode(&v); err != nil {
|
||||
return err
|
||||
}
|
||||
vs.Set(keyNode.Value, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Merge merges the given Vars into the caller one
|
||||
func (vs *Vars) Merge(other *Vars) {
|
||||
other.Range(func(key string, value Var) error {
|
||||
vs.Set(key, value)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Set sets a value to a given key
|
||||
func (vs *Vars) Set(key string, value Var) {
|
||||
if vs.Mapping == nil {
|
||||
vs.Mapping = make(map[string]Var, 1)
|
||||
}
|
||||
if !stringSliceContains(vs.Keys, key) {
|
||||
vs.Keys = append(vs.Keys, key)
|
||||
}
|
||||
vs.Mapping[key] = value
|
||||
}
|
||||
|
||||
// Range allows you to loop into the vars in its right order
|
||||
func (vs *Vars) Range(yield func(key string, value Var) error) error {
|
||||
if vs == nil {
|
||||
return nil
|
||||
}
|
||||
for _, k := range vs.Keys {
|
||||
if err := yield(k, vs.Mapping[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToCacheMap converts Vars to a map containing only the static
|
||||
// variables
|
||||
func (vs *Vars) ToCacheMap() (m map[string]interface{}) {
|
||||
m = make(map[string]interface{}, len(vs.Keys))
|
||||
vs.Range(func(k string, v Var) error {
|
||||
if v.Sh != "" {
|
||||
// Dynamic variable is not yet resolved; trigger
|
||||
// <no value> to be used in templates.
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Live != nil {
|
||||
m[k] = v.Live
|
||||
} else {
|
||||
m[k] = v.Static
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Var represents either a static or dynamic variable.
|
||||
type Var struct {
|
||||
Static string
|
||||
Live interface{}
|
||||
Sh string
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface.
|
||||
func (v *Var) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var str string
|
||||
if err := unmarshal(&str); err == nil {
|
||||
if strings.HasPrefix(str, "$") {
|
||||
v.Sh = strings.TrimPrefix(str, "$")
|
||||
} else {
|
||||
v.Static = str
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var sh struct {
|
||||
Sh string
|
||||
}
|
||||
if err := unmarshal(&sh); err == nil {
|
||||
v.Sh = sh.Sh
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrCantUnmarshalVar
|
||||
}
|
||||
2
testdata/checksum/Taskfile.yml
vendored
2
testdata/checksum/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
|
||||
2
testdata/cyclic/Taskfile.yml
vendored
2
testdata/cyclic/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
task-1:
|
||||
|
||||
2
testdata/deps/Taskfile.yml
vendored
2
testdata/deps/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
|
||||
2
testdata/dir/Taskfile.yml
vendored
2
testdata/dir/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
whereami:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
whereami:
|
||||
|
||||
2
testdata/dir/explicit_exists/Taskfile.yml
vendored
2
testdata/dir/explicit_exists/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
whereami:
|
||||
|
||||
1
testdata/dotenv/.gitignore
vendored
Normal file
1
testdata/dotenv/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.txt
|
||||
8
testdata/dotenv/default/Taskfile.yml
vendored
Normal file
8
testdata/dotenv/default/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: '3'
|
||||
|
||||
dotenv: ['../include1/.env', '../include1/envs/.env']
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include.txt
|
||||
9
testdata/dotenv/error_included_envs/Taskfile.yml
vendored
Normal file
9
testdata/dotenv/error_included_envs/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
include1: '../include1'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include-errors2.txt
|
||||
1
testdata/dotenv/include1/.env
vendored
Normal file
1
testdata/dotenv/include1/.env
vendored
Normal file
@@ -0,0 +1 @@
|
||||
INCLUDE1=from_include1
|
||||
3
testdata/dotenv/include1/Taskfile.yml
vendored
Normal file
3
testdata/dotenv/include1/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
version: '3'
|
||||
|
||||
dotenv: ['.env']
|
||||
1
testdata/dotenv/include1/envs/.env
vendored
Normal file
1
testdata/dotenv/include1/envs/.env
vendored
Normal file
@@ -0,0 +1 @@
|
||||
INCLUDE2=from_include2
|
||||
8
testdata/dotenv/missing_env/Taskfile.yml
vendored
Normal file
8
testdata/dotenv/missing_env/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: '3'
|
||||
|
||||
dotenv: ['.env']
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "INCLUDE1='$INCLUDE1' INCLUDE2='$INCLUDE2'" > include.txt
|
||||
2
testdata/dry/Taskfile.yml
vendored
2
testdata/dry/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
|
||||
2
testdata/dry_checksum/Taskfile.yml
vendored
2
testdata/dry_checksum/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
|
||||
4
testdata/empty_task/Taskfile.yml
vendored
Normal file
4
testdata/empty_task/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
2
testdata/env/Taskfile.yml
vendored
2
testdata/env/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
BAZ:
|
||||
|
||||
6
testdata/exit_immediately/Taskfile.yml
vendored
Normal file
6
testdata/exit_immediately/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default: |
|
||||
this_should_fail
|
||||
echo "This shoudn't be print"
|
||||
2
testdata/expand/Taskfile.yml
vendored
2
testdata/expand/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
pwd:
|
||||
|
||||
5
testdata/generates/Taskfile.yml
vendored
5
testdata/generates/Taskfile.yml
vendored
@@ -1,4 +1,7 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
BUILD_DIR: $pwd
|
||||
|
||||
tasks:
|
||||
abs.txt:
|
||||
|
||||
1
testdata/generates/Taskvars.yml
vendored
1
testdata/generates/Taskvars.yml
vendored
@@ -1 +0,0 @@
|
||||
BUILD_DIR: $pwd
|
||||
2
testdata/ignore_errors/Taskfile.yml
vendored
2
testdata/ignore_errors/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
task-should-pass:
|
||||
|
||||
2
testdata/includes/Taskfile.yml
vendored
2
testdata/includes/Taskfile.yml
vendored
@@ -13,6 +13,7 @@ includes:
|
||||
included_taskfile_with_dir:
|
||||
taskfile: ./module2/Taskfile.yml
|
||||
dir: ./module2
|
||||
included_os: ./Taskfile_{{OS}}.yml
|
||||
|
||||
tasks:
|
||||
default:
|
||||
@@ -24,6 +25,7 @@ tasks:
|
||||
- task: included_taskfile_without_dir:gen_dir
|
||||
- task: included_with_dir:gen_file
|
||||
- task: included_taskfile_with_dir:gen_dir
|
||||
- task: included_os:gen
|
||||
|
||||
gen:
|
||||
cmds:
|
||||
|
||||
4
testdata/includes/Taskfile_darwin.yml
vendored
Normal file
4
testdata/includes/Taskfile_darwin.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
gen: echo 'os' > os_include.txt
|
||||
4
testdata/includes/Taskfile_linux.yml
vendored
Normal file
4
testdata/includes/Taskfile_linux.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
gen: echo 'os' > os_include.txt
|
||||
4
testdata/includes/Taskfile_windows.yml
vendored
Normal file
4
testdata/includes/Taskfile_windows.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
gen: echo 'os' > os_include.txt
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included: Taskfile2.yml
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
call-root:
|
||||
|
||||
2
testdata/includes_deps/Taskfile.yml
vendored
2
testdata/includes_deps/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included: Taskfile2.yml
|
||||
|
||||
2
testdata/includes_deps/Taskfile2.yml
vendored
2
testdata/includes_deps/Taskfile2.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
|
||||
2
testdata/includes_empty/Taskfile.yml
vendored
2
testdata/includes_empty/Taskfile.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included: Taskfile2.yml
|
||||
|
||||
2
testdata/includes_empty/Taskfile2.yml
vendored
2
testdata/includes_empty/Taskfile2.yml
vendored
@@ -1,4 +1,4 @@
|
||||
version: '2'
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
FILE: file.txt
|
||||
|
||||
6
testdata/label_list/Taskfile.yml
vendored
Normal file
6
testdata/label_list/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
label: "foobar"
|
||||
desc: "task description"
|
||||
7
testdata/label_status/Taskfile.yml
vendored
Normal file
7
testdata/label_status/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
label: "foobar"
|
||||
status:
|
||||
- "false"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user