mirror of
https://github.com/go-task/task.git
synced 2026-05-18 13:15:41 +02:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88b095020e | ||
|
|
cc14996b71 | ||
|
|
375106c988 | ||
|
|
6ce6a38899 | ||
|
|
76030c9146 | ||
|
|
a71020eab5 | ||
|
|
6bef2ff8a9 | ||
|
|
413dcd28a8 | ||
|
|
da6f5c66a0 | ||
|
|
6012da7a21 | ||
|
|
46c5eafe35 | ||
|
|
830b745112 | ||
|
|
b52d4e4f40 | ||
|
|
3aaa3223a0 | ||
|
|
a9ff58d0fe | ||
|
|
eeaebaf8c7 | ||
|
|
2213141fcb | ||
|
|
19956889a7 | ||
|
|
4c580ebf18 | ||
|
|
3dccde270a | ||
|
|
53dd0b138a | ||
|
|
ea85909e8b | ||
|
|
6bf6fe7ead | ||
|
|
f39c6352ac | ||
|
|
4294cc92b9 | ||
|
|
40d77156df | ||
|
|
856ba3b8c2 | ||
|
|
0810ef01b0 | ||
|
|
527bbc3bf5 | ||
|
|
912bbcab8e | ||
|
|
aa45491510 | ||
|
|
1e25ceab29 | ||
|
|
a74b0bc679 | ||
|
|
a3fce1c302 | ||
|
|
7958cf50b3 | ||
|
|
b0efbad591 | ||
|
|
30e9c7d4cd | ||
|
|
baa5e2c378 | ||
|
|
cc97e2da1d | ||
|
|
a55e21bbb7 | ||
|
|
8d138a5eea | ||
|
|
635e3f4e7d | ||
|
|
252d549e3f | ||
|
|
182d43e8d8 | ||
|
|
f35e51e4e5 | ||
|
|
fb3c64c46e | ||
|
|
7535467f45 | ||
|
|
3e5cd6cdfd | ||
|
|
dcc060af89 | ||
|
|
55593090fa | ||
|
|
57c094f415 | ||
|
|
2f4876b71c | ||
|
|
725f929778 | ||
|
|
8266b28b48 | ||
|
|
f5c7472f64 | ||
|
|
ced3e7a579 | ||
|
|
36dd71b122 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +1,2 @@
|
||||
* text=auto
|
||||
*.mdx -linguist-detectable
|
||||
|
||||
14
.github/pull_request_template.md
vendored
14
.github/pull_request_template.md
vendored
@@ -1,5 +1,9 @@
|
||||
> Thanks for your pull request, we really appreciate contributions!
|
||||
>
|
||||
> Please understand that it may take some time to be reviewed.
|
||||
>
|
||||
> Also, make sure to follow the [Contribution Guide](https://taskfile.dev/contributing/).
|
||||
<!--
|
||||
|
||||
Thanks for your pull request, we really appreciate contributions!
|
||||
|
||||
Please understand that it may take some time to be reviewed.
|
||||
|
||||
Also, make sure to follow the [Contribution Guide](https://taskfile.dev/contributing/).
|
||||
|
||||
-->
|
||||
|
||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@@ -16,14 +16,14 @@ jobs:
|
||||
go-version: [1.21.x, 1.22.x]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{matrix.go-version}}
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: v1.55.2
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.12
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: install check-jsonschema
|
||||
run: python -m pip install 'check-jsonschema==0.27.3'
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -10,10 +10,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -18,13 +18,13 @@ jobs:
|
||||
runs-on: ${{matrix.platform}}
|
||||
steps:
|
||||
- name: Set up Go ${{matrix.go-version}}
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{matrix.go-version}}
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Go modules
|
||||
run: go mod download
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
if: github.repository == 'go-task/task'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Verify changed files
|
||||
id: changed-files
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
website/src/pages
|
||||
|
||||
- name: Install Task
|
||||
uses: arduino/setup-task@v1
|
||||
uses: arduino/setup-task@v2
|
||||
with:
|
||||
version: 3.x
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -11,11 +11,16 @@ builds:
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
- riscv64
|
||||
goarm:
|
||||
- '6'
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: '386'
|
||||
- goos: darwin
|
||||
goarch: riscv64
|
||||
- goos: windows
|
||||
goarch: riscv64
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
|
||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -1,5 +1,49 @@
|
||||
# Changelog
|
||||
|
||||
## v3.38.0 - 2024-06-30
|
||||
|
||||
- Added `TASK_EXE` special variable (#1616, #1624 by @pd93 and @andreynering).
|
||||
- Some YAML parsing errors will now show in a more user friendly way (#1619 by
|
||||
@pd93).
|
||||
- Prefixed outputs will now be colorized by default (#1572 by
|
||||
@AlexanderArvidsson)
|
||||
- [References](https://taskfile.dev/usage/#referencing-other-variables) are now
|
||||
generally available (no experiments required) (#1654 by @pd93).
|
||||
- Templating functions can now be used in references (#1645, #1654 by @pd93).
|
||||
- Added a new
|
||||
[templating reference page](https://taskfile.dev/reference/templating/) to the
|
||||
documentation (#1614, #1653 by @pd93).
|
||||
- If using the
|
||||
[Map Variables experiment (1)](https://taskfile.dev/experiments/map-variables/?proposal=1),
|
||||
references are available by
|
||||
[prefixing a string with a `#`](https://taskfile.dev/experiments/map-variables/?proposal=1#references)
|
||||
(#1654 by @pd93).
|
||||
- If using the
|
||||
[Map Variables experiment (2)](https://taskfile.dev/experiments/map-variables/?proposal=2),
|
||||
the `yaml` and `json` keys are no longer available (#1654 by @pd93).
|
||||
- Added a new `TASK_REMOTE_DIR` environment variable to configure where cached
|
||||
remote Taskfiles are stored (#1661 by @vmaerten).
|
||||
- Added a new `--clear-cache` flag to clear the cache of remote Taskfiles (#1639
|
||||
by @vmaerten).
|
||||
- Improved the readability of cached remote Taskfile filenames (#1636 by
|
||||
@vmaerten).
|
||||
- Starting releasing a binary for the `riscv64` architecture on Linux (#1699 by
|
||||
@mengzhuo).
|
||||
- Added `CLI_SILENT` and `CLI_VERBOSE` variables (#1480, #1669 by @Vince-Smith).
|
||||
- Fixed a couple of bugs with the `prompt:` feature (#1657 by @pd93).
|
||||
- Fixed JSON Schema to disallow invalid properties (#1657 by @pd93).
|
||||
- Fixed version checks not working as intended (#872, #1663 by @vmaerten).
|
||||
- Fixed a bug where included tasks were run multiple times even if `run: once`
|
||||
was set (#852, #1655 by @pd93).
|
||||
- Fixed some bugs related to column formatting in the terminal (#1350, #1637,
|
||||
#1656 by @vmaerten).
|
||||
|
||||
## v3.37.2 - 2024-05-12
|
||||
|
||||
- Fixed a bug where an empty Taskfile would cause a panic (#1648 by @pd93).
|
||||
- Fixed a bug where includes Taskfile variable were not being merged correctly
|
||||
(#1643, #1649 by @pd93).
|
||||
|
||||
## v3.37.1 - 2024-05-09
|
||||
|
||||
- Fix bug where non-string values (numbers, bools) added to `env:` weren't been
|
||||
@@ -14,7 +58,7 @@
|
||||
- Refactored how Task reads, parses and merges Taskfiles using a DAG (#1563,
|
||||
#1607 by @pd93).
|
||||
- Fix a bug which stopped tasks from using `stdin` as input (#1593, #1623 by
|
||||
@pd03).
|
||||
@pd93).
|
||||
- Fix error when a file or directory in the project contained a special char
|
||||
like `&`, `(` or `)` (#1551, #1584 by @andreynering).
|
||||
- Added alias `q` for template function `shellQuote` (#1601, #1603 by @vergenzt)
|
||||
|
||||
47
Taskfile.yml
47
Taskfile.yml
@@ -123,10 +123,53 @@ tasks:
|
||||
cmds:
|
||||
- go install github.com/goreleaser/goreleaser@latest
|
||||
|
||||
release:
|
||||
release:*:
|
||||
desc: Prepare the project for a new release
|
||||
summary: |
|
||||
This task will do the following:
|
||||
|
||||
- Update the version and date in the CHANGELOG.md file
|
||||
- Update the version in the package.json and package-lock.json files
|
||||
- Copy the latest docs to the "current" version on the website
|
||||
- Commit the changes
|
||||
- Create a new tag
|
||||
- Push the commit/tag to the repository
|
||||
- Create a GitHub release
|
||||
|
||||
To use the task, simply run "task release:<version>" where "<version>" is is one of:
|
||||
|
||||
- "major" - Bumps the major number
|
||||
- "minor" - Bumps the minor number
|
||||
- "patch" - Bumps the patch number
|
||||
- A semver compatible version number (e.g. "1.2.3")
|
||||
vars:
|
||||
VERSION:
|
||||
sh: "go run ./cmd/release --version {{index .MATCH 0}}"
|
||||
COMPLETE_MESSAGE: |
|
||||
Creating release with GoReleaser: https://github.com/go-task/task/actions/workflows/release.yml
|
||||
|
||||
Please wait for the CI to finish and then do the following:
|
||||
|
||||
- Copy the changelog for v{{.VERSION}} to the GitHub release
|
||||
- Publish the package to NPM with `task npm:publish`
|
||||
- Update and push the snapcraft manifest in https://github.com/go-task/snap/blob/main/snap/snapcraft.yaml
|
||||
preconditions:
|
||||
- sh: test $(git rev-parse --abbrev-ref HEAD) = "main"
|
||||
msg: "You must be on the main branch to release"
|
||||
- sh: "[[ -z $(git diff --shortstat main) ]]"
|
||||
msg: "You must have a clean working tree to release"
|
||||
prompt: "Are you sure you want to release version {{.VERSION}}?"
|
||||
cmds:
|
||||
- go run ./cmd/release {{.CLI_ARGS}}
|
||||
- cmd: echo "Releasing v{{.VERSION}}"
|
||||
silent: true
|
||||
- "go run ./cmd/release {{.VERSION}}"
|
||||
- "git add --all"
|
||||
- "git commit -m v{{.VERSION}}"
|
||||
- "git push"
|
||||
- "git tag v{{.VERSION}}"
|
||||
- "git push origin tag v{{.VERSION}}"
|
||||
- cmd: printf "%s" '{{.COMPLETE_MESSAGE}}'
|
||||
silent: true
|
||||
|
||||
npm:publish:
|
||||
desc: Publish release to npm
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,6 +26,16 @@ var (
|
||||
versionRegex = regexp.MustCompile(`(?m)^ "version": "\d+\.\d+\.\d+",$`)
|
||||
)
|
||||
|
||||
// Flags
|
||||
var (
|
||||
versionFlag bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
pflag.BoolVarP(&versionFlag, "version", "v", false, "resolved version number")
|
||||
pflag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := release(); err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -33,7 +44,7 @@ func main() {
|
||||
}
|
||||
|
||||
func release() error {
|
||||
if len(os.Args) != 2 {
|
||||
if len(pflag.Args()) != 1 {
|
||||
return errors.New("error: expected version number")
|
||||
}
|
||||
|
||||
@@ -42,11 +53,14 @@ func release() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bumpVersion(version, os.Args[1]); err != nil {
|
||||
if err := bumpVersion(version, pflag.Arg(0)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(version)
|
||||
if versionFlag {
|
||||
fmt.Println(version)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := changelog(version); err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/sort"
|
||||
ver "github.com/go-task/task/v3/internal/version"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
@@ -58,7 +59,7 @@ func run() error {
|
||||
entrypoint := flags.Entrypoint
|
||||
|
||||
if flags.Version {
|
||||
fmt.Printf("Task version: %s\n", ver.GetVersion())
|
||||
fmt.Printf("Task version: %s\n", ver.GetVersionWithSum())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -125,16 +126,15 @@ func run() error {
|
||||
OutputStyle: flags.Output,
|
||||
TaskSorter: taskSorter,
|
||||
}
|
||||
|
||||
listOptions := task.NewListOptions(flags.List, flags.ListAll, flags.ListJson, flags.NoStatus)
|
||||
if err := listOptions.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.Setup(); err != nil {
|
||||
err := e.Setup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if experiments.AnyVariables.Enabled {
|
||||
logger.Warnf("The 'Any Variables' experiment flag is no longer required to use non-map variable types. If you wish to use map variables, please use 'TASK_X_MAP_VARIABLES' instead. See https://github.com/go-task/task/issues/1585\n")
|
||||
}
|
||||
@@ -145,6 +145,14 @@ func run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if flags.ClearCache {
|
||||
cache, err := taskfile.NewCache(e.TempDir.Remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cache.Clear()
|
||||
}
|
||||
|
||||
if (listOptions.ShouldListTasks()) && flags.Silent {
|
||||
return e.ListTaskNames(flags.ListAll)
|
||||
}
|
||||
@@ -179,6 +187,8 @@ func run() error {
|
||||
|
||||
globals.Set("CLI_ARGS", ast.Var{Value: cliArgs})
|
||||
globals.Set("CLI_FORCE", ast.Var{Value: flags.Force || flags.ForceAll})
|
||||
globals.Set("CLI_SILENT", ast.Var{Value: flags.Silent})
|
||||
globals.Set("CLI_VERBOSE", ast.Var{Value: flags.Verbose})
|
||||
e.Taskfile.Vars.Merge(globals, nil)
|
||||
|
||||
if !flags.Watch {
|
||||
|
||||
179
errors/error_taskfile_decode.go
Normal file
179
errors/error_taskfile_decode.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/v2"
|
||||
"github.com/alecthomas/chroma/v2/quick"
|
||||
"github.com/alecthomas/chroma/v2/styles"
|
||||
"github.com/fatih/color"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
//go:embed themes/*.xml
|
||||
var embedded embed.FS
|
||||
|
||||
var typeErrorRegex = regexp.MustCompile(`line \d+: (.*)`)
|
||||
|
||||
func init() {
|
||||
r, err := embedded.Open("themes/task.xml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
style, err := chroma.NewXMLStyle(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
styles.Register(style)
|
||||
}
|
||||
|
||||
type (
|
||||
TaskfileDecodeError struct {
|
||||
Message string
|
||||
Location string
|
||||
Line int
|
||||
Column int
|
||||
Tag string
|
||||
Snippet TaskfileSnippet
|
||||
Err error
|
||||
}
|
||||
TaskfileSnippet struct {
|
||||
Lines []string
|
||||
StartLine int
|
||||
EndLine int
|
||||
Padding int
|
||||
}
|
||||
)
|
||||
|
||||
func NewTaskfileDecodeError(err error, node *yaml.Node) *TaskfileDecodeError {
|
||||
// If the error is already a DecodeError, return it
|
||||
taskfileInvalidErr := &TaskfileDecodeError{}
|
||||
if errors.As(err, &taskfileInvalidErr) {
|
||||
return taskfileInvalidErr
|
||||
}
|
||||
return &TaskfileDecodeError{
|
||||
Line: node.Line,
|
||||
Column: node.Column,
|
||||
Tag: node.ShortTag(),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (err *TaskfileDecodeError) Error() string {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
// Print the error message
|
||||
if err.Message != "" {
|
||||
fmt.Fprintln(buf, color.RedString("err: %s", err.Message))
|
||||
} else {
|
||||
// Extract the errors from the TypeError
|
||||
te := &yaml.TypeError{}
|
||||
if errors.As(err.Err, &te) {
|
||||
if len(te.Errors) > 1 {
|
||||
fmt.Fprintln(buf, color.RedString("errs:"))
|
||||
for _, message := range te.Errors {
|
||||
fmt.Fprintln(buf, color.RedString("- %s", extractTypeErrorMessage(message)))
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintln(buf, color.RedString("err: %s", extractTypeErrorMessage(te.Errors[0])))
|
||||
}
|
||||
} else {
|
||||
// Otherwise print the error message normally
|
||||
fmt.Fprintln(buf, color.RedString("err: %s", err.Err))
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(buf, color.RedString("file: %s:%d:%d", err.Location, err.Line, err.Column))
|
||||
|
||||
// Print the snippet
|
||||
maxLineNumberDigits := digits(err.Snippet.EndLine)
|
||||
lineNumberSpacer := strings.Repeat(" ", maxLineNumberDigits)
|
||||
columnSpacer := strings.Repeat(" ", err.Column-1)
|
||||
for i, line := range err.Snippet.Lines {
|
||||
currentLine := err.Snippet.StartLine + i + 1
|
||||
|
||||
lineIndicator := " "
|
||||
if currentLine == err.Line {
|
||||
lineIndicator = ">"
|
||||
}
|
||||
columnIndicator := "^"
|
||||
|
||||
// Print each line
|
||||
lineIndicator = color.RedString(lineIndicator)
|
||||
columnIndicator = color.RedString(columnIndicator)
|
||||
lineNumberFormat := fmt.Sprintf("%%%dd", maxLineNumberDigits)
|
||||
lineNumber := fmt.Sprintf(lineNumberFormat, currentLine)
|
||||
fmt.Fprintf(buf, "%s %s | %s", lineIndicator, lineNumber, line)
|
||||
|
||||
// Print the column indicator
|
||||
if currentLine == err.Line {
|
||||
fmt.Fprintf(buf, "\n %s | %s%s", lineNumberSpacer, columnSpacer, columnIndicator)
|
||||
}
|
||||
|
||||
// If there are more lines to print, add a newline
|
||||
if i < len(err.Snippet.Lines)-1 {
|
||||
fmt.Fprintln(buf)
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (err *TaskfileDecodeError) Unwrap() error {
|
||||
return err.Err
|
||||
}
|
||||
|
||||
func (err *TaskfileDecodeError) Code() int {
|
||||
return CodeTaskfileDecode
|
||||
}
|
||||
|
||||
func (err *TaskfileDecodeError) WithMessage(format string, a ...any) *TaskfileDecodeError {
|
||||
err.Message = fmt.Sprintf(format, a...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (err *TaskfileDecodeError) WithTypeMessage(t string) *TaskfileDecodeError {
|
||||
err.Message = fmt.Sprintf("cannot unmarshal %s into %s", err.Tag, t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (err *TaskfileDecodeError) WithFileInfo(location string, b []byte, padding int) *TaskfileDecodeError {
|
||||
buf := &bytes.Buffer{}
|
||||
if err := quick.Highlight(buf, string(b), "yaml", "terminal", "task"); err != nil {
|
||||
buf.WriteString(string(b))
|
||||
}
|
||||
lines := strings.Split(buf.String(), "\n")
|
||||
start := max(err.Line-1-padding, 0)
|
||||
end := min(err.Line+padding, len(lines)-1)
|
||||
|
||||
err.Location = location
|
||||
err.Snippet = TaskfileSnippet{
|
||||
Lines: lines[start:end],
|
||||
StartLine: start,
|
||||
EndLine: end,
|
||||
Padding: padding,
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func extractTypeErrorMessage(message string) string {
|
||||
matches := typeErrorRegex.FindStringSubmatch(message)
|
||||
if len(matches) == 2 {
|
||||
return matches[1]
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func digits(number int) int {
|
||||
count := 0
|
||||
for number != 0 {
|
||||
number /= 10
|
||||
count += 1
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -12,14 +12,14 @@ const (
|
||||
const (
|
||||
CodeTaskfileNotFound int = iota + 100
|
||||
CodeTaskfileAlreadyExists
|
||||
CodeTaskfileInvalid
|
||||
CodeTaskfileDecode
|
||||
CodeTaskfileFetchFailed
|
||||
CodeTaskfileNotTrusted
|
||||
CodeTaskfileNotSecure
|
||||
CodeTaskfileCacheNotFound
|
||||
CodeTaskfileVersionCheckError
|
||||
CodeTaskfileNetworkTimeout
|
||||
_ // CodeTaskfileDuplicateInclude
|
||||
CodeTaskfileInvalid
|
||||
CodeTaskfileCycle
|
||||
)
|
||||
|
||||
@@ -58,3 +58,8 @@ func Is(err, target error) bool {
|
||||
func As(err error, target any) bool {
|
||||
return errors.As(err, target)
|
||||
}
|
||||
|
||||
// Unwrap wraps the standard errors.Unwrap function so that we don't need to alias that package.
|
||||
func Unwrap(err error) error {
|
||||
return errors.Unwrap(err)
|
||||
}
|
||||
|
||||
17
errors/themes/task.xml
Normal file
17
errors/themes/task.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<style name="task">
|
||||
<entry type="Background" style="bg:#eee8d5"/>
|
||||
<entry type="Keyword" style="#859900"/>
|
||||
<entry type="KeywordConstant" style=""/>
|
||||
<entry type="KeywordNamespace" style="#dc322f"/>
|
||||
<entry type="KeywordType" style=""/>
|
||||
<entry type="Name" style="#268bd2"/>
|
||||
<entry type="NameBuiltin" style="#cb4b16"/>
|
||||
<entry type="NameClass" style="#cb4b16"/>
|
||||
<entry type="NameTag" style=""/>
|
||||
<entry type="Literal" style="#2aa198"/>
|
||||
<entry type="LiteralNumber" style=""/>
|
||||
<entry type="OperatorWord" style="#859900"/>
|
||||
<entry type="Comment" style="italic #93a1a1"/>
|
||||
<entry type="Generic" style="#d33682"/>
|
||||
<entry type="Text" style="#586e75"/>
|
||||
</style>
|
||||
11
go.mod
11
go.mod
@@ -3,12 +3,14 @@ module github.com/go-task/task/v3
|
||||
go 1.21.0
|
||||
|
||||
require (
|
||||
github.com/Ladicle/tabwriter v1.0.0
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/alecthomas/chroma/v2 v2.14.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/dominikbraun/graph v0.23.0
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/fatih/color v1.17.0
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0
|
||||
github.com/go-task/template v0.0.0-20240422130016-8f6b279b1e90
|
||||
github.com/go-task/template v0.0.0-20240602015157-960e6f576656
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mattn/go-zglob v0.0.4
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
@@ -19,17 +21,18 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/zeebo/xxh3 v1.0.2
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/term v0.19.0
|
||||
golang.org/x/term v0.21.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
mvdan.cc/sh/v3 v3.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/dlclark/regexp2 v1.11.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
)
|
||||
|
||||
28
go.sum
28
go.sum
@@ -1,21 +1,33 @@
|
||||
github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg=
|
||||
github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
|
||||
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
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/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
|
||||
github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-task/template v0.0.0-20240422130016-8f6b279b1e90 h1:JBbiZ2CXIZ9Upe3O2yI5+3ksWoa7hNVNi4BINs8TIrs=
|
||||
github.com/go-task/template v0.0.0-20240422130016-8f6b279b1e90/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k=
|
||||
github.com/go-task/template v0.0.0-20240602015157-960e6f576656 h1:knZZ4zVdTBQnevBz0zSES++4Mr7wr+cHopLvHabIgkA=
|
||||
github.com/go-task/template v0.0.0-20240602015157-960e6f576656/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
@@ -59,10 +71,10 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
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=
|
||||
|
||||
7
hash.go
7
hash.go
@@ -4,15 +4,12 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-task/task/v3/internal/hash"
|
||||
"github.com/go-task/task/v3/internal/slicesext"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
func (e *Executor) GetHash(t *ast.Task) (string, error) {
|
||||
r := t.Run
|
||||
if r == "" {
|
||||
r = e.Taskfile.Run
|
||||
}
|
||||
|
||||
r := slicesext.FirstNonZero(t.Run, e.Taskfile.Run)
|
||||
var h hash.HashFunc
|
||||
switch r {
|
||||
case "always":
|
||||
|
||||
7
help.go
7
help.go
@@ -7,8 +7,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/Ladicle/tabwriter"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/go-task/task/v3/internal/editors"
|
||||
@@ -105,7 +105,8 @@ func (e *Executor) ListTasks(o ListOptions) (bool, error) {
|
||||
for _, task := range tasks {
|
||||
e.Logger.FOutf(w, logger.Yellow, "* ")
|
||||
e.Logger.FOutf(w, logger.Green, task.Task)
|
||||
e.Logger.FOutf(w, logger.Default, ": \t%s", task.Desc)
|
||||
desc := strings.ReplaceAll(task.Desc, "\n", " ")
|
||||
e.Logger.FOutf(w, logger.Default, ": \t%s", desc)
|
||||
if len(task.Aliases) > 0 {
|
||||
e.Logger.FOutf(w, logger.Cyan, "\t(aliases: %s)", strings.Join(task.Aliases, ", "))
|
||||
}
|
||||
@@ -190,7 +191,7 @@ func (e *Executor) ToEditorOutput(tasks []*ast.Task, noStatus bool) (*editors.Ta
|
||||
}
|
||||
upToDate, err := fingerprint.IsTaskUpToDate(context.Background(), task,
|
||||
fingerprint.WithMethod(method),
|
||||
fingerprint.WithTempDir(e.TempDir),
|
||||
fingerprint.WithTempDir(e.TempDir.Fingerprint),
|
||||
fingerprint.WithDry(e.Dry),
|
||||
fingerprint.WithLogger(e.Logger),
|
||||
)
|
||||
|
||||
@@ -3,14 +3,12 @@ package compiler
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
@@ -77,18 +75,6 @@ func (c *Compiler) getVariables(t *ast.Task, call *ast.Call, evaluateShVars bool
|
||||
if err := cache.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Evaluate JSON
|
||||
if newVar.Json != "" {
|
||||
if err := json.Unmarshal([]byte(newVar.Json), &newVar.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Evaluate YAML
|
||||
if newVar.Yaml != "" {
|
||||
if err := yaml.Unmarshal([]byte(newVar.Yaml), &newVar.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// If the variable is not dynamic, we can set it and return
|
||||
if newVar.Value != nil || newVar.Sh == "" {
|
||||
result.Set(k, ast.Var{Value: newVar.Value})
|
||||
@@ -196,6 +182,7 @@ func (c *Compiler) ResetCache() {
|
||||
func (c *Compiler) getSpecialVars(t *ast.Task) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"TASK": t.Task,
|
||||
"TASK_EXE": filepath.ToSlash(os.Args[0]),
|
||||
"ROOT_TASKFILE": filepathext.SmartJoin(c.Dir, c.Entrypoint),
|
||||
"ROOT_DIR": c.Dir,
|
||||
"TASKFILE": t.Location.Taskfile,
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/Ladicle/tabwriter"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ var (
|
||||
Experiments bool
|
||||
Download bool
|
||||
Offline bool
|
||||
ClearCache bool
|
||||
Timeout time.Duration
|
||||
)
|
||||
|
||||
@@ -119,6 +120,7 @@ func init() {
|
||||
pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.")
|
||||
pflag.BoolVar(&Offline, "offline", false, "Forces Task to only use local or cached Taskfiles.")
|
||||
pflag.DurationVar(&Timeout, "timeout", time.Second*10, "Timeout for downloading remote Taskfiles.")
|
||||
pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.")
|
||||
}
|
||||
|
||||
pflag.Parse()
|
||||
@@ -129,6 +131,10 @@ func Validate() error {
|
||||
return errors.New("task: You can't set both --download and --offline flags")
|
||||
}
|
||||
|
||||
if Download && ClearCache {
|
||||
return errors.New("task: You can't set both --download and --clear-cache flags")
|
||||
}
|
||||
|
||||
if Global && Dir != "" {
|
||||
log.Fatal("task: You can't set both --global and --dir")
|
||||
return nil
|
||||
|
||||
@@ -15,7 +15,7 @@ func Empty(*ast.Task) (string, error) {
|
||||
}
|
||||
|
||||
func Name(t *ast.Task) (string, error) {
|
||||
return t.Task, nil
|
||||
return fmt.Sprintf("%s:%s", t.Location.Taskfile, t.LocalName()), nil
|
||||
}
|
||||
|
||||
func Hash(t *ast.Task) (string, error) {
|
||||
|
||||
@@ -52,6 +52,30 @@ func Red() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_RED", color.FgRed)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func BrightBlue() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BRIGHT_BLUE", color.FgHiBlue)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func BrightGreen() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BRIGHT_GREEN", color.FgHiGreen)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func BrightCyan() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BRIGHT_CYAN", color.FgHiCyan)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func BrightYellow() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BRIGHT_YELLOW", color.FgHiYellow)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func BrightMagenta() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BRIGHT_MAGENTA", color.FgHiMagenta)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func BrightRed() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BRIGHT_RED", color.FgHiRed)...).FprintfFunc()
|
||||
}
|
||||
|
||||
func envColor(env string, defaultColor color.Attribute) []color.Attribute {
|
||||
if os.Getenv("FORCE_COLOR") != "" {
|
||||
color.NoColor = false
|
||||
@@ -156,7 +180,7 @@ func (l *Logger) Prompt(color Color, prompt string, defaultValue string, continu
|
||||
return errors.New("no continue values provided")
|
||||
}
|
||||
|
||||
l.Outf(color, "%s [%s/%s]\n", prompt, strings.ToLower(continueValues[0]), strings.ToUpper(defaultValue))
|
||||
l.Outf(color, "%s [%s/%s]: ", prompt, strings.ToLower(continueValues[0]), strings.ToUpper(defaultValue))
|
||||
|
||||
reader := bufio.NewReader(l.Stdin)
|
||||
input, err := reader.ReadString('\n')
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
@@ -15,7 +16,7 @@ type Output interface {
|
||||
type CloseFunc func(err error) error
|
||||
|
||||
// Build the Output for the requested ast.Output.
|
||||
func BuildFor(o *ast.Output) (Output, error) {
|
||||
func BuildFor(o *ast.Output, logger *logger.Logger) (Output, error) {
|
||||
switch o.Name {
|
||||
case "interleaved", "":
|
||||
if err := checkOutputGroupUnset(o); err != nil {
|
||||
@@ -32,7 +33,7 @@ func BuildFor(o *ast.Output) (Output, error) {
|
||||
if err := checkOutputGroupUnset(o); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Prefixed{}, nil
|
||||
return NewPrefixed(logger), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`task: output style %q not recognized`, o.Name)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/omap"
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
@@ -107,7 +109,11 @@ func TestGroupErrorOnlyShowsOutputOnError(t *testing.T) {
|
||||
|
||||
func TestPrefixed(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
var o output.Output = output.Prefixed{}
|
||||
l := &logger.Logger{
|
||||
Color: false,
|
||||
}
|
||||
|
||||
var o output.Output = output.NewPrefixed(l)
|
||||
w, _, cleanup := o.WrapWriter(&b, io.Discard, "prefix", nil)
|
||||
|
||||
t.Run("simple use cases", func(t *testing.T) {
|
||||
@@ -132,3 +138,33 @@ func TestPrefixed(t *testing.T) {
|
||||
assert.Equal(t, "[prefix] Test!\n", b.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPrefixedWithColor(t *testing.T) {
|
||||
color.NoColor = false
|
||||
|
||||
var b bytes.Buffer
|
||||
l := &logger.Logger{
|
||||
Color: true,
|
||||
}
|
||||
|
||||
var o output.Output = output.NewPrefixed(l)
|
||||
|
||||
writers := make([]io.Writer, 16)
|
||||
for i := range writers {
|
||||
writers[i], _, _ = o.WrapWriter(&b, io.Discard, fmt.Sprintf("prefix-%d", i), nil)
|
||||
}
|
||||
|
||||
t.Run("colors should loop", func(t *testing.T) {
|
||||
for i, w := range writers {
|
||||
b.Reset()
|
||||
|
||||
color := output.PrefixColorSequence[i%len(output.PrefixColorSequence)]
|
||||
|
||||
var prefix bytes.Buffer
|
||||
l.FOutf(&prefix, color, fmt.Sprintf("prefix-%d", i))
|
||||
|
||||
fmt.Fprintln(w, "foo\nbar")
|
||||
assert.Equal(t, fmt.Sprintf("[%s] foo\n[%s] bar\n", prefix.String(), prefix.String()), b.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,20 +6,36 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
)
|
||||
|
||||
type Prefixed struct{}
|
||||
type Prefixed struct {
|
||||
logger *logger.Logger
|
||||
seen map[string]uint
|
||||
counter *uint
|
||||
}
|
||||
|
||||
func (Prefixed) WrapWriter(stdOut, _ io.Writer, prefix string, _ *templater.Cache) (io.Writer, io.Writer, CloseFunc) {
|
||||
pw := &prefixWriter{writer: stdOut, prefix: prefix}
|
||||
func NewPrefixed(logger *logger.Logger) Prefixed {
|
||||
var counter uint
|
||||
|
||||
return Prefixed{
|
||||
seen: make(map[string]uint),
|
||||
counter: &counter,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (p Prefixed) WrapWriter(stdOut, _ io.Writer, prefix string, _ *templater.Cache) (io.Writer, io.Writer, CloseFunc) {
|
||||
pw := &prefixWriter{writer: stdOut, prefix: prefix, prefixed: &p}
|
||||
return pw, pw, func(error) error { return pw.close() }
|
||||
}
|
||||
|
||||
type prefixWriter struct {
|
||||
writer io.Writer
|
||||
prefix string
|
||||
buff bytes.Buffer
|
||||
writer io.Writer
|
||||
prefixed *Prefixed
|
||||
prefix string
|
||||
buff bytes.Buffer
|
||||
}
|
||||
|
||||
func (pw *prefixWriter) Write(p []byte) (int, error) {
|
||||
@@ -56,6 +72,11 @@ func (pw *prefixWriter) writeOutputLines(force bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
var PrefixColorSequence = []logger.Color{
|
||||
logger.Yellow, logger.Blue, logger.Magenta, logger.Cyan, logger.Green, logger.Red,
|
||||
logger.BrightYellow, logger.BrightBlue, logger.BrightMagenta, logger.BrightCyan, logger.BrightGreen, logger.BrightRed,
|
||||
}
|
||||
|
||||
func (pw *prefixWriter) writeLine(line string) error {
|
||||
if line == "" {
|
||||
return nil
|
||||
@@ -63,6 +84,27 @@ func (pw *prefixWriter) writeLine(line string) error {
|
||||
if !strings.HasSuffix(line, "\n") {
|
||||
line += "\n"
|
||||
}
|
||||
_, err := fmt.Fprintf(pw.writer, "[%s] %s", pw.prefix, line)
|
||||
|
||||
idx, ok := pw.prefixed.seen[pw.prefix]
|
||||
|
||||
if !ok {
|
||||
idx = *pw.prefixed.counter
|
||||
pw.prefixed.seen[pw.prefix] = idx
|
||||
|
||||
*pw.prefixed.counter++
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(pw.writer, "["); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
color := PrefixColorSequence[idx%uint(len(PrefixColorSequence))]
|
||||
pw.prefixed.logger.FOutf(pw.writer, color, pw.prefix)
|
||||
|
||||
if _, err := fmt.Fprint(pw.writer, "] "); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := fmt.Fprint(pw.writer, line)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,3 +18,13 @@ func UniqueJoin[T cmp.Ordered](ss ...[]T) []T {
|
||||
slices.Sort(r)
|
||||
return slices.Compact(r)
|
||||
}
|
||||
|
||||
func FirstNonZero[T comparable](values ...T) T {
|
||||
var zero T
|
||||
for _, v := range values {
|
||||
if v != zero {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return zero
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package templater
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"maps"
|
||||
"strings"
|
||||
|
||||
@@ -40,7 +41,15 @@ func ResolveRef(ref string, cache *Cache) any {
|
||||
cache.cacheMap = cache.Vars.ToCacheMap()
|
||||
}
|
||||
|
||||
val, err := template.ResolveRef(ref, cache.cacheMap)
|
||||
if ref == "." {
|
||||
return cache.cacheMap
|
||||
}
|
||||
t, err := template.New("resolver").Funcs(templateFuncs).Parse(fmt.Sprintf("{{%s}}", ref))
|
||||
if err != nil {
|
||||
cache.err = err
|
||||
return nil
|
||||
}
|
||||
val, err := t.Resolve(cache.cacheMap)
|
||||
if err != nil {
|
||||
cache.err = err
|
||||
return nil
|
||||
@@ -119,8 +128,6 @@ func ReplaceVarWithExtra(v ast.Var, cache *Cache, extra map[string]any) ast.Var
|
||||
Live: v.Live,
|
||||
Ref: v.Ref,
|
||||
Dir: v.Dir,
|
||||
Json: ReplaceWithExtra(v.Json, cache, extra),
|
||||
Yaml: ReplaceWithExtra(v.Yaml, cache, extra),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,21 +5,25 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var version = ""
|
||||
|
||||
func GetVersion() string {
|
||||
if version != "" {
|
||||
return version
|
||||
}
|
||||
var (
|
||||
version = ""
|
||||
sum = ""
|
||||
)
|
||||
|
||||
func init() {
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok || info.Main.Version == "" {
|
||||
return "unknown"
|
||||
version = "unknown"
|
||||
} else {
|
||||
version = info.Main.Version
|
||||
sum = info.Main.Sum
|
||||
}
|
||||
|
||||
ver := info.Main.Version
|
||||
if info.Main.Sum != "" {
|
||||
ver += fmt.Sprintf(" (%s)", info.Main.Sum)
|
||||
}
|
||||
return ver
|
||||
}
|
||||
|
||||
func GetVersion() string {
|
||||
return version
|
||||
}
|
||||
|
||||
func GetVersionWithSum() string {
|
||||
return fmt.Sprintf("%s (%s)", version, sum)
|
||||
}
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@go-task/cli",
|
||||
"version": "3.37.1",
|
||||
"version": "3.38.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@go-task/cli",
|
||||
"version": "3.37.1",
|
||||
"version": "3.38.0",
|
||||
"description": "A task runner / simpler Make alternative written in Go",
|
||||
"scripts": {
|
||||
"postinstall": "go-npm install",
|
||||
|
||||
34
setup.go
34
setup.go
@@ -69,7 +69,7 @@ func (e *Executor) readTaskfile(node taskfile.Node) error {
|
||||
e.Download,
|
||||
e.Offline,
|
||||
e.Timeout,
|
||||
e.TempDir,
|
||||
e.TempDir.Remote,
|
||||
e.Logger,
|
||||
)
|
||||
graph, err := reader.Read()
|
||||
@@ -104,12 +104,15 @@ func (e *Executor) setupFuzzyModel() {
|
||||
}
|
||||
|
||||
func (e *Executor) setupTempDir() error {
|
||||
if e.TempDir != "" {
|
||||
if e.TempDir != (TempDir{}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if os.Getenv("TASK_TEMP_DIR") == "" {
|
||||
e.TempDir = filepathext.SmartJoin(e.Dir, ".task")
|
||||
e.TempDir = TempDir{
|
||||
Remote: filepathext.SmartJoin(e.Dir, ".task"),
|
||||
Fingerprint: filepathext.SmartJoin(e.Dir, ".task"),
|
||||
}
|
||||
} else if filepath.IsAbs(os.Getenv("TASK_TEMP_DIR")) || strings.HasPrefix(os.Getenv("TASK_TEMP_DIR"), "~") {
|
||||
tempDir, err := execext.Expand(os.Getenv("TASK_TEMP_DIR"))
|
||||
if err != nil {
|
||||
@@ -117,9 +120,28 @@ func (e *Executor) setupTempDir() error {
|
||||
}
|
||||
projectDir, _ := filepath.Abs(e.Dir)
|
||||
projectName := filepath.Base(projectDir)
|
||||
e.TempDir = filepathext.SmartJoin(tempDir, projectName)
|
||||
e.TempDir = TempDir{
|
||||
Remote: tempDir,
|
||||
Fingerprint: filepathext.SmartJoin(tempDir, projectName),
|
||||
}
|
||||
|
||||
} else {
|
||||
e.TempDir = filepathext.SmartJoin(e.Dir, os.Getenv("TASK_TEMP_DIR"))
|
||||
e.TempDir = TempDir{
|
||||
Remote: filepathext.SmartJoin(e.Dir, os.Getenv("TASK_TEMP_DIR")),
|
||||
Fingerprint: filepathext.SmartJoin(e.Dir, os.Getenv("TASK_TEMP_DIR")),
|
||||
}
|
||||
}
|
||||
|
||||
if os.Getenv("TASK_REMOTE_DIR") != "" {
|
||||
if filepath.IsAbs(os.Getenv("TASK_TEMP_DIR")) || strings.HasPrefix(os.Getenv("TASK_TEMP_DIR"), "~") {
|
||||
remoteTempDir, err := execext.Expand(filepathext.SmartJoin(e.Dir, ".task"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.TempDir.Remote = remoteTempDir
|
||||
} else {
|
||||
e.TempDir.Remote = filepathext.SmartJoin(e.Dir, ".task")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -155,7 +177,7 @@ func (e *Executor) setupOutput() error {
|
||||
}
|
||||
|
||||
var err error
|
||||
e.Output, err = output.BuildFor(&e.OutputStyle)
|
||||
e.Output, err = output.BuildFor(&e.OutputStyle, e.Logger)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ func (e *Executor) Status(ctx context.Context, calls ...*ast.Call) error {
|
||||
// Check if the task is up-to-date
|
||||
isUpToDate, err := fingerprint.IsTaskUpToDate(ctx, t,
|
||||
fingerprint.WithMethod(method),
|
||||
fingerprint.WithTempDir(e.TempDir),
|
||||
fingerprint.WithTempDir(e.TempDir.Fingerprint),
|
||||
fingerprint.WithDry(e.Dry),
|
||||
fingerprint.WithLogger(e.Logger),
|
||||
)
|
||||
@@ -46,7 +46,7 @@ func (e *Executor) statusOnError(t *ast.Task) error {
|
||||
if method == "" {
|
||||
method = e.Taskfile.Method
|
||||
}
|
||||
checker, err := fingerprint.NewSourcesChecker(method, e.TempDir, e.Dry)
|
||||
checker, err := fingerprint.NewSourcesChecker(method, e.TempDir.Fingerprint, e.Dry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
29
task.go
29
task.go
@@ -34,13 +34,18 @@ const (
|
||||
MaximumTaskCall = 1000
|
||||
)
|
||||
|
||||
type TempDir struct {
|
||||
Remote string
|
||||
Fingerprint string
|
||||
}
|
||||
|
||||
// Executor executes a Taskfile
|
||||
type Executor struct {
|
||||
Taskfile *ast.Taskfile
|
||||
|
||||
Dir string
|
||||
Entrypoint string
|
||||
TempDir string
|
||||
TempDir TempDir
|
||||
Force bool
|
||||
ForceAll bool
|
||||
Insecure bool
|
||||
@@ -183,16 +188,6 @@ func (e *Executor) RunTask(ctx context.Context, call *ast.Call) error {
|
||||
release := e.acquireConcurrencyLimit()
|
||||
defer release()
|
||||
|
||||
if t.Prompt != "" {
|
||||
if err := e.Logger.Prompt(logger.Yellow, t.Prompt, "n", "y", "yes"); errors.Is(err, logger.ErrNoTerminal) {
|
||||
return &errors.TaskCancelledNoTerminalError{TaskName: call.Task}
|
||||
} else if errors.Is(err, logger.ErrPromptCancelled) {
|
||||
return &errors.TaskCancelledByUserError{TaskName: call.Task}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return e.startExecution(ctx, t, func(ctx context.Context) error {
|
||||
e.Logger.VerboseErrf(logger.Magenta, "task: %q started\n", call.Task)
|
||||
if err := e.runDeps(ctx, t); err != nil {
|
||||
@@ -222,7 +217,7 @@ func (e *Executor) RunTask(ctx context.Context, call *ast.Call) error {
|
||||
|
||||
upToDate, err := fingerprint.IsTaskUpToDate(ctx, t,
|
||||
fingerprint.WithMethod(method),
|
||||
fingerprint.WithTempDir(e.TempDir),
|
||||
fingerprint.WithTempDir(e.TempDir.Fingerprint),
|
||||
fingerprint.WithDry(e.Dry),
|
||||
fingerprint.WithLogger(e.Logger),
|
||||
)
|
||||
@@ -238,6 +233,16 @@ func (e *Executor) RunTask(ctx context.Context, call *ast.Call) error {
|
||||
}
|
||||
}
|
||||
|
||||
if t.Prompt != "" && !e.Dry {
|
||||
if err := e.Logger.Prompt(logger.Yellow, t.Prompt, "n", "y", "yes"); errors.Is(err, logger.ErrNoTerminal) {
|
||||
return &errors.TaskCancelledNoTerminalError{TaskName: call.Task}
|
||||
} else if errors.Is(err, logger.ErrPromptCancelled) {
|
||||
return &errors.TaskCancelledByUserError{TaskName: call.Task}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := e.mkdir(t); err != nil {
|
||||
e.Logger.Errf(logger.Red, "task: cannot make directory %q: %v\n", t.Dir, err)
|
||||
}
|
||||
|
||||
153
task_test.go
153
task_test.go
@@ -62,8 +62,11 @@ func (fct fileContentTest) Run(t *testing.T) {
|
||||
}
|
||||
|
||||
e := &task.Executor{
|
||||
Dir: fct.Dir,
|
||||
TempDir: filepathext.SmartJoin(fct.Dir, ".task"),
|
||||
Dir: fct.Dir,
|
||||
TempDir: task.TempDir{
|
||||
Remote: filepathext.SmartJoin(fct.Dir, ".task"),
|
||||
Fingerprint: filepathext.SmartJoin(fct.Dir, ".task"),
|
||||
},
|
||||
Entrypoint: fct.Entrypoint,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
@@ -95,6 +98,15 @@ func TestEmptyTask(t *testing.T) {
|
||||
require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "default"}))
|
||||
}
|
||||
|
||||
func TestEmptyTaskfile(t *testing.T) {
|
||||
e := &task.Executor{
|
||||
Dir: "testdata/empty_taskfile",
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
}
|
||||
require.Error(t, e.Setup(), "e.Setup()")
|
||||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Dir: "testdata/env",
|
||||
@@ -263,11 +275,14 @@ func TestStatus(t *testing.T) {
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := &task.Executor{
|
||||
Dir: dir,
|
||||
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
Dir: dir,
|
||||
TempDir: task.TempDir{
|
||||
Remote: filepathext.SmartJoin(dir, ".task"),
|
||||
Fingerprint: filepathext.SmartJoin(dir, ".task"),
|
||||
},
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
require.NoError(t, e.Setup())
|
||||
// gen-foo creates foo.txt, and will always fail it's status check.
|
||||
@@ -459,7 +474,10 @@ func TestStatusChecksum(t *testing.T) {
|
||||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
tempdir := filepathext.SmartJoin(dir, ".task")
|
||||
tempdir := task.TempDir{
|
||||
Remote: filepathext.SmartJoin(dir, ".task"),
|
||||
Fingerprint: filepathext.SmartJoin(dir, ".task"),
|
||||
}
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
TempDir: tempdir,
|
||||
@@ -476,7 +494,7 @@ func TestStatusChecksum(t *testing.T) {
|
||||
|
||||
// Capture the modification time, so we can ensure the checksum file
|
||||
// is not regenerated when the hash hasn't changed.
|
||||
s, err := os.Stat(filepathext.SmartJoin(tempdir, "checksum/"+test.task))
|
||||
s, err := os.Stat(filepathext.SmartJoin(tempdir.Fingerprint, "checksum/"+test.task))
|
||||
require.NoError(t, err)
|
||||
time := s.ModTime()
|
||||
|
||||
@@ -484,7 +502,7 @@ func TestStatusChecksum(t *testing.T) {
|
||||
require.NoError(t, e.Run(context.Background(), &ast.Call{Task: test.task}))
|
||||
assert.Equal(t, `task: Task "`+test.task+`" is up to date`+"\n", buff.String())
|
||||
|
||||
s, err = os.Stat(filepathext.SmartJoin(tempdir, "checksum/"+test.task))
|
||||
s, err = os.Stat(filepathext.SmartJoin(tempdir.Fingerprint, "checksum/"+test.task))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, time, s.ModTime())
|
||||
})
|
||||
@@ -805,8 +823,11 @@ func TestStatusVariables(t *testing.T) {
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||
Dir: dir,
|
||||
TempDir: task.TempDir{
|
||||
Remote: filepathext.SmartJoin(dir, ".task"),
|
||||
Fingerprint: filepathext.SmartJoin(dir, ".task"),
|
||||
},
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: false,
|
||||
@@ -954,11 +975,14 @@ func TestDryChecksum(t *testing.T) {
|
||||
_ = os.Remove(checksumFile)
|
||||
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
TempDir: filepathext.SmartJoin(dir, ".task"),
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
Dry: true,
|
||||
Dir: dir,
|
||||
TempDir: task.TempDir{
|
||||
Remote: filepathext.SmartJoin(dir, ".task"),
|
||||
Fingerprint: filepathext.SmartJoin(dir, ".task"),
|
||||
},
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
Dry: true,
|
||||
}
|
||||
require.NoError(t, e.Setup())
|
||||
require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "default"}))
|
||||
@@ -1033,7 +1057,7 @@ func TestIncludesIncorrect(t *testing.T) {
|
||||
|
||||
err := e.Setup()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "task: Failed to parse testdata/includes_incorrect/incomplete.yml:")
|
||||
assert.Contains(t, err.Error(), "Failed to parse testdata/includes_incorrect/incomplete.yml:", err.Error())
|
||||
}
|
||||
|
||||
func TestIncludesEmptyMain(t *testing.T) {
|
||||
@@ -1228,6 +1252,34 @@ func TestIncludesInterpolation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncludedTaskfileVarMerging(t *testing.T) {
|
||||
const dir = "testdata/included_taskfile_var_merging"
|
||||
tests := []struct {
|
||||
name string
|
||||
task string
|
||||
expectedOutput string
|
||||
}{
|
||||
{"foo", "foo:pwd", "included_taskfile_var_merging/foo\n"},
|
||||
{"bar", "bar:pwd", "included_taskfile_var_merging/bar\n"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
require.NoError(t, e.Setup())
|
||||
|
||||
err := e.Run(context.Background(), &ast.Call{Task: test.task})
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, buff.String(), test.expectedOutput)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInternalTask(t *testing.T) {
|
||||
const dir = "testdata/internal_task"
|
||||
tests := []struct {
|
||||
@@ -1627,6 +1679,26 @@ func TestRunOnlyRunsJobsHashOnce(t *testing.T) {
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestRunOnceSharedDeps(t *testing.T) {
|
||||
const dir = "testdata/run_once_shared_deps"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
ForceAll: true,
|
||||
}
|
||||
require.NoError(t, e.Setup())
|
||||
require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "build"}))
|
||||
|
||||
rx := regexp.MustCompile(`task: \[service-[a,b]:library:build\] echo "build library"`)
|
||||
matches := rx.FindAllStringSubmatch(buff.String(), -1)
|
||||
assert.Len(t, matches, 1)
|
||||
assert.Contains(t, buff.String(), `task: [service-a:build] echo "build a"`)
|
||||
assert.Contains(t, buff.String(), `task: [service-b:build] echo "build b"`)
|
||||
}
|
||||
|
||||
func TestDeferredCmds(t *testing.T) {
|
||||
const dir = "testdata/deferred"
|
||||
var buff bytes.Buffer
|
||||
@@ -2389,3 +2461,48 @@ func TestWildcard(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReference(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
call string
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
name: "reference in command",
|
||||
call: "ref-cmd",
|
||||
expectedOutput: "1\n",
|
||||
},
|
||||
{
|
||||
name: "reference in dependency",
|
||||
call: "ref-dep",
|
||||
expectedOutput: "1\n",
|
||||
},
|
||||
{
|
||||
name: "reference using templating resolver",
|
||||
call: "ref-resolver",
|
||||
expectedOutput: "1\n",
|
||||
},
|
||||
{
|
||||
name: "reference using templating resolver and dynamic var",
|
||||
call: "ref-resolver-sh",
|
||||
expectedOutput: "Alice has 3 children called Bob, Charlie, and Diane\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.call, func(t *testing.T) {
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: "testdata/var_references",
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
Force: true,
|
||||
}
|
||||
require.NoError(t, e.Setup())
|
||||
require.NoError(t, e.Run(context.Background(), &ast.Call{Task: test.call}))
|
||||
assert.Equal(t, test.expectedOutput, buff.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/deepcopy"
|
||||
)
|
||||
|
||||
@@ -46,7 +45,7 @@ func (c *Cmd) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var cmd string
|
||||
if err := node.Decode(&cmd); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
c.Cmd = cmd
|
||||
return nil
|
||||
@@ -110,8 +109,8 @@ func (c *Cmd) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: invalid keys in command", node.Line)
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage("invalid keys in command")
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into command", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("command")
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
)
|
||||
|
||||
// Dep is a task dependency
|
||||
@@ -32,7 +32,7 @@ func (d *Dep) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var task string
|
||||
if err := node.Decode(&task); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
d.Task = task
|
||||
return nil
|
||||
@@ -45,7 +45,7 @@ func (d *Dep) UnmarshalYAML(node *yaml.Node) error {
|
||||
Silent bool
|
||||
}
|
||||
if err := node.Decode(&taskCall); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
d.Task = taskCall.Task
|
||||
d.For = taskCall.For
|
||||
@@ -54,5 +54,5 @@ func (d *Dep) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot unmarshal %s into dependency", node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("dependency")
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/deepcopy"
|
||||
)
|
||||
|
||||
@@ -22,7 +21,7 @@ func (f *For) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var from string
|
||||
if err := node.Decode(&from); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
f.From = from
|
||||
return nil
|
||||
@@ -30,7 +29,7 @@ func (f *For) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.SequenceNode:
|
||||
var list []any
|
||||
if err := node.Decode(&list); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
f.List = list
|
||||
return nil
|
||||
@@ -41,17 +40,19 @@ func (f *For) UnmarshalYAML(node *yaml.Node) error {
|
||||
Split string
|
||||
As string
|
||||
}
|
||||
if err := node.Decode(&forStruct); err == nil && forStruct.Var != "" {
|
||||
f.Var = forStruct.Var
|
||||
f.Split = forStruct.Split
|
||||
f.As = forStruct.As
|
||||
return nil
|
||||
if err := node.Decode(&forStruct); err != nil {
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: invalid keys in for", node.Line)
|
||||
if forStruct.Var == "" {
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage("invalid keys in for")
|
||||
}
|
||||
f.Var = forStruct.Var
|
||||
f.Split = forStruct.Split
|
||||
f.As = forStruct.As
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into for", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("for")
|
||||
}
|
||||
|
||||
func (f *For) DeepCopy() *For {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
)
|
||||
|
||||
type Glob struct {
|
||||
@@ -13,20 +13,22 @@ type Glob struct {
|
||||
|
||||
func (g *Glob) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.ScalarNode:
|
||||
g.Glob = node.Value
|
||||
return nil
|
||||
|
||||
case yaml.MappingNode:
|
||||
var glob struct {
|
||||
Exclude string
|
||||
}
|
||||
if err := node.Decode(&glob); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
g.Glob = glob.Exclude
|
||||
g.Negate = true
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into task", node.Line, node.ShortTag())
|
||||
}
|
||||
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("glob")
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
omap "github.com/go-task/task/v3/internal/omap"
|
||||
)
|
||||
|
||||
@@ -38,7 +37,7 @@ func (includes *Includes) UnmarshalYAML(node *yaml.Node) error {
|
||||
|
||||
var v Include
|
||||
if err := valueNode.Decode(&v); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
v.Namespace = keyNode.Value
|
||||
includes.Set(keyNode.Value, &v)
|
||||
@@ -46,7 +45,7 @@ func (includes *Includes) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into included taskfiles", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("includes")
|
||||
}
|
||||
|
||||
// Len returns the length of the map
|
||||
@@ -71,7 +70,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var str string
|
||||
if err := node.Decode(&str); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
include.Taskfile = str
|
||||
return nil
|
||||
@@ -86,7 +85,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
||||
Vars *Vars
|
||||
}
|
||||
if err := node.Decode(&includedTaskfile); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
include.Taskfile = includedTaskfile.Taskfile
|
||||
include.Dir = includedTaskfile.Dir
|
||||
@@ -98,7 +97,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into included taskfile", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("include")
|
||||
}
|
||||
|
||||
// DeepCopy creates a new instance of IncludedTaskfile and copies
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
)
|
||||
|
||||
// Output of the Task output
|
||||
@@ -25,7 +25,7 @@ func (s *Output) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var name string
|
||||
if err := node.Decode(&name); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
s.Name = name
|
||||
return nil
|
||||
@@ -35,10 +35,10 @@ func (s *Output) UnmarshalYAML(node *yaml.Node) error {
|
||||
Group *OutputGroup
|
||||
}
|
||||
if err := node.Decode(&tmp); err != nil {
|
||||
return fmt.Errorf("task: output style must be a string or mapping with a \"group\" key: %w", err)
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
if tmp.Group == nil {
|
||||
return fmt.Errorf("task: output style must have the \"group\" key when in mapping form")
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage(`output style must have the "group" key when in mapping form`)
|
||||
}
|
||||
*s = Output{
|
||||
Name: "group",
|
||||
@@ -47,7 +47,7 @@ func (s *Output) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into output", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("output")
|
||||
}
|
||||
|
||||
// OutputGroup is the style options specific to the Group style.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/goext"
|
||||
)
|
||||
|
||||
@@ -30,7 +31,7 @@ type ErrInvalidPlatform struct {
|
||||
}
|
||||
|
||||
func (err *ErrInvalidPlatform) Error() string {
|
||||
return fmt.Sprintf(`task: Invalid platform "%s"`, err.Platform)
|
||||
return fmt.Sprintf(`invalid platform "%s"`, err.Platform)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler interface.
|
||||
@@ -39,14 +40,14 @@ func (p *Platform) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var platform string
|
||||
if err := node.Decode(&platform); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
if err := p.parsePlatform(platform); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into platform", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("platform")
|
||||
}
|
||||
|
||||
// parsePlatform takes a string representing an OS/Arch combination (or either on their own)
|
||||
|
||||
@@ -26,10 +26,10 @@ func TestPlatformParsing(t *testing.T) {
|
||||
{Input: "windows/amd64", ExpectedOS: "windows", ExpectedArch: "amd64"},
|
||||
{Input: "windows/arm64", ExpectedOS: "windows", ExpectedArch: "arm64"},
|
||||
|
||||
{Input: "invalid", Error: `task: Invalid platform "invalid"`},
|
||||
{Input: "invalid/invalid", Error: `task: Invalid platform "invalid/invalid"`},
|
||||
{Input: "windows/invalid", Error: `task: Invalid platform "windows/invalid"`},
|
||||
{Input: "invalid/amd64", Error: `task: Invalid platform "invalid/amd64"`},
|
||||
{Input: "invalid", Error: `invalid platform "invalid"`},
|
||||
{Input: "invalid/invalid", Error: `invalid platform "invalid/invalid"`},
|
||||
{Input: "windows/invalid", Error: `invalid platform "windows/invalid"`},
|
||||
{Input: "invalid/amd64", Error: `invalid platform "invalid/amd64"`},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// ErrCantUnmarshalPrecondition is returned for invalid precond YAML.
|
||||
var ErrCantUnmarshalPrecondition = errors.New("task: Can't unmarshal precondition value")
|
||||
"github.com/go-task/task/v3/errors"
|
||||
)
|
||||
|
||||
// Precondition represents a precondition necessary for a task to run
|
||||
type Precondition struct {
|
||||
@@ -33,7 +31,7 @@ func (p *Precondition) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var cmd string
|
||||
if err := node.Decode(&cmd); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
p.Sh = cmd
|
||||
p.Msg = fmt.Sprintf("`%s` failed", cmd)
|
||||
@@ -45,7 +43,7 @@ func (p *Precondition) UnmarshalYAML(node *yaml.Node) error {
|
||||
Msg string
|
||||
}
|
||||
if err := node.Decode(&sh); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
p.Sh = sh.Sh
|
||||
p.Msg = sh.Msg
|
||||
@@ -55,5 +53,5 @@ func (p *Precondition) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into precondition", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("precondition")
|
||||
}
|
||||
|
||||
@@ -7,42 +7,45 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/deepcopy"
|
||||
)
|
||||
|
||||
// Task represents a task
|
||||
type Task struct {
|
||||
Task string
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
Label string
|
||||
Desc string
|
||||
Prompt string
|
||||
Summary string
|
||||
Requires *Requires
|
||||
Aliases []string
|
||||
Sources []*Glob
|
||||
Generates []*Glob
|
||||
Status []string
|
||||
Preconditions []*Precondition
|
||||
Dir string
|
||||
Set []string
|
||||
Shopt []string
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Dotenv []string
|
||||
Silent bool
|
||||
Interactive bool
|
||||
Internal bool
|
||||
Method string
|
||||
Prefix string
|
||||
IgnoreError bool
|
||||
Run string
|
||||
Task string
|
||||
Cmds []*Cmd
|
||||
Deps []*Dep
|
||||
Label string
|
||||
Desc string
|
||||
Prompt string
|
||||
Summary string
|
||||
Requires *Requires
|
||||
Aliases []string
|
||||
Sources []*Glob
|
||||
Generates []*Glob
|
||||
Status []string
|
||||
Preconditions []*Precondition
|
||||
Dir string
|
||||
Set []string
|
||||
Shopt []string
|
||||
Vars *Vars
|
||||
Env *Vars
|
||||
Dotenv []string
|
||||
Silent bool
|
||||
Interactive bool
|
||||
Internal bool
|
||||
Method string
|
||||
Prefix string
|
||||
IgnoreError bool
|
||||
Run string
|
||||
Platforms []*Platform
|
||||
Watch bool
|
||||
Location *Location
|
||||
// Populated during merging
|
||||
Namespace string
|
||||
IncludeVars *Vars
|
||||
IncludedTaskfileVars *Vars
|
||||
Platforms []*Platform
|
||||
Location *Location
|
||||
Watch bool
|
||||
}
|
||||
|
||||
func (t *Task) Name() string {
|
||||
@@ -52,6 +55,13 @@ func (t *Task) Name() string {
|
||||
return t.Task
|
||||
}
|
||||
|
||||
func (t *Task) LocalName() string {
|
||||
name := t.Task
|
||||
name = strings.TrimPrefix(name, t.Namespace)
|
||||
name = strings.TrimPrefix(name, ":")
|
||||
return name
|
||||
}
|
||||
|
||||
// WildcardMatch will check if the given string matches the name of the Task and returns any wildcard values.
|
||||
func (t *Task) WildcardMatch(name string) (bool, []string) {
|
||||
// Convert the name into a regex string
|
||||
@@ -83,7 +93,7 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.ScalarNode:
|
||||
var cmd Cmd
|
||||
if err := node.Decode(&cmd); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
t.Cmds = append(t.Cmds, &cmd)
|
||||
return nil
|
||||
@@ -92,7 +102,7 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.SequenceNode:
|
||||
var cmds []*Cmd
|
||||
if err := node.Decode(&cmds); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
t.Cmds = cmds
|
||||
return nil
|
||||
@@ -130,11 +140,11 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
Watch bool
|
||||
}
|
||||
if err := node.Decode(&task); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
if task.Cmd != nil {
|
||||
if task.Cmds != nil {
|
||||
return fmt.Errorf("yaml: line %d: task cannot have both cmd and cmds", node.Line)
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage("task cannot have both cmd and cmds")
|
||||
}
|
||||
t.Cmds = []*Cmd{task.Cmd}
|
||||
} else {
|
||||
@@ -169,7 +179,7 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into task", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("task")
|
||||
}
|
||||
|
||||
// DeepCopy creates a new instance of Task and copies
|
||||
@@ -209,6 +219,7 @@ func (t *Task) DeepCopy() *Task {
|
||||
Platforms: deepcopy.Slice(t.Platforms),
|
||||
Location: t.Location.DeepCopy(),
|
||||
Requires: t.Requires.DeepCopy(),
|
||||
Namespace: t.Namespace,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
)
|
||||
|
||||
// NamespaceSeparator contains the character that separates namespaces
|
||||
@@ -77,7 +78,7 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
|
||||
Interval time.Duration
|
||||
}
|
||||
if err := node.Decode(&taskfile); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
tf.Version = taskfile.Version
|
||||
tf.Output = taskfile.Output
|
||||
@@ -101,5 +102,5 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into taskfile", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("taskfile")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/omap"
|
||||
)
|
||||
@@ -46,7 +47,7 @@ func (t *Tasks) FindMatchingTasks(call *Call) []*MatchingTask {
|
||||
}
|
||||
|
||||
func (t1 *Tasks) Merge(t2 Tasks, include *Include, includedTaskfileVars *Vars) {
|
||||
_ = t2.Range(func(k string, v *Task) error {
|
||||
_ = t2.Range(func(name string, v *Task) error {
|
||||
// We do a deep copy of the task struct here to ensure that no data can
|
||||
// be changed elsewhere once the taskfile is merged.
|
||||
task := v.DeepCopy()
|
||||
@@ -90,11 +91,12 @@ func (t1 *Tasks) Merge(t2 Tasks, include *Include, includedTaskfileVars *Vars) {
|
||||
task.IncludeVars = &Vars{}
|
||||
}
|
||||
task.IncludeVars.Merge(include.Vars, nil)
|
||||
task.IncludedTaskfileVars = includedTaskfileVars
|
||||
task.IncludedTaskfileVars = includedTaskfileVars.DeepCopy()
|
||||
}
|
||||
|
||||
// Add the task to the merged taskfile
|
||||
taskNameWithNamespace := taskNameWithNamespace(k, include.Namespace)
|
||||
taskNameWithNamespace := taskNameWithNamespace(name, include.Namespace)
|
||||
task.Namespace = include.Namespace
|
||||
task.Task = taskNameWithNamespace
|
||||
t1.Set(taskNameWithNamespace, task)
|
||||
|
||||
@@ -118,7 +120,7 @@ func (t *Tasks) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.MappingNode:
|
||||
tasks := omap.New[string, *Task]()
|
||||
if err := node.Decode(&tasks); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
@@ -150,7 +152,7 @@ func (t *Tasks) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("yaml: line %d: cannot unmarshal %s into tasks", node.Line, node.ShortTag())
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithTypeMessage("tasks")
|
||||
}
|
||||
|
||||
func taskNameWithNamespace(taskName string, namespace string) string {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/experiments"
|
||||
"github.com/go-task/task/v3/internal/omap"
|
||||
)
|
||||
@@ -83,8 +83,6 @@ type Var struct {
|
||||
Live any
|
||||
Sh string
|
||||
Ref string
|
||||
Json string
|
||||
Yaml string
|
||||
Dir string
|
||||
}
|
||||
|
||||
@@ -95,7 +93,7 @@ func (v *Var) UnmarshalYAML(node *yaml.Node) error {
|
||||
if experiments.MapVariables.Value == "1" {
|
||||
var value any
|
||||
if err := node.Decode(&value); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
// If the value is a string and it starts with $, then it's a shell command
|
||||
if str, ok := value.(string); ok {
|
||||
@@ -103,6 +101,10 @@ func (v *Var) UnmarshalYAML(node *yaml.Node) error {
|
||||
v.Sh = str
|
||||
return nil
|
||||
}
|
||||
if str, ok = strings.CutPrefix(str, "#"); ok {
|
||||
v.Ref = str
|
||||
return nil
|
||||
}
|
||||
}
|
||||
v.Value = value
|
||||
return nil
|
||||
@@ -114,30 +116,26 @@ func (v *Var) UnmarshalYAML(node *yaml.Node) error {
|
||||
case yaml.MappingNode:
|
||||
key := node.Content[0].Value
|
||||
switch key {
|
||||
case "sh", "ref", "map", "json", "yaml":
|
||||
case "sh", "ref", "map":
|
||||
var m struct {
|
||||
Sh string
|
||||
Ref string
|
||||
Map any
|
||||
Json string
|
||||
Yaml string
|
||||
Sh string
|
||||
Ref string
|
||||
Map any
|
||||
}
|
||||
if err := node.Decode(&m); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
v.Sh = m.Sh
|
||||
v.Ref = m.Ref
|
||||
v.Value = m.Map
|
||||
v.Json = m.Json
|
||||
v.Yaml = m.Yaml
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf(`yaml: line %d: %q is not a valid variable type. Try "sh", "ref", "map", "json", "yaml" or using a scalar value`, node.Line, key)
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage(`%q is not a valid variable type. Try "sh", "ref", "map" or using a scalar value`, key)
|
||||
}
|
||||
default:
|
||||
var value any
|
||||
if err := node.Decode(&value); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
v.Value = value
|
||||
return nil
|
||||
@@ -148,22 +146,27 @@ func (v *Var) UnmarshalYAML(node *yaml.Node) error {
|
||||
switch node.Kind {
|
||||
|
||||
case yaml.MappingNode:
|
||||
if len(node.Content) > 2 || node.Content[0].Value != "sh" {
|
||||
return fmt.Errorf(`task: line %d: maps cannot be assigned to variables`, node.Line)
|
||||
key := node.Content[0].Value
|
||||
switch key {
|
||||
case "sh", "ref":
|
||||
var m struct {
|
||||
Sh string
|
||||
Ref string
|
||||
}
|
||||
if err := node.Decode(&m); err != nil {
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
v.Sh = m.Sh
|
||||
v.Ref = m.Ref
|
||||
return nil
|
||||
default:
|
||||
return errors.NewTaskfileDecodeError(nil, node).WithMessage("maps cannot be assigned to variables")
|
||||
}
|
||||
var sh struct {
|
||||
Sh string
|
||||
}
|
||||
if err := node.Decode(&sh); err != nil {
|
||||
return err
|
||||
}
|
||||
v.Sh = sh.Sh
|
||||
return nil
|
||||
|
||||
default:
|
||||
var value any
|
||||
if err := node.Decode(&value); err != nil {
|
||||
return err
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
}
|
||||
v.Value = value
|
||||
return nil
|
||||
|
||||
@@ -50,9 +50,23 @@ func (c *Cache) key(node Node) string {
|
||||
}
|
||||
|
||||
func (c *Cache) cacheFilePath(node Node) string {
|
||||
return filepath.Join(c.dir, fmt.Sprintf("%s.yaml", c.key(node)))
|
||||
return c.filePath(node, "yaml")
|
||||
}
|
||||
|
||||
func (c *Cache) checksumFilePath(node Node) string {
|
||||
return filepath.Join(c.dir, fmt.Sprintf("%s.checksum", c.key(node)))
|
||||
return c.filePath(node, "checksum")
|
||||
}
|
||||
|
||||
func (c *Cache) filePath(node Node, suffix string) string {
|
||||
lastDir, filename := node.FilenameAndLastDir()
|
||||
prefix := filename
|
||||
// Means it's not "", nor "." nor "/", so it's a valid directory
|
||||
if len(lastDir) > 1 {
|
||||
prefix = fmt.Sprintf("%s-%s", lastDir, filename)
|
||||
}
|
||||
return filepath.Join(c.dir, fmt.Sprintf("%s.%s.%s", prefix, c.key(node), suffix))
|
||||
}
|
||||
|
||||
func (c *Cache) Clear() error {
|
||||
return os.RemoveAll(c.dir)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ type Node interface {
|
||||
Remote() bool
|
||||
ResolveEntrypoint(entrypoint string) (string, error)
|
||||
ResolveDir(dir string) (string, error)
|
||||
FilenameAndLastDir() (string, string)
|
||||
}
|
||||
|
||||
func NewRootNode(
|
||||
|
||||
@@ -112,3 +112,7 @@ func (node *FileNode) ResolveDir(dir string) (string, error) {
|
||||
entrypointDir := filepath.Dir(node.Entrypoint)
|
||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||
}
|
||||
|
||||
func (node *FileNode) FilenameAndLastDir() (string, string) {
|
||||
return "", filepath.Base(node.Entrypoint)
|
||||
}
|
||||
|
||||
@@ -110,3 +110,8 @@ func (node *HTTPNode) ResolveDir(dir string) (string, error) {
|
||||
entrypointDir := filepath.Dir(node.Dir())
|
||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||
}
|
||||
|
||||
func (node *HTTPNode) FilenameAndLastDir() (string, string) {
|
||||
dir, filename := filepath.Split(node.URL.Path)
|
||||
return filepath.Base(dir), filename
|
||||
}
|
||||
|
||||
@@ -72,3 +72,7 @@ func (node *StdinNode) ResolveDir(dir string) (string, error) {
|
||||
|
||||
return filepathext.SmartJoin(node.Dir(), path), nil
|
||||
}
|
||||
|
||||
func (node *StdinNode) FilenameAndLastDir() (string, string) {
|
||||
return "", "__stdin__"
|
||||
}
|
||||
|
||||
@@ -263,23 +263,33 @@ func (r *Reader) readNode(node Node) (*ast.Taskfile, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var t ast.Taskfile
|
||||
if err := yaml.Unmarshal(b, &t); err != nil {
|
||||
var tf ast.Taskfile
|
||||
if err := yaml.Unmarshal(b, &tf); err != nil {
|
||||
// Decode the taskfile and add the file info the any errors
|
||||
taskfileInvalidErr := &errors.TaskfileDecodeError{}
|
||||
if errors.As(err, &taskfileInvalidErr) {
|
||||
return nil, taskfileInvalidErr.WithFileInfo(node.Location(), b, 2)
|
||||
}
|
||||
return nil, &errors.TaskfileInvalidError{URI: filepathext.TryAbsToRel(node.Location()), Err: err}
|
||||
}
|
||||
|
||||
// Check that the Taskfile is set and has a schema version
|
||||
if tf.Version == nil {
|
||||
return nil, &errors.TaskfileVersionCheckError{URI: node.Location()}
|
||||
}
|
||||
|
||||
// Set the taskfile/task's locations
|
||||
t.Location = node.Location()
|
||||
for _, task := range t.Tasks.Values() {
|
||||
tf.Location = node.Location()
|
||||
for _, task := range tf.Tasks.Values() {
|
||||
// If the task is not defined, create a new one
|
||||
if task == nil {
|
||||
task = &ast.Task{}
|
||||
}
|
||||
// Set the location of the taskfile for each task
|
||||
if task.Location.Taskfile == "" {
|
||||
task.Location.Taskfile = t.Location
|
||||
task.Location.Taskfile = tf.Location
|
||||
}
|
||||
}
|
||||
|
||||
return &t, nil
|
||||
return &tf, nil
|
||||
}
|
||||
|
||||
13
testdata/desc/Taskfile.yml
vendored
Normal file
13
testdata/desc/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
version: 3
|
||||
tasks:
|
||||
build:
|
||||
aliases:
|
||||
- b
|
||||
desc: |
|
||||
Multi-line escription with alias which is super long long long long long long
|
||||
another line
|
||||
third line long long long long long long long long
|
||||
test:
|
||||
aliases:
|
||||
- t
|
||||
desc: Single line description with alias
|
||||
0
testdata/empty_taskfile/Taskfile.yml
vendored
Normal file
0
testdata/empty_taskfile/Taskfile.yml
vendored
Normal file
12
testdata/included_taskfile_var_merging/Taskfile.yaml
vendored
Normal file
12
testdata/included_taskfile_var_merging/Taskfile.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
version: "3"
|
||||
|
||||
includes:
|
||||
foo:
|
||||
taskfile: ./foo/Taskfile.yaml
|
||||
bar:
|
||||
taskfile: ./bar/Taskfile.yaml
|
||||
|
||||
tasks:
|
||||
stub:
|
||||
cmds:
|
||||
- echo 0
|
||||
11
testdata/included_taskfile_var_merging/bar/Taskfile.yaml
vendored
Normal file
11
testdata/included_taskfile_var_merging/bar/Taskfile.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: "3"
|
||||
|
||||
vars:
|
||||
DIR: bar
|
||||
|
||||
tasks:
|
||||
pwd:
|
||||
dir: ./{{ .DIR }}
|
||||
cmds:
|
||||
- echo "{{ .DIR }}"
|
||||
- pwd
|
||||
11
testdata/included_taskfile_var_merging/foo/Taskfile.yaml
vendored
Normal file
11
testdata/included_taskfile_var_merging/foo/Taskfile.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: "3"
|
||||
|
||||
vars:
|
||||
DIR: foo
|
||||
|
||||
tasks:
|
||||
pwd:
|
||||
dir: ./{{ .DIR }}
|
||||
cmds:
|
||||
- echo "{{ .DIR }}"
|
||||
- pwd
|
||||
11
testdata/run_once_shared_deps/Taskfile.yml
vendored
Normal file
11
testdata/run_once_shared_deps/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
service-a: ./service-a
|
||||
service-b: ./service-b
|
||||
|
||||
tasks:
|
||||
build:
|
||||
deps:
|
||||
- service-a:build
|
||||
- service-b:build
|
||||
9
testdata/run_once_shared_deps/library/Taskfile.yml
vendored
Normal file
9
testdata/run_once_shared_deps/library/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
run: once
|
||||
cmds:
|
||||
- echo "build library"
|
||||
sources:
|
||||
- src/**/*
|
||||
15
testdata/run_once_shared_deps/service-a/Taskfile.yml
vendored
Normal file
15
testdata/run_once_shared_deps/service-a/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
library:
|
||||
taskfile: ../library/Taskfile.yml
|
||||
dir: ../library
|
||||
|
||||
tasks:
|
||||
build:
|
||||
run: once
|
||||
deps: [library:build]
|
||||
cmds:
|
||||
- echo "build a"
|
||||
sources:
|
||||
- src/**/*
|
||||
1
testdata/run_once_shared_deps/service-a/src/imasource.go
vendored
Normal file
1
testdata/run_once_shared_deps/service-a/src/imasource.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package main
|
||||
15
testdata/run_once_shared_deps/service-b/Taskfile.yml
vendored
Normal file
15
testdata/run_once_shared_deps/service-b/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
library:
|
||||
taskfile: ../library/Taskfile.yml
|
||||
dir: ../library
|
||||
|
||||
tasks:
|
||||
build:
|
||||
run: once
|
||||
deps: [library:build]
|
||||
cmds:
|
||||
- echo "build b"
|
||||
sources:
|
||||
- src/**/*
|
||||
1
testdata/run_once_shared_deps/service-b/src/imasource.go
vendored
Normal file
1
testdata/run_once_shared_deps/service-b/src/imasource.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package main
|
||||
74
testdata/var_references/Taskfile.yml
vendored
Normal file
74
testdata/var_references/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
GLOBAL_VAR: [1, 2, 2, 2, 3, 3, 4, 5]
|
||||
|
||||
tasks:
|
||||
default:
|
||||
- task: ref-cmd
|
||||
- task: ref-dep
|
||||
- task: ref-resolver
|
||||
- task: ref-resolver-sh
|
||||
|
||||
ref-cmd:
|
||||
vars:
|
||||
VAR_REF:
|
||||
ref: .GLOBAL_VAR
|
||||
cmds:
|
||||
- task: print-first
|
||||
vars:
|
||||
VAR:
|
||||
ref: .VAR_REF
|
||||
|
||||
ref-dep:
|
||||
vars:
|
||||
VAR_REF:
|
||||
ref: .GLOBAL_VAR
|
||||
deps:
|
||||
- task: print-first
|
||||
vars:
|
||||
VAR:
|
||||
ref: .VAR_REF
|
||||
|
||||
ref-resolver:
|
||||
vars:
|
||||
VAR_REF:
|
||||
ref: .GLOBAL_VAR
|
||||
cmds:
|
||||
- task: print-var
|
||||
vars:
|
||||
VAR:
|
||||
ref: (index .VAR_REF 0)
|
||||
|
||||
ref-resolver-sh:
|
||||
vars:
|
||||
JSON_STRING:
|
||||
sh: echo '{"name":"Alice","age":30,"children":[{"name":"Bob","age":5},{"name":"Charlie","age":3},{"name":"Diane","age":1}]}'
|
||||
JSON:
|
||||
ref: "fromJson .JSON_STRING"
|
||||
VAR_REF:
|
||||
ref: .JSON
|
||||
cmds:
|
||||
- task: print-story
|
||||
vars:
|
||||
VAR:
|
||||
ref: .VAR_REF
|
||||
|
||||
print-var:
|
||||
cmds:
|
||||
- echo "{{.VAR}}"
|
||||
|
||||
print-first:
|
||||
cmds:
|
||||
- echo "{{index .VAR 0}}"
|
||||
|
||||
print-story:
|
||||
cmds:
|
||||
- >-
|
||||
echo "{{.VAR.name}} has {{len .VAR.children}} children called
|
||||
{{- $children := .VAR.children -}}
|
||||
{{- range $i, $child := $children -}}
|
||||
{{- if lt $i (sub (len $children) 1)}} {{$child.name -}},
|
||||
{{- else}} and {{$child.name -}}
|
||||
{{- end -}}
|
||||
{{- end -}}"
|
||||
15
testdata/vars/any2/Taskfile.yml
vendored
15
testdata/vars/any2/Taskfile.yml
vendored
@@ -10,7 +10,6 @@ tasks:
|
||||
- task: ref-dep
|
||||
- task: ref-resolver
|
||||
- task: json
|
||||
- task: yaml
|
||||
|
||||
map:
|
||||
vars:
|
||||
@@ -93,25 +92,13 @@ tasks:
|
||||
JSON_STRING:
|
||||
sh: cat example.json
|
||||
JSON:
|
||||
json: "{{.JSON_STRING}}"
|
||||
ref: "fromJson .JSON_STRING"
|
||||
cmds:
|
||||
- task: print-story
|
||||
vars:
|
||||
VAR:
|
||||
ref: .JSON
|
||||
|
||||
yaml:
|
||||
vars:
|
||||
YAML_STRING:
|
||||
sh: cat example.yaml
|
||||
YAML:
|
||||
yaml: "{{.YAML_STRING}}"
|
||||
cmds:
|
||||
- task: print-story
|
||||
vars:
|
||||
VAR:
|
||||
ref: .YAML
|
||||
|
||||
print-var:
|
||||
cmds:
|
||||
- echo "{{.VAR}}"
|
||||
|
||||
@@ -72,6 +72,7 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task,
|
||||
Location: origTask.Location,
|
||||
Requires: origTask.Requires,
|
||||
Watch: origTask.Watch,
|
||||
Namespace: origTask.Namespace,
|
||||
}
|
||||
new.Dir, err = execext.Expand(new.Dir)
|
||||
if err != nil {
|
||||
@@ -221,8 +222,8 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task,
|
||||
}
|
||||
|
||||
if len(origTask.Status) > 0 {
|
||||
timestampChecker := fingerprint.NewTimestampChecker(e.TempDir, e.Dry)
|
||||
checksumChecker := fingerprint.NewChecksumChecker(e.TempDir, e.Dry)
|
||||
timestampChecker := fingerprint.NewTimestampChecker(e.TempDir.Fingerprint, e.Dry)
|
||||
checksumChecker := fingerprint.NewChecksumChecker(e.TempDir.Fingerprint, e.Dry)
|
||||
|
||||
for _, checker := range []fingerprint.SourcesCheckable{timestampChecker, checksumChecker} {
|
||||
value, err := checker.Value(&new)
|
||||
|
||||
@@ -103,7 +103,7 @@ tasks:
|
||||
|
||||
You can use any of the following list-based functions: `first`, `rest`, `last`,
|
||||
`initial`, `append`, `prepend`, `concat`, `reverse`, `uniq`, `without`, `has`,
|
||||
`compact`, `slice` and `chunk`. Check out the [slim-sprg lists
|
||||
`compact`, `slice` and `chunk`. Check out the [slim-sprig lists
|
||||
documentation][slim-sprig-list] for more information.
|
||||
|
||||
### Looping over variables using `for`
|
||||
|
||||
@@ -2,3 +2,5 @@ export const GITHUB_URL = 'https://github.com/go-task/task';
|
||||
export const TWITTER_URL = 'https://twitter.com/taskfiledev';
|
||||
export const MASTODON_URL = 'https://fosstodon.org/@task';
|
||||
export const DISCORD_URL = 'https://discord.gg/6TY36E39UK';
|
||||
export const STACK_OVERFLOW = 'https://stackoverflow.com/questions/tagged/taskfile';
|
||||
export const ANSWER_OVERFLOW = 'https://www.answeroverflow.com/c/974121106208354339';
|
||||
|
||||
@@ -5,6 +5,50 @@ sidebar_position: 14
|
||||
|
||||
# Changelog
|
||||
|
||||
## v3.38.0 - 2024-06-30
|
||||
|
||||
- Added `TASK_EXE` special variable (#1616, #1624 by @pd93 and @andreynering).
|
||||
- Some YAML parsing errors will now show in a more user friendly way (#1619 by
|
||||
@pd93).
|
||||
- Prefixed outputs will now be colorized by default (#1572 by
|
||||
@AlexanderArvidsson)
|
||||
- [References](https://taskfile.dev/usage/#referencing-other-variables) are now
|
||||
generally available (no experiments required) (#1654 by @pd93).
|
||||
- Templating functions can now be used in references (#1645, #1654 by @pd93).
|
||||
- Added a new
|
||||
[templating reference page](https://taskfile.dev/reference/templating/) to the
|
||||
documentation (#1614, #1653 by @pd93).
|
||||
- If using the
|
||||
[Map Variables experiment (1)](https://taskfile.dev/experiments/map-variables/?proposal=1),
|
||||
references are available by
|
||||
[prefixing a string with a `#`](https://taskfile.dev/experiments/map-variables/?proposal=1#references)
|
||||
(#1654 by @pd93).
|
||||
- If using the
|
||||
[Map Variables experiment (2)](https://taskfile.dev/experiments/map-variables/?proposal=2),
|
||||
the `yaml` and `json` keys are no longer available (#1654 by @pd93).
|
||||
- Added a new `TASK_REMOTE_DIR` environment variable to configure where cached
|
||||
remote Taskfiles are stored (#1661 by @vmaerten).
|
||||
- Added a new `--clear-cache` flag to clear the cache of remote Taskfiles (#1639
|
||||
by @vmaerten).
|
||||
- Improved the readability of cached remote Taskfile filenames (#1636 by
|
||||
@vmaerten).
|
||||
- Starting releasing a binary for the `riscv64` architecture on Linux (#1699 by
|
||||
@mengzhuo).
|
||||
- Added `CLI_SILENT` and `CLI_VERBOSE` variables (#1480, #1669 by @Vince-Smith).
|
||||
- Fixed a couple of bugs with the `prompt:` feature (#1657 by @pd93).
|
||||
- Fixed JSON Schema to disallow invalid properties (#1657 by @pd93).
|
||||
- Fixed version checks not working as intended (#872, #1663 by @vmaerten).
|
||||
- Fixed a bug where included tasks were run multiple times even if `run: once`
|
||||
was set (#852, #1655 by @pd93).
|
||||
- Fixed some bugs related to column formatting in the terminal (#1350, #1637,
|
||||
#1656 by @vmaerten).
|
||||
|
||||
## v3.37.2 - 2024-05-12
|
||||
|
||||
- Fixed a bug where an empty Taskfile would cause a panic (#1648 by @pd93).
|
||||
- Fixed a bug where includes Taskfile variable were not being merged correctly
|
||||
(#1643, #1649 by @pd93).
|
||||
|
||||
## v3.37.1 - 2024-05-09
|
||||
|
||||
- Fix bug where non-string values (numbers, bools) added to `env:` weren't been
|
||||
@@ -19,7 +63,7 @@ sidebar_position: 14
|
||||
- Refactored how Task reads, parses and merges Taskfiles using a DAG (#1563,
|
||||
#1607 by @pd93).
|
||||
- Fix a bug which stopped tasks from using `stdin` as input (#1593, #1623 by
|
||||
@pd03).
|
||||
@pd93).
|
||||
- Fix error when a file or directory in the project contained a special char
|
||||
like `&`, `(` or `)` (#1551, #1584 by @andreynering).
|
||||
- Added alias `q` for template function `shellQuote` (#1601, #1603 by @vergenzt)
|
||||
|
||||
@@ -148,6 +148,8 @@ If you have questions, feel free to ask them in the `#help` forum channel on our
|
||||
---
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[experiments]: /experiments
|
||||
[experiments-workflow]: /experiments#workflow
|
||||
[task]: https://github.com/go-task/task
|
||||
[vscode-task]: https://github.com/go-task/vscode-task
|
||||
[go]: https://go.dev
|
||||
|
||||
23
website/docs/deprecations/template_functions.mdx
Normal file
23
website/docs/deprecations/template_functions.mdx
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
slug: /deprecations/template-functions/
|
||||
---
|
||||
|
||||
# Template Functions
|
||||
|
||||
:::warning
|
||||
|
||||
This deprecation breaks the following functionality:
|
||||
|
||||
- A small set of templating functions
|
||||
|
||||
:::
|
||||
|
||||
The following templating functions are deprecated. Any replacement functions are
|
||||
listed besides the function being removed.
|
||||
|
||||
| Deprecated function | Replaced by |
|
||||
| ------------------- | ----------- |
|
||||
| `IsSH` | - |
|
||||
| `FromSlash` | `fromSlash` |
|
||||
| `ToSlash` | `toSlash` |
|
||||
| `ExeExt` | `exeExt` |
|
||||
@@ -43,9 +43,9 @@ To enable this experiment, set the environment variable:
|
||||
|
||||
:::
|
||||
|
||||
This proposal removes support for the `sh` keyword in favour of a new syntax for
|
||||
dynamically defined variables, This allows you to define a map directly as you
|
||||
would for any other type:
|
||||
This proposal removes support for the `sh` and `ref` keywords in favour of a new
|
||||
syntax for dynamically defined variables and references. This allows you to
|
||||
define a map directly as you would for any other type:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -60,11 +60,26 @@ tasks:
|
||||
|
||||
## Migration
|
||||
|
||||
Taskfiles with dynamically defined variables via the `sh` subkey will no longer
|
||||
work with this experiment enabled. In order to keep using dynamically defined
|
||||
variables, you will need to migrate your Taskfile to use the new syntax.
|
||||
Taskfiles with dynamically defined variables via the `sh` subkey or references
|
||||
defined with `ref` will no longer work with this experiment enabled. In order to
|
||||
keep using these features, you will need to migrate your Taskfile to use the new
|
||||
syntax.
|
||||
|
||||
Previously, you might have defined a dynamic variable like this:
|
||||
### Dynamic Variables
|
||||
|
||||
Previously, you had to define dynamic variables using the `sh` subkey. With this
|
||||
experiment enabled, you will need to remove the `sh` subkey and define your
|
||||
command as a string that begins with a `$`. This will instruct Task to interpret
|
||||
the string as a command instead of a literal value and the variable will be
|
||||
populated with the output of the command. For example:
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -78,10 +93,8 @@ tasks:
|
||||
- 'echo {{.CALCULATED_VAR}}'
|
||||
```
|
||||
|
||||
With this experiment enabled, you will need to remove the `sh` subkey and define
|
||||
your command as a string that begins with a `$`. This will instruct Task to
|
||||
interpret the string as a command instead of a literal value and the variable
|
||||
will be populated with the output of the command. For example:
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -89,14 +102,56 @@ version: 3
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
CALCULATED_VAR: '$echo hello'
|
||||
CALCULATED_VAR: '$echo hello' # <-- Prefix dynamic variable with a `$`
|
||||
cmds:
|
||||
- 'echo {{.CALCULATED_VAR}}'
|
||||
```
|
||||
|
||||
If your current Taskfile contains a string variable that begins with a `$`, you
|
||||
will now need to escape the `$` with a backslash (`\`) to stop Task from
|
||||
executing it as a command.
|
||||
</TabItem></Tabs>
|
||||
|
||||
### References
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
VAR: 42
|
||||
VAR_REF:
|
||||
ref: '.FOO'
|
||||
cmds:
|
||||
- 'echo {{.VAR_REF}}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
VAR: 42
|
||||
VAR_REF: '#.FOO' # <-- Prefix reference with a `#`
|
||||
cmds:
|
||||
- 'echo {{.VAR_REF}}'
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
If your current Taskfile contains a string variable that begins with a `$` or a
|
||||
`#`, you will now need to escape it with a backslash (`\`) to stop Task from
|
||||
interpreting it as a command or reference.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
@@ -123,157 +178,12 @@ tasks:
|
||||
BAR: true # <-- Other types of variables are still defined directly on the key
|
||||
BAZ:
|
||||
sh: 'echo Hello Task' # <-- The `sh` subkey is still supported
|
||||
QUX:
|
||||
ref: '.BAZ' # <-- The `ref` subkey is still supported
|
||||
cmds:
|
||||
- 'echo {{.FOO.a}}'
|
||||
```
|
||||
|
||||
## Parsing JSON and YAML
|
||||
|
||||
In addition to the new `map` keyword, this proposal also adds support for the
|
||||
`json` and `yaml` keywords for parsing JSON and YAML strings into real
|
||||
objects/arrays. This is similar to the `fromJSON` template function, but means
|
||||
that you only have to parse the JSON/YAML once when you declare the variable,
|
||||
instead of every time you want to access a value.
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: '{"a": 1, "b": 2, "c": 3}' # <-- JSON string
|
||||
cmds:
|
||||
- 'echo {{(fromJSON .FOO).a}}' # <-- Parse JSON string every time you want to access a value
|
||||
- 'echo {{(fromJSON .FOO).b}}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO:
|
||||
json: '{"a": 1, "b": 2, "c": 3}' # <-- JSON string parsed once
|
||||
cmds:
|
||||
- 'echo {{.FOO.a}}' # <-- Access values directly
|
||||
- 'echo {{.FOO.b}}'
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
## Variables by reference
|
||||
|
||||
Lastly, this proposal adds support for defining and passing variables by
|
||||
reference. This is really important now that variables can be types other than a
|
||||
string.
|
||||
|
||||
Previously, to send a variable from one task to another, you would have to use
|
||||
the templating system. Unfortunately, the templater _always_ outputs a string
|
||||
and operations on the passed variable may not have behaved as expected. With
|
||||
this proposal, you can now pass variables by reference using the `ref` subkey:
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO: '{{.FOO}}' # <-- FOO gets converted to a string when passed to bar
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .FOO 0}}' # <-- FOO is a string so the task outputs '91' which is the ASCII code for '[' instead of the expected 'A'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO:
|
||||
ref: .FOO # <-- FOO gets passed by reference to bar and maintains its type
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .FOO 0}}' # <-- FOO is still a map so the task outputs 'A' as expected
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
This means that the type of the variable is maintained when it is passed to
|
||||
another Task. This also works the same way when calling `deps` and when defining
|
||||
a variable and can be used in any combination:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
BAR:
|
||||
ref: .FOO # <-- BAR is defined as a reference to FOO
|
||||
deps:
|
||||
- task: bar
|
||||
vars:
|
||||
BAR:
|
||||
ref: .BAR # <-- BAR gets passed by reference to bar and maintains its type
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .BAR 0}}' # <-- BAR still refers to FOO so the task outputs 'A'
|
||||
```
|
||||
|
||||
All references use the same templating syntax as regular templates, so in
|
||||
addition to simply calling `.FOO`, you can also pass subkeys (`.FOO.BAR`) or
|
||||
indexes (`index .FOO 0`) and use functions (`len .FOO`):
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO:
|
||||
ref: index .FOO 0 # <-- The element at index 0 is passed by reference to bar
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{.MYVAR}}' # <-- FOO is just the letter 'A'
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
## Looping over maps
|
||||
|
||||
@@ -105,13 +105,20 @@ internet and cached locally. If for whatever reason, you lose access to the
|
||||
internet, you will still be able to run your tasks by specifying the `--offline`
|
||||
flag. This will tell Task to use the latest cached version of the file instead
|
||||
of trying to download it. You are able to use the `--download` flag to update
|
||||
the cached version of the remote files without running any tasks.
|
||||
the cached version of the remote files without running any tasks. You are able
|
||||
to use the `--clear-cache` flag to clear all cached version of the remote files
|
||||
without running any tasks.
|
||||
|
||||
By default, Task will timeout requests to download remote files after 10 seconds
|
||||
and look for a cached copy instead. This timeout can be configured by setting
|
||||
the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will
|
||||
set the timeout to 5 seconds.
|
||||
|
||||
By default, the cache is stored in the Task temp directory, represented by the
|
||||
`TASK_TEMP_DIR` [environment variable](../reference/environment.mdx) You can
|
||||
override the location of the cache by setting the `TASK_REMOTE_DIR` environment
|
||||
variable. This way, you can share the cache between different projects.
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[enabling-experiments]: ./experiments.mdx#enabling-experiments
|
||||
[man-in-the-middle-attacks]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
|
||||
|
||||
@@ -7,6 +7,25 @@ sidebar_position: 15
|
||||
|
||||
This page contains a list of frequently asked questions about Task.
|
||||
|
||||
## When will \<feature\> be released? / ETAs
|
||||
|
||||
Task is _free_ and _open source_ project maintained by a small group of
|
||||
volunteers with full time jobs and lives outside of the project. Because of
|
||||
this, it is difficult to predict how much time we will be able to dedicate to
|
||||
the project in advance and we don't want to make any promises that we can't
|
||||
keep. For this reason, we are unable to provide ETAs for new features or
|
||||
releases. We make a "best effort" to provide regular releases and fix bugs in a
|
||||
timely fashion, but sometimes our personal lives must take priority.
|
||||
|
||||
ETAs are probably the number one question we (and maintainers of other open
|
||||
source projects) get asked. We understand that you are passionate about the
|
||||
project, but it can be overwhelming to be asked this question so often. Please
|
||||
be patient and avoid asking for ETAs.
|
||||
|
||||
The best way to speed things up is to contribute to the project yourself. We
|
||||
always appreciate new contributors. If you are interested in contributing, check
|
||||
out the [contributing guide](./contributing.mdx).
|
||||
|
||||
## Why won't my task update my shell environment?
|
||||
|
||||
This is a limitation of how shells work. Task runs as a subprocess of your
|
||||
|
||||
@@ -146,6 +146,15 @@ can install Task from [winget-pkgs](https://github.com/microsoft/winget-pkgs).
|
||||
winget install Task.Task
|
||||
```
|
||||
|
||||
### Pacstall
|
||||
If you are using Debian or Ubuntu, and have [Pacstall](https://pacstall.dev/) installed, you can install Task by running:
|
||||
|
||||
```shell
|
||||
pacstall -I go-task-deb
|
||||
```
|
||||
|
||||
This installation method is community owned. After a new release of Task, it may take some time until it's available in [Pacstall](https://pacstall.dev/packages/go-task-deb).
|
||||
|
||||
## Get The Binary
|
||||
|
||||
### Binary
|
||||
@@ -185,6 +194,14 @@ default.
|
||||
|
||||
:::
|
||||
|
||||
By default, it installs the latest version available.
|
||||
You can also specify a tag (available in [releases](https://github.com/go-task/task/releases))
|
||||
to install a specific version:
|
||||
|
||||
```shell
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d v3.36.0
|
||||
```
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
If you want to install Task in GitHub Actions you can try using
|
||||
|
||||
2
website/docs/reference/_category_.yml
Normal file
2
website/docs/reference/_category_.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
position: 4
|
||||
label: Reference
|
||||
118
website/docs/reference/cli.mdx
Normal file
118
website/docs/reference/cli.mdx
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
slug: /reference/cli
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# CLI Reference
|
||||
|
||||
Task CLI commands have the following syntax:
|
||||
|
||||
```shell
|
||||
task [--flags] [tasks...] [-- CLI_ARGS...]
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If `--` is given, all remaining arguments will be assigned to a special
|
||||
`CLI_ARGS` variable
|
||||
|
||||
## Flags
|
||||
|
||||
:::
|
||||
|
||||
| Short | Flag | Type | Default | Description |
|
||||
| ----- | --------------------------- | -------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-c` | `--color` | `bool` | `true` | Colored output. Enabled by default. Set flag to `false` or use `NO_COLOR=1` to disable. |
|
||||
| `-C` | `--concurrency` | `int` | `0` | Limit number tasks to run concurrently. Zero means unlimited. |
|
||||
| `-d` | `--dir` | `string` | Working directory | Sets directory of execution. |
|
||||
| `-n` | `--dry` | `bool` | `false` | Compiles and prints tasks in the order that they would be run, without executing them. |
|
||||
| `-x` | `--exit-code` | `bool` | `false` | Pass-through the exit code of the task command. |
|
||||
| `-f` | `--force` | `bool` | `false` | Forces execution even when the task is up-to-date. |
|
||||
| `-g` | `--global` | `bool` | `false` | Runs global Taskfile, from `$HOME/Taskfile.{yml,yaml}`. |
|
||||
| `-h` | `--help` | `bool` | `false` | Shows Task usage. |
|
||||
| `-i` | `--init` | `bool` | `false` | Creates a new Taskfile.yml in the current folder. |
|
||||
| `-I` | `--interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
|
||||
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
|
||||
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
|
||||
| | `--sort` | `string` | `default` | Changes the order of the tasks when listed.<br />`default` - Alphanumeric with root tasks first<br />`alphanumeric` - Alphanumeric<br />`none` - No sorting (As they appear in the Taskfile) |
|
||||
| | `--json` | `bool` | `false` | See [JSON Output](#json-output) |
|
||||
| `-o` | `--output` | `string` | Default set in the Taskfile or `interleaved` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
|
||||
| | `--output-group-begin` | `string` | | Message template to print before a task's grouped output. |
|
||||
| | `--output-group-end` | `string` | | Message template to print after a task's grouped output. |
|
||||
| | `--output-group-error-only` | `bool` | `false` | Swallow command output on zero exit code. |
|
||||
| `-p` | `--parallel` | `bool` | `false` | Executes tasks provided on command line in parallel. |
|
||||
| `-s` | `--silent` | `bool` | `false` | Disables echoing. |
|
||||
| `-y` | `--yes` | `bool` | `false` | Assume "yes" as answer to all prompts. |
|
||||
| | `--status` | `bool` | `false` | Exits with non-zero exit code if any of the given tasks is not up-to-date. |
|
||||
| | `--summary` | `bool` | `false` | Show summary about a task. |
|
||||
| `-t` | `--taskfile` | `string` | `Taskfile.yml` or `Taskfile.yaml` | |
|
||||
| `-v` | `--verbose` | `bool` | `false` | Enables verbose mode. |
|
||||
| | `--version` | `bool` | `false` | Show Task version. |
|
||||
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task.
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Task will sometimes exit with specific exit codes. These codes are split into
|
||||
three groups with the following ranges:
|
||||
|
||||
- General errors (0-99)
|
||||
- Taskfile errors (100-199)
|
||||
- Task errors (200-299)
|
||||
|
||||
A full list of the exit codes and their descriptions can be found below:
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| 0 | Success |
|
||||
| 1 | An unknown error occurred |
|
||||
| 100 | No Taskfile was found |
|
||||
| 101 | A Taskfile already exists when trying to initialize one |
|
||||
| 102 | The Taskfile is invalid or cannot be parsed |
|
||||
| 103 | A remote Taskfile could not be downloaded |
|
||||
| 104 | A remote Taskfile was not trusted by the user |
|
||||
| 105 | A remote Taskfile was could not be fetched securely |
|
||||
| 106 | No cache was found for a remote Taskfile in offline mode |
|
||||
| 107 | No schema version was defined in the Taskfile |
|
||||
| 200 | The specified task could not be found |
|
||||
| 201 | An error occurred while executing a command inside of a task |
|
||||
| 202 | The user tried to invoke a task that is internal |
|
||||
| 203 | There a multiple tasks with the same name or alias |
|
||||
| 204 | A task was called too many times |
|
||||
| 205 | A task was cancelled by the user |
|
||||
| 206 | A task was not executed due to missing required variables |
|
||||
|
||||
These codes can also be found in the repository in
|
||||
[`errors/errors.go`](https://github.com/go-task/task/blob/main/errors/errors.go).
|
||||
|
||||
:::info
|
||||
|
||||
When Task is run with the `-x`/`--exit-code` flag, the exit code of any failed
|
||||
commands will be passed through to the user instead.
|
||||
|
||||
:::
|
||||
|
||||
## JSON Output
|
||||
|
||||
When using the `--json` flag in combination with either the `--list` or
|
||||
`--list-all` flags, the output will be a JSON object with the following
|
||||
structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"name": "",
|
||||
"desc": "",
|
||||
"summary": "",
|
||||
"up_to_date": false,
|
||||
"location": {
|
||||
"line": 54,
|
||||
"column": 3,
|
||||
"taskfile": "/path/to/Taskfile.yml"
|
||||
}
|
||||
}
|
||||
// ...
|
||||
],
|
||||
"location": "/path/to/Taskfile.yml"
|
||||
}
|
||||
```
|
||||
48
website/docs/reference/environment.mdx
Normal file
48
website/docs/reference/environment.mdx
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
slug: /reference/environment
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Environment Reference
|
||||
|
||||
Task allows you to configure some behavior using environment variables. This
|
||||
page lists all the environment variables that Task supports.
|
||||
|
||||
| ENV | Default | Description |
|
||||
| ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `TASK_TEMP_DIR` | `.task` | Location of the temp dir. Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `TASK_REMOTE_DIR` | `TASK_TEMP_DIR` | Location of the remote temp dir (used for caching). Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `FORCE_COLOR` | | Force color output usage. |
|
||||
|
||||
## Custom Colors
|
||||
|
||||
| ENV | Default | Description |
|
||||
| --------------------------- | ------- | ----------------------- |
|
||||
| `TASK_COLOR_RESET` | `0` | Color used for white. |
|
||||
| `TASK_COLOR_RED` | `31` | Color used for red. |
|
||||
| `TASK_COLOR_GREEN` | `32` | Color used for green. |
|
||||
| `TASK_COLOR_YELLOW` | `33` | Color used for yellow. |
|
||||
| `TASK_COLOR_BLUE` | `34` | Color used for blue. |
|
||||
| `TASK_COLOR_MAGENTA` | `35` | Color used for magenta. |
|
||||
| `TASK_COLOR_CYAN` | `36` | Color used for cyan. |
|
||||
| `TASK_COLOR_BRIGHT_RED` | `91` | Color used for red. |
|
||||
| `TASK_COLOR_BRIGHT_GREEN` | `92` | Color used for green. |
|
||||
| `TASK_COLOR_BRIGHT_YELLOW` | `93` | Color used for yellow. |
|
||||
| `TASK_COLOR_BRIGHT_BLUE` | `94` | Color used for blue. |
|
||||
| `TASK_COLOR_BRIGHT_MAGENTA` | `95` | Color used for magenta. |
|
||||
| `TASK_COLOR_BRIGHT_CYAN` | `96` | Color used for cyan. |
|
||||
|
||||
All color variables are [ANSI color codes][ansi]. You can specify multiple codes
|
||||
separated by a semicolon. For example: `31;1` will make the text bold and red.
|
||||
Task also supports 8-bit color (256 colors). You can specify these colors by
|
||||
using the sequence `38;2;R:G:B` for foreground colors and `48;2;R:G:B` for
|
||||
background colors where `R`, `G` and `B` should be replaced with values between
|
||||
0 and 255.
|
||||
|
||||
For convenience, we allow foreground colors to be specified using shorthand,
|
||||
comma-separated syntax: `R,G,B`. For example, `255,0,0` is equivalent to
|
||||
`38;2;255:0:0`.
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
{/* prettier-ignore-end */}
|
||||
@@ -1,171 +1,11 @@
|
||||
---
|
||||
slug: /api/
|
||||
sidebar_position: 4
|
||||
slug: /reference/schema
|
||||
sidebar_position: 2
|
||||
toc_min_heading_level: 2
|
||||
toc_max_heading_level: 5
|
||||
---
|
||||
|
||||
# API Reference
|
||||
|
||||
## CLI
|
||||
|
||||
Task command line tool has the following syntax:
|
||||
|
||||
```shell
|
||||
task [--flags] [tasks...] [-- CLI_ARGS...]
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If `--` is given, all remaining arguments will be assigned to a special
|
||||
`CLI_ARGS` variable
|
||||
|
||||
:::
|
||||
|
||||
| Short | Flag | Type | Default | Description |
|
||||
| ----- | --------------------------- | -------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-c` | `--color` | `bool` | `true` | Colored output. Enabled by default. Set flag to `false` or use `NO_COLOR=1` to disable. |
|
||||
| `-C` | `--concurrency` | `int` | `0` | Limit number tasks to run concurrently. Zero means unlimited. |
|
||||
| `-d` | `--dir` | `string` | Working directory | Sets directory of execution. |
|
||||
| `-n` | `--dry` | `bool` | `false` | Compiles and prints tasks in the order that they would be run, without executing them. |
|
||||
| `-x` | `--exit-code` | `bool` | `false` | Pass-through the exit code of the task command. |
|
||||
| `-f` | `--force` | `bool` | `false` | Forces execution even when the task is up-to-date. |
|
||||
| `-g` | `--global` | `bool` | `false` | Runs global Taskfile, from `$HOME/Taskfile.{yml,yaml}`. |
|
||||
| `-h` | `--help` | `bool` | `false` | Shows Task usage. |
|
||||
| `-i` | `--init` | `bool` | `false` | Creates a new Taskfile.yml in the current folder. |
|
||||
| `-I` | `--interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
|
||||
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
|
||||
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
|
||||
| | `--sort` | `string` | `default` | Changes the order of the tasks when listed.<br />`default` - Alphanumeric with root tasks first<br />`alphanumeric` - Alphanumeric<br />`none` - No sorting (As they appear in the Taskfile) |
|
||||
| | `--json` | `bool` | `false` | See [JSON Output](#json-output) |
|
||||
| `-o` | `--output` | `string` | Default set in the Taskfile or `intervealed` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
|
||||
| | `--output-group-begin` | `string` | | Message template to print before a task's grouped output. |
|
||||
| | `--output-group-end` | `string` | | Message template to print after a task's grouped output. |
|
||||
| | `--output-group-error-only` | `bool` | `false` | Swallow command output on zero exit code. |
|
||||
| `-p` | `--parallel` | `bool` | `false` | Executes tasks provided on command line in parallel. |
|
||||
| `-s` | `--silent` | `bool` | `false` | Disables echoing. |
|
||||
| `-y` | `--yes` | `bool` | `false` | Assume "yes" as answer to all prompts. |
|
||||
| | `--status` | `bool` | `false` | Exits with non-zero exit code if any of the given tasks is not up-to-date. |
|
||||
| | `--summary` | `bool` | `false` | Show summary about a task. |
|
||||
| `-t` | `--taskfile` | `string` | `Taskfile.yml` or `Taskfile.yaml` | |
|
||||
| `-v` | `--verbose` | `bool` | `false` | Enables verbose mode. |
|
||||
| | `--version` | `bool` | `false` | Show Task version. |
|
||||
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task. |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Task will sometimes exit with specific exit codes. These codes are split into
|
||||
three groups with the following ranges:
|
||||
|
||||
- General errors (0-99)
|
||||
- Taskfile errors (100-199)
|
||||
- Task errors (200-299)
|
||||
|
||||
A full list of the exit codes and their descriptions can be found below:
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| 0 | Success |
|
||||
| 1 | An unknown error occurred |
|
||||
| 100 | No Taskfile was found |
|
||||
| 101 | A Taskfile already exists when trying to initialize one |
|
||||
| 102 | The Taskfile is invalid or cannot be parsed |
|
||||
| 103 | A remote Taskfile could not be downloaded |
|
||||
| 104 | A remote Taskfile was not trusted by the user |
|
||||
| 105 | A remote Taskfile was could not be fetched securely |
|
||||
| 106 | No cache was found for a remote Taskfile in offline mode |
|
||||
| 107 | No schema version was defined in the Taskfile |
|
||||
| 200 | The specified task could not be found |
|
||||
| 201 | An error occurred while executing a command inside of a task |
|
||||
| 202 | The user tried to invoke a task that is internal |
|
||||
| 203 | There a multiple tasks with the same name or alias |
|
||||
| 204 | A task was called too many times |
|
||||
| 205 | A task was cancelled by the user |
|
||||
| 206 | A task was not executed due to missing required variables |
|
||||
|
||||
These codes can also be found in the repository in
|
||||
[`errors/errors.go`](https://github.com/go-task/task/blob/main/errors/errors.go).
|
||||
|
||||
:::info
|
||||
|
||||
When Task is run with the `-x`/`--exit-code` flag, the exit code of any failed
|
||||
commands will be passed through to the user instead.
|
||||
|
||||
:::
|
||||
|
||||
## JSON Output
|
||||
|
||||
When using the `--json` flag in combination with either the `--list` or
|
||||
`--list-all` flags, the output will be a JSON object with the following
|
||||
structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"name": "",
|
||||
"desc": "",
|
||||
"summary": "",
|
||||
"up_to_date": false,
|
||||
"location": {
|
||||
"line": 54,
|
||||
"column": 3,
|
||||
"taskfile": "/path/to/Taskfile.yml"
|
||||
}
|
||||
}
|
||||
// ...
|
||||
],
|
||||
"location": "/path/to/Taskfile.yml"
|
||||
}
|
||||
```
|
||||
|
||||
## Special Variables
|
||||
|
||||
There are some special variables that is available on the templating system:
|
||||
|
||||
| Var | Description |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `CLI_ARGS` | Contain all extra arguments passed after `--` when calling Task through the CLI. |
|
||||
| `CLI_FORCE` | A boolean containing whether the `--force` or `--force-all` flags were set. |
|
||||
| `TASK` | The name of the current task. |
|
||||
| `ROOT_TASKFILE` | The absolute path of the root Taskfile. |
|
||||
| `ROOT_DIR` | The absolute path of the root Taskfile directory. |
|
||||
| `TASKFILE` | The absolute path of the included Taskfile. |
|
||||
| `TASKFILE_DIR` | The absolute path of the included Taskfile directory. |
|
||||
| `USER_WORKING_DIR` | The absolute path of the directory `task` was called from. |
|
||||
| `CHECKSUM` | The checksum of the files listed in `sources`. Only available within the `status` prop and if method is set to `checksum`. |
|
||||
| `TIMESTAMP` | The date object of the greatest timestamp of the files listed in `sources`. Only available within the `status` prop and if method is set to `timestamp`. |
|
||||
| `TASK_VERSION` | The current version of task. |
|
||||
| `ITEM` | The value of the current iteration when using the `for` property. Can be changed to a different variable name using `as:`. |
|
||||
|
||||
## ENV
|
||||
|
||||
Some environment variables can be overridden to adjust Task behavior.
|
||||
|
||||
| ENV | Default | Description |
|
||||
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| `TASK_TEMP_DIR` | `.task` | Location of the temp dir. Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `TASK_COLOR_RESET` | `0` | Color used for white. |
|
||||
| `TASK_COLOR_BLUE` | `34` | Color used for blue. |
|
||||
| `TASK_COLOR_GREEN` | `32` | Color used for green. |
|
||||
| `TASK_COLOR_CYAN` | `36` | Color used for cyan. |
|
||||
| `TASK_COLOR_YELLOW` | `33` | Color used for yellow. |
|
||||
| `TASK_COLOR_MAGENTA` | `35` | Color used for magenta. |
|
||||
| `TASK_COLOR_RED` | `31` | Color used for red. |
|
||||
| `FORCE_COLOR` | | Force color output usage. |
|
||||
|
||||
All color variables are [ANSI color codes][ansi]. You can specify multiple codes
|
||||
separated by a semicolon. For example: `31;1` will make the text bold and red.
|
||||
Task also supports 8-bit color (256 colors). You can specify these colors by
|
||||
using the sequence `38;2;R:G:B` for foreground colors and `48;2;R:G:B` for
|
||||
background colors where `R`, `G` and `B` should be replaced with values between
|
||||
0 and 255.
|
||||
|
||||
For convenience, we allow foreground colors to be specified using shorthand,
|
||||
comma-separated syntax: `R,G,B`. For example, `255,0,0` is equivalent to
|
||||
`38;2;255:0:0`.
|
||||
|
||||
## Taskfile Schema
|
||||
# Schema Reference
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| ---------- | ---------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -183,7 +23,7 @@ comma-separated syntax: `R,G,B`. For example, `255,0,0` is equivalent to
|
||||
| `set` | `[]string` | | Specify options for the [`set` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html). |
|
||||
| `shopt` | `[]string` | | Specify option for the [`shopt` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html). |
|
||||
|
||||
### Include
|
||||
## Include
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| ---------- | --------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -206,7 +46,7 @@ includes:
|
||||
|
||||
:::
|
||||
|
||||
### Variable
|
||||
## Variable
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | -------- | ------- | ------------------------------------------------------------------------ |
|
||||
@@ -239,7 +79,7 @@ vars:
|
||||
|
||||
:::
|
||||
|
||||
### Task
|
||||
## Task
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------------- | ---------------------------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -289,7 +129,7 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### Command
|
||||
### Command
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| -------------- | ---------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -318,7 +158,7 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### Dependency
|
||||
### Dependency
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | ---------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -339,7 +179,7 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### For
|
||||
### For
|
||||
|
||||
The `for` parameter can be defined as a string, a list of strings or a map. If
|
||||
it is defined as a string, you can give it any of the following values:
|
||||
@@ -359,7 +199,7 @@ variable to define the values to loop over:
|
||||
| `split` | `string` | (any whitespace) | What string the variable should be split on. |
|
||||
| `as` | `string` | `ITEM` | The name of the iterator variable. |
|
||||
|
||||
#### Precondition
|
||||
### Precondition
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
@@ -379,12 +219,8 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### Requires
|
||||
### Requires
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | ---------- | ------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `vars` | `[]string` | | List of variable or environment variable names that must be set if this task is to execute and run |
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
{/* prettier-ignore-end */}
|
||||
406
website/docs/reference/templating.mdx
Normal file
406
website/docs/reference/templating.mdx
Normal file
@@ -0,0 +1,406 @@
|
||||
---
|
||||
slug: /reference/templating/
|
||||
sidebar_position: 3
|
||||
toc_min_heading_level: 2
|
||||
toc_max_heading_level: 5
|
||||
---
|
||||
|
||||
# Templating Reference
|
||||
|
||||
Task's templating engine uses Go's [text/template][text/template] package to
|
||||
interpolate values. For detailed information about the usage of Go's templating
|
||||
engine, we recommend reading [the official documentation][text/template].
|
||||
However, we will provide a basic overview of the main features here.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Most string values in Task (though, not all) can be templated. The templating
|
||||
engine uses double curly braces `{{` and `}}` to denote a template. Anything
|
||||
inside the curly braces will be executed as a Go template and the result will be
|
||||
inserted into the resulting string. For example:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
hello:
|
||||
vars:
|
||||
MESSAGE: 'Hello, World!'
|
||||
cmds:
|
||||
- 'echo {{.MESSAGE}}'
|
||||
```
|
||||
|
||||
In this example, we have a task called `hello` with a single variable, `MESSAGE`
|
||||
defined. When the command is run, the templating engine will evaluate the
|
||||
variable and replace `{{.MESSAGE}}` with the variable's contents. This task will
|
||||
output `Hello, World!` to the terminal. Note that when referring to a variable,
|
||||
you must use dot notation.
|
||||
|
||||
You are also able to do more complex things in templates, such as conditional
|
||||
logic:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
maybe-happy:
|
||||
vars:
|
||||
SMILE: ':\)'
|
||||
FROWN: ':\('
|
||||
HAPPY: true
|
||||
cmds:
|
||||
- 'echo {{if .HAPPY}}{{.SMILE}}{{else}}{{.FROWN}}{{end}}'
|
||||
```
|
||||
|
||||
```txt
|
||||
:)
|
||||
```
|
||||
|
||||
...calling functions and piping values:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
uniq:
|
||||
vars:
|
||||
NUMBERS: '0,1,1,1,2,2,3'
|
||||
cmds:
|
||||
- 'echo {{splitList "," .NUMBERS | uniq | join ", " }}!'
|
||||
```
|
||||
|
||||
```txt
|
||||
0, 1, 2, 3
|
||||
```
|
||||
|
||||
...looping over values with control flow operators:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
loop:
|
||||
vars:
|
||||
NUMBERS: [0, 1, 1, 1, 2, 2, 3]
|
||||
cmds:
|
||||
# Ranges over NUMBERS and prints the index and value of each number until it finds a number greater than 1
|
||||
- "{{range $index, $num := .NUMBERS}}{{if gt $num 1 }}{{break}}{{end}}echo {{$index}}: {{$num}}\n{{end}}"
|
||||
```
|
||||
|
||||
```txt
|
||||
0: 0
|
||||
1: 1
|
||||
2: 1
|
||||
3: 1
|
||||
```
|
||||
|
||||
## Special Variables
|
||||
|
||||
Task defines some special variables that are always available to the templating
|
||||
engine. If you define a variable with the same name as a special variable, the
|
||||
special variable will be overridden.
|
||||
|
||||
| Var | Description |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `CLI_ARGS` | Contain all extra arguments passed after `--` when calling Task through the CLI. |
|
||||
| `CLI_FORCE` | A boolean containing whether the `--force` or `--force-all` flags were set. |
|
||||
| `TASK` | The name of the current task. |
|
||||
| `TASK_EXE` | The Task executable name or path. |
|
||||
| `ROOT_TASKFILE` | The absolute path of the root Taskfile. |
|
||||
| `ROOT_DIR` | The absolute path of the root Taskfile directory. |
|
||||
| `TASKFILE` | The absolute path of the included Taskfile. |
|
||||
| `TASKFILE_DIR` | The absolute path of the included Taskfile directory. |
|
||||
| `USER_WORKING_DIR` | The absolute path of the directory `task` was called from. |
|
||||
| `CHECKSUM` | The checksum of the files listed in `sources`. Only available within the `status` prop and if method is set to `checksum`. |
|
||||
| `TIMESTAMP` | The date object of the greatest timestamp of the files listed in `sources`. Only available within the `status` prop and if method is set to `timestamp`. |
|
||||
| `TASK_VERSION` | The current version of task. |
|
||||
| `ITEM` | The value of the current iteration when using the `for` property. Can be changed to a different variable name using `as:`. |
|
||||
|
||||
## Functions
|
||||
|
||||
Functions are provided at a few different levels in Task. Below, we list all the
|
||||
functions available for use in Task.
|
||||
|
||||
:::note
|
||||
|
||||
Functions marked with an asterisk (\*) also have `must` variants that will panic
|
||||
rather than erroring.
|
||||
|
||||
:::
|
||||
|
||||
### Built-in Functions
|
||||
|
||||
The first set of functions are [provided by Golang
|
||||
itself][go-template-functions]:
|
||||
|
||||
| Function | Description |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `and` | Returns the boolean AND of its arguments by returning the first empty argument or the last argument. That is, `and x y` behaves as `if x then y else x`. Evaluation proceeds through the arguments left to right and returns when the result is determined. |
|
||||
| `call` | Returns the result of calling the first argument, which must be a function, with the remaining arguments as parameters. Thus `call .X.Y 1 2` is, in Go notation, `dot.X.Y(1, 2)` where `Y` is a func-valued field, map entry, or the like. The first argument must be the result of an evaluation that yields a value of function type (as distinct from a predefined function such as print). The function must return either one or two result values, the second of which is of type error. If the arguments don't match the function or the returned error value is non-nil, execution stops. |
|
||||
| `html` | Returns the escaped HTML equivalent of the textual representation of its arguments. This function is unavailable in [html/template][html/template], with a few exceptions. |
|
||||
| `index` | Returns the result of indexing its first argument by the following arguments. Thus `index x 1 2 3` is, in Go syntax, `x[1][2][3]`. Each indexed item must be a map, slice, or array. |
|
||||
| `slice` | slice returns the result of slicing its first argument by the remaining arguments. Thus `slice x 1 2` is, in Go syntax, `x[1:2]`, while `slice x` is `x[:]`, `slice x 1` is `x[1:]`, and `slice x 1 2 3` is `x[1:2:3]`. The first argument must be a string, slice, or array. |
|
||||
| `js` | Returns the escaped JavaScript equivalent of the textual representation of its arguments. |
|
||||
| `len` | Returns the integer length of its argument. |
|
||||
| `not` | Returns the boolean negation of its single argument. |
|
||||
| `or` | Returns the boolean OR of its arguments by returning the first non-empty argument or the last argument, that is, `or x y` behaves as `if x then x else y`. Evaluation proceeds through the arguments left to right and returns when the result is determined. |
|
||||
| `print` | An alias for `fmt.Sprint`. |
|
||||
| `printf` | An alias for `fmt.Sprintf`. |
|
||||
| `println` | An alias for `fmt.Sprintln`. |
|
||||
| `urlquery` | Returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query. This function is unavailable in [html/template][html/template], with a few exceptions. |
|
||||
|
||||
### Slim-Sprig Functions
|
||||
|
||||
In addition to the built-in functions, Task also provides a set of functions
|
||||
imported via the [slim-sprig][slim-sprig] package. We only provide a very basic
|
||||
description here for completeness. For detailed usage, please refer to the
|
||||
[slim-sprig documentation][slim-sprig]:
|
||||
|
||||
#### [String Functions][string-functions]
|
||||
|
||||
| Function | Description |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `trim` | Removes space from either side of a string. |
|
||||
| `trimAll` | Removes given characters from the front or back of a string. |
|
||||
| `trimSuffix` | Trims just the suffix from a string. |
|
||||
| `trimPrefix` | Trims just the prefix from a string. |
|
||||
| `upper` | Converts the entire string to uppercase. |
|
||||
| `lower` | Converts the entire string to lowercase. |
|
||||
| `title` | Converts to title case. |
|
||||
| `repeat` | Repeats a string multiple times. |
|
||||
| `substr` | Gets a substring from a string. |
|
||||
| `trunc` | Truncates a string. |
|
||||
| `contains` | Tests to see if one string is contained inside of another. |
|
||||
| `hasPrefix` | Tests whether a string has a given prefix. |
|
||||
| `hasSuffix` | Tests whether a string has a given suffix. |
|
||||
| `quote` | Wraps a string in double quotes. |
|
||||
| `squote` | Wraps a string in single quotes. |
|
||||
| `cat` | Concatenates multiple strings together into one, separating them with spaces. |
|
||||
| `indent` | Indents every line in a given string to the specified indent width. |
|
||||
| `nindent` | Identical to `indent`, but prepends a new line to the beginning of the string. |
|
||||
| `replace` | Replaces a string. |
|
||||
| `plural` | Pluralizes a string. |
|
||||
| `regexMatch`\* | Returns true if the input string contains any match of the regular expression. |
|
||||
| `regexFindAll`\* | Returns a slice of all matches of the regular expression in the input string. |
|
||||
| `regexFind`\* | Returns the first (left most) match of the regular expression in the input string. |
|
||||
| `regexReplaceAll`\* | Returns a copy of the input string, replacing matches of the Regexp with the replacement string replacement. |
|
||||
| `regexReplaceAllLiteral`\* | Returns a copy of the input string, replacing matches of the Regexp with the replacement string replacement without expanding `$`. |
|
||||
| `regexSplit`\* | Slices the input string into substrings separated by the expression and returns a slice of the substrings between those expression matches. |
|
||||
| `regexQuoteMeta`\* | Returns a string that escapes all regular expression metacharacters inside the argument text. |
|
||||
|
||||
#### [String Slice Functions][string-list-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | ----------------------------------------------------------------------- |
|
||||
| `join` | Joins a list of strings into a single string, with the given separator. |
|
||||
| `splitList` | Splits a string into a list of strings. |
|
||||
| `split` | Splits a string into a map of strings where each key is an index. |
|
||||
| `splitn` | Identical to `split`, but stops splitting after `n` values. |
|
||||
| `sortAlpha` | Sorts a list of strings into alphabetical (lexicographical) order. |
|
||||
|
||||
#### [Integer Functions][math-functions]
|
||||
|
||||
| Function | Description |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `add` | Sum a set of numbers. |
|
||||
| `add1` | Increments a number by 1. |
|
||||
| `sub` | Subtracts one number from another. |
|
||||
| `div` | Performs integer division. |
|
||||
| `mod` | Modulo. |
|
||||
| `mul` | Multiplies a set of numbers. |
|
||||
| `max` | Returns the largest of a set of integers. |
|
||||
| `min` | Returns the smallest of a set of integers. |
|
||||
| `floor` | Returns the greatest float value less than or equal to input value |
|
||||
| `ceil` | Returns the greatest float value greater than or equal to input value |
|
||||
| `round` | Returns a float value with the remainder rounded to the given number to digits after the decimal point. |
|
||||
| `randInt` | Returns a random integer value from min (inclusive) to max (exclusive). |
|
||||
|
||||
#### [Integer Slice Functions][integer-list-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | --------------------------------------------------------------------------- |
|
||||
| `until` | Builds a range of integers. |
|
||||
| `untilStep` | Builds a range of integers, but allows you to define a start, stop and step |
|
||||
| `seq` | Works like the bash `seq` command. |
|
||||
|
||||
#### [Date Functions][date-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------ |
|
||||
| `now` | Gets the current date/time. |
|
||||
| `ago` | Returns the duration since the given date/time. |
|
||||
| `date` | Formats a date. |
|
||||
| `dateInZone` | Identical to `date`, but with the given timezone. |
|
||||
| `duration` | Formats the number of seconds into a string. |
|
||||
| `durationRound` | Identical to `duration`, but rounds the duration to the most significant unit. |
|
||||
| `unixEpoch` | Returns the seconds since the unix epoch for the given date/time. |
|
||||
| `dateModify`\* | Modifies a date using the given input string. |
|
||||
| `htmlDate` | Formats a date for inserting into an HTML date picker input field. |
|
||||
| `htmlDateInZone` | Identical to `htmlDate`, but with the given timezone. |
|
||||
| `toDate`\* | Converts a string to a date/time. |
|
||||
|
||||
#### [Default Functions][default-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ---------- | ------------------------------------------------------------------------ |
|
||||
| `default` | Uses a default value if the given value is considered "zero" or "empty". |
|
||||
| `empty` | Returns true if a value is considered "zero" or "empty". |
|
||||
| `coalesce` | Takes a list of values and returns the first non-empty one. |
|
||||
| `all` | Returns true if all values are non-empty. |
|
||||
| `any` | Returns true if any value is non-empty. |
|
||||
| `ternary` | The ternary function takes two values, and a test value. If the test value is true, the first value will be returned. If the test value is empty, the second value will be returned. |
|
||||
|
||||
#### [Encoding Functions][encoding-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ---------------- | ------------------------------------------------------------------ |
|
||||
| `fromJson`\* | Decodes a JSON string into an object. |
|
||||
| `toJson`\* | Encodes an object as a JSON string. |
|
||||
| `toPrettyJson`\* | Encodes an object as a JSON string with new lines and indentation. |
|
||||
| `toRawJson`\* | Encodes an object as a JSON string with HTML characters unescaped. |
|
||||
| `b64enc` | Encodes a string into base 64. |
|
||||
| `b64dec` | Decodes a string from base 64. |
|
||||
| `b32enc` | Encodes a string into base 32. |
|
||||
| `b32dec` | Decodes a string from base 32. |
|
||||
|
||||
#### [List Functions][list-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | ---------------------------------------------------------------- |
|
||||
| `list` | Creates a list from a set of values. |
|
||||
| `first`\* | Gets the first value in a list. |
|
||||
| `rest`\* | Gets all values except the first value in the list. |
|
||||
| `last`\* | Gets the last value in the list. |
|
||||
| `initial`\* | Get all values except the last value in the list. |
|
||||
| `append`\* | Adds a new value to the end of the list. |
|
||||
| `prepend`\* | Adds a new value to the start of the list. |
|
||||
| `concat` | Joins two or more lists together. |
|
||||
| `reverse`\* | Reverses the order of a list. |
|
||||
| `uniq`\* | Generate a list with all of the duplicates removed. |
|
||||
| `without`\* | Filters matching items out of a list. |
|
||||
| `has`\* | Tests to see if a list has a particular element. |
|
||||
| `compact`\* | Removes entries with empty values. |
|
||||
| `slice`\* | Returns a partial copy of a list given start and end parameters. |
|
||||
| `chunk` | Splits a list into chunks of given size. |
|
||||
|
||||
#### [Dictionary Functions][dictionary-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------ |
|
||||
| `dict` | Creates a dictionary from a set of key/value pairs. |
|
||||
| `get` | Gets the value from the dictionary with the given key. |
|
||||
| `set` | Adds a new key/value pair to a dictionary. |
|
||||
| `unset` | Deletes a key from a dictionary. |
|
||||
| `hasKey` | Returns true if a dictionary contains the given key. |
|
||||
| `pluck` | Gets a list of all of the matching values in a set of maps given a key. |
|
||||
| `dig` | Returns the value in a nested map given a path of keys. |
|
||||
| `merge`\* | Merges two or more dictionaries into one. |
|
||||
| `mergeOverwrite`\* | Identical to `merge`, but giving precedence from right to left. |
|
||||
| `keys` | Returns a list of all of the keys in a dictionary. |
|
||||
| `pick` | Creates a new dictionary containing only the given keys of an existing map. |
|
||||
| `omit` | Creates a new dictionary containing all the keys of an existing map except the ones given. |
|
||||
| `values` | Returns a list of all the values in a dictionary. |
|
||||
|
||||
#### [Type Conversion Functions][type-conversion-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | ------------------------------------------------------ |
|
||||
| `atoi` | Converts a string to an integer. |
|
||||
| `float64` | Converts to a float64. |
|
||||
| `int` | Converts to an int at the system's width. |
|
||||
| `int64` | Converts to an int64. |
|
||||
| `toDecimal` | Converts a unix octal to a int64. |
|
||||
| `toString` | Converts to a string. |
|
||||
| `toStrings` | Converts a list, slice, or array to a list of strings. |
|
||||
| `toStrings` | Produces a slice of strings from any list. |
|
||||
| `toDecimal` | Given a unix octal permission, produce a decimal. |
|
||||
|
||||
#### [Path and Filepath Functions][path-functions]
|
||||
|
||||
| Function | Description |
|
||||
| --------- | ----------------------------------------- |
|
||||
| `base` | Returns the last element of a path. |
|
||||
| `dir` | Returns the directory of a path. |
|
||||
| `clean` | Cleans up a path. |
|
||||
| `ext` | Returns the file extension of a path. |
|
||||
| `isAbs` | Checks if a path is absolute. |
|
||||
| `osBase` | Returns the last element of a filepath. |
|
||||
| `osDir` | Returns the directory of a filepath. |
|
||||
| `osClean` | Cleans up a filepath. |
|
||||
| `osExt` | Returns the file extension of a filepath. |
|
||||
| `osIsAbs` | Checks if a filepath is absolute. |
|
||||
|
||||
#### [Flow Control Functions][flow-control-functions]
|
||||
|
||||
| Function | Description |
|
||||
| -------- | ----------------------------------------------------------------------------- |
|
||||
| `fail` | Unconditionally returns an empty string and an error with the specified text. |
|
||||
|
||||
#### [OS Functions][os-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | --------------------------------------------- |
|
||||
| `env` | Reads an environment variable. |
|
||||
| `expandenv` | Substitutes environment variables in a string |
|
||||
|
||||
#### [Reflection Functions][reflection-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ------------ | ------------------------------------------------------ |
|
||||
| `kindOf` | Returns the kind of a value. |
|
||||
| `kindIs` | Verifies that a value is a particular kind. |
|
||||
| `typeOf` | Returns the underlying type of a value. |
|
||||
| `typeIs` | Verifies that a value is of a particular type. |
|
||||
| `typeIsLike` | Identical to `typeIs`, but also dereferences pointers. |
|
||||
| `deepEqual` | Returns true if two values are "deeply equal". |
|
||||
|
||||
#### [Cryptographic and Security Functions][crypto-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ------------ | -------------------------------------- |
|
||||
| `sha1sum` | Computes a string's SHA1 digest. |
|
||||
| `sha256sum` | Computes a string's SHA256 digest. |
|
||||
| `adler32sum` | Computes a string's Adler-32 checksum. |
|
||||
|
||||
### Task Functions
|
||||
|
||||
Lastly, Task itself provides a few functions:
|
||||
|
||||
| Function | Description |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `OS` | Returns the operating system. Possible values are `windows`, `linux`, `darwin` (macOS) and `freebsd`. |
|
||||
| `ARCH` | return the architecture Task was compiled to: `386`, `amd64`, `arm` or `s390x`. |
|
||||
| `splitLines` | Splits Unix (`\n`) and Windows (`\r\n`) styled newlines. |
|
||||
| `catLines` | Replaces Unix (`\n`) and Windows (`\r\n`) styled newlines with a space. |
|
||||
| `toSlash` | Does nothing on Unix, but on Windows converts a string from `\` path format to `/`. |
|
||||
| `fromSlash` | Opposite of `toSlash`. Does nothing on Unix, but on Windows converts a string from `/` path format to `\`. |
|
||||
| `exeExt` | Returns the right executable extension for the current OS (`".exe"` for Windows, `""` for others). |
|
||||
| `shellQuote` | (aliased to `q`): Quotes a string to make it safe for use in shell scripts. Task uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/syntax#Quote) for this. The Bash dialect is assumed. |
|
||||
| `splitArgs` | Splits a string as if it were a command's arguments. Task uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/shell#Fields). |
|
||||
| `joinPath` | Joins any number of arguments into a path. The same as Go's [filepath.Join](https://pkg.go.dev/path/filepath#Join). |
|
||||
| `relPath` | Converts an absolute path (second argument) into a relative path, based on a base path (first argument). The same as Go's [filepath.Rel](https://pkg.go.dev/path/filepath#Rel). |
|
||||
| `merge` | Creates a new map that is a copy of the first map with the keys of each subsequent map merged into it. If there is a duplicate key, the value of the last map with that key is used. |
|
||||
| `spew` | Returns the Go representation of a specific variable. Useful for debugging. Uses the [davecgh/go-spew](https://github.com/davecgh/go-spew) package. |
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[text/template]: https://pkg.go.dev/text/template
|
||||
[html/template]: https://pkg.go.dev/html/template
|
||||
[go-template-functions]: https://pkg.go.dev/text/template#hdr-Functions
|
||||
[slim-sprig]: https://go-task.github.io/slim-sprig/
|
||||
[os-functions]: https://go-task.github.io/slim-sprig/os.html
|
||||
[string-functions]: https://go-task.github.io/slim-sprig/strings.html
|
||||
[string-list-functions]: https://go-task.github.io/slim-sprig/string_slice.html
|
||||
[math-functions]: https://go-task.github.io/slim-sprig/math.html
|
||||
[integer-list-functions]: https://go-task.github.io/slim-sprig/integer_slice.html
|
||||
[date-functions]: https://go-task.github.io/slim-sprig/date.html
|
||||
[default-functions]: https://go-task.github.io/slim-sprig/defaults.html
|
||||
[encoding-functions]: https://go-task.github.io/slim-sprig/encoding.html
|
||||
[list-functions]: https://go-task.github.io/slim-sprig/lists.html
|
||||
[dictionary-functions]: https://go-task.github.io/slim-sprig/dicts.html
|
||||
[type-conversion-functions]: https://go-task.github.io/slim-sprig/conversion.html
|
||||
[path-functions]: https://go-task.github.io/slim-sprig/paths.html
|
||||
[flow-control-functions]: https://go-task.github.io/slim-sprig/flow_control.html
|
||||
[os-functions]: https://go-task.github.io/slim-sprig/os.html
|
||||
[reflection-functions]: https://go-task.github.io/slim-sprig/reflection.html
|
||||
[crypto-functions]: https://go-task.github.io/slim-sprig/crypto.html
|
||||
{/* prettier-ignore-end */}
|
||||
@@ -5,259 +5,68 @@ sidebar_position: 5
|
||||
|
||||
# Taskfile Versions
|
||||
|
||||
The Taskfile syntax and features changed with time. This document explains what
|
||||
changed on each version and how to upgrade your Taskfile.
|
||||
The Taskfile schema slowly changes as new features are added and old ones are
|
||||
removed. This document explains how to use a Taskfile's schema version to ensure
|
||||
that the users of your Taskfile are using the correct versions of Task.
|
||||
|
||||
## What the Taskfile version mean
|
||||
## What the Taskfile version means
|
||||
|
||||
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. 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 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 XXH3 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:
|
||||
The schema version at the top of every Taskfile corresponds to a version of the
|
||||
Task CLI, and by extension, the features that are provided by that version. When
|
||||
creating a Taskfile, you should specify the _minimum_ version of Task that
|
||||
supports the features you require. If you try to run a Taskfile with a version
|
||||
of Task that does not meet this minimum required version, it will exit with an
|
||||
error. For example, given a Taskfile that starts with:
|
||||
|
||||
```yaml
|
||||
includes:
|
||||
docs:
|
||||
taskfile: ./docs
|
||||
dir: ./docs
|
||||
version: '3.2.1'
|
||||
```
|
||||
|
||||
- Implemented short task syntax. All below syntaxes are equivalent:
|
||||
When executed with Task `v3.2.0`, it will exit with an error. Running with
|
||||
version `v3.2.1` or higher will work as expected.
|
||||
|
||||
Task accepts any [SemVer][semver] compatible string including versions which
|
||||
omit the minor or patch numbers. For example, `3`, `3.0`, and `3.0.0` all mean
|
||||
the same thing and are all valid. Most Taskfiles only specify the major version
|
||||
number. However it can be useful to be more specific when you intend to share a
|
||||
Taskfile with others.
|
||||
|
||||
For example, the Taskfile below makes use of aliases:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print:
|
||||
hello:
|
||||
aliases:
|
||||
- hi
|
||||
- hey
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
- echo "Hello, world!"
|
||||
```
|
||||
|
||||
Aliases were introduced in Task `v3.17.0`, but the Taskfile only specifies `3`
|
||||
as the version. This means that a user who has `v3.16.0` or lower installed will
|
||||
get a potentially confusing error message when trying to run the Task as the
|
||||
Taskfile specifies that any version greater or equal to `v3.0.0` is fine.
|
||||
|
||||
Instead, we should start the file like this:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print:
|
||||
- echo "Hello, World!"
|
||||
version: '3.17'
|
||||
```
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
Now when someone tries to run the Taskfile with an older version of Task, they
|
||||
will receive an error prompting them to upgrade their version of Task to
|
||||
`v3.17.0` or greater.
|
||||
|
||||
tasks:
|
||||
print: echo "Hello, World!"
|
||||
```
|
||||
## Versions 1 & 2
|
||||
|
||||
- There was a major refactor on how variables are handled. They're now easier to
|
||||
understand. The `expansions:` setting was removed as it became unnecessary.
|
||||
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
|
||||
Version 1 and 2 of Task are no longer officially supported and anyone still
|
||||
using them is strongly encouraged to upgrade to the latest version of Task.
|
||||
|
||||
## Version 2.6
|
||||
While `version: 2` of Task did support schema versions, the behavior did not
|
||||
work in quite the same way and cannot be relied upon for the purposes discussed
|
||||
above.
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
Version 2.6 comes with `preconditions` stanza in tasks.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
upload_environment:
|
||||
preconditions:
|
||||
- test -f .env
|
||||
cmds:
|
||||
- aws s3 cp .env s3://myenvironment
|
||||
```
|
||||
|
||||
Please check the [documentation][includes]
|
||||
|
||||
## Version 2.2
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
Version 2.2 comes with a global `includes` options to include other Taskfiles:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
includes:
|
||||
docs: ./documentation # will look for ./documentation/Taskfile.yml
|
||||
docker: ./DockerTasks.yml
|
||||
```
|
||||
|
||||
## Version 2.1
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
Version 2.1 includes a global `output` option, to allow having more control over
|
||||
how commands output are printed to the console (see [documentation][output] for
|
||||
more info):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
output: prefixed
|
||||
|
||||
tasks:
|
||||
server:
|
||||
cmds:
|
||||
- go run main.go
|
||||
prefix: server
|
||||
```
|
||||
|
||||
From this version it's also possible to ignore errors of a command or task
|
||||
(check documentation [here][ignore_errors]):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
example-1:
|
||||
cmds:
|
||||
- cmd: exit 1
|
||||
ignore_error: true
|
||||
- echo "This will be print"
|
||||
|
||||
example-2:
|
||||
cmds:
|
||||
- exit 1
|
||||
- echo "This will be print"
|
||||
ignore_error: true
|
||||
```
|
||||
|
||||
## Version 2.0
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
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:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
```
|
||||
|
||||
Version 2 allows you to write global variables directly in the Taskfile, if you
|
||||
don't want to create a `Taskvars.yml`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
vars:
|
||||
GREETING: Hello, World!
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
cmds:
|
||||
- echo "{{.GREETING}}"
|
||||
```
|
||||
|
||||
The variable priority order changed to the following:
|
||||
|
||||
1. Task variables
|
||||
2. Call variables
|
||||
3. Taskfile variables
|
||||
4. Taskvars file variables
|
||||
5. Environment variables
|
||||
|
||||
A new global option was added to configure the number of variables expansions
|
||||
(which default to 2):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
expansions: 3
|
||||
|
||||
vars:
|
||||
FOO: foo
|
||||
BAR: bar
|
||||
BAZ: baz
|
||||
FOOBAR: '{{.FOO}}{{.BAR}}'
|
||||
FOOBARBAZ: '{{.FOOBAR}}{{.BAZ}}'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "{{.FOOBARBAZ}}"
|
||||
```
|
||||
|
||||
## Version 1
|
||||
|
||||
:::caution
|
||||
|
||||
v1 schema support was removed in Task >= v3.0.0.
|
||||
|
||||
:::
|
||||
|
||||
In the first version of the `Taskfile`, the `version:` key was not available,
|
||||
because the tasks was in the root of the YAML document. Like this:
|
||||
|
||||
```yaml
|
||||
echo:
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
```
|
||||
|
||||
The variable priority order was also different:
|
||||
|
||||
1. Call variables
|
||||
2. Environment
|
||||
3. Task variables
|
||||
4. `Taskvars.yml` variables
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[deprecate-version-2-schema]: ./deprecations/version_2_schema.mdx
|
||||
[output]: ./usage.mdx#output-syntax
|
||||
[ignore_errors]: ./usage.mdx#ignore-errors
|
||||
[includes]: ./usage.mdx#including-other-taskfiles
|
||||
{/* prettier-ignore-end */}
|
||||
[semver]: https://semver.org/
|
||||
|
||||
@@ -3,6 +3,9 @@ slug: /usage/
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# Usage
|
||||
|
||||
## Getting started
|
||||
@@ -964,10 +967,48 @@ Maps are not supported by default, but there is an
|
||||
you're interested in this functionality, we would appreciate your feedback.
|
||||
:pray:
|
||||
|
||||
In the meantime, it is technically possible to define a map using a `ref` resolver and a templating function. For example:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
task-with-map:
|
||||
vars:
|
||||
FOO:
|
||||
ref: dict "a" "1" "b" "2" "c" "3"
|
||||
cmds:
|
||||
- echo {{.FOO}}
|
||||
```
|
||||
|
||||
```txt
|
||||
map[a:1 b:2 c:3]
|
||||
```
|
||||
|
||||
OR by using the same technique with JSON:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
task-with-map:
|
||||
vars:
|
||||
JSON: '{"a": 1, "b": 2, "c": 3}'
|
||||
FOO:
|
||||
ref: "fromJson .JSON"
|
||||
cmds:
|
||||
- echo {{.FOO}}
|
||||
```
|
||||
|
||||
```txt
|
||||
map[a:1 b:2 c:3]
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Variables can be set in many places in a Taskfile. When executing templates,
|
||||
Task will look for variables in the order listed below (most important first):
|
||||
Variables can be set in many places in a Taskfile. When executing
|
||||
[templates][templating-reference], Task will look for variables in the order
|
||||
listed below (most important first):
|
||||
|
||||
- Variables declared in the task definition
|
||||
- Variables given while calling a task from another (See
|
||||
@@ -1046,6 +1087,103 @@ tasks:
|
||||
|
||||
This works for all types of variables.
|
||||
|
||||
### Referencing other variables
|
||||
|
||||
Templating is great for referencing string values if you want to pass
|
||||
a value from one task to another. However, the templating engine is only able to
|
||||
output strings. If you want to pass something other than a string to another
|
||||
task then you will need to use a reference (`ref`) instead.
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{ label: 'Templating Engine', value: '1' },
|
||||
{ label: 'Reference', value: '2' }
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO: '{{.FOO}}' # <-- FOO gets converted to a string when passed to bar
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .FOO 0}}' # <-- FOO is a string so the task outputs '91' which is the ASCII code for '[' instead of the expected 'A'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO:
|
||||
ref: .FOO # <-- FOO gets passed by reference to bar and maintains its type
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .FOO 0}}' # <-- FOO is still a map so the task outputs 'A' as expected
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
This also works the same way when calling `deps` and when defining
|
||||
a variable and can be used in any combination:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
BAR:
|
||||
ref: .FOO # <-- BAR is defined as a reference to FOO
|
||||
deps:
|
||||
- task: bar
|
||||
vars:
|
||||
BAR:
|
||||
ref: .BAR # <-- BAR gets passed by reference to bar and maintains its type
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .BAR 0}}' # <-- BAR still refers to FOO so the task outputs 'A'
|
||||
```
|
||||
|
||||
All references use the same templating syntax as regular templates, so in
|
||||
addition to simply calling `.FOO`, you can also pass subkeys (`.FOO.BAR`) or
|
||||
indexes (`index .FOO 0`) and use functions (`len .FOO`) as described in the
|
||||
[templating-reference][templating-reference]:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO:
|
||||
ref: index .FOO 0 # <-- The element at index 0 is passed by reference to bar
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{.MYVAR}}' # <-- FOO is just the letter 'A'
|
||||
```
|
||||
|
||||
## Looping over values
|
||||
|
||||
As of v3.28.0, Task allows you to loop over certain values and execute a command
|
||||
@@ -1142,8 +1280,7 @@ tasks:
|
||||
cmd: cat {{.ITEM}}
|
||||
```
|
||||
|
||||
You can also loop over arrays directly (and maps if you have the
|
||||
[maps experiment](/experiments/map-variables) enabled):
|
||||
You can also loop over arrays directly and maps:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -1383,81 +1520,6 @@ commands are executed in the reverse order if you schedule multiple of them.
|
||||
|
||||
:::
|
||||
|
||||
## Go's template engine
|
||||
|
||||
Task parse commands as [Go's template engine][gotemplate] before executing them.
|
||||
Variables are accessible through dot syntax (`.VARNAME`).
|
||||
|
||||
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: '3'
|
||||
|
||||
tasks:
|
||||
print-date:
|
||||
cmds:
|
||||
- echo {{now | date "2006-01-02"}}
|
||||
```
|
||||
|
||||
Task also adds the following functions:
|
||||
|
||||
- `OS`: Returns the operating system. Possible values are `windows`, `linux`,
|
||||
`darwin` (macOS) and `freebsd`.
|
||||
- `ARCH`: return the architecture Task was compiled to: `386`, `amd64`, `arm` or
|
||||
`s390x`.
|
||||
- `splitLines`: Splits Unix (`\n`) and Windows (`\r\n`) styled newlines.
|
||||
- `catLines`: Replaces Unix (`\n`) and Windows (`\r\n`) styled newlines with a
|
||||
space.
|
||||
- `toSlash`: Does nothing on Unix, but on Windows converts a string from `\`
|
||||
path format to `/`.
|
||||
- `fromSlash`: Opposite of `toSlash`. Does nothing on Unix, but on Windows
|
||||
converts a string from `/` path format to `\`.
|
||||
- `exeExt`: Returns the right executable extension for the current OS (`".exe"`
|
||||
for Windows, `""` for others).
|
||||
- `shellQuote` (aliased to `q`): Quotes a string to make it safe for use in shell scripts. Task
|
||||
uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/syntax#Quote)
|
||||
for this. The Bash dialect is assumed.
|
||||
- `splitArgs`: Splits a string as if it were a command's arguments. Task uses
|
||||
[this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/shell#Fields)
|
||||
- `joinPath`: Joins any number of arguments into a path. The same as Go's
|
||||
[filepath.Join](https://pkg.go.dev/path/filepath#Join).
|
||||
- `relPath`: Converts an absolute path (second argument) into a relative path,
|
||||
based on a base path (first argument). The same as Go's
|
||||
[filepath.Rel](https://pkg.go.dev/path/filepath#Rel).
|
||||
- `merge`: Creates a new map that is a copy of the first map with the keys of
|
||||
each subsequent map merged into it. If there is a duplicate key, the value of
|
||||
the last map with that key is used.
|
||||
- `spew`: Returns the Go representation of a specific variable. Useful for
|
||||
debugging. Uses the [davecgh/go-spew](https://github.com/davecgh/go-spew)
|
||||
package.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print-os:
|
||||
cmds:
|
||||
- echo '{{OS}} {{ARCH}}'
|
||||
- echo '{{if eq OS "windows"}}windows-command{{else}}unix-command{{end}}'
|
||||
# This will be path/to/file on Unix but path\to\file on Windows
|
||||
- echo '{{fromSlash "path/to/file"}}'
|
||||
enumerated-file:
|
||||
vars:
|
||||
CONTENT: |
|
||||
foo
|
||||
bar
|
||||
cmds:
|
||||
- |
|
||||
cat << EOF > output.txt
|
||||
{{range $i, $line := .CONTENT | splitLines -}}
|
||||
{{printf "%3d" $i}}: {{$line}}
|
||||
{{end}}EOF
|
||||
```
|
||||
|
||||
## Help
|
||||
|
||||
Running `task --list` (or `task -l`) lists all tasks with a description. The
|
||||
@@ -1996,4 +2058,5 @@ if called by another task, either directly or as a dependency.
|
||||
{/* prettier-ignore-start */}
|
||||
[gotemplate]: https://golang.org/pkg/text/template/
|
||||
[map-variables]: ./experiments/map_variables.mdx
|
||||
[templating-reference]: ./reference/templating.mdx
|
||||
{/* prettier-ignore-end */}
|
||||
|
||||
@@ -9,6 +9,8 @@ import { DISCORD_URL } from './constants';
|
||||
import { GITHUB_URL } from './constants';
|
||||
import { MASTODON_URL } from './constants';
|
||||
import { TWITTER_URL } from './constants';
|
||||
import { STACK_OVERFLOW } from './constants';
|
||||
import { ANSWER_OVERFLOW } from './constants';
|
||||
|
||||
import lightCodeTheme from './src/themes/prismLight';
|
||||
import darkCodeTheme from './src/themes/prismDark';
|
||||
@@ -62,7 +64,10 @@ const config: Config = {
|
||||
}
|
||||
}
|
||||
},
|
||||
blog: {},
|
||||
blog: {
|
||||
blogSidebarTitle: 'All posts',
|
||||
blogSidebarCount: 'ALL'
|
||||
},
|
||||
theme: {
|
||||
customCss: [
|
||||
'./src/css/custom.css',
|
||||
@@ -187,6 +192,14 @@ const config: Config = {
|
||||
label: 'Discord',
|
||||
href: DISCORD_URL
|
||||
},
|
||||
{
|
||||
label: 'Stack Overflow',
|
||||
href: STACK_OVERFLOW
|
||||
},
|
||||
{
|
||||
label: 'Answer Overflow',
|
||||
href: ANSWER_OVERFLOW
|
||||
},
|
||||
{
|
||||
label: 'OpenCollective',
|
||||
href: 'https://opencollective.com/task'
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
(function () {
|
||||
function attachAd() {
|
||||
var wrapper = document.getElementById('sidebar-ads');
|
||||
var blogSidebar = document.querySelector('[class*="BlogSidebar"]');
|
||||
|
||||
if (!wrapper && blogSidebar) {
|
||||
wrapper = document.createElement('div');
|
||||
wrapper.id = 'sidebar-ads';
|
||||
blogSidebar.appendChild(wrapper);
|
||||
}
|
||||
|
||||
if (wrapper) {
|
||||
var el = document.createElement('script');
|
||||
el.setAttribute('type', 'text/javascript');
|
||||
|
||||
@@ -277,17 +277,9 @@
|
||||
"map": {
|
||||
"type": "object",
|
||||
"description": "The value will be treated as a literal map type and stored in the variable"
|
||||
},
|
||||
"json": {
|
||||
"type": "string",
|
||||
"description": "The value will parsed as a JSON string and stored in the variable"
|
||||
},
|
||||
"yaml": {
|
||||
"type": "string",
|
||||
"description": "The value will parsed as a YAML string and stored in the variable"
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"task_call": {
|
||||
"type": "object",
|
||||
@@ -496,7 +488,8 @@
|
||||
"description": "Failure message to display when the condition fails",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"glob": {
|
||||
"anyOf": [
|
||||
@@ -515,7 +508,8 @@
|
||||
"description": "File or glob pattern to exclude from the list",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"run": {
|
||||
"type": "string",
|
||||
@@ -545,7 +539,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"requires_obj": {
|
||||
"type": "object",
|
||||
@@ -557,7 +552,8 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
|
||||
@@ -5,6 +5,50 @@ sidebar_position: 14
|
||||
|
||||
# Changelog
|
||||
|
||||
## v3.38.0 - 2024-06-30
|
||||
|
||||
- Added `TASK_EXE` special variable (#1616, #1624 by @pd93 and @andreynering).
|
||||
- Some YAML parsing errors will now show in a more user friendly way (#1619 by
|
||||
@pd93).
|
||||
- Prefixed outputs will now be colorized by default (#1572 by
|
||||
@AlexanderArvidsson)
|
||||
- [References](https://taskfile.dev/usage/#referencing-other-variables) are now
|
||||
generally available (no experiments required) (#1654 by @pd93).
|
||||
- Templating functions can now be used in references (#1645, #1654 by @pd93).
|
||||
- Added a new
|
||||
[templating reference page](https://taskfile.dev/reference/templating/) to the
|
||||
documentation (#1614, #1653 by @pd93).
|
||||
- If using the
|
||||
[Map Variables experiment (1)](https://taskfile.dev/experiments/map-variables/?proposal=1),
|
||||
references are available by
|
||||
[prefixing a string with a `#`](https://taskfile.dev/experiments/map-variables/?proposal=1#references)
|
||||
(#1654 by @pd93).
|
||||
- If using the
|
||||
[Map Variables experiment (2)](https://taskfile.dev/experiments/map-variables/?proposal=2),
|
||||
the `yaml` and `json` keys are no longer available (#1654 by @pd93).
|
||||
- Added a new `TASK_REMOTE_DIR` environment variable to configure where cached
|
||||
remote Taskfiles are stored (#1661 by @vmaerten).
|
||||
- Added a new `--clear-cache` flag to clear the cache of remote Taskfiles (#1639
|
||||
by @vmaerten).
|
||||
- Improved the readability of cached remote Taskfile filenames (#1636 by
|
||||
@vmaerten).
|
||||
- Starting releasing a binary for the `riscv64` architecture on Linux (#1699 by
|
||||
@mengzhuo).
|
||||
- Added `CLI_SILENT` and `CLI_VERBOSE` variables (#1480, #1669 by @Vince-Smith).
|
||||
- Fixed a couple of bugs with the `prompt:` feature (#1657 by @pd93).
|
||||
- Fixed JSON Schema to disallow invalid properties (#1657 by @pd93).
|
||||
- Fixed version checks not working as intended (#872, #1663 by @vmaerten).
|
||||
- Fixed a bug where included tasks were run multiple times even if `run: once`
|
||||
was set (#852, #1655 by @pd93).
|
||||
- Fixed some bugs related to column formatting in the terminal (#1350, #1637,
|
||||
#1656 by @vmaerten).
|
||||
|
||||
## v3.37.2 - 2024-05-12
|
||||
|
||||
- Fixed a bug where an empty Taskfile would cause a panic (#1648 by @pd93).
|
||||
- Fixed a bug where includes Taskfile variable were not being merged correctly
|
||||
(#1643, #1649 by @pd93).
|
||||
|
||||
## v3.37.1 - 2024-05-09
|
||||
|
||||
- Fix bug where non-string values (numbers, bools) added to `env:` weren't been
|
||||
@@ -19,7 +63,7 @@ sidebar_position: 14
|
||||
- Refactored how Task reads, parses and merges Taskfiles using a DAG (#1563,
|
||||
#1607 by @pd93).
|
||||
- Fix a bug which stopped tasks from using `stdin` as input (#1593, #1623 by
|
||||
@pd03).
|
||||
@pd93).
|
||||
- Fix error when a file or directory in the project contained a special char
|
||||
like `&`, `(` or `)` (#1551, #1584 by @andreynering).
|
||||
- Added alias `q` for template function `shellQuote` (#1601, #1603 by @vergenzt)
|
||||
|
||||
@@ -148,6 +148,8 @@ If you have questions, feel free to ask them in the `#help` forum channel on our
|
||||
---
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[experiments]: /experiments
|
||||
[experiments-workflow]: /experiments#workflow
|
||||
[task]: https://github.com/go-task/task
|
||||
[vscode-task]: https://github.com/go-task/vscode-task
|
||||
[go]: https://go.dev
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
slug: /deprecations/template-functions/
|
||||
---
|
||||
|
||||
# Template Functions
|
||||
|
||||
:::warning
|
||||
|
||||
This deprecation breaks the following functionality:
|
||||
|
||||
- A small set of templating functions
|
||||
|
||||
:::
|
||||
|
||||
The following templating functions are deprecated. Any replacement functions are
|
||||
listed besides the function being removed.
|
||||
|
||||
| Deprecated function | Replaced by |
|
||||
| ------------------- | ----------- |
|
||||
| `IsSH` | - |
|
||||
| `FromSlash` | `fromSlash` |
|
||||
| `ToSlash` | `toSlash` |
|
||||
| `ExeExt` | `exeExt` |
|
||||
@@ -43,9 +43,9 @@ To enable this experiment, set the environment variable:
|
||||
|
||||
:::
|
||||
|
||||
This proposal removes support for the `sh` keyword in favour of a new syntax for
|
||||
dynamically defined variables, This allows you to define a map directly as you
|
||||
would for any other type:
|
||||
This proposal removes support for the `sh` and `ref` keywords in favour of a new
|
||||
syntax for dynamically defined variables and references. This allows you to
|
||||
define a map directly as you would for any other type:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -60,11 +60,26 @@ tasks:
|
||||
|
||||
## Migration
|
||||
|
||||
Taskfiles with dynamically defined variables via the `sh` subkey will no longer
|
||||
work with this experiment enabled. In order to keep using dynamically defined
|
||||
variables, you will need to migrate your Taskfile to use the new syntax.
|
||||
Taskfiles with dynamically defined variables via the `sh` subkey or references
|
||||
defined with `ref` will no longer work with this experiment enabled. In order to
|
||||
keep using these features, you will need to migrate your Taskfile to use the new
|
||||
syntax.
|
||||
|
||||
Previously, you might have defined a dynamic variable like this:
|
||||
### Dynamic Variables
|
||||
|
||||
Previously, you had to define dynamic variables using the `sh` subkey. With this
|
||||
experiment enabled, you will need to remove the `sh` subkey and define your
|
||||
command as a string that begins with a `$`. This will instruct Task to interpret
|
||||
the string as a command instead of a literal value and the variable will be
|
||||
populated with the output of the command. For example:
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -78,10 +93,8 @@ tasks:
|
||||
- 'echo {{.CALCULATED_VAR}}'
|
||||
```
|
||||
|
||||
With this experiment enabled, you will need to remove the `sh` subkey and define
|
||||
your command as a string that begins with a `$`. This will instruct Task to
|
||||
interpret the string as a command instead of a literal value and the variable
|
||||
will be populated with the output of the command. For example:
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
@@ -89,14 +102,56 @@ version: 3
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
CALCULATED_VAR: '$echo hello'
|
||||
CALCULATED_VAR: '$echo hello' # <-- Prefix dynamic variable with a `$`
|
||||
cmds:
|
||||
- 'echo {{.CALCULATED_VAR}}'
|
||||
```
|
||||
|
||||
If your current Taskfile contains a string variable that begins with a `$`, you
|
||||
will now need to escape the `$` with a backslash (`\`) to stop Task from
|
||||
executing it as a command.
|
||||
</TabItem></Tabs>
|
||||
|
||||
### References
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
VAR: 42
|
||||
VAR_REF:
|
||||
ref: '.FOO'
|
||||
cmds:
|
||||
- 'echo {{.VAR_REF}}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
VAR: 42
|
||||
VAR_REF: '#.FOO' # <-- Prefix reference with a `#`
|
||||
cmds:
|
||||
- 'echo {{.VAR_REF}}'
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
If your current Taskfile contains a string variable that begins with a `$` or a
|
||||
`#`, you will now need to escape it with a backslash (`\`) to stop Task from
|
||||
interpreting it as a command or reference.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
@@ -123,157 +178,12 @@ tasks:
|
||||
BAR: true # <-- Other types of variables are still defined directly on the key
|
||||
BAZ:
|
||||
sh: 'echo Hello Task' # <-- The `sh` subkey is still supported
|
||||
QUX:
|
||||
ref: '.BAZ' # <-- The `ref` subkey is still supported
|
||||
cmds:
|
||||
- 'echo {{.FOO.a}}'
|
||||
```
|
||||
|
||||
## Parsing JSON and YAML
|
||||
|
||||
In addition to the new `map` keyword, this proposal also adds support for the
|
||||
`json` and `yaml` keywords for parsing JSON and YAML strings into real
|
||||
objects/arrays. This is similar to the `fromJSON` template function, but means
|
||||
that you only have to parse the JSON/YAML once when you declare the variable,
|
||||
instead of every time you want to access a value.
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: '{"a": 1, "b": 2, "c": 3}' # <-- JSON string
|
||||
cmds:
|
||||
- 'echo {{(fromJSON .FOO).a}}' # <-- Parse JSON string every time you want to access a value
|
||||
- 'echo {{(fromJSON .FOO).b}}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO:
|
||||
json: '{"a": 1, "b": 2, "c": 3}' # <-- JSON string parsed once
|
||||
cmds:
|
||||
- 'echo {{.FOO.a}}' # <-- Access values directly
|
||||
- 'echo {{.FOO.b}}'
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
## Variables by reference
|
||||
|
||||
Lastly, this proposal adds support for defining and passing variables by
|
||||
reference. This is really important now that variables can be types other than a
|
||||
string.
|
||||
|
||||
Previously, to send a variable from one task to another, you would have to use
|
||||
the templating system. Unfortunately, the templater _always_ outputs a string
|
||||
and operations on the passed variable may not have behaved as expected. With
|
||||
this proposal, you can now pass variables by reference using the `ref` subkey:
|
||||
|
||||
<Tabs defaultValue="2"
|
||||
values={[
|
||||
{label: 'Before', value: '1'},
|
||||
{label: 'After', value: '2'}
|
||||
]}>
|
||||
|
||||
<TabItem value="1">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO: '{{.FOO}}' # <-- FOO gets converted to a string when passed to bar
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .FOO 0}}' # <-- FOO is a string so the task outputs '91' which is the ASCII code for '[' instead of the expected 'A'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2">
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO:
|
||||
ref: .FOO # <-- FOO gets passed by reference to bar and maintains its type
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .FOO 0}}' # <-- FOO is still a map so the task outputs 'A' as expected
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
This means that the type of the variable is maintained when it is passed to
|
||||
another Task. This also works the same way when calling `deps` and when defining
|
||||
a variable and can be used in any combination:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
BAR:
|
||||
ref: .FOO # <-- BAR is defined as a reference to FOO
|
||||
deps:
|
||||
- task: bar
|
||||
vars:
|
||||
BAR:
|
||||
ref: .BAR # <-- BAR gets passed by reference to bar and maintains its type
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{index .BAR 0}}' # <-- BAR still refers to FOO so the task outputs 'A'
|
||||
```
|
||||
|
||||
All references use the same templating syntax as regular templates, so in
|
||||
addition to simply calling `.FOO`, you can also pass subkeys (`.FOO.BAR`) or
|
||||
indexes (`index .FOO 0`) and use functions (`len .FOO`):
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
|
||||
tasks:
|
||||
foo:
|
||||
vars:
|
||||
FOO: [A, B, C] # <-- FOO is defined as an array
|
||||
cmds:
|
||||
- task: bar
|
||||
vars:
|
||||
FOO:
|
||||
ref: index .FOO 0 # <-- The element at index 0 is passed by reference to bar
|
||||
bar:
|
||||
cmds:
|
||||
- 'echo {{.MYVAR}}' # <-- FOO is just the letter 'A'
|
||||
```
|
||||
|
||||
</TabItem></Tabs>
|
||||
|
||||
## Looping over maps
|
||||
|
||||
@@ -105,13 +105,20 @@ internet and cached locally. If for whatever reason, you lose access to the
|
||||
internet, you will still be able to run your tasks by specifying the `--offline`
|
||||
flag. This will tell Task to use the latest cached version of the file instead
|
||||
of trying to download it. You are able to use the `--download` flag to update
|
||||
the cached version of the remote files without running any tasks.
|
||||
the cached version of the remote files without running any tasks. You are able
|
||||
to use the `--clear-cache` flag to clear all cached version of the remote files
|
||||
without running any tasks.
|
||||
|
||||
By default, Task will timeout requests to download remote files after 10 seconds
|
||||
and look for a cached copy instead. This timeout can be configured by setting
|
||||
the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will
|
||||
set the timeout to 5 seconds.
|
||||
|
||||
By default, the cache is stored in the Task temp directory, represented by the
|
||||
`TASK_TEMP_DIR` [environment variable](../reference/environment.mdx) You can
|
||||
override the location of the cache by setting the `TASK_REMOTE_DIR` environment
|
||||
variable. This way, you can share the cache between different projects.
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[enabling-experiments]: ./experiments.mdx#enabling-experiments
|
||||
[man-in-the-middle-attacks]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
|
||||
|
||||
@@ -7,6 +7,25 @@ sidebar_position: 15
|
||||
|
||||
This page contains a list of frequently asked questions about Task.
|
||||
|
||||
## When will \<feature\> be released? / ETAs
|
||||
|
||||
Task is _free_ and _open source_ project maintained by a small group of
|
||||
volunteers with full time jobs and lives outside of the project. Because of
|
||||
this, it is difficult to predict how much time we will be able to dedicate to
|
||||
the project in advance and we don't want to make any promises that we can't
|
||||
keep. For this reason, we are unable to provide ETAs for new features or
|
||||
releases. We make a "best effort" to provide regular releases and fix bugs in a
|
||||
timely fashion, but sometimes our personal lives must take priority.
|
||||
|
||||
ETAs are probably the number one question we (and maintainers of other open
|
||||
source projects) get asked. We understand that you are passionate about the
|
||||
project, but it can be overwhelming to be asked this question so often. Please
|
||||
be patient and avoid asking for ETAs.
|
||||
|
||||
The best way to speed things up is to contribute to the project yourself. We
|
||||
always appreciate new contributors. If you are interested in contributing, check
|
||||
out the [contributing guide](./contributing.mdx).
|
||||
|
||||
## Why won't my task update my shell environment?
|
||||
|
||||
This is a limitation of how shells work. Task runs as a subprocess of your
|
||||
|
||||
@@ -146,6 +146,15 @@ can install Task from [winget-pkgs](https://github.com/microsoft/winget-pkgs).
|
||||
winget install Task.Task
|
||||
```
|
||||
|
||||
### Pacstall
|
||||
If you are using Debian or Ubuntu, and have [Pacstall](https://pacstall.dev/) installed, you can install Task by running:
|
||||
|
||||
```shell
|
||||
pacstall -I go-task-deb
|
||||
```
|
||||
|
||||
This installation method is community owned. After a new release of Task, it may take some time until it's available in [Pacstall](https://pacstall.dev/packages/go-task-deb).
|
||||
|
||||
## Get The Binary
|
||||
|
||||
### Binary
|
||||
@@ -185,6 +194,14 @@ default.
|
||||
|
||||
:::
|
||||
|
||||
By default, it installs the latest version available.
|
||||
You can also specify a tag (available in [releases](https://github.com/go-task/task/releases))
|
||||
to install a specific version:
|
||||
|
||||
```shell
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d v3.36.0
|
||||
```
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
If you want to install Task in GitHub Actions you can try using
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
position: 4
|
||||
label: Reference
|
||||
118
website/versioned_docs/version-latest/reference/cli.mdx
Normal file
118
website/versioned_docs/version-latest/reference/cli.mdx
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
slug: /reference/cli
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# CLI Reference
|
||||
|
||||
Task CLI commands have the following syntax:
|
||||
|
||||
```shell
|
||||
task [--flags] [tasks...] [-- CLI_ARGS...]
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If `--` is given, all remaining arguments will be assigned to a special
|
||||
`CLI_ARGS` variable
|
||||
|
||||
## Flags
|
||||
|
||||
:::
|
||||
|
||||
| Short | Flag | Type | Default | Description |
|
||||
| ----- | --------------------------- | -------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-c` | `--color` | `bool` | `true` | Colored output. Enabled by default. Set flag to `false` or use `NO_COLOR=1` to disable. |
|
||||
| `-C` | `--concurrency` | `int` | `0` | Limit number tasks to run concurrently. Zero means unlimited. |
|
||||
| `-d` | `--dir` | `string` | Working directory | Sets directory of execution. |
|
||||
| `-n` | `--dry` | `bool` | `false` | Compiles and prints tasks in the order that they would be run, without executing them. |
|
||||
| `-x` | `--exit-code` | `bool` | `false` | Pass-through the exit code of the task command. |
|
||||
| `-f` | `--force` | `bool` | `false` | Forces execution even when the task is up-to-date. |
|
||||
| `-g` | `--global` | `bool` | `false` | Runs global Taskfile, from `$HOME/Taskfile.{yml,yaml}`. |
|
||||
| `-h` | `--help` | `bool` | `false` | Shows Task usage. |
|
||||
| `-i` | `--init` | `bool` | `false` | Creates a new Taskfile.yml in the current folder. |
|
||||
| `-I` | `--interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
|
||||
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
|
||||
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
|
||||
| | `--sort` | `string` | `default` | Changes the order of the tasks when listed.<br />`default` - Alphanumeric with root tasks first<br />`alphanumeric` - Alphanumeric<br />`none` - No sorting (As they appear in the Taskfile) |
|
||||
| | `--json` | `bool` | `false` | See [JSON Output](#json-output) |
|
||||
| `-o` | `--output` | `string` | Default set in the Taskfile or `interleaved` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
|
||||
| | `--output-group-begin` | `string` | | Message template to print before a task's grouped output. |
|
||||
| | `--output-group-end` | `string` | | Message template to print after a task's grouped output. |
|
||||
| | `--output-group-error-only` | `bool` | `false` | Swallow command output on zero exit code. |
|
||||
| `-p` | `--parallel` | `bool` | `false` | Executes tasks provided on command line in parallel. |
|
||||
| `-s` | `--silent` | `bool` | `false` | Disables echoing. |
|
||||
| `-y` | `--yes` | `bool` | `false` | Assume "yes" as answer to all prompts. |
|
||||
| | `--status` | `bool` | `false` | Exits with non-zero exit code if any of the given tasks is not up-to-date. |
|
||||
| | `--summary` | `bool` | `false` | Show summary about a task. |
|
||||
| `-t` | `--taskfile` | `string` | `Taskfile.yml` or `Taskfile.yaml` | |
|
||||
| `-v` | `--verbose` | `bool` | `false` | Enables verbose mode. |
|
||||
| | `--version` | `bool` | `false` | Show Task version. |
|
||||
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task.
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Task will sometimes exit with specific exit codes. These codes are split into
|
||||
three groups with the following ranges:
|
||||
|
||||
- General errors (0-99)
|
||||
- Taskfile errors (100-199)
|
||||
- Task errors (200-299)
|
||||
|
||||
A full list of the exit codes and their descriptions can be found below:
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| 0 | Success |
|
||||
| 1 | An unknown error occurred |
|
||||
| 100 | No Taskfile was found |
|
||||
| 101 | A Taskfile already exists when trying to initialize one |
|
||||
| 102 | The Taskfile is invalid or cannot be parsed |
|
||||
| 103 | A remote Taskfile could not be downloaded |
|
||||
| 104 | A remote Taskfile was not trusted by the user |
|
||||
| 105 | A remote Taskfile was could not be fetched securely |
|
||||
| 106 | No cache was found for a remote Taskfile in offline mode |
|
||||
| 107 | No schema version was defined in the Taskfile |
|
||||
| 200 | The specified task could not be found |
|
||||
| 201 | An error occurred while executing a command inside of a task |
|
||||
| 202 | The user tried to invoke a task that is internal |
|
||||
| 203 | There a multiple tasks with the same name or alias |
|
||||
| 204 | A task was called too many times |
|
||||
| 205 | A task was cancelled by the user |
|
||||
| 206 | A task was not executed due to missing required variables |
|
||||
|
||||
These codes can also be found in the repository in
|
||||
[`errors/errors.go`](https://github.com/go-task/task/blob/main/errors/errors.go).
|
||||
|
||||
:::info
|
||||
|
||||
When Task is run with the `-x`/`--exit-code` flag, the exit code of any failed
|
||||
commands will be passed through to the user instead.
|
||||
|
||||
:::
|
||||
|
||||
## JSON Output
|
||||
|
||||
When using the `--json` flag in combination with either the `--list` or
|
||||
`--list-all` flags, the output will be a JSON object with the following
|
||||
structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"name": "",
|
||||
"desc": "",
|
||||
"summary": "",
|
||||
"up_to_date": false,
|
||||
"location": {
|
||||
"line": 54,
|
||||
"column": 3,
|
||||
"taskfile": "/path/to/Taskfile.yml"
|
||||
}
|
||||
}
|
||||
// ...
|
||||
],
|
||||
"location": "/path/to/Taskfile.yml"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
slug: /reference/environment
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Environment Reference
|
||||
|
||||
Task allows you to configure some behavior using environment variables. This
|
||||
page lists all the environment variables that Task supports.
|
||||
|
||||
| ENV | Default | Description |
|
||||
| ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `TASK_TEMP_DIR` | `.task` | Location of the temp dir. Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `TASK_REMOTE_DIR` | `TASK_TEMP_DIR` | Location of the remote temp dir (used for caching). Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `FORCE_COLOR` | | Force color output usage. |
|
||||
|
||||
## Custom Colors
|
||||
|
||||
| ENV | Default | Description |
|
||||
| --------------------------- | ------- | ----------------------- |
|
||||
| `TASK_COLOR_RESET` | `0` | Color used for white. |
|
||||
| `TASK_COLOR_RED` | `31` | Color used for red. |
|
||||
| `TASK_COLOR_GREEN` | `32` | Color used for green. |
|
||||
| `TASK_COLOR_YELLOW` | `33` | Color used for yellow. |
|
||||
| `TASK_COLOR_BLUE` | `34` | Color used for blue. |
|
||||
| `TASK_COLOR_MAGENTA` | `35` | Color used for magenta. |
|
||||
| `TASK_COLOR_CYAN` | `36` | Color used for cyan. |
|
||||
| `TASK_COLOR_BRIGHT_RED` | `91` | Color used for red. |
|
||||
| `TASK_COLOR_BRIGHT_GREEN` | `92` | Color used for green. |
|
||||
| `TASK_COLOR_BRIGHT_YELLOW` | `93` | Color used for yellow. |
|
||||
| `TASK_COLOR_BRIGHT_BLUE` | `94` | Color used for blue. |
|
||||
| `TASK_COLOR_BRIGHT_MAGENTA` | `95` | Color used for magenta. |
|
||||
| `TASK_COLOR_BRIGHT_CYAN` | `96` | Color used for cyan. |
|
||||
|
||||
All color variables are [ANSI color codes][ansi]. You can specify multiple codes
|
||||
separated by a semicolon. For example: `31;1` will make the text bold and red.
|
||||
Task also supports 8-bit color (256 colors). You can specify these colors by
|
||||
using the sequence `38;2;R:G:B` for foreground colors and `48;2;R:G:B` for
|
||||
background colors where `R`, `G` and `B` should be replaced with values between
|
||||
0 and 255.
|
||||
|
||||
For convenience, we allow foreground colors to be specified using shorthand,
|
||||
comma-separated syntax: `R,G,B`. For example, `255,0,0` is equivalent to
|
||||
`38;2;255:0:0`.
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
{/* prettier-ignore-end */}
|
||||
@@ -1,171 +1,11 @@
|
||||
---
|
||||
slug: /api/
|
||||
sidebar_position: 4
|
||||
slug: /reference/schema
|
||||
sidebar_position: 2
|
||||
toc_min_heading_level: 2
|
||||
toc_max_heading_level: 5
|
||||
---
|
||||
|
||||
# API Reference
|
||||
|
||||
## CLI
|
||||
|
||||
Task command line tool has the following syntax:
|
||||
|
||||
```shell
|
||||
task [--flags] [tasks...] [-- CLI_ARGS...]
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If `--` is given, all remaining arguments will be assigned to a special
|
||||
`CLI_ARGS` variable
|
||||
|
||||
:::
|
||||
|
||||
| Short | Flag | Type | Default | Description |
|
||||
| ----- | --------------------------- | -------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-c` | `--color` | `bool` | `true` | Colored output. Enabled by default. Set flag to `false` or use `NO_COLOR=1` to disable. |
|
||||
| `-C` | `--concurrency` | `int` | `0` | Limit number tasks to run concurrently. Zero means unlimited. |
|
||||
| `-d` | `--dir` | `string` | Working directory | Sets directory of execution. |
|
||||
| `-n` | `--dry` | `bool` | `false` | Compiles and prints tasks in the order that they would be run, without executing them. |
|
||||
| `-x` | `--exit-code` | `bool` | `false` | Pass-through the exit code of the task command. |
|
||||
| `-f` | `--force` | `bool` | `false` | Forces execution even when the task is up-to-date. |
|
||||
| `-g` | `--global` | `bool` | `false` | Runs global Taskfile, from `$HOME/Taskfile.{yml,yaml}`. |
|
||||
| `-h` | `--help` | `bool` | `false` | Shows Task usage. |
|
||||
| `-i` | `--init` | `bool` | `false` | Creates a new Taskfile.yml in the current folder. |
|
||||
| `-I` | `--interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). |
|
||||
| `-l` | `--list` | `bool` | `false` | Lists tasks with description of current Taskfile. |
|
||||
| `-a` | `--list-all` | `bool` | `false` | Lists tasks with or without a description. |
|
||||
| | `--sort` | `string` | `default` | Changes the order of the tasks when listed.<br />`default` - Alphanumeric with root tasks first<br />`alphanumeric` - Alphanumeric<br />`none` - No sorting (As they appear in the Taskfile) |
|
||||
| | `--json` | `bool` | `false` | See [JSON Output](#json-output) |
|
||||
| `-o` | `--output` | `string` | Default set in the Taskfile or `intervealed` | Sets output style: [`interleaved`/`group`/`prefixed`]. |
|
||||
| | `--output-group-begin` | `string` | | Message template to print before a task's grouped output. |
|
||||
| | `--output-group-end` | `string` | | Message template to print after a task's grouped output. |
|
||||
| | `--output-group-error-only` | `bool` | `false` | Swallow command output on zero exit code. |
|
||||
| `-p` | `--parallel` | `bool` | `false` | Executes tasks provided on command line in parallel. |
|
||||
| `-s` | `--silent` | `bool` | `false` | Disables echoing. |
|
||||
| `-y` | `--yes` | `bool` | `false` | Assume "yes" as answer to all prompts. |
|
||||
| | `--status` | `bool` | `false` | Exits with non-zero exit code if any of the given tasks is not up-to-date. |
|
||||
| | `--summary` | `bool` | `false` | Show summary about a task. |
|
||||
| `-t` | `--taskfile` | `string` | `Taskfile.yml` or `Taskfile.yaml` | |
|
||||
| `-v` | `--verbose` | `bool` | `false` | Enables verbose mode. |
|
||||
| | `--version` | `bool` | `false` | Show Task version. |
|
||||
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task. |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Task will sometimes exit with specific exit codes. These codes are split into
|
||||
three groups with the following ranges:
|
||||
|
||||
- General errors (0-99)
|
||||
- Taskfile errors (100-199)
|
||||
- Task errors (200-299)
|
||||
|
||||
A full list of the exit codes and their descriptions can be found below:
|
||||
|
||||
| Code | Description |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| 0 | Success |
|
||||
| 1 | An unknown error occurred |
|
||||
| 100 | No Taskfile was found |
|
||||
| 101 | A Taskfile already exists when trying to initialize one |
|
||||
| 102 | The Taskfile is invalid or cannot be parsed |
|
||||
| 103 | A remote Taskfile could not be downloaded |
|
||||
| 104 | A remote Taskfile was not trusted by the user |
|
||||
| 105 | A remote Taskfile was could not be fetched securely |
|
||||
| 106 | No cache was found for a remote Taskfile in offline mode |
|
||||
| 107 | No schema version was defined in the Taskfile |
|
||||
| 200 | The specified task could not be found |
|
||||
| 201 | An error occurred while executing a command inside of a task |
|
||||
| 202 | The user tried to invoke a task that is internal |
|
||||
| 203 | There a multiple tasks with the same name or alias |
|
||||
| 204 | A task was called too many times |
|
||||
| 205 | A task was cancelled by the user |
|
||||
| 206 | A task was not executed due to missing required variables |
|
||||
|
||||
These codes can also be found in the repository in
|
||||
[`errors/errors.go`](https://github.com/go-task/task/blob/main/errors/errors.go).
|
||||
|
||||
:::info
|
||||
|
||||
When Task is run with the `-x`/`--exit-code` flag, the exit code of any failed
|
||||
commands will be passed through to the user instead.
|
||||
|
||||
:::
|
||||
|
||||
## JSON Output
|
||||
|
||||
When using the `--json` flag in combination with either the `--list` or
|
||||
`--list-all` flags, the output will be a JSON object with the following
|
||||
structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"name": "",
|
||||
"desc": "",
|
||||
"summary": "",
|
||||
"up_to_date": false,
|
||||
"location": {
|
||||
"line": 54,
|
||||
"column": 3,
|
||||
"taskfile": "/path/to/Taskfile.yml"
|
||||
}
|
||||
}
|
||||
// ...
|
||||
],
|
||||
"location": "/path/to/Taskfile.yml"
|
||||
}
|
||||
```
|
||||
|
||||
## Special Variables
|
||||
|
||||
There are some special variables that is available on the templating system:
|
||||
|
||||
| Var | Description |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `CLI_ARGS` | Contain all extra arguments passed after `--` when calling Task through the CLI. |
|
||||
| `CLI_FORCE` | A boolean containing whether the `--force` or `--force-all` flags were set. |
|
||||
| `TASK` | The name of the current task. |
|
||||
| `ROOT_TASKFILE` | The absolute path of the root Taskfile. |
|
||||
| `ROOT_DIR` | The absolute path of the root Taskfile directory. |
|
||||
| `TASKFILE` | The absolute path of the included Taskfile. |
|
||||
| `TASKFILE_DIR` | The absolute path of the included Taskfile directory. |
|
||||
| `USER_WORKING_DIR` | The absolute path of the directory `task` was called from. |
|
||||
| `CHECKSUM` | The checksum of the files listed in `sources`. Only available within the `status` prop and if method is set to `checksum`. |
|
||||
| `TIMESTAMP` | The date object of the greatest timestamp of the files listed in `sources`. Only available within the `status` prop and if method is set to `timestamp`. |
|
||||
| `TASK_VERSION` | The current version of task. |
|
||||
| `ITEM` | The value of the current iteration when using the `for` property. Can be changed to a different variable name using `as:`. |
|
||||
|
||||
## ENV
|
||||
|
||||
Some environment variables can be overridden to adjust Task behavior.
|
||||
|
||||
| ENV | Default | Description |
|
||||
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| `TASK_TEMP_DIR` | `.task` | Location of the temp dir. Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `TASK_COLOR_RESET` | `0` | Color used for white. |
|
||||
| `TASK_COLOR_BLUE` | `34` | Color used for blue. |
|
||||
| `TASK_COLOR_GREEN` | `32` | Color used for green. |
|
||||
| `TASK_COLOR_CYAN` | `36` | Color used for cyan. |
|
||||
| `TASK_COLOR_YELLOW` | `33` | Color used for yellow. |
|
||||
| `TASK_COLOR_MAGENTA` | `35` | Color used for magenta. |
|
||||
| `TASK_COLOR_RED` | `31` | Color used for red. |
|
||||
| `FORCE_COLOR` | | Force color output usage. |
|
||||
|
||||
All color variables are [ANSI color codes][ansi]. You can specify multiple codes
|
||||
separated by a semicolon. For example: `31;1` will make the text bold and red.
|
||||
Task also supports 8-bit color (256 colors). You can specify these colors by
|
||||
using the sequence `38;2;R:G:B` for foreground colors and `48;2;R:G:B` for
|
||||
background colors where `R`, `G` and `B` should be replaced with values between
|
||||
0 and 255.
|
||||
|
||||
For convenience, we allow foreground colors to be specified using shorthand,
|
||||
comma-separated syntax: `R,G,B`. For example, `255,0,0` is equivalent to
|
||||
`38;2;255:0:0`.
|
||||
|
||||
## Taskfile Schema
|
||||
# Schema Reference
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| ---------- | ---------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -183,7 +23,7 @@ comma-separated syntax: `R,G,B`. For example, `255,0,0` is equivalent to
|
||||
| `set` | `[]string` | | Specify options for the [`set` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html). |
|
||||
| `shopt` | `[]string` | | Specify option for the [`shopt` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html). |
|
||||
|
||||
### Include
|
||||
## Include
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| ---------- | --------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -206,7 +46,7 @@ includes:
|
||||
|
||||
:::
|
||||
|
||||
### Variable
|
||||
## Variable
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | -------- | ------- | ------------------------------------------------------------------------ |
|
||||
@@ -239,7 +79,7 @@ vars:
|
||||
|
||||
:::
|
||||
|
||||
### Task
|
||||
## Task
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------------- | ---------------------------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -289,7 +129,7 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### Command
|
||||
### Command
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| -------------- | ---------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -318,7 +158,7 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### Dependency
|
||||
### Dependency
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | ---------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -339,7 +179,7 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### For
|
||||
### For
|
||||
|
||||
The `for` parameter can be defined as a string, a list of strings or a map. If
|
||||
it is defined as a string, you can give it any of the following values:
|
||||
@@ -359,7 +199,7 @@ variable to define the values to loop over:
|
||||
| `split` | `string` | (any whitespace) | What string the variable should be split on. |
|
||||
| `as` | `string` | `ITEM` | The name of the iterator variable. |
|
||||
|
||||
#### Precondition
|
||||
### Precondition
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
@@ -379,12 +219,8 @@ tasks:
|
||||
|
||||
:::
|
||||
|
||||
#### Requires
|
||||
### Requires
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | ---------- | ------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `vars` | `[]string` | | List of variable or environment variable names that must be set if this task is to execute and run |
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
{/* prettier-ignore-end */}
|
||||
406
website/versioned_docs/version-latest/reference/templating.mdx
Normal file
406
website/versioned_docs/version-latest/reference/templating.mdx
Normal file
@@ -0,0 +1,406 @@
|
||||
---
|
||||
slug: /reference/templating/
|
||||
sidebar_position: 3
|
||||
toc_min_heading_level: 2
|
||||
toc_max_heading_level: 5
|
||||
---
|
||||
|
||||
# Templating Reference
|
||||
|
||||
Task's templating engine uses Go's [text/template][text/template] package to
|
||||
interpolate values. For detailed information about the usage of Go's templating
|
||||
engine, we recommend reading [the official documentation][text/template].
|
||||
However, we will provide a basic overview of the main features here.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Most string values in Task (though, not all) can be templated. The templating
|
||||
engine uses double curly braces `{{` and `}}` to denote a template. Anything
|
||||
inside the curly braces will be executed as a Go template and the result will be
|
||||
inserted into the resulting string. For example:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
hello:
|
||||
vars:
|
||||
MESSAGE: 'Hello, World!'
|
||||
cmds:
|
||||
- 'echo {{.MESSAGE}}'
|
||||
```
|
||||
|
||||
In this example, we have a task called `hello` with a single variable, `MESSAGE`
|
||||
defined. When the command is run, the templating engine will evaluate the
|
||||
variable and replace `{{.MESSAGE}}` with the variable's contents. This task will
|
||||
output `Hello, World!` to the terminal. Note that when referring to a variable,
|
||||
you must use dot notation.
|
||||
|
||||
You are also able to do more complex things in templates, such as conditional
|
||||
logic:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
maybe-happy:
|
||||
vars:
|
||||
SMILE: ':\)'
|
||||
FROWN: ':\('
|
||||
HAPPY: true
|
||||
cmds:
|
||||
- 'echo {{if .HAPPY}}{{.SMILE}}{{else}}{{.FROWN}}{{end}}'
|
||||
```
|
||||
|
||||
```txt
|
||||
:)
|
||||
```
|
||||
|
||||
...calling functions and piping values:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
uniq:
|
||||
vars:
|
||||
NUMBERS: '0,1,1,1,2,2,3'
|
||||
cmds:
|
||||
- 'echo {{splitList "," .NUMBERS | uniq | join ", " }}!'
|
||||
```
|
||||
|
||||
```txt
|
||||
0, 1, 2, 3
|
||||
```
|
||||
|
||||
...looping over values with control flow operators:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
loop:
|
||||
vars:
|
||||
NUMBERS: [0, 1, 1, 1, 2, 2, 3]
|
||||
cmds:
|
||||
# Ranges over NUMBERS and prints the index and value of each number until it finds a number greater than 1
|
||||
- "{{range $index, $num := .NUMBERS}}{{if gt $num 1 }}{{break}}{{end}}echo {{$index}}: {{$num}}\n{{end}}"
|
||||
```
|
||||
|
||||
```txt
|
||||
0: 0
|
||||
1: 1
|
||||
2: 1
|
||||
3: 1
|
||||
```
|
||||
|
||||
## Special Variables
|
||||
|
||||
Task defines some special variables that are always available to the templating
|
||||
engine. If you define a variable with the same name as a special variable, the
|
||||
special variable will be overridden.
|
||||
|
||||
| Var | Description |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `CLI_ARGS` | Contain all extra arguments passed after `--` when calling Task through the CLI. |
|
||||
| `CLI_FORCE` | A boolean containing whether the `--force` or `--force-all` flags were set. |
|
||||
| `TASK` | The name of the current task. |
|
||||
| `TASK_EXE` | The Task executable name or path. |
|
||||
| `ROOT_TASKFILE` | The absolute path of the root Taskfile. |
|
||||
| `ROOT_DIR` | The absolute path of the root Taskfile directory. |
|
||||
| `TASKFILE` | The absolute path of the included Taskfile. |
|
||||
| `TASKFILE_DIR` | The absolute path of the included Taskfile directory. |
|
||||
| `USER_WORKING_DIR` | The absolute path of the directory `task` was called from. |
|
||||
| `CHECKSUM` | The checksum of the files listed in `sources`. Only available within the `status` prop and if method is set to `checksum`. |
|
||||
| `TIMESTAMP` | The date object of the greatest timestamp of the files listed in `sources`. Only available within the `status` prop and if method is set to `timestamp`. |
|
||||
| `TASK_VERSION` | The current version of task. |
|
||||
| `ITEM` | The value of the current iteration when using the `for` property. Can be changed to a different variable name using `as:`. |
|
||||
|
||||
## Functions
|
||||
|
||||
Functions are provided at a few different levels in Task. Below, we list all the
|
||||
functions available for use in Task.
|
||||
|
||||
:::note
|
||||
|
||||
Functions marked with an asterisk (\*) also have `must` variants that will panic
|
||||
rather than erroring.
|
||||
|
||||
:::
|
||||
|
||||
### Built-in Functions
|
||||
|
||||
The first set of functions are [provided by Golang
|
||||
itself][go-template-functions]:
|
||||
|
||||
| Function | Description |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `and` | Returns the boolean AND of its arguments by returning the first empty argument or the last argument. That is, `and x y` behaves as `if x then y else x`. Evaluation proceeds through the arguments left to right and returns when the result is determined. |
|
||||
| `call` | Returns the result of calling the first argument, which must be a function, with the remaining arguments as parameters. Thus `call .X.Y 1 2` is, in Go notation, `dot.X.Y(1, 2)` where `Y` is a func-valued field, map entry, or the like. The first argument must be the result of an evaluation that yields a value of function type (as distinct from a predefined function such as print). The function must return either one or two result values, the second of which is of type error. If the arguments don't match the function or the returned error value is non-nil, execution stops. |
|
||||
| `html` | Returns the escaped HTML equivalent of the textual representation of its arguments. This function is unavailable in [html/template][html/template], with a few exceptions. |
|
||||
| `index` | Returns the result of indexing its first argument by the following arguments. Thus `index x 1 2 3` is, in Go syntax, `x[1][2][3]`. Each indexed item must be a map, slice, or array. |
|
||||
| `slice` | slice returns the result of slicing its first argument by the remaining arguments. Thus `slice x 1 2` is, in Go syntax, `x[1:2]`, while `slice x` is `x[:]`, `slice x 1` is `x[1:]`, and `slice x 1 2 3` is `x[1:2:3]`. The first argument must be a string, slice, or array. |
|
||||
| `js` | Returns the escaped JavaScript equivalent of the textual representation of its arguments. |
|
||||
| `len` | Returns the integer length of its argument. |
|
||||
| `not` | Returns the boolean negation of its single argument. |
|
||||
| `or` | Returns the boolean OR of its arguments by returning the first non-empty argument or the last argument, that is, `or x y` behaves as `if x then x else y`. Evaluation proceeds through the arguments left to right and returns when the result is determined. |
|
||||
| `print` | An alias for `fmt.Sprint`. |
|
||||
| `printf` | An alias for `fmt.Sprintf`. |
|
||||
| `println` | An alias for `fmt.Sprintln`. |
|
||||
| `urlquery` | Returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query. This function is unavailable in [html/template][html/template], with a few exceptions. |
|
||||
|
||||
### Slim-Sprig Functions
|
||||
|
||||
In addition to the built-in functions, Task also provides a set of functions
|
||||
imported via the [slim-sprig][slim-sprig] package. We only provide a very basic
|
||||
description here for completeness. For detailed usage, please refer to the
|
||||
[slim-sprig documentation][slim-sprig]:
|
||||
|
||||
#### [String Functions][string-functions]
|
||||
|
||||
| Function | Description |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `trim` | Removes space from either side of a string. |
|
||||
| `trimAll` | Removes given characters from the front or back of a string. |
|
||||
| `trimSuffix` | Trims just the suffix from a string. |
|
||||
| `trimPrefix` | Trims just the prefix from a string. |
|
||||
| `upper` | Converts the entire string to uppercase. |
|
||||
| `lower` | Converts the entire string to lowercase. |
|
||||
| `title` | Converts to title case. |
|
||||
| `repeat` | Repeats a string multiple times. |
|
||||
| `substr` | Gets a substring from a string. |
|
||||
| `trunc` | Truncates a string. |
|
||||
| `contains` | Tests to see if one string is contained inside of another. |
|
||||
| `hasPrefix` | Tests whether a string has a given prefix. |
|
||||
| `hasSuffix` | Tests whether a string has a given suffix. |
|
||||
| `quote` | Wraps a string in double quotes. |
|
||||
| `squote` | Wraps a string in single quotes. |
|
||||
| `cat` | Concatenates multiple strings together into one, separating them with spaces. |
|
||||
| `indent` | Indents every line in a given string to the specified indent width. |
|
||||
| `nindent` | Identical to `indent`, but prepends a new line to the beginning of the string. |
|
||||
| `replace` | Replaces a string. |
|
||||
| `plural` | Pluralizes a string. |
|
||||
| `regexMatch`\* | Returns true if the input string contains any match of the regular expression. |
|
||||
| `regexFindAll`\* | Returns a slice of all matches of the regular expression in the input string. |
|
||||
| `regexFind`\* | Returns the first (left most) match of the regular expression in the input string. |
|
||||
| `regexReplaceAll`\* | Returns a copy of the input string, replacing matches of the Regexp with the replacement string replacement. |
|
||||
| `regexReplaceAllLiteral`\* | Returns a copy of the input string, replacing matches of the Regexp with the replacement string replacement without expanding `$`. |
|
||||
| `regexSplit`\* | Slices the input string into substrings separated by the expression and returns a slice of the substrings between those expression matches. |
|
||||
| `regexQuoteMeta`\* | Returns a string that escapes all regular expression metacharacters inside the argument text. |
|
||||
|
||||
#### [String Slice Functions][string-list-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | ----------------------------------------------------------------------- |
|
||||
| `join` | Joins a list of strings into a single string, with the given separator. |
|
||||
| `splitList` | Splits a string into a list of strings. |
|
||||
| `split` | Splits a string into a map of strings where each key is an index. |
|
||||
| `splitn` | Identical to `split`, but stops splitting after `n` values. |
|
||||
| `sortAlpha` | Sorts a list of strings into alphabetical (lexicographical) order. |
|
||||
|
||||
#### [Integer Functions][math-functions]
|
||||
|
||||
| Function | Description |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `add` | Sum a set of numbers. |
|
||||
| `add1` | Increments a number by 1. |
|
||||
| `sub` | Subtracts one number from another. |
|
||||
| `div` | Performs integer division. |
|
||||
| `mod` | Modulo. |
|
||||
| `mul` | Multiplies a set of numbers. |
|
||||
| `max` | Returns the largest of a set of integers. |
|
||||
| `min` | Returns the smallest of a set of integers. |
|
||||
| `floor` | Returns the greatest float value less than or equal to input value |
|
||||
| `ceil` | Returns the greatest float value greater than or equal to input value |
|
||||
| `round` | Returns a float value with the remainder rounded to the given number to digits after the decimal point. |
|
||||
| `randInt` | Returns a random integer value from min (inclusive) to max (exclusive). |
|
||||
|
||||
#### [Integer Slice Functions][integer-list-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | --------------------------------------------------------------------------- |
|
||||
| `until` | Builds a range of integers. |
|
||||
| `untilStep` | Builds a range of integers, but allows you to define a start, stop and step |
|
||||
| `seq` | Works like the bash `seq` command. |
|
||||
|
||||
#### [Date Functions][date-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------ |
|
||||
| `now` | Gets the current date/time. |
|
||||
| `ago` | Returns the duration since the given date/time. |
|
||||
| `date` | Formats a date. |
|
||||
| `dateInZone` | Identical to `date`, but with the given timezone. |
|
||||
| `duration` | Formats the number of seconds into a string. |
|
||||
| `durationRound` | Identical to `duration`, but rounds the duration to the most significant unit. |
|
||||
| `unixEpoch` | Returns the seconds since the unix epoch for the given date/time. |
|
||||
| `dateModify`\* | Modifies a date using the given input string. |
|
||||
| `htmlDate` | Formats a date for inserting into an HTML date picker input field. |
|
||||
| `htmlDateInZone` | Identical to `htmlDate`, but with the given timezone. |
|
||||
| `toDate`\* | Converts a string to a date/time. |
|
||||
|
||||
#### [Default Functions][default-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ---------- | ------------------------------------------------------------------------ |
|
||||
| `default` | Uses a default value if the given value is considered "zero" or "empty". |
|
||||
| `empty` | Returns true if a value is considered "zero" or "empty". |
|
||||
| `coalesce` | Takes a list of values and returns the first non-empty one. |
|
||||
| `all` | Returns true if all values are non-empty. |
|
||||
| `any` | Returns true if any value is non-empty. |
|
||||
| `ternary` | The ternary function takes two values, and a test value. If the test value is true, the first value will be returned. If the test value is empty, the second value will be returned. |
|
||||
|
||||
#### [Encoding Functions][encoding-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ---------------- | ------------------------------------------------------------------ |
|
||||
| `fromJson`\* | Decodes a JSON string into an object. |
|
||||
| `toJson`\* | Encodes an object as a JSON string. |
|
||||
| `toPrettyJson`\* | Encodes an object as a JSON string with new lines and indentation. |
|
||||
| `toRawJson`\* | Encodes an object as a JSON string with HTML characters unescaped. |
|
||||
| `b64enc` | Encodes a string into base 64. |
|
||||
| `b64dec` | Decodes a string from base 64. |
|
||||
| `b32enc` | Encodes a string into base 32. |
|
||||
| `b32dec` | Decodes a string from base 32. |
|
||||
|
||||
#### [List Functions][list-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | ---------------------------------------------------------------- |
|
||||
| `list` | Creates a list from a set of values. |
|
||||
| `first`\* | Gets the first value in a list. |
|
||||
| `rest`\* | Gets all values except the first value in the list. |
|
||||
| `last`\* | Gets the last value in the list. |
|
||||
| `initial`\* | Get all values except the last value in the list. |
|
||||
| `append`\* | Adds a new value to the end of the list. |
|
||||
| `prepend`\* | Adds a new value to the start of the list. |
|
||||
| `concat` | Joins two or more lists together. |
|
||||
| `reverse`\* | Reverses the order of a list. |
|
||||
| `uniq`\* | Generate a list with all of the duplicates removed. |
|
||||
| `without`\* | Filters matching items out of a list. |
|
||||
| `has`\* | Tests to see if a list has a particular element. |
|
||||
| `compact`\* | Removes entries with empty values. |
|
||||
| `slice`\* | Returns a partial copy of a list given start and end parameters. |
|
||||
| `chunk` | Splits a list into chunks of given size. |
|
||||
|
||||
#### [Dictionary Functions][dictionary-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------ |
|
||||
| `dict` | Creates a dictionary from a set of key/value pairs. |
|
||||
| `get` | Gets the value from the dictionary with the given key. |
|
||||
| `set` | Adds a new key/value pair to a dictionary. |
|
||||
| `unset` | Deletes a key from a dictionary. |
|
||||
| `hasKey` | Returns true if a dictionary contains the given key. |
|
||||
| `pluck` | Gets a list of all of the matching values in a set of maps given a key. |
|
||||
| `dig` | Returns the value in a nested map given a path of keys. |
|
||||
| `merge`\* | Merges two or more dictionaries into one. |
|
||||
| `mergeOverwrite`\* | Identical to `merge`, but giving precedence from right to left. |
|
||||
| `keys` | Returns a list of all of the keys in a dictionary. |
|
||||
| `pick` | Creates a new dictionary containing only the given keys of an existing map. |
|
||||
| `omit` | Creates a new dictionary containing all the keys of an existing map except the ones given. |
|
||||
| `values` | Returns a list of all the values in a dictionary. |
|
||||
|
||||
#### [Type Conversion Functions][type-conversion-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | ------------------------------------------------------ |
|
||||
| `atoi` | Converts a string to an integer. |
|
||||
| `float64` | Converts to a float64. |
|
||||
| `int` | Converts to an int at the system's width. |
|
||||
| `int64` | Converts to an int64. |
|
||||
| `toDecimal` | Converts a unix octal to a int64. |
|
||||
| `toString` | Converts to a string. |
|
||||
| `toStrings` | Converts a list, slice, or array to a list of strings. |
|
||||
| `toStrings` | Produces a slice of strings from any list. |
|
||||
| `toDecimal` | Given a unix octal permission, produce a decimal. |
|
||||
|
||||
#### [Path and Filepath Functions][path-functions]
|
||||
|
||||
| Function | Description |
|
||||
| --------- | ----------------------------------------- |
|
||||
| `base` | Returns the last element of a path. |
|
||||
| `dir` | Returns the directory of a path. |
|
||||
| `clean` | Cleans up a path. |
|
||||
| `ext` | Returns the file extension of a path. |
|
||||
| `isAbs` | Checks if a path is absolute. |
|
||||
| `osBase` | Returns the last element of a filepath. |
|
||||
| `osDir` | Returns the directory of a filepath. |
|
||||
| `osClean` | Cleans up a filepath. |
|
||||
| `osExt` | Returns the file extension of a filepath. |
|
||||
| `osIsAbs` | Checks if a filepath is absolute. |
|
||||
|
||||
#### [Flow Control Functions][flow-control-functions]
|
||||
|
||||
| Function | Description |
|
||||
| -------- | ----------------------------------------------------------------------------- |
|
||||
| `fail` | Unconditionally returns an empty string and an error with the specified text. |
|
||||
|
||||
#### [OS Functions][os-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ----------- | --------------------------------------------- |
|
||||
| `env` | Reads an environment variable. |
|
||||
| `expandenv` | Substitutes environment variables in a string |
|
||||
|
||||
#### [Reflection Functions][reflection-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ------------ | ------------------------------------------------------ |
|
||||
| `kindOf` | Returns the kind of a value. |
|
||||
| `kindIs` | Verifies that a value is a particular kind. |
|
||||
| `typeOf` | Returns the underlying type of a value. |
|
||||
| `typeIs` | Verifies that a value is of a particular type. |
|
||||
| `typeIsLike` | Identical to `typeIs`, but also dereferences pointers. |
|
||||
| `deepEqual` | Returns true if two values are "deeply equal". |
|
||||
|
||||
#### [Cryptographic and Security Functions][crypto-functions]
|
||||
|
||||
| Function | Description |
|
||||
| ------------ | -------------------------------------- |
|
||||
| `sha1sum` | Computes a string's SHA1 digest. |
|
||||
| `sha256sum` | Computes a string's SHA256 digest. |
|
||||
| `adler32sum` | Computes a string's Adler-32 checksum. |
|
||||
|
||||
### Task Functions
|
||||
|
||||
Lastly, Task itself provides a few functions:
|
||||
|
||||
| Function | Description |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `OS` | Returns the operating system. Possible values are `windows`, `linux`, `darwin` (macOS) and `freebsd`. |
|
||||
| `ARCH` | return the architecture Task was compiled to: `386`, `amd64`, `arm` or `s390x`. |
|
||||
| `splitLines` | Splits Unix (`\n`) and Windows (`\r\n`) styled newlines. |
|
||||
| `catLines` | Replaces Unix (`\n`) and Windows (`\r\n`) styled newlines with a space. |
|
||||
| `toSlash` | Does nothing on Unix, but on Windows converts a string from `\` path format to `/`. |
|
||||
| `fromSlash` | Opposite of `toSlash`. Does nothing on Unix, but on Windows converts a string from `/` path format to `\`. |
|
||||
| `exeExt` | Returns the right executable extension for the current OS (`".exe"` for Windows, `""` for others). |
|
||||
| `shellQuote` | (aliased to `q`): Quotes a string to make it safe for use in shell scripts. Task uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/syntax#Quote) for this. The Bash dialect is assumed. |
|
||||
| `splitArgs` | Splits a string as if it were a command's arguments. Task uses [this Go function](https://pkg.go.dev/mvdan.cc/sh/v3@v3.4.0/shell#Fields). |
|
||||
| `joinPath` | Joins any number of arguments into a path. The same as Go's [filepath.Join](https://pkg.go.dev/path/filepath#Join). |
|
||||
| `relPath` | Converts an absolute path (second argument) into a relative path, based on a base path (first argument). The same as Go's [filepath.Rel](https://pkg.go.dev/path/filepath#Rel). |
|
||||
| `merge` | Creates a new map that is a copy of the first map with the keys of each subsequent map merged into it. If there is a duplicate key, the value of the last map with that key is used. |
|
||||
| `spew` | Returns the Go representation of a specific variable. Useful for debugging. Uses the [davecgh/go-spew](https://github.com/davecgh/go-spew) package. |
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[text/template]: https://pkg.go.dev/text/template
|
||||
[html/template]: https://pkg.go.dev/html/template
|
||||
[go-template-functions]: https://pkg.go.dev/text/template#hdr-Functions
|
||||
[slim-sprig]: https://go-task.github.io/slim-sprig/
|
||||
[os-functions]: https://go-task.github.io/slim-sprig/os.html
|
||||
[string-functions]: https://go-task.github.io/slim-sprig/strings.html
|
||||
[string-list-functions]: https://go-task.github.io/slim-sprig/string_slice.html
|
||||
[math-functions]: https://go-task.github.io/slim-sprig/math.html
|
||||
[integer-list-functions]: https://go-task.github.io/slim-sprig/integer_slice.html
|
||||
[date-functions]: https://go-task.github.io/slim-sprig/date.html
|
||||
[default-functions]: https://go-task.github.io/slim-sprig/defaults.html
|
||||
[encoding-functions]: https://go-task.github.io/slim-sprig/encoding.html
|
||||
[list-functions]: https://go-task.github.io/slim-sprig/lists.html
|
||||
[dictionary-functions]: https://go-task.github.io/slim-sprig/dicts.html
|
||||
[type-conversion-functions]: https://go-task.github.io/slim-sprig/conversion.html
|
||||
[path-functions]: https://go-task.github.io/slim-sprig/paths.html
|
||||
[flow-control-functions]: https://go-task.github.io/slim-sprig/flow_control.html
|
||||
[os-functions]: https://go-task.github.io/slim-sprig/os.html
|
||||
[reflection-functions]: https://go-task.github.io/slim-sprig/reflection.html
|
||||
[crypto-functions]: https://go-task.github.io/slim-sprig/crypto.html
|
||||
{/* prettier-ignore-end */}
|
||||
@@ -5,259 +5,68 @@ sidebar_position: 5
|
||||
|
||||
# Taskfile Versions
|
||||
|
||||
The Taskfile syntax and features changed with time. This document explains what
|
||||
changed on each version and how to upgrade your Taskfile.
|
||||
The Taskfile schema slowly changes as new features are added and old ones are
|
||||
removed. This document explains how to use a Taskfile's schema version to ensure
|
||||
that the users of your Taskfile are using the correct versions of Task.
|
||||
|
||||
## What the Taskfile version mean
|
||||
## What the Taskfile version means
|
||||
|
||||
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. 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 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 XXH3 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:
|
||||
The schema version at the top of every Taskfile corresponds to a version of the
|
||||
Task CLI, and by extension, the features that are provided by that version. When
|
||||
creating a Taskfile, you should specify the _minimum_ version of Task that
|
||||
supports the features you require. If you try to run a Taskfile with a version
|
||||
of Task that does not meet this minimum required version, it will exit with an
|
||||
error. For example, given a Taskfile that starts with:
|
||||
|
||||
```yaml
|
||||
includes:
|
||||
docs:
|
||||
taskfile: ./docs
|
||||
dir: ./docs
|
||||
version: '3.2.1'
|
||||
```
|
||||
|
||||
- Implemented short task syntax. All below syntaxes are equivalent:
|
||||
When executed with Task `v3.2.0`, it will exit with an error. Running with
|
||||
version `v3.2.1` or higher will work as expected.
|
||||
|
||||
Task accepts any [SemVer][semver] compatible string including versions which
|
||||
omit the minor or patch numbers. For example, `3`, `3.0`, and `3.0.0` all mean
|
||||
the same thing and are all valid. Most Taskfiles only specify the major version
|
||||
number. However it can be useful to be more specific when you intend to share a
|
||||
Taskfile with others.
|
||||
|
||||
For example, the Taskfile below makes use of aliases:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print:
|
||||
hello:
|
||||
aliases:
|
||||
- hi
|
||||
- hey
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
- echo "Hello, world!"
|
||||
```
|
||||
|
||||
Aliases were introduced in Task `v3.17.0`, but the Taskfile only specifies `3`
|
||||
as the version. This means that a user who has `v3.16.0` or lower installed will
|
||||
get a potentially confusing error message when trying to run the Task as the
|
||||
Taskfile specifies that any version greater or equal to `v3.0.0` is fine.
|
||||
|
||||
Instead, we should start the file like this:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
print:
|
||||
- echo "Hello, World!"
|
||||
version: '3.17'
|
||||
```
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
Now when someone tries to run the Taskfile with an older version of Task, they
|
||||
will receive an error prompting them to upgrade their version of Task to
|
||||
`v3.17.0` or greater.
|
||||
|
||||
tasks:
|
||||
print: echo "Hello, World!"
|
||||
```
|
||||
## Versions 1 & 2
|
||||
|
||||
- There was a major refactor on how variables are handled. They're now easier to
|
||||
understand. The `expansions:` setting was removed as it became unnecessary.
|
||||
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
|
||||
Version 1 and 2 of Task are no longer officially supported and anyone still
|
||||
using them is strongly encouraged to upgrade to the latest version of Task.
|
||||
|
||||
## Version 2.6
|
||||
While `version: 2` of Task did support schema versions, the behavior did not
|
||||
work in quite the same way and cannot be relied upon for the purposes discussed
|
||||
above.
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
Version 2.6 comes with `preconditions` stanza in tasks.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
upload_environment:
|
||||
preconditions:
|
||||
- test -f .env
|
||||
cmds:
|
||||
- aws s3 cp .env s3://myenvironment
|
||||
```
|
||||
|
||||
Please check the [documentation][includes]
|
||||
|
||||
## Version 2.2
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
Version 2.2 comes with a global `includes` options to include other Taskfiles:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
includes:
|
||||
docs: ./documentation # will look for ./documentation/Taskfile.yml
|
||||
docker: ./DockerTasks.yml
|
||||
```
|
||||
|
||||
## Version 2.1
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
Version 2.1 includes a global `output` option, to allow having more control over
|
||||
how commands output are printed to the console (see [documentation][output] for
|
||||
more info):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
output: prefixed
|
||||
|
||||
tasks:
|
||||
server:
|
||||
cmds:
|
||||
- go run main.go
|
||||
prefix: server
|
||||
```
|
||||
|
||||
From this version it's also possible to ignore errors of a command or task
|
||||
(check documentation [here][ignore_errors]):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
example-1:
|
||||
cmds:
|
||||
- cmd: exit 1
|
||||
ignore_error: true
|
||||
- echo "This will be print"
|
||||
|
||||
example-2:
|
||||
cmds:
|
||||
- exit 1
|
||||
- echo "This will be print"
|
||||
ignore_error: true
|
||||
```
|
||||
|
||||
## Version 2.0
|
||||
|
||||
:::caution
|
||||
|
||||
v2 schemas are [no longer supported by the latest version of
|
||||
Task][deprecate-version-2-schema].
|
||||
|
||||
:::
|
||||
|
||||
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:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
echo:
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
```
|
||||
|
||||
Version 2 allows you to write global variables directly in the Taskfile, if you
|
||||
don't want to create a `Taskvars.yml`:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
vars:
|
||||
GREETING: Hello, World!
|
||||
|
||||
tasks:
|
||||
greet:
|
||||
cmds:
|
||||
- echo "{{.GREETING}}"
|
||||
```
|
||||
|
||||
The variable priority order changed to the following:
|
||||
|
||||
1. Task variables
|
||||
2. Call variables
|
||||
3. Taskfile variables
|
||||
4. Taskvars file variables
|
||||
5. Environment variables
|
||||
|
||||
A new global option was added to configure the number of variables expansions
|
||||
(which default to 2):
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
expansions: 3
|
||||
|
||||
vars:
|
||||
FOO: foo
|
||||
BAR: bar
|
||||
BAZ: baz
|
||||
FOOBAR: '{{.FOO}}{{.BAR}}'
|
||||
FOOBARBAZ: '{{.FOOBAR}}{{.BAZ}}'
|
||||
|
||||
tasks:
|
||||
default:
|
||||
cmds:
|
||||
- echo "{{.FOOBARBAZ}}"
|
||||
```
|
||||
|
||||
## Version 1
|
||||
|
||||
:::caution
|
||||
|
||||
v1 schema support was removed in Task >= v3.0.0.
|
||||
|
||||
:::
|
||||
|
||||
In the first version of the `Taskfile`, the `version:` key was not available,
|
||||
because the tasks was in the root of the YAML document. Like this:
|
||||
|
||||
```yaml
|
||||
echo:
|
||||
cmds:
|
||||
- echo "Hello, World!"
|
||||
```
|
||||
|
||||
The variable priority order was also different:
|
||||
|
||||
1. Call variables
|
||||
2. Environment
|
||||
3. Task variables
|
||||
4. `Taskvars.yml` variables
|
||||
|
||||
{/* prettier-ignore-start */}
|
||||
[deprecate-version-2-schema]: ./deprecations/version_2_schema.mdx
|
||||
[output]: ./usage.mdx#output-syntax
|
||||
[ignore_errors]: ./usage.mdx#ignore-errors
|
||||
[includes]: ./usage.mdx#including-other-taskfiles
|
||||
{/* prettier-ignore-end */}
|
||||
[semver]: https://semver.org/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user