Compare commits

..

16 Commits

Author SHA1 Message Date
Andrey Nering
cd086228b2 v3.42.0 2025-03-08 22:34:07 -03:00
Andrey Nering
1b8b399c7e fix(changelog): add missing # to issue number 2025-03-08 22:32:55 -03:00
renovate[bot]
8426f84b18 chore(deps): update all non-major dependencies (#2097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-07 08:24:04 +01:00
sblondon
14bbb324e5 doc: fix: remove a word (#2093)
The 'you' word has no sense here
2025-02-27 17:29:52 +00:00
Valentin Maerten
b9d202c491 chore: changelog for #2092 2025-02-26 18:07:31 +01:00
Valentin Maerten
c23c46e326 fix: include with dynamic vars (#2092) 2025-02-26 17:49:05 +01:00
Oleksandr Redko
a266fba93e chore: add linter mirror (#2060) 2025-02-24 09:06:54 -03:00
Pete Davison
fb631902ce refactor: run task through modernize tool (#2088) 2025-02-24 11:59:50 +00:00
Pete Davison
b14125bacd fix: remove debug line 2025-02-24 02:16:53 +00:00
Pete Davison
3c5782f4a4 chore: changelog for #2084 2025-02-23 18:31:18 +00:00
Pete Davison
60c8ee0ce6 refactor: ast.Call should be in main task package (#2084) 2025-02-23 18:30:42 +00:00
Pete Davison
cdaf69e03d chore: changelog for #2069 2025-02-23 18:18:22 +00:00
Pete Davison
d6234af49a feat: allow variable references in a matrix (#2069) 2025-02-23 18:13:56 +00:00
renovate[bot]
a31f2cf4a8 chore(deps): update all non-major dependencies (#2064) 2025-02-23 15:10:00 -03:00
Pete Davison
0dd6f78855 chore: changelog for #2086 2025-02-23 18:00:00 +00:00
Pete Davison
6f80777faf docs: getting started (#2086)
* docs: getting started

* docs: update intro with links to getting started docs
2025-02-23 17:56:55 +00:00
72 changed files with 1209 additions and 762 deletions

View File

@@ -9,6 +9,7 @@ linters:
- goimports
- gofmt
- gofumpt
- mirror
- misspell
- noctx
- paralleltest

2
.nvmrc
View File

@@ -1 +1 @@
22.13.1
22.14.0

View File

@@ -1,6 +1,6 @@
# Changelog
## Unreleased
## v3.42.0 - 2025-03-08
- Made `--init` less verbose by default and respect `--silent` and `--verbose`
flags (#2009, #2011 by @HeCorr).
@@ -15,7 +15,7 @@
- Print warnings when attempting to enable an inactive experiment or an active
experiment with an invalid value (#1979, #2049 by @pd93).
- Refactored the experiments package and added tests (#2049 by @pd93).
- Show allowed values when a variable with an enum is missing (#2027, 2052 by
- Show allowed values when a variable with an enum is missing (#2027, #2052 by
@vmaerten).
- Refactored how snippets in error work and added tests (#2068 by @pd93).
- Fixed a bug where errors decoding commands were sometimes unhelpful (#2068 by
@@ -25,6 +25,12 @@
- Refactored how task sorting functions work (#1798 by @pd93).
- Added a new `.taskrc.yml` (or `.taskrc.yaml`) file to let users enable
experiments (similar to `.env`) (#1982 by @vmaerten).
- Added new [Getting Started docs](https://taskfile.dev/getting-started) (#2086
by @pd93).
- Allow `matrix` to use references to other variables (#2065, #2069 by @pd93).
- Fixed a bug where, when a dynamic variable is provided, even if it is not
used, all other variables become unavailable in the templating system within
the include (#2092 by @vmaerten).
#### Package API
@@ -47,7 +53,8 @@ stabilize the API in the future. #121 now tracks this piece of work.
(#2068 by @pd93).
- The caller is now expected to create the snippet themselves (see below).
- [`TaskfileSnippet`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Snippet)
and related code moved from `v3/errors` to `v3/taskfile` (#2068 by @pd93).
and related code moved from the `errors` package to the `taskfile` package
(#2068 by @pd93).
- Renamed `TaskMissingRequiredVars` to
[`TaskMissingRequiredVarsError`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskMissingRequiredVarsError)
(#2052 by @vmaerten).
@@ -57,8 +64,8 @@ stabilize the API in the future. #121 now tracks this piece of work.
- The
[`taskfile.Reader`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Reader)
is now constructed using the functional options pattern (#2082 by @pd93).
- Removed our internal `logger.Logger` from the entire `v3/taskfile` package
(#2082 by @pd93).
- Removed our internal `logger.Logger` from the entire `taskfile` package (#2082
by @pd93).
- Users are now expected to pass a custom debug/prompt functions into
[`taskfile.Reader`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Reader)
if they want this functionality by using the new
@@ -66,8 +73,15 @@ stabilize the API in the future. #121 now tracks this piece of work.
and
[`WithPromptFunc`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#WithPromptFunc)
functional options.
- Remove `Range` functions in `v3/taskfile/ast` in favour of new iterator
functions (#1798 by @pd93).
- Remove `Range` functions in the `taskfile/ast` package in favour of new
iterator functions (#1798 by @pd93).
- `ast.Call` was moved from the `taskfile/ast` package to the main `task`
package (#2084 by @pd93).
- `ast.Tasks.FindMatchingTasks` was moved from the `taskfile/ast` package to the
`task.Executor.FindMatchingTasks` in the main `task` package (#2084 by @pd93).
- The `Compiler` and its `GetVariables` and `FastGetVariables` methods were
moved from the `internal/compiler` package to the main `task` package (#2084
by @pd93).
## v3.41.0 - 2025-01-18

View File

@@ -3,17 +3,18 @@ package args
import (
"strings"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/taskfile/ast"
)
// Parse parses command line argument: tasks and global variables
func Parse(args ...string) ([]*ast.Call, *ast.Vars) {
calls := []*ast.Call{}
func Parse(args ...string) ([]*task.Call, *ast.Vars) {
calls := []*task.Call{}
globals := ast.NewVars()
for _, arg := range args {
if !strings.Contains(arg, "=") {
calls = append(calls, &ast.Call{Task: arg})
calls = append(calls, &task.Call{Task: arg})
continue
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3"
"github.com/go-task/task/v3/args"
"github.com/go-task/task/v3/taskfile/ast"
)
@@ -15,12 +16,12 @@ func TestArgs(t *testing.T) {
tests := []struct {
Args []string
ExpectedCalls []*ast.Call
ExpectedCalls []*task.Call
ExpectedGlobals *ast.Vars
}{
{
Args: []string{"task-a", "task-b", "task-c"},
ExpectedCalls: []*ast.Call{
ExpectedCalls: []*task.Call{
{Task: "task-a"},
{Task: "task-b"},
{Task: "task-c"},
@@ -28,7 +29,7 @@ func TestArgs(t *testing.T) {
},
{
Args: []string{"task-a", "FOO=bar", "task-b", "task-c", "BAR=baz", "BAZ=foo"},
ExpectedCalls: []*ast.Call{
ExpectedCalls: []*task.Call{
{Task: "task-a"},
{Task: "task-b"},
{Task: "task-c"},
@@ -56,7 +57,7 @@ func TestArgs(t *testing.T) {
},
{
Args: []string{"task-a", "CONTENT=with some spaces"},
ExpectedCalls: []*ast.Call{
ExpectedCalls: []*task.Call{
{Task: "task-a"},
},
ExpectedGlobals: ast.NewVars(
@@ -70,7 +71,7 @@ func TestArgs(t *testing.T) {
},
{
Args: []string{"FOO=bar", "task-a", "task-b"},
ExpectedCalls: []*ast.Call{
ExpectedCalls: []*task.Call{
{Task: "task-a"},
{Task: "task-b"},
},
@@ -85,15 +86,15 @@ func TestArgs(t *testing.T) {
},
{
Args: nil,
ExpectedCalls: []*ast.Call{},
ExpectedCalls: []*task.Call{},
},
{
Args: []string{},
ExpectedCalls: []*ast.Call{},
ExpectedCalls: []*task.Call{},
},
{
Args: []string{"FOO=bar", "BAR=baz"},
ExpectedCalls: []*ast.Call{},
ExpectedCalls: []*task.Call{},
ExpectedGlobals: ast.NewVars(
&ast.VarElement{
Key: "FOO",

View File

@@ -1,9 +1,11 @@
package ast
package task
import "github.com/go-task/task/v3/taskfile/ast"
// Call is the parameters to a task call
type Call struct {
Task string
Vars *Vars
Vars *ast.Vars
Silent bool
Indirect bool // True if the task was called by another task
}

View File

@@ -201,7 +201,7 @@ func run() error {
}
var (
calls []*ast.Call
calls []*task.Call
globals *ast.Vars
)
@@ -214,7 +214,7 @@ func run() error {
// If there are no calls, run the default task instead
if len(calls) == 0 {
calls = append(calls, &ast.Call{Task: "default"})
calls = append(calls, &task.Call{Task: "default"})
}
globals.Set("CLI_ARGS", ast.Var{Value: cliArgs})

View File

@@ -1,4 +1,4 @@
package compiler
package task
import (
"bytes"
@@ -36,16 +36,16 @@ func (c *Compiler) GetTaskfileVariables() (*ast.Vars, error) {
return c.getVariables(nil, nil, true)
}
func (c *Compiler) GetVariables(t *ast.Task, call *ast.Call) (*ast.Vars, error) {
func (c *Compiler) GetVariables(t *ast.Task, call *Call) (*ast.Vars, error) {
return c.getVariables(t, call, true)
}
func (c *Compiler) FastGetVariables(t *ast.Task, call *ast.Call) (*ast.Vars, error) {
func (c *Compiler) FastGetVariables(t *ast.Task, call *Call) (*ast.Vars, error) {
return c.getVariables(t, call, false)
}
func (c *Compiler) getVariables(t *ast.Task, call *ast.Call, evaluateShVars bool) (*ast.Vars, error) {
result := GetEnviron()
func (c *Compiler) getVariables(t *ast.Task, call *Call, evaluateShVars bool) (*ast.Vars, error) {
result := env.GetEnviron()
specialVars, err := c.getSpecialVars(t, call)
if err != nil {
return nil, err
@@ -196,7 +196,7 @@ func (c *Compiler) ResetCache() {
c.dynamicCache = nil
}
func (c *Compiler) getSpecialVars(t *ast.Task, call *ast.Call) (map[string]string, error) {
func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, error) {
allVars := map[string]string{
"TASK_EXE": filepath.ToSlash(os.Args[0]),
"ROOT_TASKFILE": filepathext.SmartJoin(c.Dir, c.Entrypoint),

28
go.mod
View File

@@ -12,7 +12,7 @@ require (
github.com/elliotchance/orderedmap/v3 v3.1.0
github.com/fatih/color v1.18.0
github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git/v5 v5.13.2
github.com/go-git/go-git/v5 v5.14.0
github.com/go-task/slim-sprig/v3 v3.0.0
github.com/go-task/template v0.1.0
github.com/joho/godotenv v1.5.1
@@ -24,22 +24,22 @@ require (
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
github.com/zeebo/xxh3 v1.0.2
golang.org/x/sync v0.11.0
golang.org/x/term v0.29.0
golang.org/x/sync v0.12.0
golang.org/x/term v0.30.0
gopkg.in/yaml.v3 v3.0.1
mvdan.cc/sh/v3 v3.10.0
mvdan.cc/sh/v3 v3.11.0
)
require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.5 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
github.com/cloudflare/circl v1.6.0 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
@@ -50,13 +50,13 @@ require (
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.22.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/tools v0.27.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

26
go.sum
View File

@@ -7,6 +7,8 @@ github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lpr
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
@@ -23,10 +25,14 @@ github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiw
github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -52,6 +58,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -60,6 +68,8 @@ github.com/go-task/template v0.1.0 h1:ym/r2G937RZA1bsgiWedNnY9e5kxDT+3YcoAnuIetT
github.com/go-task/template v0.1.0/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
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=
@@ -113,6 +123,8 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -131,15 +143,22 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -151,15 +170,20 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -172,3 +196,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4=
mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY=
mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw=
mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg=

View File

@@ -1,20 +0,0 @@
package compiler
import (
"os"
"strings"
"github.com/go-task/task/v3/taskfile/ast"
)
// GetEnviron the all return all environment variables encapsulated on a
// ast.Vars
func GetEnviron() *ast.Vars {
m := ast.NewVars()
for _, e := range os.Environ() {
keyVal := strings.SplitN(e, "=", 2)
key, val := keyVal[0], keyVal[1]
m.Set(key, ast.Var{Value: val})
}
return m
}

13
internal/env/env.go vendored
View File

@@ -3,6 +3,7 @@ package env
import (
"fmt"
"os"
"strings"
"github.com/go-task/task/v3/internal/experiments"
"github.com/go-task/task/v3/taskfile/ast"
@@ -10,6 +11,18 @@ import (
const taskVarPrefix = "TASK_"
// GetEnviron the all return all environment variables encapsulated on a
// ast.Vars
func GetEnviron() *ast.Vars {
m := ast.NewVars()
for _, e := range os.Environ() {
keyVal := strings.SplitN(e, "=", 2)
key, val := keyVal[0], keyVal[1]
m.Set(key, ast.Var{Value: val})
}
return m
}
func Get(t *ast.Task) []string {
if t.Env == nil {
return nil

View File

@@ -1,6 +1,7 @@
package sort
import (
"slices"
"sort"
"strings"
)
@@ -11,9 +12,7 @@ type Sorter func(items []string, namespaces []string) []string
// AlphaNumeric sorts the JSON output so that tasks are in alpha numeric order
// by task name.
func AlphaNumeric(items []string, namespaces []string) []string {
sort.Slice(items, func(i, j int) bool {
return items[i] < items[j]
})
slices.Sort(items)
return items
}

View File

@@ -7,10 +7,10 @@ import (
"github.com/go-task/task/v3/taskfile/ast"
)
func PrintTasks(l *logger.Logger, t *ast.Taskfile, c []*ast.Call) {
func PrintTasks(l *logger.Logger, t *ast.Taskfile, c []string) {
for i, call := range c {
PrintSpaceBetweenSummaries(l, i)
if task, ok := t.Tasks.Get(call.Task); ok {
if task, ok := t.Tasks.Get(call); ok {
PrintTask(l, task)
}
}

View File

@@ -179,7 +179,8 @@ func TestPrintAllWithSpaces(t *testing.T) {
summary.PrintTasks(&l,
&ast.Taskfile{Tasks: tasks},
[]*ast.Call{{Task: "t1"}, {Task: "t2"}, {Task: "t3"}})
[]string{"t1", "t2", "t3"},
)
assert.True(t, strings.HasPrefix(buffer.String(), "task: t1"))
assert.Contains(t, buffer.String(), "\n(task does not have description or summary)\n\n\ntask: t2")

View File

@@ -1,6 +1,7 @@
package templater
import (
"maps"
"path/filepath"
"runtime"
"strings"
@@ -60,13 +61,9 @@ func init() {
cap += len(m)
}
result := make(map[string]any, cap)
for k, v := range base {
result[k] = v
}
maps.Copy(result, base)
for _, m := range v {
for k, v := range m {
result[k] = v
}
maps.Copy(result, m)
}
return result
},
@@ -84,7 +81,5 @@ func init() {
taskFuncs["ExeExt"] = taskFuncs["exeExt"]
templateFuncs = template.FuncMap(sprig.TxtFuncMap())
for k, v := range taskFuncs {
templateFuncs[k] = v
}
maps.Copy(templateFuncs, taskFuncs)
}

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "@go-task/cli",
"version": "3.41.0",
"version": "3.42.0",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

@@ -1,6 +1,6 @@
{
"name": "@go-task/cli",
"version": "3.41.0",
"version": "3.42.0",
"description": "A task runner / simpler Make alternative written in Go",
"scripts": {
"postinstall": "go-npm install",

View File

@@ -2,7 +2,6 @@ package task
import (
"context"
"slices"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/env"
@@ -15,7 +14,7 @@ import (
var ErrPreconditionFailed = errors.New("task: precondition not met")
func (e *Executor) areTaskPreconditionsMet(ctx context.Context, t *ast.Task) (bool, error) {
for _, p := range slices.Concat(e.Taskfile.Preconditions.Values, t.Preconditions) {
for _, p := range t.Preconditions {
err := execext.RunCommand(ctx, &execext.RunCommandOptions{
Command: p.Sh,
Dir: t.Dir,

View File

@@ -13,7 +13,6 @@ import (
"github.com/sajari/fuzzy"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/env"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/filepathext"
@@ -198,7 +197,7 @@ func (e *Executor) setupCompiler() error {
}
}
e.Compiler = &compiler.Compiler{
e.Compiler = &Compiler{
Dir: e.Dir,
Entrypoint: e.Entrypoint,
UserWorkingDir: e.UserWorkingDir,
@@ -214,7 +213,12 @@ func (e *Executor) readDotEnvFiles() error {
return nil
}
env, err := taskfile.Dotenv(e.Compiler, e.Taskfile, e.Dir)
vars, err := e.Compiler.GetTaskfileVariables()
if err != nil {
return err
}
env, err := taskfile.Dotenv(vars, e.Taskfile, e.Dir)
if err != nil {
return err
}

View File

@@ -9,7 +9,7 @@ import (
)
// Status returns an error if any the of given tasks is not up-to-date
func (e *Executor) Status(ctx context.Context, calls ...*ast.Call) error {
func (e *Executor) Status(ctx context.Context, calls ...*Call) error {
for _, call := range calls {
// Compile the task

60
task.go
View File

@@ -11,10 +11,7 @@ import (
"sync/atomic"
"time"
"mvdan.cc/sh/v3/interp"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/env"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/fingerprint"
@@ -28,6 +25,7 @@ import (
"github.com/sajari/fuzzy"
"golang.org/x/sync/errgroup"
"mvdan.cc/sh/v3/interp"
)
const (
@@ -71,7 +69,7 @@ type Executor struct {
Stderr io.Writer
Logger *logger.Logger
Compiler *compiler.Compiler
Compiler *Compiler
Output output.Output
OutputStyle ast.Output
TaskSorter sort.Sorter
@@ -87,8 +85,15 @@ type Executor struct {
executionHashesMutex sync.Mutex
}
// MatchingTask represents a task that matches a given call. It includes the
// task itself and a list of wildcards that were matched.
type MatchingTask struct {
Task *ast.Task
Wildcards []string
}
// Run runs Task
func (e *Executor) Run(ctx context.Context, calls ...*ast.Call) error {
func (e *Executor) Run(ctx context.Context, calls ...*Call) error {
// check if given tasks exist
for _, call := range calls {
task, err := e.GetTask(call)
@@ -150,7 +155,7 @@ func (e *Executor) Run(ctx context.Context, calls ...*ast.Call) error {
return nil
}
func (e *Executor) splitRegularAndWatchCalls(calls ...*ast.Call) (regularCalls []*ast.Call, watchCalls []*ast.Call, err error) {
func (e *Executor) splitRegularAndWatchCalls(calls ...*Call) (regularCalls []*Call, watchCalls []*Call, err error) {
for _, c := range calls {
t, err := e.GetTask(c)
if err != nil {
@@ -167,7 +172,7 @@ func (e *Executor) splitRegularAndWatchCalls(calls ...*ast.Call) (regularCalls [
}
// RunTask runs a task by its name
func (e *Executor) RunTask(ctx context.Context, call *ast.Call) error {
func (e *Executor) RunTask(ctx context.Context, call *Call) error {
t, err := e.FastCompiledTask(call)
if err != nil {
return err
@@ -317,7 +322,7 @@ func (e *Executor) runDeps(ctx context.Context, t *ast.Task) error {
for _, d := range t.Deps {
d := d
g.Go(func() error {
err := e.RunTask(ctx, &ast.Call{Task: d.Task, Vars: d.Vars, Silent: d.Silent, Indirect: true})
err := e.RunTask(ctx, &Call{Task: d.Task, Vars: d.Vars, Silent: d.Silent, Indirect: true})
if err != nil {
return err
}
@@ -328,7 +333,7 @@ func (e *Executor) runDeps(ctx context.Context, t *ast.Task) error {
return g.Wait()
}
func (e *Executor) runDeferred(t *ast.Task, call *ast.Call, i int, deferredExitCode *uint8) {
func (e *Executor) runDeferred(t *ast.Task, call *Call, i int, deferredExitCode *uint8) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -353,7 +358,7 @@ func (e *Executor) runDeferred(t *ast.Task, call *ast.Call, i int, deferredExitC
}
}
func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *ast.Call, i int) error {
func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i int) error {
cmd := t.Cmds[i]
switch {
@@ -361,7 +366,7 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *ast.Call,
reacquire := e.releaseConcurrencyLimit()
defer reacquire()
err := e.RunTask(ctx, &ast.Call{Task: cmd.Task, Vars: cmd.Vars, Silent: cmd.Silent, Indirect: true})
err := e.RunTask(ctx, &Call{Task: cmd.Task, Vars: cmd.Vars, Silent: cmd.Silent, Indirect: true})
if err != nil {
return err
}
@@ -447,12 +452,39 @@ func (e *Executor) startExecution(ctx context.Context, t *ast.Task, execute func
return execute(ctx)
}
// FindMatchingTasks returns a list of tasks that match the given call. A task
// matches a call if its name is equal to the call's task name or if it matches
// a wildcard pattern. The function returns a list of MatchingTask structs, each
// containing a task and a list of wildcards that were matched.
func (e *Executor) FindMatchingTasks(call *Call) []*MatchingTask {
if call == nil {
return nil
}
var matchingTasks []*MatchingTask
// If there is a direct match, return it
if task, ok := e.Taskfile.Tasks.Get(call.Task); ok {
matchingTasks = append(matchingTasks, &MatchingTask{Task: task, Wildcards: nil})
return matchingTasks
}
// Attempt a wildcard match
// For now, we can just nil check the task before each loop
for _, value := range e.Taskfile.Tasks.All(nil) {
if match, wildcards := value.WildcardMatch(call.Task); match {
matchingTasks = append(matchingTasks, &MatchingTask{
Task: value,
Wildcards: wildcards,
})
}
}
return matchingTasks
}
// GetTask will return the task with the name matching the given call from the taskfile.
// If no task is found, it will search for tasks with a matching alias.
// If multiple tasks contain the same alias or no matches are found an error is returned.
func (e *Executor) GetTask(call *ast.Call) (*ast.Task, error) {
func (e *Executor) GetTask(call *Call) (*ast.Task, error) {
// Search for a matching task
matchingTasks := e.Taskfile.Tasks.FindMatchingTasks(call)
matchingTasks := e.FindMatchingTasks(call)
switch len(matchingTasks) {
case 0: // Carry on
case 1:
@@ -532,7 +564,7 @@ func (e *Executor) GetTaskList(filters ...FilterFunc) ([]*ast.Task, error) {
// Compile the list of tasks
for i := range tasks {
g.Go(func() error {
compiledTask, err := e.FastCompiledTask(&ast.Call{Task: tasks[i].Task})
compiledTask, err := e.FastCompiledTask(&Call{Task: tasks[i].Task})
if err != nil {
return err
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,15 +10,25 @@ import (
"github.com/go-task/task/v3/internal/deepcopy"
)
type Matrix struct {
om *orderedmap.OrderedMap[string, []any]
}
type MatrixElement orderedmap.Element[string, []any]
type (
// Matrix is an ordered map of variable names to arrays of values.
Matrix struct {
om *orderedmap.OrderedMap[string, *MatrixRow]
}
// A MatrixElement is a key-value pair that is used for initializing a
// Matrix structure.
MatrixElement orderedmap.Element[string, *MatrixRow]
// A MatrixRow list of values for a matrix key or a reference to another
// variable.
MatrixRow struct {
Ref string
Value []any
}
)
func NewMatrix(els ...*MatrixElement) *Matrix {
matrix := &Matrix{
om: orderedmap.NewOrderedMap[string, []any](),
om: orderedmap.NewOrderedMap[string, *MatrixRow](),
}
for _, el := range els {
matrix.Set(el.Key, el.Value)
@@ -33,27 +43,27 @@ func (matrix *Matrix) Len() int {
return matrix.om.Len()
}
func (matrix *Matrix) Get(key string) ([]any, bool) {
func (matrix *Matrix) Get(key string) (*MatrixRow, bool) {
if matrix == nil || matrix.om == nil {
return nil, false
}
return matrix.om.Get(key)
}
func (matrix *Matrix) Set(key string, value []any) bool {
func (matrix *Matrix) Set(key string, value *MatrixRow) bool {
if matrix == nil {
matrix = NewMatrix()
}
if matrix.om == nil {
matrix.om = orderedmap.NewOrderedMap[string, []any]()
matrix.om = orderedmap.NewOrderedMap[string, *MatrixRow]()
}
return matrix.om.Set(key, value)
}
// All returns an iterator that loops over all task key-value pairs.
func (matrix *Matrix) All() iter.Seq2[string, []any] {
func (matrix *Matrix) All() iter.Seq2[string, *MatrixRow] {
if matrix == nil || matrix.om == nil {
return func(yield func(string, []any) bool) {}
return func(yield func(string, *MatrixRow) bool) {}
}
return matrix.om.AllFromFront()
}
@@ -67,9 +77,9 @@ func (matrix *Matrix) Keys() iter.Seq[string] {
}
// Values returns an iterator that loops over all task values.
func (matrix *Matrix) Values() iter.Seq[[]any] {
func (matrix *Matrix) Values() iter.Seq[*MatrixRow] {
if matrix == nil || matrix.om == nil {
return func(yield func([]any) bool) {}
return func(yield func(*MatrixRow) bool) {}
}
return matrix.om.Values()
}
@@ -93,14 +103,36 @@ func (matrix *Matrix) UnmarshalYAML(node *yaml.Node) error {
keyNode := node.Content[i]
valueNode := node.Content[i+1]
// Decode the value node into a Matrix struct
var v []any
if err := valueNode.Decode(&v); err != nil {
return errors.NewTaskfileDecodeError(err, node)
}
switch valueNode.Kind {
case yaml.SequenceNode:
// Decode the value node into a Matrix struct
var v []any
if err := valueNode.Decode(&v); err != nil {
return errors.NewTaskfileDecodeError(err, node)
}
// Add the task to the ordered map
matrix.Set(keyNode.Value, v)
// Add the row to the ordered map
matrix.Set(keyNode.Value, &MatrixRow{
Value: v,
})
case yaml.MappingNode:
// Decode the value node into a Matrix struct
var refStruct struct {
Ref string
}
if err := valueNode.Decode(&refStruct); err != nil {
return errors.NewTaskfileDecodeError(err, node)
}
// Add the reference to the ordered map
matrix.Set(keyNode.Value, &MatrixRow{
Ref: refStruct.Ref,
})
default:
return errors.NewTaskfileDecodeError(nil, node).WithMessage("matrix values must be an array or a reference")
}
}
return nil
}

View File

@@ -9,12 +9,10 @@ import (
)
// Precondition represents a precondition necessary for a task to run
type (
Precondition struct {
Sh string
Msg string
}
)
type Precondition struct {
Sh string
Msg string
}
func (p *Precondition) DeepCopy() *Precondition {
if p == nil {

View File

@@ -1,47 +0,0 @@
package ast
import (
"sync"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/deepcopy"
"gopkg.in/yaml.v3"
)
// Precondition represents a precondition necessary for a task to run
type (
Preconditions struct {
Values []*Precondition
mutex sync.RWMutex
}
)
func NewPreconditions() *Preconditions {
return &Preconditions{
Values: make([]*Precondition, 0),
}
}
func (p *Preconditions) DeepCopy() *Preconditions {
if p == nil {
return nil
}
defer p.mutex.RUnlock()
p.mutex.RLock()
return &Preconditions{
Values: deepcopy.Slice(p.Values),
}
}
func (p *Preconditions) UnmarshalYAML(node *yaml.Node) error {
if p == nil || p.Values == nil {
*p = *NewPreconditions()
}
if err := node.Decode(&p.Values); err != nil {
return errors.NewTaskfileDecodeError(err, node).WithTypeMessage("preconditions")
}
return nil
}

View File

@@ -18,26 +18,22 @@ var V3 = semver.MustParse("3")
// ErrIncludedTaskfilesCantHaveDotenvs is returned when a included Taskfile contains dotenvs
var ErrIncludedTaskfilesCantHaveDotenvs = errors.New("task: Included Taskfiles can't have dotenv declarations. Please, move the dotenv declaration to the main Taskfile")
// ErrIncludedTaskfilesCantHavePreconditions is returned when a included Taskfile contains Preconditions
var ErrIncludedTaskfilesCantHavePreconditions = errors.New("task: Included Taskfiles can't have preconditions declarations. Please, move the preconditions declaration to the main Taskfile")
// Taskfile is the abstract syntax tree for a Taskfile
type Taskfile struct {
Location string
Version *semver.Version
Output Output
Method string
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Preconditions *Preconditions
Tasks *Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
Location string
Version *semver.Version
Output Output
Method string
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks *Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
}
// Merge merges the second Taskfile into the first
@@ -48,9 +44,6 @@ func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include) error {
if len(t2.Dotenv) > 0 {
return ErrIncludedTaskfilesCantHaveDotenvs
}
if len(t2.Preconditions.Values) > 0 {
return ErrIncludedTaskfilesCantHavePreconditions
}
if t2.Output.IsSet() {
t1.Output = t2.Output
}
@@ -66,9 +59,6 @@ func (t1 *Taskfile) Merge(t2 *Taskfile, include *Include) error {
if t1.Tasks == nil {
t1.Tasks = NewTasks()
}
if t1.Preconditions == nil {
t1.Preconditions = NewPreconditions()
}
t1.Vars.Merge(t2.Vars, include)
t1.Env.Merge(t2.Env, include)
return t1.Tasks.Merge(t2.Tasks, include, t1.Vars)
@@ -78,20 +68,19 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
switch node.Kind {
case yaml.MappingNode:
var taskfile struct {
Version *semver.Version
Output Output
Method string
Includes *Includes
Preconditions *Preconditions
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks *Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
Version *semver.Version
Output Output
Method string
Includes *Includes
Set []string
Shopt []string
Vars *Vars
Env *Vars
Tasks *Tasks
Silent bool
Dotenv []string
Run string
Interval time.Duration
}
if err := node.Decode(&taskfile); err != nil {
return errors.NewTaskfileDecodeError(err, node)
@@ -109,7 +98,6 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
tf.Dotenv = taskfile.Dotenv
tf.Run = taskfile.Run
tf.Interval = taskfile.Interval
tf.Preconditions = taskfile.Preconditions
if tf.Includes == nil {
tf.Includes = NewIncludes()
}
@@ -122,9 +110,6 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error {
if tf.Tasks == nil {
tf.Tasks = NewTasks()
}
if tf.Preconditions == nil {
tf.Preconditions = NewPreconditions()
}
return nil
}

View File

@@ -24,12 +24,6 @@ type (
// A TaskElement is a key-value pair that is used for initializing a Tasks
// structure.
TaskElement orderedmap.Element[string, *Task]
// MatchingTask represents a task that matches a given call. It includes the
// task itself and a list of wildcards that were matched.
MatchingTask struct {
Task *Task
Wildcards []string
}
)
// NewTasks creates a new instance of Tasks and initializes it with the provided
@@ -124,33 +118,6 @@ func (t *Tasks) Values(sorter sort.Sorter) iter.Seq[*Task] {
}
}
// FindMatchingTasks returns a list of tasks that match the given call. A task
// matches a call if its name is equal to the call's task name or if it matches
// a wildcard pattern. The function returns a list of MatchingTask structs, each
// containing a task and a list of wildcards that were matched.
func (t *Tasks) FindMatchingTasks(call *Call) []*MatchingTask {
if call == nil {
return nil
}
var matchingTasks []*MatchingTask
// If there is a direct match, return it
if task, ok := t.Get(call.Task); ok {
matchingTasks = append(matchingTasks, &MatchingTask{Task: task, Wildcards: nil})
return matchingTasks
}
// Attempt a wildcard match
// For now, we can just nil check the task before each loop
for _, value := range t.All(nil) {
if match, wildcards := value.WildcardMatch(call.Task); match {
matchingTasks = append(matchingTasks, &MatchingTask{
Task: value,
Wildcards: wildcards,
})
}
}
return matchingTasks
}
func (t1 *Tasks) Merge(t2 *Tasks, include *Include, includedTaskfileVars *Vars) error {
defer t2.mutex.RUnlock()
t2.mutex.RLock()

View File

@@ -105,7 +105,7 @@ func (vars *Vars) ToCacheMap() (m map[string]any) {
if v.Sh != nil && *v.Sh != "" {
// Dynamic variable is not yet resolved; trigger
// <no value> to be used in templates.
return nil
continue
}
if v.Live != nil {
m[k] = v.Live

View File

@@ -6,22 +6,16 @@ import (
"github.com/joho/godotenv"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile/ast"
)
func Dotenv(c *compiler.Compiler, tf *ast.Taskfile, dir string) (*ast.Vars, error) {
func Dotenv(vars *ast.Vars, tf *ast.Taskfile, dir string) (*ast.Vars, error) {
if len(tf.Dotenv) == 0 {
return nil, nil
}
vars, err := c.GetTaskfileVariables()
if err != nil {
return nil, err
}
env := ast.NewVars()
cache := &templater.Cache{Vars: vars}

View File

@@ -12,7 +12,7 @@ import (
"gopkg.in/yaml.v3"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/env"
"github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile/ast"
@@ -188,7 +188,7 @@ func (r *Reader) include(node Node) error {
// Loop over each included taskfile
for _, include := range vertex.Taskfile.Includes.All() {
vars := compiler.GetEnviron()
vars := env.GetEnviron()
vars.Merge(vertex.Taskfile.Vars, nil)
// Start a goroutine to process each included Taskfile
g.Go(func() error {

View File

@@ -59,7 +59,7 @@ func NewSnippet(b []byte, opts ...SnippetOption) *Snippet {
// Syntax highlight the input and split it into lines
buf := &bytes.Buffer{}
if err := quick.Highlight(buf, string(b), "yaml", "terminal", "task"); err != nil {
buf.WriteString(string(b))
buf.Write(b)
}
linesRaw := strings.Split(string(b), "\n")
linesHighlighted := strings.Split(buf.String(), "\n")

View File

@@ -1,5 +1,10 @@
version: "3"
vars:
OS_VAR: ["windows", "linux", "darwin"]
ARCH_VAR: ["amd64", "arm64"]
NOT_A_LIST: "not a list"
tasks:
# Loop over a list of values
loop-explicit:
@@ -15,6 +20,26 @@ tasks:
ARCH: ["amd64", "arm64"]
cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
loop-matrix-ref:
cmds:
- for:
matrix:
OS:
ref: .OS_VAR
ARCH:
ref: .ARCH_VAR
cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
loop-matrix-ref-error:
cmds:
- for:
matrix:
OS:
ref: .OS_VAR
ARCH:
ref: .NOT_A_LIST
cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
# Loop over the task's sources
loop-sources:
sources:

View File

@@ -1,5 +1,10 @@
version: "3"
vars:
OS_VAR: ["windows", "linux", "darwin"]
ARCH_VAR: ["amd64", "arm64"]
NOT_A_LIST: "not a list"
tasks:
# Loop over a list of values
loop-explicit:
@@ -19,6 +24,30 @@ tasks:
vars:
TEXT: "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
loop-matrix-ref:
deps:
- for:
matrix:
OS:
ref: .OS_VAR
ARCH:
ref: .ARCH_VAR
task: echo
vars:
TEXT: "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
loop-matrix-ref-error:
deps:
- for:
matrix:
OS:
ref: .OS_VAR
ARCH:
ref: .NOT_A_LIST
task: echo
vars:
TEXT: "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
# Loop over the task's sources
loop-sources:
sources:

View File

@@ -0,0 +1,10 @@
version: "3"
vars:
INCLUDE: include
FOO:
sh : echo bar
includes:
included1:
taskfile: '{{.INCLUDE}}/Taskfile.include.yml'

View File

@@ -0,0 +1 @@
version: "3"

View File

@@ -1,9 +0,0 @@
version: '3'
preconditions:
- sh: "[ 1 = 0 ]"
msg: "1 != 0 obviously!"
tasks:
impossible:
cmd: echo "won't run"

View File

@@ -1,8 +0,0 @@
version: 3
includes:
included: included.yml
preconditions:
- sh: "[ 1 = 0 ]"
msg: "1 != 0 obviously!"

View File

@@ -1,5 +0,0 @@
version: 3
preconditions:
- sh: "[ 1 = 0 ]"
msg: "1 != 0 obviously!"

View File

@@ -1,12 +0,0 @@
version: '3'
preconditions:
- test -f foo.txt
tasks:
foo:
impossible:
preconditions:
- sh: "[ 1 = 0 ]"
msg: "1 != 0 obviously!"

View File

View File

@@ -1,6 +1,8 @@
package task
import (
"fmt"
"maps"
"os"
"path/filepath"
"strings"
@@ -18,16 +20,16 @@ import (
// CompiledTask returns a copy of a task, but replacing variables in almost all
// properties using the Go template package.
func (e *Executor) CompiledTask(call *ast.Call) (*ast.Task, error) {
func (e *Executor) CompiledTask(call *Call) (*ast.Task, error) {
return e.compiledTask(call, true)
}
// FastCompiledTask is like CompiledTask, but it skippes dynamic variables.
func (e *Executor) FastCompiledTask(call *ast.Call) (*ast.Task, error) {
func (e *Executor) FastCompiledTask(call *Call) (*ast.Task, error) {
return e.compiledTask(call, false)
}
func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task, error) {
func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, error) {
origTask, err := e.GetTask(call)
if err != nil {
return nil, err
@@ -151,7 +153,7 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task,
continue
}
if cmd.For != nil {
list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, vars, origTask.Location)
list, keys, err := itemsFromFor(cmd.For, new.Dir, new.Sources, vars, origTask.Location, cache)
if err != nil {
return nil, err
}
@@ -198,7 +200,7 @@ func (e *Executor) compiledTask(call *ast.Call, evaluateShVars bool) (*ast.Task,
continue
}
if dep.For != nil {
list, keys, err := itemsFromFor(dep.For, new.Dir, new.Sources, vars, origTask.Location)
list, keys, err := itemsFromFor(dep.For, new.Dir, new.Sources, vars, origTask.Location, cache)
if err != nil {
return nil, err
}
@@ -270,11 +272,18 @@ func itemsFromFor(
sources []*ast.Glob,
vars *ast.Vars,
location *ast.Location,
cache *templater.Cache,
) ([]any, []string, error) {
var keys []string // The list of keys to loop over (only if looping over a map)
var values []any // The list of values to loop over
// Get the list from a matrix
if f.Matrix.Len() != 0 {
if err := resolveMatrixRefs(f.Matrix, cache); err != nil {
return nil, nil, errors.TaskfileInvalidError{
URI: location.Taskfile,
Err: err,
}
}
return asAnySlice(product(f.Matrix)), nil, nil
}
// Get the list from the explicit for list
@@ -333,9 +342,27 @@ func itemsFromFor(
return values, keys, nil
}
func resolveMatrixRefs(matrix *ast.Matrix, cache *templater.Cache) error {
if matrix.Len() == 0 {
return nil
}
for _, row := range matrix.All() {
if row.Ref != "" {
v := templater.ResolveRef(row.Ref, cache)
switch value := v.(type) {
case []any:
row.Value = value
default:
return fmt.Errorf("matrix reference %q must resolve to a list", row.Ref)
}
}
}
return nil
}
// product generates the cartesian product of the input map of slices.
func product(inputMap *ast.Matrix) []map[string]any {
if inputMap.Len() == 0 {
func product(matrix *ast.Matrix) []map[string]any {
if matrix.Len() == 0 {
return nil
}
@@ -343,18 +370,16 @@ func product(inputMap *ast.Matrix) []map[string]any {
result := []map[string]any{{}}
// Iterate over each slice in the slices
for key, slice := range inputMap.All() {
for key, row := range matrix.All() {
var newResult []map[string]any
// For each combination in the current result
for _, combination := range result {
// Append each element from the current slice to the combinations
for _, item := range slice {
for _, item := range row.Value {
newComb := make(map[string]any, len(combination))
// Copy the existing combination
for k, v := range combination {
newComb[k] = v
}
maps.Copy(newComb, combination)
// Add the current item with the corresponding key
newComb[key] = item
newResult = append(newResult, newComb)

View File

@@ -15,13 +15,12 @@ import (
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/internal/fingerprint"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/taskfile/ast"
)
const defaultWatchInterval = 5 * time.Second
// watchTasks start watching the given tasks
func (e *Executor) watchTasks(calls ...*ast.Call) error {
func (e *Executor) watchTasks(calls ...*Call) error {
tasks := make([]string, len(calls))
for i, c := range calls {
tasks[i] = c.Task
@@ -119,24 +118,24 @@ func closeOnInterrupt(w *watcher.Watcher) {
}()
}
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...*ast.Call) error {
func (e *Executor) registerWatchedFiles(w *watcher.Watcher, calls ...*Call) error {
watchedFiles := w.WatchedFiles()
var registerTaskFiles func(*ast.Call) error
registerTaskFiles = func(c *ast.Call) error {
var registerTaskFiles func(*Call) error
registerTaskFiles = func(c *Call) error {
task, err := e.CompiledTask(c)
if err != nil {
return err
}
for _, d := range task.Deps {
if err := registerTaskFiles(&ast.Call{Task: d.Task, Vars: d.Vars}); err != nil {
if err := registerTaskFiles(&Call{Task: d.Task, Vars: d.Vars}); err != nil {
return err
}
}
for _, c := range task.Cmds {
if c.Task != "" {
if err := registerTaskFiles(&ast.Call{Task: c.Task, Vars: c.Vars}); err != nil {
if err := registerTaskFiles(&Call{Task: c.Task, Vars: c.Vars}); err != nil {
return err
}
}

View File

@@ -5,6 +5,89 @@ sidebar_position: 14
# Changelog
## v3.42.0 - 2025-03-08
- Made `--init` less verbose by default and respect `--silent` and `--verbose`
flags (#2009, #2011 by @HeCorr).
- `--init` now accepts a file name or directory as an argument (#2008, #2018 by
@HeCorr).
- Fix a bug where an HTTP node's location was being mutated incorrectly (#2007
by @jeongukjae).
- Fixed a bug where allowed values didn't work with dynamic var (#2032, #2033 by
@vmaerten).
- Use only the relevant checker (timestamp or checksum) to improve performance
(#2029, #2031 by @vmaerten).
- Print warnings when attempting to enable an inactive experiment or an active
experiment with an invalid value (#1979, #2049 by @pd93).
- Refactored the experiments package and added tests (#2049 by @pd93).
- Show allowed values when a variable with an enum is missing (#2027, #2052 by
@vmaerten).
- Refactored how snippets in error work and added tests (#2068 by @pd93).
- Fixed a bug where errors decoding commands were sometimes unhelpful (#2068 by
@pd93).
- Fixed a bug in the Taskfile schema where `defer` statements in the shorthand
`cmds` syntax were not considered valid (#2068 by @pd93).
- Refactored how task sorting functions work (#1798 by @pd93).
- Added a new `.taskrc.yml` (or `.taskrc.yaml`) file to let users enable
experiments (similar to `.env`) (#1982 by @vmaerten).
- Added new [Getting Started docs](https://taskfile.dev/getting-started) (#2086
by @pd93).
- Allow `matrix` to use references to other variables (#2065, #2069 by @pd93).
- Fixed a bug where, when a dynamic variable is provided, even if it is not
used, all other variables become unavailable in the templating system within
the include (#2092 by @vmaerten).
#### Package API
Unlike our CLI tool,
[Task's package API is not currently stable](https://taskfile.dev/reference/package).
In an effort to ease the pain of breaking changes for our users, we will be
providing changelogs for our package API going forwards. The hope is that these
changes will provide a better long-term experience for our users and allow to
stabilize the API in the future. #121 now tracks this piece of work.
- Bumped the minimum required Go version to 1.23 (#2059 by @pd93).
- [`task.InitTaskfile`](https://pkg.go.dev/github.com/go-task/task/v3#InitTaskfile)
(#2011, ff8c913 by @HeCorr and @pd93)
- No longer accepts an `io.Writer` (output is now the caller's
responsibility).
- The path argument can now be a filename OR a directory.
- The function now returns the full path of the generated file.
- [`TaskfileDecodeError.WithFileInfo`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskfileDecodeError.WithFileInfo)
now accepts a string instead of the arguments required to generate a snippet
(#2068 by @pd93).
- The caller is now expected to create the snippet themselves (see below).
- [`TaskfileSnippet`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Snippet)
and related code moved from the `errors` package to the `taskfile` package
(#2068 by @pd93).
- Renamed `TaskMissingRequiredVars` to
[`TaskMissingRequiredVarsError`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskMissingRequiredVarsError)
(#2052 by @vmaerten).
- Renamed `TaskNotAllowedVars` to
[`TaskNotAllowedVarsError`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskNotAllowedVarsError)
(#2052 by @vmaerten).
- The
[`taskfile.Reader`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Reader)
is now constructed using the functional options pattern (#2082 by @pd93).
- Removed our internal `logger.Logger` from the entire `taskfile` package (#2082
by @pd93).
- Users are now expected to pass a custom debug/prompt functions into
[`taskfile.Reader`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Reader)
if they want this functionality by using the new
[`WithDebugFunc`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#WithDebugFunc)
and
[`WithPromptFunc`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#WithPromptFunc)
functional options.
- Remove `Range` functions in the `taskfile/ast` package in favour of new
iterator functions (#1798 by @pd93).
- `ast.Call` was moved from the `taskfile/ast` package to the main `task`
package (#2084 by @pd93).
- `ast.Tasks.FindMatchingTasks` was moved from the `taskfile/ast` package to the
`task.Executor.FindMatchingTasks` in the main `task` package (#2084 by @pd93).
- The `Compiler` and its `GetVariables` and `FastGetVariables` methods were
moved from the `internal/compiler` package to the main `task` package (#2084
by @pd93).
## v3.41.0 - 2025-01-18
- Fixed an issue where dynamic variables were not properly logged in verbose

View File

@@ -1,6 +1,6 @@
---
slug: /community/
sidebar_position: 9
sidebar_position: 10
---
# Community

View File

@@ -1,6 +1,6 @@
---
slug: /contributing/
sidebar_position: 11
sidebar_position: 12
---
# Contributing

View File

@@ -1,6 +1,6 @@
---
slug: /deprecations/
sidebar_position: 7
sidebar_position: 8
---
# Deprecations

View File

@@ -1,6 +1,6 @@
---
slug: /experiments/
sidebar_position: 6
sidebar_position: 7
---
import Tabs from '@theme/Tabs';

View File

@@ -0,0 +1,143 @@
---
slug: /getting-started/
sidebar_position: 3
---
# Getting Started
The following guide will help introduce you to the basics of Task. We'll cover
how to create a Taskfile, how to write a basic task and how to call it. If you
haven't installed Task yet, head over to our [installation
guide][installation].
## Creating your first Taskfile
Once Task is installed, you can create your first Taskfile by running:
```shell
task --init
```
This will create a file called `Taskfile.yml` in the current directory. If you
want to create the file in another directory, you can pass an absolute or
relative path to the directory into the command:
```shell
task --init ./subdirectory
```
Or if you want the Taskfile to have a specific name, you can pass in the name of
the file:
```shell
task --init Custom.yml
```
This will create a Taskfile that looks something like this:
```yaml
version: '3'
vars:
GREETING: Hello, World!
tasks:
default:
cmds:
- echo "{{.GREETING}}"
silent: true
```
As you can see, all Taskfiles are written in [YAML format][yaml]. The `version`
attribute specifies the minimum version of Task that can be used to run this
file. The `vars` attribute is used to define variables that can be used in
tasks. In this case, we are creating a string variable called `GREETING` with a
value of `Hello, World!`.
Finally, the `tasks` attribute is used to define the tasks that can be run. In
this case, we have a task called `default` that echoes the value of the
`GREETING` variable. The `silent` attribute is set to `true`, which means that
the task metadata will not be printed when the task is run - only the output of
the commands.
## Calling a task
To call the task, you simply invoke `task` followed by the name of the task you
want to run. In this case, the name of the task is `default`, so you should run:
```shell
task default
```
Note that we don't have to specify the name of the Taskfile. Task will
automatically look for a file called `Taskfile.yml` (or any of Task's [supported
file names][supported-file-names]) in the current directory. Additionally, tasks
with the name `default` are special. They can also be run without specifying the
task name.
If you created a Taskfile in a different directory, you can run it by passing
the absolute or relative path to the directory as an argument using the `--dir`
flag:
```shell
task --dir ./subdirectory
```
Or if you created a Taskfile with a different name, you can run it by passing
the name of the Taskfile as an argument using the `--taskfile` flag:
```shell
task --taskfile Custom.yml
```
## Adding a build task
Let's create a task to build a program in Go. Start by adding a new task called
`build` below the existing `default` task. We can then add a `cmds` attribute
with a single command to build the program.
Task uses [mvdan/sh][mvdan/sh], a native Go sh interpreter. So you can write
sh/bash-like commands - even in environments where `sh` or `bash` are usually
not available (like Windows). Just remember any executables called must be
available as a built-in or in the system's `PATH`.
When you're done, it should look something like this:
```yaml
version: '3'
vars:
GREETING: Hello, World!
tasks:
default:
cmds:
- echo "{{.GREETING}}"
silent: true
build:
cmds:
- go build ./cmd/main.go
```
Call the task by running:
```shell
task build
```
That's about it for the basics, but there's _so much_ more that you can do with
Task. Check out the rest of the documentation to learn more about all the
features Task has to offer! We recommend taking a look at the [usage
guide][usage] next. Alternatively, you can check out our reference docs for the
[Taskfile schema][schema] and [CLI][cli].
{/* prettier-ignore-start */}
[yaml]: https://yaml.org/
[installation]: /installation/
[supported-file-names]: /usage/#supported-file-names
[mvdan/sh]: https://github.com/mvdan/sh
[usage]: /usage/
[schema]: /reference/schema/
[cli]: /reference/cli/
{/* prettier-ignore-end */}

View File

@@ -1,6 +1,6 @@
---
slug: /integrations/
sidebar_position: 8
sidebar_position: 9
---
# Integrations

View File

@@ -17,24 +17,6 @@ Since it's written in [Go][go], Task is just a single binary and has no other
dependencies, which means you don't need to mess with any complicated install
setups just to use a build tool.
Once [installed](/installation), you just need to describe your build tasks
using a simple [YAML][yaml] schema in a file called `Taskfile.yml`:
```yaml title="Taskfile.yml"
version: '3'
tasks:
hello:
cmds:
- echo 'Hello World from Task!'
silent: true
```
And call it by running `task hello` from your terminal.
The above example is just the start, you can take a look at the [usage](/usage)
guide to check the full schema documentation and Task features.
## Features
- [Easy installation](/installation): just download a single binary, add to
@@ -50,6 +32,15 @@ guide to check the full schema documentation and Task features.
of files haven't changed since last run (based either on its timestamp or
content).
## Documentation
- If you're new to Task, we recommend taking a look at our [getting started
guide][getting-started] for an quick introduction.
- You can also browse our [usage documentation][usage] for more details on how
all the features work.
- Or use our quick reference documentation for the [Taskfile schema][schema] or
[CLI][cli].
## Gold Sponsors
<table class="gold-sponsors">
@@ -70,4 +61,8 @@ guide to check the full schema documentation and Task features.
[snapcraft]: https://snapcraft.io/
[scoop]: https://scoop.sh/
[sh]: https://github.com/mvdan/sh
[getting-started]: /getting-started/
[usage]: /usage/
[schema]: /reference/schema/
[cli]: /reference/cli/
{/* prettier-ignore-end */}

View File

@@ -1,2 +1,2 @@
position: 4
position: 5
label: Reference

View File

@@ -1,9 +1,9 @@
---
slug: /styleguide/
sidebar_position: 10
sidebar_position: 11
---
# Style guide
# Style Guide
This is the official style guide for `Taskfile.yml` files. It provides basic
instructions for keeping your Taskfiles clean and familiar to other users.

View File

@@ -1,6 +1,6 @@
---
slug: /taskfile-versions/
sidebar_position: 5
sidebar_position: 6
---
# Taskfile Versions

View File

@@ -1,6 +1,6 @@
---
slug: /usage/
sidebar_position: 3
sidebar_position: 4
---
import Tabs from '@theme/Tabs';
@@ -8,56 +8,29 @@ import TabItem from '@theme/TabItem';
# Usage
## Getting started
## Running Taskfiles
Create a file called `Taskfile.yml` in the root of your project. The `cmds`
attribute should contain the commands of a task. The example below allows
compiling a Go app and uses [esbuild](https://esbuild.github.io/) to concat and
minify multiple CSS files into a single one.
Specific Taskfiles can be called by specifying the `--taskfile` flag. If you
don't specify a Taskfile, Task will automatically look for a file with one of
the [supported file names](#supported-file-names) in the current directory. If
you want to search in a different directory, you can use the `--dir` flag.
```yaml
version: '3'
### Supported file names
tasks:
build:
cmds:
- go build -v -i main.go
Task looks for files with the following names, in order of priority:
assets:
cmds:
- esbuild --bundle --minify css/index.css > public/bundle.css
```
- `Taskfile.yml`
- `taskfile.yml`
- `Taskfile.yaml`
- `taskfile.yaml`
- `Taskfile.dist.yml`
- `taskfile.dist.yml`
- `Taskfile.dist.yaml`
- `taskfile.dist.yaml`
Running the tasks is as simple as running:
```shell
task assets build
```
Task uses [mvdan.cc/sh](https://mvdan.cc/sh/), a native Go sh interpreter. So
you can write sh/bash commands, and it will work even on Windows, where `sh` or
`bash` are usually not available. Just remember any executable called must be
available by the OS or in PATH.
If you omit a task name, "default" will be assumed.
## Supported file names
Task will look for the following file names, in order of priority:
- Taskfile.yml
- taskfile.yml
- Taskfile.yaml
- taskfile.yaml
- Taskfile.dist.yml
- taskfile.dist.yml
- Taskfile.dist.yaml
- taskfile.dist.yaml
The intention of having the `.dist` variants is to allow projects to have one
committed version (`.dist`) while still allowing individual users to override
the Taskfile by adding an additional `Taskfile.yml` (which would be on
`.gitignore`).
The `.dist` variants allow projects to have one committed file (`.dist`) while
still allowing individual users to override the Taskfile by adding an additional
`Taskfile.yml` (which would be in your `.gitignore`).
### Running a Taskfile from a subdirectory
@@ -263,11 +236,7 @@ Taskfile.
### OS-specific Taskfiles
With `version: '2'`, task automatically includes any `Taskfile_{{OS}}.yml` if it
exists (for example: `Taskfile_windows.yml`, `Taskfile_linux.yml` or
`Taskfile_darwin.yml`). Since this behavior was a bit too implicit, it was
removed on version 3, but you still can have a similar behavior by explicitly
importing these files:
You can include OS-specific Taskfiles by using a templating function:
```yaml
version: '3'
@@ -442,7 +411,7 @@ If you run `task -a` it will print:
task: Found multiple tasks (greet) included by "lib"
```
If you the included Taskfile has a task with the same name as a task in the main Taskfile,
If the included Taskfile has a task with the same name as a task in the main Taskfile,
you may want to exclude it from the flattened tasks.
You can do this by using the [`excludes` option](#exclude-tasks-from-being-included).
@@ -1019,28 +988,6 @@ tasks:
- echo "I will not run"
```
They can be defined at two levels:
- Global Level: Applies to all tasks.
- Task Level: Applies only to a specific task.
```yaml
version: '3'
preconditions:
- sh: 'exit 1'
tasks:
task-will-fail: echo "I will not run"
```
:::info
Please note that you are not currently able to use the `preconditions` key inside
included Taskfiles. It'll produce an error.
:::
### Limiting when tasks run
If a task executed by multiple `cmds` or multiple `deps` you can control when it
@@ -1465,6 +1412,27 @@ darwin/amd64
darwin/arm64
```
You can also use references to other variables as long as they are also lists:
```yaml
version: "3"
vars:
OS_VAR: ["windows", "linux", "darwin"]
ARCH_VAR: ["amd64", "arm64"]
tasks:
default:
cmds:
- for:
matrix:
OS:
ref: .OS_VAR
ARCH:
ref: .ARCH_VAR
cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
```
### Looping over your task's sources
You are also able to loop over the sources of your task:

View File

@@ -699,13 +699,6 @@
"description": "A set of global environment variables.",
"$ref": "#/definitions/env"
},
"preconditions": {
"description": "A list of commands to check if any task should run. If a condition is not met, the task will return an error.",
"type": "array",
"items": {
"$ref": "#/definitions/precondition"
}
},
"tasks": {
"description": "A set of task definitions.",
"$ref": "#/definitions/tasks"

View File

@@ -5,6 +5,89 @@ sidebar_position: 14
# Changelog
## v3.42.0 - 2025-03-08
- Made `--init` less verbose by default and respect `--silent` and `--verbose`
flags (#2009, #2011 by @HeCorr).
- `--init` now accepts a file name or directory as an argument (#2008, #2018 by
@HeCorr).
- Fix a bug where an HTTP node's location was being mutated incorrectly (#2007
by @jeongukjae).
- Fixed a bug where allowed values didn't work with dynamic var (#2032, #2033 by
@vmaerten).
- Use only the relevant checker (timestamp or checksum) to improve performance
(#2029, #2031 by @vmaerten).
- Print warnings when attempting to enable an inactive experiment or an active
experiment with an invalid value (#1979, #2049 by @pd93).
- Refactored the experiments package and added tests (#2049 by @pd93).
- Show allowed values when a variable with an enum is missing (#2027, #2052 by
@vmaerten).
- Refactored how snippets in error work and added tests (#2068 by @pd93).
- Fixed a bug where errors decoding commands were sometimes unhelpful (#2068 by
@pd93).
- Fixed a bug in the Taskfile schema where `defer` statements in the shorthand
`cmds` syntax were not considered valid (#2068 by @pd93).
- Refactored how task sorting functions work (#1798 by @pd93).
- Added a new `.taskrc.yml` (or `.taskrc.yaml`) file to let users enable
experiments (similar to `.env`) (#1982 by @vmaerten).
- Added new [Getting Started docs](https://taskfile.dev/getting-started) (#2086
by @pd93).
- Allow `matrix` to use references to other variables (#2065, #2069 by @pd93).
- Fixed a bug where, when a dynamic variable is provided, even if it is not
used, all other variables become unavailable in the templating system within
the include (#2092 by @vmaerten).
#### Package API
Unlike our CLI tool,
[Task's package API is not currently stable](https://taskfile.dev/reference/package).
In an effort to ease the pain of breaking changes for our users, we will be
providing changelogs for our package API going forwards. The hope is that these
changes will provide a better long-term experience for our users and allow to
stabilize the API in the future. #121 now tracks this piece of work.
- Bumped the minimum required Go version to 1.23 (#2059 by @pd93).
- [`task.InitTaskfile`](https://pkg.go.dev/github.com/go-task/task/v3#InitTaskfile)
(#2011, ff8c913 by @HeCorr and @pd93)
- No longer accepts an `io.Writer` (output is now the caller's
responsibility).
- The path argument can now be a filename OR a directory.
- The function now returns the full path of the generated file.
- [`TaskfileDecodeError.WithFileInfo`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskfileDecodeError.WithFileInfo)
now accepts a string instead of the arguments required to generate a snippet
(#2068 by @pd93).
- The caller is now expected to create the snippet themselves (see below).
- [`TaskfileSnippet`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Snippet)
and related code moved from the `errors` package to the `taskfile` package
(#2068 by @pd93).
- Renamed `TaskMissingRequiredVars` to
[`TaskMissingRequiredVarsError`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskMissingRequiredVarsError)
(#2052 by @vmaerten).
- Renamed `TaskNotAllowedVars` to
[`TaskNotAllowedVarsError`](https://pkg.go.dev/github.com/go-task/task/v3/errors#TaskNotAllowedVarsError)
(#2052 by @vmaerten).
- The
[`taskfile.Reader`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Reader)
is now constructed using the functional options pattern (#2082 by @pd93).
- Removed our internal `logger.Logger` from the entire `taskfile` package (#2082
by @pd93).
- Users are now expected to pass a custom debug/prompt functions into
[`taskfile.Reader`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#Reader)
if they want this functionality by using the new
[`WithDebugFunc`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#WithDebugFunc)
and
[`WithPromptFunc`](https://pkg.go.dev/github.com/go-task/task/v3/taskfile#WithPromptFunc)
functional options.
- Remove `Range` functions in the `taskfile/ast` package in favour of new
iterator functions (#1798 by @pd93).
- `ast.Call` was moved from the `taskfile/ast` package to the main `task`
package (#2084 by @pd93).
- `ast.Tasks.FindMatchingTasks` was moved from the `taskfile/ast` package to the
`task.Executor.FindMatchingTasks` in the main `task` package (#2084 by @pd93).
- The `Compiler` and its `GetVariables` and `FastGetVariables` methods were
moved from the `internal/compiler` package to the main `task` package (#2084
by @pd93).
## v3.41.0 - 2025-01-18
- Fixed an issue where dynamic variables were not properly logged in verbose

View File

@@ -1,6 +1,6 @@
---
slug: /community/
sidebar_position: 9
sidebar_position: 10
---
# Community

View File

@@ -1,6 +1,6 @@
---
slug: /contributing/
sidebar_position: 11
sidebar_position: 12
---
# Contributing

View File

@@ -1,6 +1,6 @@
---
slug: /deprecations/
sidebar_position: 7
sidebar_position: 8
---
# Deprecations

View File

@@ -1,8 +1,11 @@
---
slug: /experiments/
sidebar_position: 6
sidebar_position: 7
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Experiments
:::caution
@@ -39,7 +42,7 @@ Which method you use depends on how you intend to use the experiment:
1. Prefixing your task commands with the relevant environment variable(s). For
example, `TASK_X_{FEATURE}=1 task {my-task}`. This is intended for one-off
invocations of Task to test out experimental features.
1. Adding the relevant environment variable(s) in your "dotfiles" (e.g.
2. Adding the relevant environment variable(s) in your "dotfiles" (e.g.
`.bashrc`, `.zshrc` etc.). This will permanently enable experimental features
for your personal environment.
@@ -47,15 +50,33 @@ Which method you use depends on how you intend to use the experiment:
export TASK_X_FEATURE=1
```
1. Creating a `.env` file in the same directory as your root Taskfile that
contains the relevant environment variable(s). This allows you to enable an
experimental feature at a project level. If you commit the `.env` file to
source control then other users of your project will also have these
experiments enabled.
3. Creating a `.env` or a `.task-experiments.yml` file in the same directory as
your root Taskfile.\
The `.env` file should contain the relevant environment
variable(s), while the `.task-experiments.yml` file should use a YAML format
where each experiment is defined as a key with a corresponding value.
```shell title=".env"
TASK_X_FEATURE=1
```
This allows you to enable an experimental feature at a project level. If you
commit this file to source control, then other users of your project will
also have these experiments enabled.
If both files are present, the values in the `.task-experiments.yml` file
will take precedence.
<Tabs values={[ {label: '.task-experiments.yml', value: 'yaml'}, {label: '.env', value: 'env'}]}>
<TabItem value="yaml">
```yaml title=".taskrc.yml"
experiments:
FEATURE: 1
```
</TabItem>
<TabItem value="env">
```shell title=".env"
TASK_X_FEATURE=1
```
</TabItem>
</Tabs>
## Workflow

View File

@@ -0,0 +1,143 @@
---
slug: /getting-started/
sidebar_position: 3
---
# Getting Started
The following guide will help introduce you to the basics of Task. We'll cover
how to create a Taskfile, how to write a basic task and how to call it. If you
haven't installed Task yet, head over to our [installation
guide][installation].
## Creating your first Taskfile
Once Task is installed, you can create your first Taskfile by running:
```shell
task --init
```
This will create a file called `Taskfile.yml` in the current directory. If you
want to create the file in another directory, you can pass an absolute or
relative path to the directory into the command:
```shell
task --init ./subdirectory
```
Or if you want the Taskfile to have a specific name, you can pass in the name of
the file:
```shell
task --init Custom.yml
```
This will create a Taskfile that looks something like this:
```yaml
version: '3'
vars:
GREETING: Hello, World!
tasks:
default:
cmds:
- echo "{{.GREETING}}"
silent: true
```
As you can see, all Taskfiles are written in [YAML format][yaml]. The `version`
attribute specifies the minimum version of Task that can be used to run this
file. The `vars` attribute is used to define variables that can be used in
tasks. In this case, we are creating a string variable called `GREETING` with a
value of `Hello, World!`.
Finally, the `tasks` attribute is used to define the tasks that can be run. In
this case, we have a task called `default` that echoes the value of the
`GREETING` variable. The `silent` attribute is set to `true`, which means that
the task metadata will not be printed when the task is run - only the output of
the commands.
## Calling a task
To call the task, you simply invoke `task` followed by the name of the task you
want to run. In this case, the name of the task is `default`, so you should run:
```shell
task default
```
Note that we don't have to specify the name of the Taskfile. Task will
automatically look for a file called `Taskfile.yml` (or any of Task's [supported
file names][supported-file-names]) in the current directory. Additionally, tasks
with the name `default` are special. They can also be run without specifying the
task name.
If you created a Taskfile in a different directory, you can run it by passing
the absolute or relative path to the directory as an argument using the `--dir`
flag:
```shell
task --dir ./subdirectory
```
Or if you created a Taskfile with a different name, you can run it by passing
the name of the Taskfile as an argument using the `--taskfile` flag:
```shell
task --taskfile Custom.yml
```
## Adding a build task
Let's create a task to build a program in Go. Start by adding a new task called
`build` below the existing `default` task. We can then add a `cmds` attribute
with a single command to build the program.
Task uses [mvdan/sh][mvdan/sh], a native Go sh interpreter. So you can write
sh/bash-like commands - even in environments where `sh` or `bash` are usually
not available (like Windows). Just remember any executables called must be
available as a built-in or in the system's `PATH`.
When you're done, it should look something like this:
```yaml
version: '3'
vars:
GREETING: Hello, World!
tasks:
default:
cmds:
- echo "{{.GREETING}}"
silent: true
build:
cmds:
- go build ./cmd/main.go
```
Call the task by running:
```shell
task build
```
That's about it for the basics, but there's _so much_ more that you can do with
Task. Check out the rest of the documentation to learn more about all the
features Task has to offer! We recommend taking a look at the [usage
guide][usage] next. Alternatively, you can check out our reference docs for the
[Taskfile schema][schema] and [CLI][cli].
{/* prettier-ignore-start */}
[yaml]: https://yaml.org/
[installation]: /installation/
[supported-file-names]: /usage/#supported-file-names
[mvdan/sh]: https://github.com/mvdan/sh
[usage]: /usage/
[schema]: /reference/schema/
[cli]: /reference/cli/
{/* prettier-ignore-end */}

View File

@@ -1,6 +1,6 @@
---
slug: /integrations/
sidebar_position: 8
sidebar_position: 9
---
# Integrations

View File

@@ -17,24 +17,6 @@ Since it's written in [Go][go], Task is just a single binary and has no other
dependencies, which means you don't need to mess with any complicated install
setups just to use a build tool.
Once [installed](/installation), you just need to describe your build tasks
using a simple [YAML][yaml] schema in a file called `Taskfile.yml`:
```yaml title="Taskfile.yml"
version: '3'
tasks:
hello:
cmds:
- echo 'Hello World from Task!'
silent: true
```
And call it by running `task hello` from your terminal.
The above example is just the start, you can take a look at the [usage](/usage)
guide to check the full schema documentation and Task features.
## Features
- [Easy installation](/installation): just download a single binary, add to
@@ -50,6 +32,15 @@ guide to check the full schema documentation and Task features.
of files haven't changed since last run (based either on its timestamp or
content).
## Documentation
- If you're new to Task, we recommend taking a look at our [getting started
guide][getting-started] for an quick introduction.
- You can also browse our [usage documentation][usage] for more details on how
all the features work.
- Or use our quick reference documentation for the [Taskfile schema][schema] or
[CLI][cli].
## Gold Sponsors
<table class="gold-sponsors">
@@ -70,4 +61,8 @@ guide to check the full schema documentation and Task features.
[snapcraft]: https://snapcraft.io/
[scoop]: https://scoop.sh/
[sh]: https://github.com/mvdan/sh
[getting-started]: /getting-started/
[usage]: /usage/
[schema]: /reference/schema/
[cli]: /reference/cli/
{/* prettier-ignore-end */}

View File

@@ -1,2 +1,2 @@
position: 4
position: 5
label: Reference

View File

@@ -16,10 +16,10 @@ task [--flags] [tasks...] [-- CLI_ARGS...]
If `--` is given, all remaining arguments will be assigned to a special
`CLI_ARGS` variable
## Flags
:::
## 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. |
@@ -45,7 +45,7 @@ If `--` is given, all remaining arguments will be assigned to a special
| `-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` | |
| `-t` | `--taskfile` | `string` | | Taskfile path to run.<br />Check the list of default filenames [here](../usage/#supported-file-names). |
| `-v` | `--verbose` | `bool` | `false` | Enables verbose mode. |
| | `--version` | `bool` | `false` | Show Task version. |
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task.

View File

@@ -1,9 +1,9 @@
---
slug: /styleguide/
sidebar_position: 10
sidebar_position: 11
---
# Style guide
# Style Guide
This is the official style guide for `Taskfile.yml` files. It provides basic
instructions for keeping your Taskfiles clean and familiar to other users.

View File

@@ -1,6 +1,6 @@
---
slug: /taskfile-versions/
sidebar_position: 5
sidebar_position: 6
---
# Taskfile Versions

View File

@@ -1,6 +1,6 @@
---
slug: /usage/
sidebar_position: 3
sidebar_position: 4
---
import Tabs from '@theme/Tabs';
@@ -8,56 +8,29 @@ import TabItem from '@theme/TabItem';
# Usage
## Getting started
## Running Taskfiles
Create a file called `Taskfile.yml` in the root of your project. The `cmds`
attribute should contain the commands of a task. The example below allows
compiling a Go app and uses [esbuild](https://esbuild.github.io/) to concat and
minify multiple CSS files into a single one.
Specific Taskfiles can be called by specifying the `--taskfile` flag. If you
don't specify a Taskfile, Task will automatically look for a file with one of
the [supported file names](#supported-file-names) in the current directory. If
you want to search in a different directory, you can use the `--dir` flag.
```yaml
version: '3'
### Supported file names
tasks:
build:
cmds:
- go build -v -i main.go
Task looks for files with the following names, in order of priority:
assets:
cmds:
- esbuild --bundle --minify css/index.css > public/bundle.css
```
- `Taskfile.yml`
- `taskfile.yml`
- `Taskfile.yaml`
- `taskfile.yaml`
- `Taskfile.dist.yml`
- `taskfile.dist.yml`
- `Taskfile.dist.yaml`
- `taskfile.dist.yaml`
Running the tasks is as simple as running:
```shell
task assets build
```
Task uses [mvdan.cc/sh](https://mvdan.cc/sh/), a native Go sh interpreter. So
you can write sh/bash commands, and it will work even on Windows, where `sh` or
`bash` are usually not available. Just remember any executable called must be
available by the OS or in PATH.
If you omit a task name, "default" will be assumed.
## Supported file names
Task will look for the following file names, in order of priority:
- Taskfile.yml
- taskfile.yml
- Taskfile.yaml
- taskfile.yaml
- Taskfile.dist.yml
- taskfile.dist.yml
- Taskfile.dist.yaml
- taskfile.dist.yaml
The intention of having the `.dist` variants is to allow projects to have one
committed version (`.dist`) while still allowing individual users to override
the Taskfile by adding an additional `Taskfile.yml` (which would be on
`.gitignore`).
The `.dist` variants allow projects to have one committed file (`.dist`) while
still allowing individual users to override the Taskfile by adding an additional
`Taskfile.yml` (which would be in your `.gitignore`).
### Running a Taskfile from a subdirectory
@@ -263,11 +236,7 @@ Taskfile.
### OS-specific Taskfiles
With `version: '2'`, task automatically includes any `Taskfile_{{OS}}.yml` if it
exists (for example: `Taskfile_windows.yml`, `Taskfile_linux.yml` or
`Taskfile_darwin.yml`). Since this behavior was a bit too implicit, it was
removed on version 3, but you still can have a similar behavior by explicitly
importing these files:
You can include OS-specific Taskfiles by using a templating function:
```yaml
version: '3'
@@ -442,7 +411,7 @@ If you run `task -a` it will print:
task: Found multiple tasks (greet) included by "lib"
```
If you the included Taskfile has a task with the same name as a task in the main Taskfile,
If the included Taskfile has a task with the same name as a task in the main Taskfile,
you may want to exclude it from the flattened tasks.
You can do this by using the [`excludes` option](#exclude-tasks-from-being-included).
@@ -1443,6 +1412,27 @@ darwin/amd64
darwin/arm64
```
You can also use references to other variables as long as they are also lists:
```yaml
version: "3"
vars:
OS_VAR: ["windows", "linux", "darwin"]
ARCH_VAR: ["amd64", "arm64"]
tasks:
default:
cmds:
- for:
matrix:
OS:
ref: .OS_VAR
ARCH:
ref: .ARCH_VAR
cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
```
### Looping over your task's sources
You are also able to loop over the sources of your task:

View File

@@ -2437,9 +2437,9 @@
"@types/react" "*"
"@types/react@*", "@types/react@^19.0.0":
version "19.0.8"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.8.tgz#7098e6159f2a61e4f4cef2c1223c044a9bec590e"
integrity sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw==
version "19.0.10"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.10.tgz#d0c66dafd862474190fe95ce11a68de69ed2b0eb"
integrity sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==
dependencies:
csstype "^3.0.2"
@@ -5497,9 +5497,9 @@ markdown-table@^2.0.0:
repeat-string "^1.0.0"
markdown-table@^3.0.0:
version "3.0.3"
resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz"
integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==
version "3.0.4"
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.4.tgz#fe44d6d410ff9d6f2ea1797a3f60aa4d2b631c2a"
integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==
math-intrinsics@^1.1.0:
version "1.1.0"
@@ -5521,17 +5521,7 @@ mdast-util-directive@^3.0.0:
stringify-entities "^4.0.0"
unist-util-visit-parents "^6.0.0"
mdast-util-find-and-replace@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz"
integrity sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==
dependencies:
"@types/mdast" "^4.0.0"
escape-string-regexp "^5.0.0"
unist-util-is "^6.0.0"
unist-util-visit-parents "^6.0.0"
mdast-util-find-and-replace@^3.0.1:
mdast-util-find-and-replace@^3.0.0, mdast-util-find-and-replace@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz#70a3174c894e14df722abf43bc250cbae44b11df"
integrity sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==
@@ -5572,9 +5562,9 @@ mdast-util-frontmatter@^2.0.0:
micromark-extension-frontmatter "^2.0.0"
mdast-util-gfm-autolink-literal@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz"
integrity sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==
version "2.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5"
integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==
dependencies:
"@types/mdast" "^4.0.0"
ccount "^2.0.0"
@@ -5583,9 +5573,9 @@ mdast-util-gfm-autolink-literal@^2.0.0:
micromark-util-character "^2.0.0"
mdast-util-gfm-footnote@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz"
integrity sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==
version "2.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz#7778e9d9ca3df7238cc2bd3fa2b1bf6a65b19403"
integrity sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==
dependencies:
"@types/mdast" "^4.0.0"
devlop "^1.1.0"
@@ -5595,7 +5585,7 @@ mdast-util-gfm-footnote@^2.0.0:
mdast-util-gfm-strikethrough@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz#d44ef9e8ed283ac8c1165ab0d0dfd058c2764c16"
integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==
dependencies:
"@types/mdast" "^4.0.0"
@@ -5604,7 +5594,7 @@ mdast-util-gfm-strikethrough@^2.0.0:
mdast-util-gfm-table@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz#7a435fb6223a72b0862b33afbd712b6dae878d38"
integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==
dependencies:
"@types/mdast" "^4.0.0"
@@ -5615,7 +5605,7 @@ mdast-util-gfm-table@^2.0.0:
mdast-util-gfm-task-list-item@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz#e68095d2f8a4303ef24094ab642e1047b991a936"
integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==
dependencies:
"@types/mdast" "^4.0.0"
@@ -5624,9 +5614,9 @@ mdast-util-gfm-task-list-item@^2.0.0:
mdast-util-to-markdown "^2.0.0"
mdast-util-gfm@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz"
integrity sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==
version "3.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz#2cdf63b92c2a331406b0fb0db4c077c1b0331751"
integrity sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==
dependencies:
mdast-util-from-markdown "^2.0.0"
mdast-util-gfm-autolink-literal "^2.0.0"
@@ -5822,9 +5812,9 @@ micromark-extension-frontmatter@^2.0.0:
micromark-util-types "^2.0.0"
micromark-extension-gfm-autolink-literal@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz"
integrity sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935"
integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==
dependencies:
micromark-util-character "^2.0.0"
micromark-util-sanitize-uri "^2.0.0"
@@ -5832,9 +5822,9 @@ micromark-extension-gfm-autolink-literal@^2.0.0:
micromark-util-types "^2.0.0"
micromark-extension-gfm-footnote@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz"
integrity sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750"
integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==
dependencies:
devlop "^1.0.0"
micromark-core-commonmark "^2.0.0"
@@ -5846,9 +5836,9 @@ micromark-extension-gfm-footnote@^2.0.0:
micromark-util-types "^2.0.0"
micromark-extension-gfm-strikethrough@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz"
integrity sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923"
integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==
dependencies:
devlop "^1.0.0"
micromark-util-chunked "^2.0.0"
@@ -5858,9 +5848,9 @@ micromark-extension-gfm-strikethrough@^2.0.0:
micromark-util-types "^2.0.0"
micromark-extension-gfm-table@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz"
integrity sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==
version "2.1.1"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz#fac70bcbf51fe65f5f44033118d39be8a9b5940b"
integrity sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==
dependencies:
devlop "^1.0.0"
micromark-factory-space "^2.0.0"
@@ -5870,15 +5860,15 @@ micromark-extension-gfm-table@^2.0.0:
micromark-extension-gfm-tagfilter@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz#f26d8a7807b5985fba13cf61465b58ca5ff7dc57"
integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==
dependencies:
micromark-util-types "^2.0.0"
micromark-extension-gfm-task-list-item@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz"
integrity sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c"
integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==
dependencies:
devlop "^1.0.0"
micromark-factory-space "^2.0.0"
@@ -5888,7 +5878,7 @@ micromark-extension-gfm-task-list-item@^2.0.0:
micromark-extension-gfm@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz#3e13376ab95dd7a5cfd0e29560dfe999657b3c5b"
integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==
dependencies:
micromark-extension-gfm-autolink-literal "^2.0.0"
@@ -7720,9 +7710,9 @@ remark-frontmatter@^5.0.0:
unified "^11.0.0"
remark-gfm@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz"
integrity sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==
version "4.0.1"
resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.1.tgz#33227b2a74397670d357bf05c098eaf8513f0d6b"
integrity sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==
dependencies:
"@types/mdast" "^4.0.0"
mdast-util-gfm "^3.0.0"
@@ -7774,7 +7764,7 @@ remark-rehype@^11.0.0:
remark-stringify@^11.0.0:
version "11.0.0"
resolved "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz"
resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3"
integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==
dependencies:
"@types/mdast" "^4.0.0"
@@ -8530,9 +8520,9 @@ typedarray-to-buffer@^3.1.5:
is-typedarray "^1.0.0"
typescript@^5.3.3:
version "5.7.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e"
integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
version "5.8.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==
undici-types@~6.20.0:
version "6.20.0"