7.5 KiB
Task
Task runner aiming to be simpler and easier to use than GNU Make.
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 / Azure Devops]'s pipelines, and if one has any experience with them one knows what a pain that can be.
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
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
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.