指南
运行 Taskfile
可以通过指定 --taskfile 标志来调用特定的 Taskfile。如果没有指定 Taskfile,Task 将自动在当前目录中查找具有以下支持的文件名之一的文件。如果要搜索不同的目录,可以使用 --dir 标志。
支持的文件名
Task 会按优先级顺序查找以下名称的文件:
Taskfile.ymltaskfile.ymlTaskfile.yamltaskfile.yamlTaskfile.dist.ymltaskfile.dist.ymlTaskfile.dist.yamltaskfile.dist.yaml
.dist 变体允许项目提交一个文件(.dist),同时仍允许单个用户通过添加额外的 Taskfile.yml(这应该在您的 .gitignore 中)来覆盖 Taskfile。
从子目录运行 Taskfile
如果在当前工作目录中找不到 Taskfile,它将向上遍历文件树直到找到一个(类似于 git 的工作方式)。当从这样的子目录运行 Task 时,它将表现得好像您是从包含 Taskfile 的目录运行它一样。
您可以使用此功能结合特殊的 {{.USER_WORKING_DIR}} 变量来创建一些非常有用的可重用任务。例如,如果您有一个单仓库,其中包含每个微服务的目录,您可以 cd 进入微服务目录并运行任务命令来启动它,而无需创建具有相同内容的多个任务或 Taskfile。例如:
version: '3'
tasks:
up:
dir: '{{.USER_WORKING_DIR}}'
preconditions:
- test -f docker-compose.yml
cmds:
- docker-compose up -d在这个示例中,我们可以运行 cd <service> 和 task up,只要 <service> 目录包含 docker-compose.yml,Docker 组合就会启动。
运行全局 Taskfile
如果使用 --global(别名 -g)标志调用 Task,它将查找您的主目录而不是工作目录。简而言之,Task 将查找匹配 $HOME/{T,t}askfile.{yml,yaml} 的 Taskfile。
这对于在系统中的任何位置运行自动化任务非常有用!
INFO
使用 -g 运行全局 Taskfile 时,任务默认将在 $HOME 上运行,而不是在您的工作目录上!
如上一节所述,{{.USER_WORKING_DIR}} 特殊变量在这里非常有用,用于在调用 task -g 的目录上运行内容。
version: '3'
tasks:
from-home:
cmds:
- pwd
from-working-directory:
dir: '{{.USER_WORKING_DIR}}'
cmds:
- pwd从 stdin 读取 Taskfile
Taskfile 还支持从 stdin 读取。这在动态生成 Taskfile 且不想将其写入磁盘时非常有用。要告诉 task 从 stdin 读取,必须使用特殊的 - 值指定 -t/--taskfile 标志。然后,您可以像管道到任何其他程序一样管道到 Task:
task -t - <(cat ./Taskfile.yml)
# OR
cat ./Taskfile.yml | task -t -环境变量
Task
您可以使用 env 为特定任务设置自定义环境变量:
version: '3'
tasks:
greet:
cmds:
- echo $GREETING
env:
GREETING: Hey, there!此外,您可以设置全局环境变量,这些变量将对所有任务可用:
version: '3'
env:
GREETING: Hey, there!
tasks:
greet:
cmds:
- echo $GREETINGINFO
env 支持像变量一样展开和从 shell 命令检索输出,如变量部分所述。
.env 文件
您也可以使用 dotenv: 设置让 Task 包含 .env 之类的文件:
KEYNAME=VALUEENDPOINT=testing.comversion: '3'
env:
ENV: testing
dotenv: ['.env', '{{.ENV}}/.env', '{{.HOME}}/.env']
tasks:
greet:
cmds:
- echo "Using $KEYNAME and endpoint $ENDPOINT"Dotenv 文件也可以在任务级别指定:
version: '3'
env:
ENV: testing
tasks:
greet:
dotenv: ['.env', '{{.ENV}}/.env', '{{.HOME}}/.env']
cmds:
- echo "Using $KEYNAME and endpoint $ENDPOINT"在任务级别显式指定的环境变量将覆盖 dotfiles 中定义的变量:
version: '3'
env:
ENV: testing
tasks:
greet:
dotenv: ['.env', '{{.ENV}}/.env', '{{.HOME}}/.env']
env:
KEYNAME: DIFFERENT_VALUE
cmds:
- echo "Using $KEYNAME and endpoint $ENDPOINT"INFO
请注意,您目前无法在包含的 Taskfile 中使用 dotenv 键。
包含其他 Taskfile
如果您想在不同的项目(Taskfile)之间共享任务,可以使用 includes 关键字通过导入机制包含其他 Taskfile:
version: '3'
includes:
docs: ./documentation # will look for ./documentation/Taskfile.yml
docker: ./DockerTasks.yml给定 Taskfile 中描述的任务将使用指定的命名空间可用。因此,您可以调用 task docs:serve 来运行 documentation/Taskfile.yml 中的 serve 任务,或调用 task docker:build 来运行 DockerTasks.yml 文件中的 build 任务。
相对路径是相对于包含 Taskfile 的目录解析的。
特定于操作系统的 Taskfile
您可以使用模板函数来包含特定于操作系统的 Taskfile:
version: '3'
includes:
build: ./Taskfile_{{OS}}.yml包含 Taskfile 的目录
默认情况下,包含的 Taskfile 的任务将在当前目录中运行,即使 Taskfile 在另一个目录中,但您可以使用此替代语法强制其任务在另一个目录中运行:
version: '3'
includes:
docs:
taskfile: ./docs/Taskfile.yml
dir: ./docsINFO
包含的 Taskfile 必须使用与主 Taskfile 相同的模式版本。
可选包含
标记为可选的包含将允许 Task 在缺少包含的文件时正常继续执行。
version: '3'
includes:
tests:
taskfile: ./tests/Taskfile.yml
optional: true
tasks:
greet:
cmds:
- echo "This command can still be successfully executed if
./tests/Taskfile.yml does not exist"内部包含
标记为内部的包含将设置包含文件的所有任务也为内部(参见下面的内部任务部分)。这在包含不打算由用户直接使用的实用任务时非常有用。
version: '3'
includes:
tests:
taskfile: ./taskfiles/Utils.yml
internal: true展平包含
您可以使用 flatten 选项将包含的 Taskfile 任务展平到主 Taskfile 中。这意味着包含的 Taskfile 任务将无需命名空间即可可用。
version: '3'
includes:
lib:
taskfile: ./Included.yml
flatten: true
tasks:
greet:
cmds:
- echo "Greet"
- task: fooversion: '3'
tasks:
foo:
cmds:
- echo "Foo"如果您运行 task -a,它将打印:
task: Available tasks for this project:
* greet:
* foo您可以直接运行 task foo 而无需命名空间。
您也可以在其他任务中引用任务而无需命名空间。因此,如果您运行 task greet,它将运行 greet 和 foo 任务,输出将是:
Greet
Foo如果多个任务具有相同的名称,将抛出错误:
version: '3'
includes:
lib:
taskfile: ./Included.yml
flatten: true
tasks:
greet:
cmds:
- echo "Greet"
- task: fooversion: '3'
tasks:
greet:
cmds:
- echo "Foo"如果您运行 task -a,它将打印:
task: Found multiple tasks (greet) included by "lib"如果包含的 Taskfile 具有与主 Taskfile 中任务相同名称的任务,您可能希望将其从展平任务中排除。
您可以通过使用excludes 选项来实现这一点。
从包含中排除任务
您可以使用 excludes 选项从包含中排除任务。此选项接受要从此包含中排除的任务列表。
version: '3'
includes:
included:
taskfile: ./Included.yml
excludes: [foo]version: '3'
tasks:
foo: echo "Foo"
bar: echo "Bar"task included:foo 将抛出错误,因为 foo 任务被排除,但 task included:bar 将工作并显示 Bar。
它与 flatten 选项兼容。
包含 Taskfile 的变量
在包含 Taskfile 时,您也可以指定变量。这对于具有可重用 Taskfile 可能很有用,可以调整它甚至多次包含:
version: '3'
includes:
backend:
taskfile: ./taskfiles/Docker.yml
vars:
DOCKER_IMAGE: backend_image
frontend:
taskfile: ./taskfiles/Docker.yml
vars:
DOCKER_IMAGE: frontend_image命名空间别名
在包含 Taskfile 时,您可以为命名空间提供 aliases 列表。这的工作方式与任务别名相同,并且可以一起使用以创建更短且更容易输入的命令。
version: '3'
includes:
generate:
taskfile: ./taskfiles/Generate.yml
aliases: [gen]INFO
在包含的 Taskfile 中声明的变量优先于包含 Taskfile 中的变量!如果您希望包含 Taskfile 中的变量可覆盖,请使用default 函数:MY_VAR: '{{.MY_VAR | default "my-default-value"}}'。
内部任务
内部任务是用户无法直接调用的任务。它们不会在运行 task --list|--list-all 时出现在输出中。其他任务可以像往常一样调用内部任务。这对于创建可重用、函数式的任务非常有用,这些任务在命令行上没有有用的目的。
version: '3'
tasks:
build-image-1:
cmds:
- task: build-image
vars:
DOCKER_IMAGE: image-1
build-image:
internal: true
cmds:
- docker build -t {{.DOCKER_IMAGE}} .任务目录
默认情况下,任务将在 Taskfile 所在的目录中执行。但您可以轻松地让任务在另一个文件夹中运行,通过指定 dir:
version: '3'
tasks:
serve:
dir: public/www
cmds:
# run http server
- caddy如果目录不存在,task 将创建它。
任务依赖
依赖并行运行,因此任务的依赖不应相互依赖。如果您想强制任务串行运行,请查看下面的调用另一个任务部分。
您可能有依赖于其他任务的任务。只需在 deps 上指向它们,它们将在运行父任务之前自动运行:
version: '3'
tasks:
build:
deps: [assets]
cmds:
- go build -v -i main.go
assets:
cmds:
- esbuild --bundle --minify css/index.css > public/bundle.css在上面的示例中,如果您运行 task build,assets 将始终在 build 之前运行。
任务可以仅具有依赖而没有命令来将任务组合在一起:
version: '3'
tasks:
assets:
deps: [js, css]
js:
cmds:
- esbuild --bundle --minify js/index.js > public/bundle.js
css:
cmds:
- esbuild --bundle --minify css/index.css > public/bundle.css如果有多个依赖,它们总是并行运行以获得更好的性能。
TIP
您也可以使用 --parallel 标志(别名 -p)让命令行给出的任务并行运行。例如:task --parallel js css。
如果您想将信息传递给依赖,可以以与调用另一个任务相同的方式进行:
version: '3'
tasks:
default:
deps:
- task: echo_sth
vars: { TEXT: 'before 1' }
- task: echo_sth
vars: { TEXT: 'before 2' }
silent: true
cmds:
- echo "after"
echo_sth:
cmds:
- echo {{.TEXT}}特定于平台的任务和命令
如果您想将任务运行限制为显式平台,可以使用 platforms: 键来实现。任务可以限制为特定的操作系统、架构或两者的组合。在不匹配时,任务或命令将被跳过,不会抛出错误。
允许作为 OS 或 Arch 的值是有效的 GOOS 和 GOARCH 值,如 Go 语言这里定义。
下面的 build-windows 任务仅在 Windows 上运行,并且在任何架构上运行:
version: '3'
tasks:
build-windows:
platforms: [windows]
cmds:
- echo 'Running command on Windows'这可以限制为特定架构,如下所示:
version: '3'
tasks:
build-windows-amd64:
platforms: [windows/amd64]
cmds:
- echo 'Running command on Windows (amd64)'也可以将任务限制为特定架构:
version: '3'
tasks:
build-amd64:
platforms: [amd64]
cmds:
- echo 'Running command on amd64'可以指定多个平台,如下所示:
version: '3'
tasks:
build:
platforms: [windows/amd64, darwin]
cmds:
- echo 'Running command on Windows (amd64) and macOS'单个命令也可以限制为特定平台:
version: '3'
tasks:
build:
cmds:
- cmd: echo 'Running command on Windows (amd64) and macOS'
platforms: [windows/amd64, darwin]
- cmd: echo 'Running on all platforms'调用另一个任务
当任务有许多依赖时,它们会并发执行。这通常会导致更快的构建管道。然而,在某些情况下,您可能需要串行调用其他任务。在这种情况下,使用以下语法:
version: '3'
tasks:
main-task:
cmds:
- task: task-to-be-called
- task: another-task
- echo "Both done"
task-to-be-called:
cmds:
- echo "Task to be called"
another-task:
cmds:
- echo "Another task"使用 vars 和 silent 属性,您可以选择在每次调用时传递变量并切换静默模式:
version: '3'
tasks:
greet:
vars:
RECIPIENT: '{{default "World" .RECIPIENT}}'
cmds:
- echo "Hello, {{.RECIPIENT}}!"
greet-pessimistically:
cmds:
- task: greet
vars: { RECIPIENT: 'Cruel World' }
silent: true上述语法也支持在 deps 中使用。
TIP
注意:如果您想从包含的 Taskfile中调用根 Taskfile 中声明的任务,请添加前导 : ,如下所示:task: :task-name。
防止不必要的操作
通过指纹本地生成的文件及其源
如果任务生成某些内容,您可以告知 Task 源文件和生成文件,以便 Task 在不需要时防止运行它们。
version: '3'
tasks:
build:
deps: [js, css]
cmds:
- go build -v -i main.go
js:
cmds:
- esbuild --bundle --minify js/index.js > public/bundle.js
sources:
- src/js/**/*.js
generates:
- public/bundle.js
css:
cmds:
- esbuild --bundle --minify css/index.css > public/bundle.css
sources:
- src/css/**/*.css
generates:
- public/bundle.csssources 和 generates 可以是文件或 glob 模式。当给出时,Task 将比较源文件的校验和,以确定是否需要运行任务。如果不需要,它将仅打印类似 Task "js" is up to date 的消息。
exclude: 也可以用于从指纹中排除文件。源按顺序评估,因此 exclude: 必须在其否定的正 glob 之后出现。
version: '3'
tasks:
css:
sources:
- mysources/**/*.css
- exclude: mysources/ignoreme.css
generates:
- public/bundle.css如果您更喜欢通过文件的修改时间戳而不是其校验和(内容)来进行这些检查,只需将 method 属性设置为 timestamp。这可以在两个级别进行:
在特定任务的任务级别:
version: '3'
tasks:
build:
cmds:
- go build .
sources:
- ./*.go
generates:
- app{{exeExt}}
method: timestamp在 Taskfile 的根级别,以全局应用于所有任务:
version: '3'
method: timestamp # Will be the default for all tasks
tasks:
build:
cmds:
- go build .
sources:
- ./*.go
generates:
- app{{exeExt}}在需要更多灵活性的情况下,可以使用 status 关键字。您甚至可以结合两者。有关示例,请参见status的文档。
INFO
默认情况下,task 在项目目录中的本地 .task 目录中存储校验和。大多数情况下,您会希望将此目录放在 .gitignore(或等效位置)中,以便不提交它。(如果您有一个提交的代码生成任务,则提交该任务的校验和可能也有意义。)
如果您希望这些文件存储在另一个目录中,您可以在机器上设置 TASK_TEMP_DIR 环境变量。它可以包含相对路径,如 tmp/task,将被解释为相对于项目目录的路径,或绝对路径或主路径,如 /tmp/.task 或 ~/.task(将为每个项目创建子目录)。
export TASK_TEMP_DIR='~/.task'INFO
每个任务仅为其 sources 存储一个校验和。如果您想根据其任何输入变量来区分任务,您可以将这些变量作为任务标签的一部分,它将被视为不同的任务。
这对于为每个不同的输入集运行一次任务直到源实际更改非常有用。例如,如果源依赖于变量的值,或者即使源未更改,您也希望任务在某些参数更改时重新运行。
TIP
none 方法跳过任何验证并始终运行任务。
INFO
对于 checksum(默认)或 timestamp 方法工作,只需告知源文件即可。当使用 timestamp 方法时,运行任务的最后时间被视为生成。
使用程序化检查指示任务是最新的
或者,您可以将一系列测试告知为 status。如果没有返回错误(退出状态 0),则任务被视为最新的:
version: '3'
tasks:
generate-files:
cmds:
- mkdir directory
- touch directory/file1.txt
- touch directory/file2.txt
# test existence of files
status:
- test -d directory
- test -f directory/file1.txt
- test -f directory/file2.txt通常,您会结合 sources 和 generates 使用 - 但对于生成远程工件(Docker 镜像、部署、CD 发布)的任务,校验和源和时间戳需要访问工件或 .checksum 指纹文件的带外刷新。
两个特殊变量 {{.CHECKSUM}} 和 {{.TIMESTAMP}} 可用于在 cmds 和 status 命令中插值,取决于分配给指纹源的方法。只有 source glob 被指纹。
请注意,{{.TIMESTAMP}} 变量是一个“实时”Go time.Time 结构,可以使用 time.Time 响应的任何方法进行格式化。
有关更多信息,请参见Go Time 文档。
如果您想强制运行即使是最新的任务,可以使用 --force 或 -f。
此外,task --status [tasks]... 将在任何任务不是最新的情况下以非零退出代码退出。
status 可以与指纹结合使用,以便任务在源/生成工件更改或程序化检查失败时运行:
version: '3'
tasks:
build:prod:
desc: Build for production usage.
cmds:
- composer install
# Run this task if source files changes.
sources:
- composer.json
- composer.lock
generates:
- ./vendor/composer/installed.json
- ./vendor/autoload.php
# But also run the task if the last build was not a production build.
status:
- grep -q '"dev": false' ./vendor/composer/installed.json使用程序化检查取消任务及其依赖的执行
除了 status 检查之外,preconditions 检查是 status 检查的逻辑逆。如果您需要某些条件为 true,可以使用 preconditions 段落。preconditions 类似于 status 行,除了它们支持 sh 展开,并且它们都应返回 0。
version: '3'
tasks:
generate-files:
cmds:
- mkdir directory
- touch directory/file1.txt
- touch directory/file2.txt
# test existence of files
preconditions:
- test -f .env
- sh: '[ 1 = 0 ]'
msg: "One doesn't equal Zero, Halting"先决条件可以设置特定的失败消息,使用 msg 字段告诉用户需要采取什么步骤。
如果任务依赖于具有先决条件的子任务,并且该先决条件未满足 - 调用任务将失败。请注意,具有失败先决条件的任务除非给出 --force,否则不会运行。
与 status 不同,后者如果任务是最新的将跳过任务并继续执行依赖它的任务,precondition 将使任务失败,连同任何依赖它的其他任务。
version: '3'
tasks:
task-will-fail:
preconditions:
- sh: 'exit 1'
task-will-also-fail:
deps:
- task-will-fail
task-will-still-fail:
cmds:
- task: task-will-fail
- echo "I will not run"限制任务运行时间
如果任务由多个 cmds 或多个 deps 执行,您可以使用 run 控制何时执行它。run 也可以在 Taskfile 的根部设置,以更改所有任务的行为,除非显式覆盖。
run 的支持值:
always(默认)无论之前执行的次数多少,总是尝试调用任务once无论引用次数多少,只调用此任务一次when_changed只为传递给任务的每个唯一变量集调用任务一次
version: '3'
tasks:
default:
cmds:
- task: generate-file
vars: { CONTENT: '1' }
- task: generate-file
vars: { CONTENT: '2' }
- task: generate-file
vars: { CONTENT: '2' }
generate-file:
run: when_changed
deps:
- install-deps
cmds:
- echo {{.CONTENT}}
install-deps:
run: once
cmds:
- sleep 5 # long operation like installing packages确保必需的变量已设置
如果您想在运行任务之前检查某些变量是否已设置,则可以使用 requires。这在用户不清楚需要哪些变量时,或希望提供有关所需内容的明确消息时非常有用。此外,一些任务如果使用未设置的变量运行可能会有危险的副作用。
使用 requires,您在 requires 下的 vars 子部分指定一个字符串数组,这些字符串是要在运行任务之前检查的变量名称。如果任何变量未设置,则任务将出错并不运行。
环境变量也会被检查。
语法:
requires:
vars: [] # Array of stringsINFO
设置为零长度字符串的变量,将通过 requires 检查。
使用 requires 的示例:
version: '3'
tasks:
docker-build:
cmds:
- 'docker build . -t {{.IMAGE_NAME}}:{{.IMAGE_TAG}}'
# Make sure these variables are set before running
requires:
vars: [IMAGE_NAME, IMAGE_TAG]确保必需的变量具有允许的值
如果您想确保在执行任务之前变量设置为预定义的有效值集之一,可以使用 requires。这在变量可以取的值有严格要求,并且您想在检测到无效值时向用户提供明确反馈时特别有用。
要使用 requires,您在 requires 下的 vars 子部分指定允许值的数组。Task 将检查变量是否设置为允许值之一。如果变量不匹配这些值中的任何一个,任务将引发错误并停止执行。
此检查适用于用户定义的变量和环境变量。
使用 requires 的示例:
version: '3'
tasks:
deploy:
cmds:
- echo "deploying to {{.ENV}}"
requires:
vars:
- name: ENV
enum: [dev, beta, prod]如果 ENV 不是 'dev'、'beta' 或 'prod' 之一,将引发错误。
INFO
这仅支持字符串变量。
变量
Task 允许您使用 vars 关键字设置变量。支持以下变量类型:
stringboolintfloatarraymap
INFO
定义 map 需要使用特殊的 map 子键(参见下面的示例)。
version: 3
tasks:
foo:
vars:
STRING: 'Hello, World!'
BOOL: true
INT: 42
FLOAT: 3.14
ARRAY: [1, 2, 3]
MAP:
map: { A: 1, B: 2, C: 3 }
cmds:
- 'echo {{.STRING}}' # Hello, World!
- 'echo {{.BOOL}}' # true
- 'echo {{.INT}}' # 42
- 'echo {{.FLOAT}}' # 3.14
- 'echo {{.ARRAY}}' # [1 2 3]
- 'echo {{index .ARRAY 0}}' # 1
- 'echo {{.MAP}}' # map[A:1 B:2 C:3]
- 'echo {{.MAP.A}}' # 1变量可以在 Taskfile 的许多地方设置。在执行模板时,Task 将按下面列出的顺序查找变量(最重要的先):
- 在任务定义中声明的变量
- 在从另一个任务调用任务时给出的变量(参见上面的调用另一个任务)
- 包含 Taskfile 的变量(当任务被包含时)
- Taskfile 包含 的变量(当任务被包含时)
- 全局变量(在 Taskfile 中的
vars:选项中声明的那些) - 环境变量
使用环境变量发送参数的示例:
$ TASK_VARIABLE=a-value task do-somethingTIP
一个特殊的变量 .TASK 始终可用,包含任务名称。
由于某些 shell 不支持上述设置环境变量的语法(Windows),任务还接受类似样式,当不在命令开头时。
$ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!"本地声明 vars 的示例:
version: '3'
tasks:
print-var:
cmds:
- echo "{{.VAR}}"
vars:
VAR: Hello!Taskfile.yml 中全局 vars 的示例:
version: '3'
vars:
GREETING: Hello from Taskfile!
tasks:
greet:
cmds:
- echo "{{.GREETING}}"从 CLI 覆盖的 default 值的示例:
version: '3'
tasks:
greet_user:
desc: 'Greet the user with a name.'
vars:
USER_NAME: '{{.USER_NAME| default "DefaultUser"}}'
cmds:
- echo "Hello, {{.USER_NAME}}!"$ task greet_user
task: [greet_user] echo "Hello, DefaultUser!"
Hello, DefaultUser!
$ task greet_user USER_NAME="Bob"
task: [greet_user] echo "Hello, Bob!"
Hello, Bob!动态变量
下面的语法(变量中的 sh: 属性)被视为动态变量。值将被视为命令并分配输出。如果有一个或多个尾随换行符,最后一个换行符将被修剪。
version: '3'
tasks:
build:
cmds:
- go build -ldflags="-X main.Version={{.GIT_COMMIT}}" main.go
vars:
GIT_COMMIT:
sh: git log -n 1 --format=%h这适用于所有类型的变量。
引用其他变量
模板对于引用字符串值很棒,如果您想从一个任务传递值到另一个任务。然而,模板引擎只能输出字符串。如果您想将非字符串的东西传递给另一个任务,则需要使用引用(ref)。
version: 3
tasks:
foo:
vars:
FOO: [A, B, C] # <-- FOO is defined as an array
cmds:
- task: bar
vars:
FOO: '{{.FOO}}' # <-- FOO gets converted to a string when passed to bar
bar:
cmds:
- 'echo {{index .FOO 0}}' # <-- FOO is a string so the task outputs '91' which is the ASCII code for '[' instead of the expected 'A'version: 3
tasks:
foo:
vars:
FOO: [A, B, C] # <-- FOO is defined as an array
cmds:
- task: bar
vars:
FOO:
ref: .FOO # <-- FOO gets passed by reference to bar and maintains its type
bar:
cmds:
- 'echo {{index .FOO 0}}' # <-- FOO is still a map so the task outputs 'A' as expected这在调用 deps 和定义变量时也以相同方式工作,并且可以以任何组合使用:
version: 3
tasks:
foo:
vars:
FOO: [A, B, C] # <-- FOO is defined as an array
BAR:
ref: .FOO # <-- BAR is defined as a reference to FOO
deps:
- task: bar
vars:
BAR:
ref: .BAR # <-- BAR gets passed by reference to bar and maintains its type
bar:
cmds:
- 'echo {{index .BAR 0}}' # <-- BAR still refers to FOO so the task outputs 'A'所有引用使用与常规模板相同的模板语法,因此除了调用 .FOO 之外,您还可以传递子键(.FOO.BAR)或索引(index .FOO 0)并使用函数(len .FOO),如templating-reference中所述:
version: 3
tasks:
foo:
vars:
FOO: [A, B, C] # <-- FOO is defined as an array
cmds:
- task: bar
vars:
FOO:
ref: index .FOO 0 # <-- The element at index 0 is passed by reference to bar
bar:
cmds:
- 'echo {{.FOO}}' # <-- FOO is just the letter 'A'将 JSON/YAML 解析为 map 变量
如果您有一个原始的 JSON 或 YAML 字符串想在 Task 中处理,您可以使用 ref 关键字和 fromJson 或 fromYaml 模板函数的组合将其解析为 map 变量。例如:
version: '3'
tasks:
task-with-map:
vars:
JSON: '{"a": 1, "b": 2, "c": 3}'
FOO:
ref: 'fromJson .JSON'
cmds:
- echo {{.FOO}}map[a:1 b:2 c:3]循环遍历值
Task 允许您循环遍历某些值并为每个值执行命令。根据您想循环遍历的值的类型,有多种方法可以实现这一点。
循环遍历静态列表
最简单的循环是显式循环。这在您想循环遍历已知的一组值时非常有用。
version: '3'
tasks:
default:
cmds:
- for: ['foo.txt', 'bar.txt']
cmd: cat {{ .ITEM }}循环遍历矩阵
如果您需要循环遍历多个列表的所有排列组合,可以使用 matrix 属性。这对于任何使用过 CI/CD 管道中矩阵的人来说应该很熟悉。
version: '3'
tasks:
default:
silent: true
cmds:
- for:
matrix:
OS: ['windows', 'linux', 'darwin']
ARCH: ['amd64', 'arm64']
cmd:
echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"这将输出:
windows/amd64
windows/arm64
linux/amd64
linux/arm64
darwin/amd64
darwin/arm64您也可以使用对其他变量的引用,只要它们也是列表:
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}}"循环遍历任务的源或生成的文件
您也可以循环遍历任务的源或它生成的文件:
version: '3'
tasks:
default:
sources:
- foo.txt
- bar.txt
cmds:
- for: sources
cmd: cat {{ .ITEM }}version: '3'
tasks:
default:
generates:
- foo.txt
- bar.txt
cmds:
- for: generates
cmd: cat {{ .ITEM }}如果您在 sources 或 generates 中使用 globbing 语法,这也将工作。例如,如果您为 *.txt 指定源,循环将迭代所有匹配该 glob 的文件。
路径将始终作为相对于任务目录的路径返回。如果您需要将其转换为绝对路径,可以使用内置的 joinPath 函数。有些特殊变量您可能发现对这个有用。
version: '3'
tasks:
default:
vars:
MY_DIR: /path/to/dir
dir: '{{.MY_DIR}}'
sources:
- foo.txt
- bar.txt
cmds:
- for: sources
cmd: cat {{joinPath .MY_DIR .ITEM}}version: '3'
tasks:
default:
vars:
MY_DIR: /path/to/dir
dir: '{{.MY_DIR}}'
generates:
- foo.txt
- bar.txt
cmds:
- for: generates
cmd: cat {{joinPath .MY_DIR .ITEM}}循环遍历变量
要循环遍历变量的内容,请使用 var 键,后跟您想循环遍历的变量名称。默认情况下,字符串变量将按任何空白字符分割。
version: '3'
tasks:
default:
vars:
MY_VAR: foo.txt bar.txt
cmds:
- for: { var: MY_VAR }
cmd: cat {{.ITEM}}如果您需要在不同的字符上分割字符串,可以通过指定 split 属性来实现:
version: '3'
tasks:
default:
vars:
MY_VAR: foo.txt,bar.txt
cmds:
- for: { var: MY_VAR, split: ',' }
cmd: cat {{.ITEM}}您也可以直接循环遍历数组和 map:
version: 3
tasks:
foo:
vars:
LIST: [foo, bar, baz]
cmds:
- for:
var: LIST
cmd: echo {{.ITEM}}当循环遍历 map 时,我们还使一个额外的 {{.KEY}} 变量可用,其中包含 map 键的字符串值。请记住,map 是无序的,因此循环遍历项的顺序是随机的。
所有这些也适用于动态变量!
version: '3'
tasks:
default:
vars:
MY_VAR:
sh: find -type f -name '*.txt'
cmds:
- for: { var: MY_VAR }
cmd: cat {{.ITEM}}重命名变量
如果您想重命名迭代器变量以使其更清楚值包含什么,可以通过指定 as 属性来实现:
version: '3'
tasks:
default:
vars:
MY_VAR: foo.txt bar.txt
cmds:
- for: { var: MY_VAR, as: FILE }
cmd: cat {{.FILE}}循环遍历任务
由于 for 属性定义在 cmds 级别,您也可以将其与 task 关键字一起使用,以使用不同的变量多次运行任务。
version: '3'
tasks:
default:
cmds:
- for: [foo, bar]
task: my-task
vars:
FILE: '{{.ITEM}}'
my-task:
cmds:
- echo '{{.FILE}}'或者,如果您想根据循环的值运行不同的任务:
version: '3'
tasks:
default:
cmds:
- for: [foo, bar]
task: task-{{.ITEM}}
task-foo:
cmds:
- echo 'foo'
task-bar:
cmds:
- echo 'bar'循环遍历依赖
上述所有循环技术也可以应用于 deps 属性。这允许您将循环与并发结合:
version: '3'
tasks:
default:
deps:
- for: [foo, bar]
task: my-task
vars:
FILE: '{{.ITEM}}'
my-task:
cmds:
- echo '{{.FILE}}'重要的是要注意,由于 deps 并行运行,迭代运行的顺序不保证,输出可能会有所不同。例如,上述示例的输出可能是:
foo
bar或
bar
foo将 CLI 参数转发到命令
如果 CLI 中给出 --,则所有后续参数将被添加到特殊的 .CLI_ARGS 变量中。这对于将参数转发到另一个命令非常有用。
下面的示例将运行 yarn install。
$ task yarn -- installversion: '3'
tasks:
yarn:
cmds:
- yarn {{.CLI_ARGS}}通配符参数
将参数解析到任务的另一种方法是在任务名称中使用通配符。通配符由星号 (*) 表示,并且可以在任务名称中使用多次以传入多个参数。
匹配的参数将被捕获并存储在 .MATCH 变量中,然后可以像其他变量一样在任务的命令中使用。此变量是一个字符串数组,因此需要索引以访问单个参数。我们建议为每个参数创建一个命名变量,以使其清楚它们包含什么:
version: '3'
tasks:
start:*:*:
vars:
SERVICE: '{{index .MATCH 0}}'
REPLICAS: '{{index .MATCH 1}}'
cmds:
- echo "Starting {{.SERVICE}} with {{.REPLICAS}} replicas"
start:*:
vars:
SERVICE: '{{index .MATCH 0}}'
cmds:
- echo "Starting {{.SERVICE}}"此调用匹配 start:* 任务,字符串 "foo" 被通配符捕获并存储在 .MATCH 变量中。然后我们索引 .MATCH 数组并将结果存储在 .SERVICE 变量中,然后在 cmds 中回显:
$ task start:foo
Starting foo只要您引用任务名称,就可以为参数使用空白字符:
$ task "start:foo bar"
Starting foo bar如果找到多个匹配任务,则 Taskfile 中列出的第一个将被使用。如果您使用包含的 Taskfile,则父文件中的任务将被首先考虑。
$ task start:foo:3
Starting foo with 3 replicas使用 defer 执行任务清理
使用 defer 关键字,可以安排清理在任务完成时运行。与将其作为最后一个命令放置的区别在于,即使任务失败,此命令也会运行。
在下面的示例中,即使第三个命令失败,rm -rf tmpdir/ 也会运行:
version: '3'
tasks:
default:
cmds:
- mkdir -p tmpdir/
- defer: rm -rf tmpdir/
- echo 'Do work on tmpdir/'如果您想将清理命令移动到另一个任务中,那也是可能的:
version: '3'
tasks:
default:
cmds:
- mkdir -p tmpdir/
- defer: { task: cleanup }
- echo 'Do work on tmpdir/'
cleanup: rm -rf tmpdir/INFO
由于Go 自己的 defer 工作方式的性质,如果您调度多个,它们将以相反顺序执行。
当命令以非零退出代码退出时,会暴露一个特殊的变量 .EXIT_CODE。您可以检查其存在来知道任务是否成功完成:
version: '3'
tasks:
default:
cmds:
- defer:
echo '{{if .EXIT_CODE}}Failed with {{.EXIT_CODE}}!{{else}}Success!{{end}}'
- exit 1帮助
运行 task --list(或 task -l)将列出所有带有描述的任务。以下 Taskfile:
version: '3'
tasks:
build:
desc: Build the go binary.
cmds:
- go build -v -i main.go
test:
desc: Run all the go tests.
cmds:
- go test -race ./...
js:
cmds:
- esbuild --bundle --minify js/index.js > public/bundle.js
css:
cmds:
- esbuild --bundle --minify css/index.css > public/bundle.css将打印以下输出:
* build: Build the go binary.
* test: Run all the go tests.如果您想查看所有任务,还有一个 --list-all(别名 -a)标志。
显示任务摘要
运行 task --summary task-name 将显示任务的摘要。以下 Taskfile:
version: '3'
tasks:
release:
deps: [build]
summary: |
Release your project to github
It will build your project before starting the release.
Please make sure that you have set GITHUB_TOKEN before starting.
cmds:
- your-release-tool
build:
cmds:
- your-build-tool使用运行 task --summary release 将打印以下输出:
task: release
Release your project to github
It will build your project before starting the release.
Please make sure that you have set GITHUB_TOKEN before starting.
dependencies:
- build
commands:
- your-release-tool如果缺少摘要,将打印描述。如果任务没有摘要或描述,将打印警告。
请注意:显示摘要不会执行命令。
任务别名
别名是任务的替代名称。它们可以用于更容易和更快地运行具有长名称或难以输入名称的任务。您可以在命令行上使用它们,在 Taskfile 中调用子任务时使用它们,并在包含来自另一个 Taskfile 的任务时使用别名。它们也可以与命名空间别名一起使用。
version: '3'
tasks:
generate:
aliases: [gen]
cmds:
- task: gen-mocks
generate-mocks:
aliases: [gen-mocks]
cmds:
- echo "generating..."覆盖任务名称
有时您可能想覆盖打印在摘要、最新消息到 STDOUT 等上的任务名称。在这种情况下,您只需设置 label:,它也可以与变量插值:
version: '3'
tasks:
default:
cmds:
- task: print
vars:
MESSAGE: hello
- task: print
vars:
MESSAGE: world
print:
label: 'print-{{.MESSAGE}}'
cmds:
- echo "{{.MESSAGE}}"警告提示
警告提示用于在执行任务之前提示用户确认。
下面是一个使用 prompt 的示例,其中一个危险命令在两个安全命令之间调用:
version: '3'
tasks:
example:
cmds:
- task: not-dangerous
- task: dangerous
- task: another-not-dangerous
not-dangerous:
cmds:
- echo 'not dangerous command'
another-not-dangerous:
cmds:
- echo 'another not dangerous command'
dangerous:
prompt: This is a dangerous command... Do you want to continue?
cmds:
- echo 'dangerous command'❯ task dangerous
task: "This is a dangerous command... Do you want to continue?" [y/N]提示可以是单个值或提示列表,如下面所示:
version: '3'
tasks:
example:
cmds:
- task: dangerous
dangerous:
prompt:
- This is a dangerous command... Do you want to continue?
- Are you sure?
cmds:
- echo 'dangerous command'警告提示在执行任务之前调用。如果提示被拒绝,Task 将以退出代码 205 退出。如果批准,Task 将正常继续。
❯ task example
not dangerous command
task: "This is a dangerous command. Do you want to continue?" [y/N]
y
dangerous command
another not dangerous command要自动跳过警告提示,可以在使用任务时使用 --yes(别名 -y)选项。通过包含此选项,所有警告将被自动确认,不会显示提示。
WARNING
具有提示的任务在非终端环境(如 CI)中默认总是失败,其中 stdin 不可用于用户回答。在这些情况下,使用 --yes(-y)强制所有具有提示的任务运行。
静默模式
静默模式在 Task 运行命令之前禁用命令的回显。对于以下 Taskfile:
version: '3'
tasks:
echo:
cmds:
- echo "Print something"正常情况下,这将打印:
echo "Print something"
Print something开启静默模式时,将打印以下内容:
Print something有四种方式启用静默模式:
- 在命令级别:
version: '3'
tasks:
echo:
cmds:
- cmd: echo "Print something"
silent: true- 在任务级别:
version: '3'
tasks:
echo:
cmds:
- echo "Print something"
silent: true- 在 Taskfile 级别全局:
version: '3'
silent: true
tasks:
echo:
cmds:
- echo "Print something"- 或使用
--silent或-s标志全局
如果您想抑制 STDOUT,只需将命令重定向到 /dev/null:
version: '3'
tasks:
echo:
cmds:
- echo "This will print nothing" > /dev/null干运行模式
干运行模式(--dry)编译并逐步执行每个任务,打印将运行的命令而不执行它们。这对于调试您的 Taskfile 非常有用。
忽略错误
您可以选择在命令执行期间忽略错误。给定以下 Taskfile:
version: '3'
tasks:
echo:
cmds:
- exit 1
- echo "Hello World"Task 将在运行 exit 1 后中止执行,因为状态码 1 表示 EXIT_FAILURE。但是,可以使用 ignore_error 继续执行:
version: '3'
tasks:
echo:
cmds:
- cmd: exit 1
ignore_error: true
- echo "Hello World"ignore_error 也可以为任务设置,这意味着所有命令的错误将被抑制。请记住,此选项不会传播到通过 deps 或 cmds 调用的其他任务!
输出语法
默认情况下,Task 只是将运行命令的 STDOUT 和 STDERR 实时重定向到 shell。这对于命令打印的日志提供实时反馈很好,但如果您有多个命令同时运行并打印大量内容,输出可能会变得混乱。
为了使其更可自定义,目前有三种不同的输出选项可供选择:
interleaved(默认)groupprefixed
要选择另一个,只需在 Taskfile 的根部设置它:
version: '3'
output: 'group'
tasks:
# ...group 输出将在命令完成后打印命令的整个输出,因此您不会对运行时间长的命令有实时反馈。
在使用 group 输出时,您可以选择提供一个模板消息,在组的开始和结束时打印。这对于指示 CI 系统对给定任务的所有输出进行分组非常有用,例如使用GitHub Actions 的 ::group:: 命令或Azure Pipelines。
version: '3'
output:
group:
begin: '::group::{{.TASK}}'
end: '::endgroup::'
tasks:
default:
cmds:
- echo 'Hello, World!'
silent: true$ task default
::group::default
Hello, World!
::endgroup::在使用 group 输出时,如果执行的命令未失败(零退出代码),您可以吞没标准输出和标准错误上的输出。
version: '3'
silent: true
output:
group:
error_only: true
tasks:
passes: echo 'output-of-passes'
errors: echo 'output-of-errors' && exit 1$ task passes
$ task errors
output-of-errors
task: Failed to run task "errors": exit status 1prefix 输出将使用 [task-name] 作为前缀为命令打印的每一行添加前缀,但您可以使用 prefix: 属性为命令自定义前缀:
version: '3'
output: prefixed
tasks:
default:
deps:
- task: print
vars: { TEXT: foo }
- task: print
vars: { TEXT: bar }
- task: print
vars: { TEXT: baz }
print:
cmds:
- echo "{{.TEXT}}"
prefix: 'print-{{.TEXT}}'
silent: true$ task default
[print-foo] foo
[print-bar] bar
[print-baz] bazTIP
output 选项也可以通过 --output 或 -o 标志指定。
交互式 CLI 应用程序
在 Task 中运行交互式 CLI 应用程序时,它们有时会表现得奇怪,特别是当输出模式设置为非 interleaved(默认)时,或当交互式应用程序与其他任务并行运行时。
interactive: true 告诉 Task 这是一个交互式应用程序,Task 将尝试为其优化:
version: '3'
tasks:
default:
cmds:
- vim my-file.txt
interactive: true如果您通过 Task 运行交互式应用程序仍有问题,请为此打开一个问题。
简短任务语法
从 Task v3 开始,如果任务具有默认设置(例如,没有自定义 env:、vars:、desc:、silent: 等),您现在可以以更短的语法编写任务:
version: '3'
tasks:
build: go build -v -o ./app{{exeExt}} .
run:
- task: build
- ./app{{exeExt}} -h localhost -p 8080set 和 shopt
可以指定set和shopt内置的选项。这可以在全局、任务或命令级别添加。
version: '3'
set: [pipefail]
shopt: [globstar]
tasks:
# `globstar` required for double star globs to work
default: echo **/*.goINFO
请记住,并非所有选项都在 Task 使用的shell 解释器库中可用。
监视任务
使用标志 --watch 或 -w,task 将监视文件更改并再次运行任务。这需要给出 sources 属性,以便 task 知道监视哪些文件。
默认监视间隔为 100 毫秒,但可以通过在 Taskfile 的根部设置 interval: '500ms' 或像 --interval=500ms 一样作为参数传递来更改它。此间隔是 Task 等待重复事件的时间。即使在间隔内发生多个更改,它也只运行一次任务。
也可以在给定任务中设置 watch: true,它将自动以监视模式运行:
version: '3'
interval: 500ms
tasks:
build:
desc: Builds the Go application
watch: true
sources:
- '**/*.go'
cmds:
- go build # ...INFO
请注意,当为任务设置 watch: true 时,它仅在通过 CLI 运行 task my-watch-task 时以监视模式运行,但如果由另一个任务直接调用或作为依赖调用,则不会以监视模式运行。