8.6 KiB
Task
Task runner aiming to be simpler and easier to use than GNU Make.
- TL;DR
- Usage
- Variables
- Call other tasks
- Run tasks in a specific order
- Run tasks concurrently
- Troubleshooting
- Further readings
TL;DR
Taskfiles are Task's Makefile counterpart.
Taskfiles are written in YAML.
Tasks in Task are what targets are for Make.
Task leverages mvdan.cc/sh to run commands, which is a native Go shell interpreter.
It allows to write sh/bash commands and have them work even where sh or bash are usually not available (e.g.:
Windows) as long as any called executable is available in PATH.
Pros:
-
Taskfiles are more readable than Makefiles. Specifically:
- There is no need to explicitly use tabs in tasks' definitions.
- There is no need for special symbols, like
@. - Environment variables management is easier.
Cons:
- Taskfiles are written in YAML. ≈(・ཀ・≈)
That makes them very much similar to [Gitlab and Azure Devops]'s pipelines, with all the pain that comes with it.
Uses Go's text/template and slim-sprig packages to interpolate values.
Environment variables (env: {}, dotenv: []) are available in the shell used by commands.
Variables (vars: {}) are only available to Task while executing templates, but will default to environment
variables with the same name.
Setup
# Install the executable.
brew install 'go-task'
choco install 'go-task'
docker pull 'taskfile/task'
dnf install 'go-task'
go install 'github.com/go-task/task/v3/cmd/task@latest'
pip install --user 'go_task_bin'
snap install 'task' --classic
zypper install 'https://github.com/go-task/task/releases/download/v3.39.2/task_linux_amd64.rpm'
# Setup the shell's completion.
task --completion 'fish' > ~/'.config/fish/completions/task.fish'
task --completion 'zsh' > '/usr/local/share/zsh/site-functions/_task'
task --completion 'bash' > '/etc/bash_completion.d/task'
# Create a new 'Taskfile.yml' file in the current folder.
task --init
Usage
# Run tasks.
# No tasks given --> assumed one named 'default'
task
task 'assets'
task -v 'build:python' 'deploy:app'
# Simulate running tasks.
task -n 'bootstrap'
task --dry --verbose 'lint' 'validate:ansible'
Usage
-
Create a file called
Taskfile.yml,taskfile.yml,Taskfile.yaml,taskfile.yaml,Taskfile.dist.yml,taskfile.dist.yml,Taskfile.dist.yaml, ortaskfile.dist.yaml(ordered by priority) in the root of one's project. -
Run tasks by their name:
task 'assets' 'build:python' task --dry 'bootstrap'If task names are omitted, Task will try and execute a task named
default.
Variables
Set environment variables at global or task level with env: {}.
They are made available in the shell used by commands.
env:
SOME_VAR: some DEFAULT value
tasks:
env_vars:test:
env:
SOME_VAR: some value
cmds:
- echo $SOME_VAR
Exported and command-specific shell variables take precedence over the ones defined in the Taskfile.
$ task env_vars:test
some value
$ set SOME_VAR 'some OTHER value'
$ task env_vars:test
some value
$ set -x SOME_VAR 'some OTHER value'
$ task env_vars:test
some OTHER value
$ SOME_VAR='some EPHEMERAL value' task env_vars:test
some EPHEMERAL value
Task accepts setting environment variables inside the command itself like make due to some shells not supporting
the usual syntax.
# These are equivalent
CONTENT='Hello, World!' FILE=file.txt MESSAGE="All done!" task write-file print
task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!"
Include environment variables from .env-like files at global or task level with dotenv: [].
Non-existing files are ignored in a similar manner to make's -include directive (with the prefixed dash).
dotenv:
- .env
- .env.local
tasks:
env_vars:test:
dotenv:
- .env.task
- .env.task.local
Environment variables set in env: {} take precedence over the ones loaded from dotenv at the same level.
graph LR
gd["`dotenv: []`"] --- ge["`env: {}`"]
ge["`env: {}`"] --- td["`task.dotenv: []`"]
td["`task.dotenv: []`"] --- te["`task.env: {}`"]
te["`task.env: {}`"] --- se["`shell.export`"]
se["`shell.export`"] --- ce["`command.env`"]
Variables (vars: {}) are only available to Task while executing templates, but will default to environment
variables with the same name.
Task execution looks for variables in the following order (first-come-first-served):
- Variables declared in the task's definition.
- Variables provided when calling a task from another.
- Variables defined in included Taskfiles.
- Variables provided when including Taskfiles.
- Global variables.
- Environment variables.
graph LR
ev["`environment variables`"] --- gv["`vars: {}`"]
gv["`vars: {}`"] --- iv["`includes[].vars: {}`"]
iv["`includes[].vars: {}`"] --- it["`includes[]`"]
it["`includes[]`"] --- tc["`task.cmd.'task'`"]
tc["`task.cmd.'task'`"] --- te["`task.env`"]
Call other tasks
Use task: followed by the called task name as the command in the calling task.
tasks:
task:being:called: { … }
task:calling:
cmd: task: task:being:called
another:task:calling:
cmds:
- task: task:being:called
vars: { … }
Call root tasks from non-flattened included files
Refer an empty namespace by prepending the name of the task with :.
# $ROOT/Taskfile.yml
includes:
subproject:
taskfile: subproject
dir: subproject
tasks:
task:of:interest: { … }
# $ROOT/subproject/Taskfile.yml
tasks:
some:task:
cmd:
task: :task:of:interest
Run tasks in a specific order
Specify them in order in the cmds key of another task:
tasks:
default:
desc: Run lint, build, and test in order
cmds:
- task: lint
- task: build
- task: test
Do not name them in the task's deps, as they will run concurrently and with no order.
Run tasks concurrently
Execute task with the --parallel option and naming all the tasks that should run concurrently:
task --parallel 'task1' 'task2'
Tasks that run in parallel are not guaranteed to run in order.
Parallelization is meant for tasks that are independent from each other.
Tasks' dependencies run concurrently by default.
Naming other tasks in tasks' deps key ensures that all of them are executed before the one calling them starts,
but does not guarantee their order other than the dependencies they define themselves.
Troubleshooting
Dry run does not print the commands that would be executed
Root cause
Command simulations do not print commands to output when setting silent: true at any level.
Solution
Force the print using -v, --verbose when silent is set to true, or set it to false at task level.