mirror of
https://github.com/go-task/task.git
synced 2025-03-19 21:17:46 +02:00
commit
6d90c781c9
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Add ability to set `aliases` for tasks and namespaces ([#268](https://github.com/go-task/task/pull/268), [#340](https://github.com/go-task/task/pull/340), [#879](https://github.com/go-task/task/pull/879)).
|
||||||
- Improvements to Fish shell completion
|
- Improvements to Fish shell completion
|
||||||
([#897](https://github.com/go-task/task/pull/897)).
|
([#897](https://github.com/go-task/task/pull/897)).
|
||||||
- Added ability to set a different watch interval by setting
|
- Added ability to set a different watch interval by setting
|
||||||
|
@ -2,6 +2,7 @@ version: '3'
|
|||||||
|
|
||||||
includes:
|
includes:
|
||||||
docs:
|
docs:
|
||||||
|
aliases: [d]
|
||||||
taskfile: ./docs
|
taskfile: ./docs
|
||||||
dir: ./docs
|
dir: ./docs
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ tasks:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
desc: Installs Task
|
desc: Installs Task
|
||||||
|
aliases: [i]
|
||||||
sources:
|
sources:
|
||||||
- './**/*.go'
|
- './**/*.go'
|
||||||
cmds:
|
cmds:
|
||||||
@ -42,6 +44,7 @@ tasks:
|
|||||||
|
|
||||||
lint:
|
lint:
|
||||||
desc: Runs golangci-lint
|
desc: Runs golangci-lint
|
||||||
|
aliases: [l]
|
||||||
sources:
|
sources:
|
||||||
- './**/*.go'
|
- './**/*.go'
|
||||||
cmds:
|
cmds:
|
||||||
@ -65,6 +68,7 @@ tasks:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
desc: Runs test suite
|
desc: Runs test suite
|
||||||
|
aliases: [t]
|
||||||
deps: [install]
|
deps: [install]
|
||||||
cmds:
|
cmds:
|
||||||
- go test {{catLines .GO_PACKAGES}}
|
- go test {{catLines .GO_PACKAGES}}
|
||||||
|
@ -8,6 +8,7 @@ tasks:
|
|||||||
|
|
||||||
start:
|
start:
|
||||||
desc: Start website
|
desc: Start website
|
||||||
|
aliases: [s]
|
||||||
vars:
|
vars:
|
||||||
HOST: '{{default "localhost" .HOST}}'
|
HOST: '{{default "localhost" .HOST}}'
|
||||||
PORT: '{{default "3001" .PORT}}'
|
PORT: '{{default "3001" .PORT}}'
|
||||||
@ -25,6 +26,7 @@ tasks:
|
|||||||
- rm -rf ./build
|
- rm -rf ./build
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
desc: Build and deploy Docusaurus. Requires GIT_USER and GIT_PASS envs to be previous set
|
desc: Build and deploy Docusaurus
|
||||||
|
summary: Requires GIT_USER and GIT_PASS envs to be previous set
|
||||||
cmds:
|
cmds:
|
||||||
- npx docusaurus deploy
|
- npx docusaurus deploy
|
||||||
|
@ -91,7 +91,6 @@ Some environment variables can be overriden to adjust Task behavior.
|
|||||||
| `dotenv` | `[]string` | | A list of `.env` file paths to be parsed. |
|
| `dotenv` | `[]string` | | A list of `.env` file paths to be parsed. |
|
||||||
| `tasks` | [`map[string]Task`](#task) | | The task definitions. |
|
| `tasks` | [`map[string]Task`](#task) | | The task definitions. |
|
||||||
|
|
||||||
|
|
||||||
### Include
|
### Include
|
||||||
|
|
||||||
| Attribute | Type | Default | Description |
|
| Attribute | Type | Default | Description |
|
||||||
@ -99,7 +98,8 @@ Some environment variables can be overriden to adjust Task behavior.
|
|||||||
| `taskfile` | `string` | | The path for the Taskfile or directory to be included. If a directory, Task will look for files named `Taskfile.yml` or `Taskfile.yaml` inside that directory. If a relative path, resolved relative to the directory containing the including Taskfile. |
|
| `taskfile` | `string` | | The path for the Taskfile or directory to be included. If a directory, Task will look for files named `Taskfile.yml` or `Taskfile.yaml` inside that directory. If a relative path, resolved relative to the directory containing the including Taskfile. |
|
||||||
| `dir` | `string` | The parent Taskfile directory | The working directory of the included tasks when run. |
|
| `dir` | `string` | The parent Taskfile directory | The working directory of the included tasks when run. |
|
||||||
| `optional` | `bool` | `false` | If `true`, no errors will be thrown if the specified file does not exist. |
|
| `optional` | `bool` | `false` | If `true`, no errors will be thrown if the specified file does not exist. |
|
||||||
| `internal` | `bool` | `false` | If `true`, tasks will be omitted from both `--list` and `--list-all`. |
|
| `internal` | `bool` | `false` | If `true`, tasks will not be callable from the command line and will be omitted from both `--list` and `--list-all`. |
|
||||||
|
| `aliases` | `[]string` | | Alternative names for the namespace of the included Taskfile. |
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
@ -118,11 +118,13 @@ includes:
|
|||||||
| - | - | - | - |
|
| - | - | - | - |
|
||||||
| `desc` | `string` | | A short description of the task. This is listed when calling `task --list`. |
|
| `desc` | `string` | | A short description of the task. This is listed when calling `task --list`. |
|
||||||
| `summary` | `string` | | A longer description of the task. This is listed when calling `task --summary [task]`. |
|
| `summary` | `string` | | A longer description of the task. This is listed when calling `task --summary [task]`. |
|
||||||
|
| `aliases` | `[]string` | | Alternative names for the task. |
|
||||||
|
| `label` | `string` | | Overrides the name of the task in the output when a task is run. Supports variables. |
|
||||||
| `sources` | `[]string` | | List of sources to check before running this task. Relevant for `checksum` and `timestamp` methods. Can be file paths or star globs. |
|
| `sources` | `[]string` | | List of sources to check before running this task. Relevant for `checksum` and `timestamp` methods. Can be file paths or star globs. |
|
||||||
| `dir` | `string` | | The current directory which this task should run. |
|
| `dir` | `string` | | The current directory which this task should run. |
|
||||||
| `method` | `string` | `checksum` | Method used by this task. Default to the one declared globally or `checksum`. Available options: `checksum`, `timestamp` and `none` |
|
| `method` | `string` | `checksum` | Method used by this task. Default to the one declared globally or `checksum`. Available options: `checksum`, `timestamp` and `none` |
|
||||||
| `silent` | `bool` | `false` | Skips some output for this task. Note that STDOUT and STDERR of the commands will still be redirected. |
|
| `silent` | `bool` | `false` | Skips some output for this task. Note that STDOUT and STDERR of the commands will still be redirected. |
|
||||||
| `internal` | `bool` | `false` | If `true`, omit this task from both `--list` and `--list-all`. |
|
| `internal` | `bool` | `false` | If `true`, this task will not be callable from the command line and will be omitted from both `--list` and `--list-all`. |
|
||||||
| `run` | `string` | The one declared globally in the Taskfile or `always` | Specifies whether the task should run again or not if called more than once. Available options: `always`, `once` and `when_changed`. |
|
| `run` | `string` | The one declared globally in the Taskfile or `always` | Specifies whether the task should run again or not if called more than once. Available options: `always`, `once` and `when_changed`. |
|
||||||
| `prefix` | `string` | | Allows to override the prefix print before the STDOUT. Only relevant when using the `prefixed` output mode. |
|
| `prefix` | `string` | | Allows to override the prefix print before the STDOUT. Only relevant when using the `prefixed` output mode. |
|
||||||
| `ignore_error` | `bool` | `false` | Continue execution if errors happen while executing the commands. |
|
| `ignore_error` | `bool` | `false` | Continue execution if errors happen while executing the commands. |
|
||||||
|
@ -230,6 +230,21 @@ includes:
|
|||||||
DOCKER_IMAGE: frontend_image
|
DOCKER_IMAGE: frontend_image
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Namespace aliases
|
||||||
|
|
||||||
|
When including a Taskfile, you can give the namespace a list of `aliases`.
|
||||||
|
This works in the same way as [task aliases](#task-aliases) and can be used
|
||||||
|
together to create shorter and easier-to-type commands.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
generate:
|
||||||
|
taskfile: ./taskfiles/Generate.yml
|
||||||
|
aliases: [gen]
|
||||||
|
```
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
Vars declared in the included Taskfile have preference over the
|
Vars declared in the included Taskfile have preference over the
|
||||||
@ -965,6 +980,30 @@ If the task does not have a summary or a description, a warning is printed.
|
|||||||
|
|
||||||
Please note: *showing the summary will not execute the command*.
|
Please note: *showing the summary will not execute the command*.
|
||||||
|
|
||||||
|
## Task aliases
|
||||||
|
|
||||||
|
Aliases are alternative names for tasks. They can be used to make it easier and
|
||||||
|
quicker to run tasks with long or hard-to-type names. You can use them on the
|
||||||
|
command line, when [calling sub-tasks](#calling-another-task) in your Taskfile
|
||||||
|
and when [including tasks](#including-other-taskfiles) with aliases from another
|
||||||
|
Taskfile. They can also be used together with [namespace
|
||||||
|
aliases](#namespace-aliases).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
generate:
|
||||||
|
aliases: [gen]
|
||||||
|
cmds:
|
||||||
|
- task: gen-mocks
|
||||||
|
|
||||||
|
generate-mocks:
|
||||||
|
aliases: [gen-mocks]
|
||||||
|
cmds:
|
||||||
|
- echo "generating..."
|
||||||
|
```
|
||||||
|
|
||||||
## Overriding task name
|
## Overriding task name
|
||||||
|
|
||||||
Sometimes you may want to override the task name printed on the summary, up-to-date
|
Sometimes you may want to override the task name printed on the summary, up-to-date
|
||||||
|
10
errors.go
10
errors.go
@ -3,6 +3,7 @@ package task
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
)
|
)
|
||||||
@ -20,6 +21,15 @@ func (err *taskNotFoundError) Error() string {
|
|||||||
return fmt.Sprintf(`task: Task %q not found`, err.taskName)
|
return fmt.Sprintf(`task: Task %q not found`, err.taskName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type multipleTasksWithAliasError struct {
|
||||||
|
aliasName string
|
||||||
|
taskNames []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *multipleTasksWithAliasError) Error() string {
|
||||||
|
return fmt.Sprintf(`task: Multiple tasks (%s) with alias %q found`, strings.Join(err.taskNames, ", "), err.aliasName)
|
||||||
|
}
|
||||||
|
|
||||||
type taskInternalError struct {
|
type taskInternalError struct {
|
||||||
taskName string
|
taskName string
|
||||||
}
|
}
|
||||||
|
3
go.mod
3
go.mod
@ -9,6 +9,7 @@ require (
|
|||||||
github.com/radovskyb/watcher v1.0.7
|
github.com/radovskyb/watcher v1.0.7
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
|
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
mvdan.cc/sh/v3 v3.6.0-0.dev.0.20220704111049-a6e3029cd899
|
mvdan.cc/sh/v3 v3.6.0-0.dev.0.20220704111049-a6e3029cd899
|
||||||
@ -19,7 +20,7 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||||
)
|
)
|
||||||
|
9
go.sum
9
go.sum
@ -7,7 +7,7 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF
|
|||||||
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
|
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
@ -34,16 +34,17 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||||
|
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
3
help.go
3
help.go
@ -47,6 +47,9 @@ func (e *Executor) printTasks(listAll bool) {
|
|||||||
e.Logger.FOutf(w, logger.Yellow, "* ")
|
e.Logger.FOutf(w, logger.Yellow, "* ")
|
||||||
e.Logger.FOutf(w, logger.Green, task.Task)
|
e.Logger.FOutf(w, logger.Green, task.Task)
|
||||||
e.Logger.FOutf(w, logger.Default, ": \t%s", task.Desc)
|
e.Logger.FOutf(w, logger.Default, ": \t%s", task.Desc)
|
||||||
|
if len(task.Aliases) > 0 {
|
||||||
|
e.Logger.FOutf(w, logger.Cyan, "\t(aliases: %s)", strings.Join(task.Aliases, ", "))
|
||||||
|
}
|
||||||
fmt.Fprint(w, "\n")
|
fmt.Fprint(w, "\n")
|
||||||
}
|
}
|
||||||
w.Flush()
|
w.Flush()
|
||||||
|
@ -28,6 +28,7 @@ func PrintTask(l *logger.Logger, t *taskfile.Task) {
|
|||||||
printTaskName(l, t)
|
printTaskName(l, t)
|
||||||
printTaskDescribingText(t, l)
|
printTaskDescribingText(t, l)
|
||||||
printTaskDependencies(l, t)
|
printTaskDependencies(l, t)
|
||||||
|
printTaskAliases(l, t)
|
||||||
printTaskCommands(l, t)
|
printTaskCommands(l, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +62,18 @@ func printTaskName(l *logger.Logger, t *taskfile.Task) {
|
|||||||
l.Outf(logger.Default, "")
|
l.Outf(logger.Default, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printTaskAliases(l *logger.Logger, t *taskfile.Task) {
|
||||||
|
if len(t.Aliases) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.Outf(logger.Default, "")
|
||||||
|
l.Outf(logger.Default, "aliases:")
|
||||||
|
for _, alias := range t.Aliases {
|
||||||
|
l.FOutf(l.Stdout, logger.Default, " - ")
|
||||||
|
l.Outf(logger.Cyan, alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func hasDescription(t *taskfile.Task) bool {
|
func hasDescription(t *taskfile.Task) bool {
|
||||||
return t.Desc != ""
|
return t.Desc != ""
|
||||||
}
|
}
|
||||||
|
53
task.go
53
task.go
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/templater"
|
"github.com/go-task/task/v3/internal/templater"
|
||||||
"github.com/go-task/task/v3/taskfile"
|
"github.com/go-task/task/v3/taskfile"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,16 +65,15 @@ type Executor struct {
|
|||||||
// Run runs Task
|
// Run runs Task
|
||||||
func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
||||||
// check if given tasks exist
|
// check if given tasks exist
|
||||||
for _, c := range calls {
|
for _, call := range calls {
|
||||||
t, ok := e.Taskfile.Tasks[c.Task]
|
task, err := e.GetTask(call)
|
||||||
if !ok {
|
if err != nil {
|
||||||
// FIXME: move to the main package
|
|
||||||
e.ListTasksWithDesc()
|
e.ListTasksWithDesc()
|
||||||
return &taskNotFoundError{taskName: c.Task}
|
return err
|
||||||
}
|
}
|
||||||
if t.Internal {
|
if task.Internal {
|
||||||
e.ListTasksWithDesc()
|
e.ListTasksWithDesc()
|
||||||
return &taskInternalError{taskName: c.Task}
|
return &taskInternalError{taskName: call.Task}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,8 +113,8 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !e.Watch && atomic.AddInt32(e.taskCallCount[call.Task], 1) >= MaximumTaskCall {
|
if !e.Watch && atomic.AddInt32(e.taskCallCount[t.Task], 1) >= MaximumTaskCall {
|
||||||
return &MaximumTaskCallExceededError{task: call.Task}
|
return &MaximumTaskCallExceededError{task: t.Task}
|
||||||
}
|
}
|
||||||
|
|
||||||
release := e.acquireConcurrencyLimit()
|
release := e.acquireConcurrencyLimit()
|
||||||
@ -331,3 +331,38 @@ func (e *Executor) startExecution(ctx context.Context, t *taskfile.Task, execute
|
|||||||
|
|
||||||
return execute(ctx)
|
return execute(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 taskfile.Call) (*taskfile.Task, error) {
|
||||||
|
// Search for a matching task
|
||||||
|
matchingTask, ok := e.Taskfile.Tasks[call.Task]
|
||||||
|
if ok {
|
||||||
|
return matchingTask, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If didn't find one, search for a task with a matching alias
|
||||||
|
var aliasedTasks []string
|
||||||
|
for _, task := range e.Taskfile.Tasks {
|
||||||
|
if slices.Contains(task.Aliases, call.Task) {
|
||||||
|
aliasedTasks = append(aliasedTasks, task.Task)
|
||||||
|
matchingTask = task
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we found multiple tasks
|
||||||
|
if len(aliasedTasks) > 1 {
|
||||||
|
return nil, &multipleTasksWithAliasError{
|
||||||
|
aliasName: call.Task,
|
||||||
|
taskNames: aliasedTasks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we found no tasks
|
||||||
|
if len(aliasedTasks) == 0 {
|
||||||
|
return nil, &taskNotFoundError{
|
||||||
|
taskName: call.Task,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingTask, nil
|
||||||
|
}
|
||||||
|
56
task_test.go
56
task_test.go
@ -477,6 +477,58 @@ func TestStatusChecksum(t *testing.T) {
|
|||||||
assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String())
|
assert.Equal(t, `task: Task "build" is up to date`+"\n", buff.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAlias(t *testing.T) {
|
||||||
|
const dir = "testdata/alias"
|
||||||
|
|
||||||
|
data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias.txt"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
}
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "f"}))
|
||||||
|
assert.Equal(t, string(data), buff.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuplicateAlias(t *testing.T) {
|
||||||
|
const dir = "testdata/alias"
|
||||||
|
|
||||||
|
data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias-duplicate.txt"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
}
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
assert.Error(t, e.Run(context.Background(), taskfile.Call{Task: "x"}))
|
||||||
|
assert.Equal(t, string(data), buff.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAliasSummary(t *testing.T) {
|
||||||
|
const dir = "testdata/alias"
|
||||||
|
|
||||||
|
data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias-summary.txt"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
e := task.Executor{
|
||||||
|
Dir: dir,
|
||||||
|
Summary: true,
|
||||||
|
Stdout: &buff,
|
||||||
|
Stderr: &buff,
|
||||||
|
}
|
||||||
|
assert.NoError(t, e.Setup())
|
||||||
|
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "f"}))
|
||||||
|
assert.Equal(t, string(data), buff.String())
|
||||||
|
}
|
||||||
|
|
||||||
func TestLabelUpToDate(t *testing.T) {
|
func TestLabelUpToDate(t *testing.T) {
|
||||||
const dir = "testdata/label_uptodate"
|
const dir = "testdata/label_uptodate"
|
||||||
|
|
||||||
@ -990,7 +1042,7 @@ func TestIncludesInternal(t *testing.T) {
|
|||||||
|
|
||||||
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
||||||
if test.expectedErr {
|
if test.expectedErr {
|
||||||
assert.Error(t, err, test.expectedErr)
|
assert.Error(t, err)
|
||||||
} else {
|
} else {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1030,7 +1082,7 @@ func TestInternalTask(t *testing.T) {
|
|||||||
|
|
||||||
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
err := e.Run(context.Background(), taskfile.Call{Task: test.task})
|
||||||
if test.expectedErr {
|
if test.expectedErr {
|
||||||
assert.Error(t, err, test.expectedErr)
|
assert.Error(t, err)
|
||||||
} else {
|
} else {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
23
taskfile/copy.go
Normal file
23
taskfile/copy.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package taskfile
|
||||||
|
|
||||||
|
import "golang.org/x/exp/constraints"
|
||||||
|
|
||||||
|
func deepCopySlice[T any](orig []T) []T {
|
||||||
|
if orig == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c := make([]T, len(orig))
|
||||||
|
copy(c, orig)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopyMap[K constraints.Ordered, V any](orig map[K]V) map[K]V {
|
||||||
|
if orig == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c := make(map[K]V, len(orig))
|
||||||
|
for k, v := range orig {
|
||||||
|
c[k] = v
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/go-task/task/v3/internal/execext"
|
"github.com/go-task/task/v3/internal/execext"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ type IncludedTaskfile struct {
|
|||||||
Dir string
|
Dir string
|
||||||
Optional bool
|
Optional bool
|
||||||
Internal bool
|
Internal bool
|
||||||
|
Aliases []string
|
||||||
AdvancedImport bool
|
AdvancedImport bool
|
||||||
Vars *Vars
|
Vars *Vars
|
||||||
BaseDir string // The directory from which the including taskfile was loaded; used to resolve relative paths
|
BaseDir string // The directory from which the including taskfile was loaded; used to resolve relative paths
|
||||||
@ -71,7 +73,7 @@ func (tfs *IncludedTaskfiles) Set(key string, includedTaskfile IncludedTaskfile)
|
|||||||
if tfs.Mapping == nil {
|
if tfs.Mapping == nil {
|
||||||
tfs.Mapping = make(map[string]IncludedTaskfile, 1)
|
tfs.Mapping = make(map[string]IncludedTaskfile, 1)
|
||||||
}
|
}
|
||||||
if !stringSliceContains(tfs.Keys, key) {
|
if !slices.Contains(tfs.Keys, key) {
|
||||||
tfs.Keys = append(tfs.Keys, key)
|
tfs.Keys = append(tfs.Keys, key)
|
||||||
}
|
}
|
||||||
tfs.Mapping[key] = includedTaskfile
|
tfs.Mapping[key] = includedTaskfile
|
||||||
@ -103,6 +105,7 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
|||||||
Dir string
|
Dir string
|
||||||
Optional bool
|
Optional bool
|
||||||
Internal bool
|
Internal bool
|
||||||
|
Aliases []string
|
||||||
Vars *Vars
|
Vars *Vars
|
||||||
}
|
}
|
||||||
if err := unmarshal(&includedTaskfile); err != nil {
|
if err := unmarshal(&includedTaskfile); err != nil {
|
||||||
@ -112,11 +115,29 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
|||||||
it.Dir = includedTaskfile.Dir
|
it.Dir = includedTaskfile.Dir
|
||||||
it.Optional = includedTaskfile.Optional
|
it.Optional = includedTaskfile.Optional
|
||||||
it.Internal = includedTaskfile.Internal
|
it.Internal = includedTaskfile.Internal
|
||||||
|
it.Aliases = includedTaskfile.Aliases
|
||||||
it.AdvancedImport = true
|
it.AdvancedImport = true
|
||||||
it.Vars = includedTaskfile.Vars
|
it.Vars = includedTaskfile.Vars
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopy creates a new instance of IncludedTaskfile and copies
|
||||||
|
// data by value from the source struct.
|
||||||
|
func (it *IncludedTaskfile) DeepCopy() *IncludedTaskfile {
|
||||||
|
if it == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &IncludedTaskfile{
|
||||||
|
Taskfile: it.Taskfile,
|
||||||
|
Dir: it.Dir,
|
||||||
|
Optional: it.Optional,
|
||||||
|
Internal: it.Internal,
|
||||||
|
AdvancedImport: it.AdvancedImport,
|
||||||
|
Vars: it.Vars.DeepCopy(),
|
||||||
|
BaseDir: it.BaseDir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FullTaskfilePath returns the fully qualified path to the included taskfile
|
// FullTaskfilePath returns the fully qualified path to the included taskfile
|
||||||
func (it *IncludedTaskfile) FullTaskfilePath() (string, error) {
|
func (it *IncludedTaskfile) FullTaskfilePath() (string, error) {
|
||||||
return it.resolvePath(it.Taskfile)
|
return it.resolvePath(it.Taskfile)
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
const NamespaceSeparator = ":"
|
const NamespaceSeparator = ":"
|
||||||
|
|
||||||
// Merge merges the second Taskfile into the first
|
// Merge merges the second Taskfile into the first
|
||||||
func Merge(t1, t2 *Taskfile, internal bool, namespaces ...string) error {
|
func Merge(t1, t2 *Taskfile, includedTaskfile *IncludedTaskfile, namespaces ...string) error {
|
||||||
if t1.Version != t2.Version {
|
if t1.Version != t2.Version {
|
||||||
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
|
return fmt.Errorf(`task: Taskfiles versions should match. First is "%s" but second is "%s"`, t1.Version, t2.Version)
|
||||||
}
|
}
|
||||||
@ -39,22 +39,38 @@ func Merge(t1, t2 *Taskfile, internal bool, namespaces ...string) error {
|
|||||||
t1.Tasks = make(Tasks)
|
t1.Tasks = make(Tasks)
|
||||||
}
|
}
|
||||||
for k, v := range t2.Tasks {
|
for k, v := range t2.Tasks {
|
||||||
// FIXME(@andreynering): Refactor this block, otherwise we can
|
// We do a deep copy of the task struct here to ensure that no data can
|
||||||
// have serious side-effects in the future, since we're editing
|
// be changed elsewhere once the taskfile is merged.
|
||||||
// the original references instead of deep copying them.
|
task := v.DeepCopy()
|
||||||
|
|
||||||
v.Internal = v.Internal || internal
|
// Set the task to internal if EITHER the included task or the included
|
||||||
|
// taskfile are marked as internal
|
||||||
|
task.Internal = task.Internal || includedTaskfile.Internal
|
||||||
|
|
||||||
t1.Tasks[taskNameWithNamespace(k, namespaces...)] = v
|
// Add namespaces to dependencies, commands and aliases
|
||||||
|
for _, dep := range task.Deps {
|
||||||
for _, dep := range v.Deps {
|
|
||||||
dep.Task = taskNameWithNamespace(dep.Task, namespaces...)
|
dep.Task = taskNameWithNamespace(dep.Task, namespaces...)
|
||||||
}
|
}
|
||||||
for _, cmd := range v.Cmds {
|
for _, cmd := range task.Cmds {
|
||||||
if cmd != nil && cmd.Task != "" {
|
if cmd != nil && cmd.Task != "" {
|
||||||
cmd.Task = taskNameWithNamespace(cmd.Task, namespaces...)
|
cmd.Task = taskNameWithNamespace(cmd.Task, namespaces...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i, alias := range task.Aliases {
|
||||||
|
task.Aliases[i] = taskNameWithNamespace(alias, namespaces...)
|
||||||
|
}
|
||||||
|
// Add namespace aliases
|
||||||
|
if includedTaskfile != nil {
|
||||||
|
for _, namespaceAlias := range includedTaskfile.Aliases {
|
||||||
|
task.Aliases = append(task.Aliases, taskNameWithNamespace(task.Task, namespaceAlias))
|
||||||
|
for _, alias := range v.Aliases {
|
||||||
|
task.Aliases = append(task.Aliases, taskNameWithNamespace(alias, namespaceAlias))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the task to the merged taskfile
|
||||||
|
t1.Tasks[taskNameWithNamespace(k, namespaces...)] = task
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -79,6 +79,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
|||||||
Dir: tr.Replace(includedTask.Dir),
|
Dir: tr.Replace(includedTask.Dir),
|
||||||
Optional: includedTask.Optional,
|
Optional: includedTask.Optional,
|
||||||
Internal: includedTask.Internal,
|
Internal: includedTask.Internal,
|
||||||
|
Aliases: includedTask.Aliases,
|
||||||
AdvancedImport: includedTask.AdvancedImport,
|
AdvancedImport: includedTask.AdvancedImport,
|
||||||
Vars: includedTask.Vars,
|
Vars: includedTask.Vars,
|
||||||
BaseDir: includedTask.BaseDir,
|
BaseDir: includedTask.BaseDir,
|
||||||
@ -149,7 +150,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = taskfile.Merge(t, includedTaskfile, includedTask.Internal, namespace); err != nil {
|
if err = taskfile.Merge(t, includedTaskfile, &includedTask, namespace); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -165,7 +166,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = taskfile.Merge(t, osTaskfile, false); err != nil {
|
if err = taskfile.Merge(t, osTaskfile, nil); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package taskfile
|
|
||||||
|
|
||||||
func stringSliceContains(s []string, str string) bool {
|
|
||||||
for _, v := range s {
|
|
||||||
if v == str {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ type Task struct {
|
|||||||
Label string
|
Label string
|
||||||
Desc string
|
Desc string
|
||||||
Summary string
|
Summary string
|
||||||
|
Aliases []string
|
||||||
Sources []string
|
Sources []string
|
||||||
Generates []string
|
Generates []string
|
||||||
Status []string
|
Status []string
|
||||||
@ -56,6 +57,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
Label string
|
Label string
|
||||||
Desc string
|
Desc string
|
||||||
Summary string
|
Summary string
|
||||||
|
Aliases []string
|
||||||
Sources []string
|
Sources []string
|
||||||
Generates []string
|
Generates []string
|
||||||
Status []string
|
Status []string
|
||||||
@ -78,6 +80,7 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
t.Deps = task.Deps
|
t.Deps = task.Deps
|
||||||
t.Label = task.Label
|
t.Label = task.Label
|
||||||
t.Desc = task.Desc
|
t.Desc = task.Desc
|
||||||
|
t.Aliases = task.Aliases
|
||||||
t.Summary = task.Summary
|
t.Summary = task.Summary
|
||||||
t.Sources = task.Sources
|
t.Sources = task.Sources
|
||||||
t.Generates = task.Generates
|
t.Generates = task.Generates
|
||||||
@ -95,3 +98,35 @@ func (t *Task) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||||||
t.Run = task.Run
|
t.Run = task.Run
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopy creates a new instance of Task and copies
|
||||||
|
// data by value from the source struct.
|
||||||
|
func (t *Task) DeepCopy() *Task {
|
||||||
|
c := &Task{
|
||||||
|
Task: t.Task,
|
||||||
|
Cmds: deepCopySlice(t.Cmds),
|
||||||
|
Deps: deepCopySlice(t.Deps),
|
||||||
|
Label: t.Label,
|
||||||
|
Desc: t.Desc,
|
||||||
|
Summary: t.Summary,
|
||||||
|
Aliases: deepCopySlice(t.Aliases),
|
||||||
|
Sources: deepCopySlice(t.Sources),
|
||||||
|
Generates: deepCopySlice(t.Generates),
|
||||||
|
Status: deepCopySlice(t.Status),
|
||||||
|
Preconditions: deepCopySlice(t.Preconditions),
|
||||||
|
Dir: t.Dir,
|
||||||
|
Vars: t.Vars.DeepCopy(),
|
||||||
|
Env: t.Env.DeepCopy(),
|
||||||
|
Silent: t.Silent,
|
||||||
|
Interactive: t.Interactive,
|
||||||
|
Internal: t.Internal,
|
||||||
|
Method: t.Method,
|
||||||
|
Prefix: t.Prefix,
|
||||||
|
IgnoreError: t.IgnoreError,
|
||||||
|
Run: t.Run,
|
||||||
|
IncludeVars: t.IncludeVars.DeepCopy(),
|
||||||
|
IncludedTaskfileVars: t.IncludedTaskfileVars.DeepCopy(),
|
||||||
|
IncludedTaskfile: t.IncludedTaskfile.DeepCopy(),
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package taskfile
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,6 +35,18 @@ func (vs *Vars) UnmarshalYAML(node *yaml.Node) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopy creates a new instance of Vars and copies
|
||||||
|
// data by value from the source struct.
|
||||||
|
func (vs *Vars) DeepCopy() *Vars {
|
||||||
|
if vs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Vars{
|
||||||
|
Keys: deepCopySlice(vs.Keys),
|
||||||
|
Mapping: deepCopyMap(vs.Mapping),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Merge merges the given Vars into the caller one
|
// Merge merges the given Vars into the caller one
|
||||||
func (vs *Vars) Merge(other *Vars) {
|
func (vs *Vars) Merge(other *Vars) {
|
||||||
_ = other.Range(func(key string, value Var) error {
|
_ = other.Range(func(key string, value Var) error {
|
||||||
@ -47,7 +60,7 @@ func (vs *Vars) Set(key string, value Var) {
|
|||||||
if vs.Mapping == nil {
|
if vs.Mapping == nil {
|
||||||
vs.Mapping = make(map[string]Var, 1)
|
vs.Mapping = make(map[string]Var, 1)
|
||||||
}
|
}
|
||||||
if !stringSliceContains(vs.Keys, key) {
|
if !slices.Contains(vs.Keys, key) {
|
||||||
vs.Keys = append(vs.Keys, key)
|
vs.Keys = append(vs.Keys, key)
|
||||||
}
|
}
|
||||||
vs.Mapping[key] = value
|
vs.Mapping[key] = value
|
||||||
|
19
testdata/alias/Taskfile.yml
vendored
Normal file
19
testdata/alias/Taskfile.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
includes:
|
||||||
|
included:
|
||||||
|
taskfile: Taskfile2.yml
|
||||||
|
aliases: [inc, i]
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
foo:
|
||||||
|
aliases: [f, x]
|
||||||
|
cmds:
|
||||||
|
- echo "foo"
|
||||||
|
- task: b
|
||||||
|
|
||||||
|
bar:
|
||||||
|
aliases: [b, x]
|
||||||
|
cmds:
|
||||||
|
- echo "bar"
|
||||||
|
- task: inc:q
|
7
testdata/alias/Taskfile2.yml
vendored
Normal file
7
testdata/alias/Taskfile2.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
qux:
|
||||||
|
aliases: [q, x]
|
||||||
|
cmds:
|
||||||
|
- echo "qux"
|
1
testdata/alias/alias-duplicate.txt
vendored
Normal file
1
testdata/alias/alias-duplicate.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
task: No tasks with description available. Try --list-all to list all tasks
|
11
testdata/alias/alias-summary.txt
vendored
Normal file
11
testdata/alias/alias-summary.txt
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
task: foo
|
||||||
|
|
||||||
|
(task does not have description or summary)
|
||||||
|
|
||||||
|
aliases:
|
||||||
|
- f
|
||||||
|
- x
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- echo "foo"
|
||||||
|
- Task: b
|
6
testdata/alias/alias.txt
vendored
Normal file
6
testdata/alias/alias.txt
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
task: [foo] echo "foo"
|
||||||
|
foo
|
||||||
|
task: [bar] echo "bar"
|
||||||
|
bar
|
||||||
|
task: [included:qux] echo "qux"
|
||||||
|
qux
|
@ -22,13 +22,12 @@ func (e *Executor) FastCompiledTask(call taskfile.Call) (*taskfile.Task, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskfile.Task, error) {
|
func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskfile.Task, error) {
|
||||||
origTask, ok := e.Taskfile.Tasks[call.Task]
|
origTask, err := e.GetTask(call)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return nil, &taskNotFoundError{call.Task}
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var vars *taskfile.Vars
|
var vars *taskfile.Vars
|
||||||
var err error
|
|
||||||
if evaluateShVars {
|
if evaluateShVars {
|
||||||
vars, err = e.Compiler.GetVariables(origTask, call)
|
vars, err = e.Compiler.GetVariables(origTask, call)
|
||||||
} else {
|
} else {
|
||||||
@ -50,6 +49,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
|||||||
Label: r.Replace(origTask.Label),
|
Label: r.Replace(origTask.Label),
|
||||||
Desc: r.Replace(origTask.Desc),
|
Desc: r.Replace(origTask.Desc),
|
||||||
Summary: r.Replace(origTask.Summary),
|
Summary: r.Replace(origTask.Summary),
|
||||||
|
Aliases: origTask.Aliases,
|
||||||
Sources: r.ReplaceSlice(origTask.Sources),
|
Sources: r.ReplaceSlice(origTask.Sources),
|
||||||
Generates: r.ReplaceSlice(origTask.Generates),
|
Generates: r.ReplaceSlice(origTask.Generates),
|
||||||
Dir: r.Replace(origTask.Dir),
|
Dir: r.Replace(origTask.Dir),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user