Using the Task Tool
Table of Contents
Task is a task runner and build tool. It provides a consistent framework for sets of tasks, enabling you to run the same workflows on multiple platforms and environments.
Task is also known as go-task.
How Task Works #
Each copy of Task is a single executable file, with versions for Linux, macOS and Windows. This executable is relatively small, being about 8Mb for the 64-bit Linux version. It uses sets of tasks that are defined in YAML files, and includes a shell interpreter, so that you can use the same syntax for tasks on any platform.
This means that you can use Task in any environment. It only requires a copy of the Task executable, and has no configuration files apart from the YAML files that contain the tasks.
It also provides features for you to customise the behavior of your tasks for the different environments that you might use. The built-in template functions enable you to get consistent inputs for your tasks across different platforms. When needed, you can define operating system specific files, so that Task uses the specific implementation for the current platform.
Task includes two other key features: conditional execution of tasks and running tasks on file changes. These features are designed to be usable with any type of software development.
Here is an example of a Taskfile.yaml, with a build task that only runs when the sources change:
# Tasks for a Hugo static website project
#
# Hugo: https://gohugo.io
version: "3"
silent: true
tasks:
default:
cmds:
- task: build
build:
desc: Build Website
cmds:
- hugo
sources:
- content/**/*.md
generates:
- public/**
clean:
desc: Delete generated files
cmds:
- for: [".hugo_build.lock", "public"]
cmd: rm -fr {{.ITEM}}
deploy:
desc: Deploy Website
deps: [build]
cmds:
- hugo deploy
serve:
desc: Run Website in development server
cmds:
- hugo server
Installing Task #
Consider using a tool version manager like mise or asdf to install Task. For example, this command installs the latest version of Task with mise:
mise use -gy task
If you use Visual Studio Code and have a Dev Container configuration for a project, use the go-task feature, as shown in the section below.
To add Task to container images or systems without a tool version manager, see the section below for how to install Task with a script.
All of these methods enable you to specify a version of Task for each project that you work on, and ensure that the expected version of Task is present. If possible, avoid using operating system packages. A package installs a single shared copy of Task, and is likely to provide an older version.
Installing Task with a Script #
The Task project provide a script for downloading task from GitHub. You may either fetch this installation script each time, as the documentation describes, or save it.
If you build Docker container images that contain a copy of Task, use a saved copy of the script. This ensures that container image builds are consistent.
To save the installation script:
curl -L https://taskfile.dev/install.sh > install-task.sh
To use the installation script, call it with the Git tag and the -b option. The Git tag specifies the version of Task. The -b option specifies which directory to install it to:
./install-task.sh -b $HOME/.local/bin v3.38.0
Installing Task with Operating System Packages #
If you do need to install Task with an operating system package manager, it is available for several popular systems. For example, these commands install Task:
winget install Task.Task # winget on Microsoft Windows
brew install go-task # Homebrew on macOS
doas apk add go-task # apk on Alpine Linux
sudo dnf install go-task # dnf on Fedora Linux
To install Task on Alpine Linux, you need to enable the community package repository.
Alpine Linux installs Task as go-task. This means that you need to use the name go-task rather than task on the command-line. For example go-task –list.
Enabling Visual Studio Code Integration #
To use Task with Visual Studio Code, install the redhat.vscode-yaml and task.vscode-task extensions.
The vscode-yaml extension enables YAML formatting and validation, and vscode-task adds a graphical integration for running tasks.
You must install Task to use the vscode-task extension.
Enabling Integration with JetBrains IDEs #
To enable support for Task in JetBrains IDEs such as PyCharm, install the Taskfile plugin.
Enabling Autocompletion #
To enable autocompletion for Task in a shell, download the appropriate script and install it into the correct location. For example, this command enables autocompletion in the fish shell:
curl -L https://raw.githubusercontent.com/go-task/task/main/completion/fish/task.fish > $HOME/.config/fish/completions/task.fish
The Task project currently provides autocompletions for Bash, zsh, fish and PowerShell.
Adding Task to a Dev Container #
If you are using a Dev Container with Visual Studio Code, you can add the feature go-task to your devcontainer.json file to download Task from GitHub:
"features": {
"ghcr.io/devcontainers-contrib/features/go-task:1": {
"version": "3.38.0"
}
}
Ensure that you also include the redhat.vscode-yaml and task.vscode-task extensions in the devcontainer.json file:
"customizations": {
"vscode": {
"extensions": [
"redhat.vscode-yaml",
"task.vscode-task"
]
}
}
The vscode-yaml extension enables YAML formatting and validation, and vscode-task adds a graphical integration for running tasks.
Creating a User Taskfile for Global Tasks #
To define tasks that are available at any time, create a file with the name Taskfile.yaml in your home directory.
Create a task in the Taskfile.yaml with the name default. When Task is invoked without the name of a task, it runs the default task in the Taskfile.yaml.
This example user Taskfile.yaml includes a default task that lists the available tasks:
version: "3"
silent: true
tasks:
default:
cmds:
- task: list
list:
desc: List available tasks
cmds:
- task --list
system-info:
desc: Display system information
cmds:
- "echo CPU architecture: {{ARCH}}"
- "echo Operating system: {{OS}}"
Use the option -g to run the user Taskfile.yaml, rather than the nearest Taskfile:
task -g system-info
For convenience, add an alias to your shell configuration. For example, add these lines in .config/fish/config.fish to enable an alias in the Fish shell:
# Add abbr to call tasks in global Taskfile by typing ".t TASK-NAME"
if command -s task > /dev/null
abbr --add .t task -g
end
Using Task in a Project #
First, add the .task directory to the exclusions for source control. This directory is used to hold files for tracking changes.
Always use the name Taskfile.yaml or Taskfile.yml for Task files. This enables tools that support JSON Schemas to identify the format of the files, so that they can provide autocompletion and validation.
If a project only requires one small set of tasks, then use a single Taskfile. If you need to manage several sets of tasks, use these features:
Adding Taskfile.yaml files in subdirectories enables you to override the set of tasks for a project when you change your working directory in the project. This lets you define sets of tasks that are appropriate to the context.
The includes feature of Task enables you to define groups of tasks that can be added to any Taskfile. These groups automatically become namespaces, which ensures that tasks with the same name do not override each other. For example, if you create an include for python and an include for web, they may both have a task called test, which you can call as python:test and web:test.
Using Includes #
If you decide to use Task includes in your project, consider following these guidelines:
- Create the first task in the root Taskfile.yaml with the name default. When Task is invoked without a namespace or task name, it runs the default task in the Taskfile.yaml.
- Create subdirectory called tasks/. For each namespace, create a directory with the same name as the namespace, with a Taskfile.yaml file in the directory. Write the tasks for the namespace in the relevant Taskfile.yaml file. Use includes in the root Taskfile.yaml file to enable these namespaces.
- Use the root Taskfile.yaml to define standard tasks for the project. Each of these should call the relevant tasks in one or more namespaces. Avoid writing tasks in the root Taskfile.yaml that do anything other than running tasks that are defined in namespaces.
- Remember to include a default task for each namespace. This means that the default task runs when a user types the name of the namespace without specifying the name of the task.
- Specify any relevant aliases for a namespace with the includes attribute.
This diagram shows the suggested directory structure for a project with task includes:
.
|
| - tasks/
| |
| |- pre-commit
| | |
| | |- Taskfile.yaml
| |
| |- package
| |
| |- Taskfile_darwin.yaml
| |- Taskfile_linux.yaml
| |- Taskfile_windows.yaml
|
|- Taskfile.yaml
Example Taskfile.yaml for a Project #
# Tasks for the Task runner:
#
# https://taskfile.dev
version: "3"
silent: true
# Namespaces
includes:
package: tasks/package/Taskfile_{{OS}}.yaml
pre-commit: tasks/pre-commit
# Top-level tasks
tasks:
default:
cmds:
- task: list
bootstrap:
desc: Set up environment for development
cmds:
- task: pre-commit:setup
build:
desc: Build packages
cmds:
- task: package:build
clean:
desc: Delete generated files
cmds:
- task: package:clean
fmt:
desc: Format code
aliases: [format]
cmds:
- task: pre-commit:run
vars: { HOOK_ID: "ruff-format" }
lint:
desc: Run all checks
aliases: [check]
cmds:
- task: pre-commit:check
list:
desc: List available tasks
cmds:
- task --list
The default task runs the list task, so this command displays a list of all of the available tasks, including the tasks in the namespaces:
task
Example Namespace of Tasks for a Project #
# Tasks for pre-commit
#
# https://pre-commit.com/
version: "3"
silent: true
tasks:
default:
cmds:
- task: check
check:
desc: Check the project with pre-commit
cmds:
- pre-commit run --all-files
run:
desc: Run a specific pre-commit check on the project
cmds:
- pre-commit run "{{.HOOK_ID}}" --all-files
requires:
vars: [HOOK_ID]
setup:
desc: Setup pre-commit for use
cmds:
- pre-commit install
The default task in this file runs check, so this command runs the check task:
task pre-commit
The result is the same as this command:
task pre-commit:check
Writing Taskfiles #
Follow the style guidelines when writing tasks. Here are some extra suggestions:
- Use a YAML formatter to format your Task files. The redhat.vscode-yaml extension adds support for formatting YAML files to Visual Studio Code. The Prettier tool formats YAML files, and can be used in any environment.
- Always put a desc attribute for each task. The description appears next to the task in the output of task –list.
- Consider adding a summary attribute for each task. The summary appears in the output of task –summary TASK-NAME.
- Use argument forwarding or wildcard task names to get inputs for a task from the command-line.
- Specify the requires attribute for each task that uses a variable. This ensures that the task has the necessary variables.
- Use dotenv files to get configuration from files.
- Use Bash shell syntax for tasks. Task uses mvdan/sh to provide the equivalent of the bash shell.
- To ensure that your tasks are portable, check the options for UNIX commands that you call in tasks, such as rm. Different operating systems and Linux distributions provide different implementations of these commands, which means that the options may not be consistent across environments.
- When it is possible, use the template functions instead of shell commands, because these will behave consistently across different environments.
- Provide operating system specific Taskfiles when necessary.
Running Tasks #
To run a task in a Taskfile.yaml, enter task followed by the name of the task:
task example-task
If a task accepts forwarding of arguments, add the arguments to the command:
task example-task -- my-argument-value
You may set variables by specifying environment values with the Task command:
MY_VARIABLE_NAME=my-variable-value task example-task
Checking Taskfiles #
The Task project publish the schema for Task files as a JSON Schema. This means that any software that supports JSON Schemas for YAML documents can check that your Task files are valid. To ensure that your Task files are consistently formatted, use standard tools for YAML files.
Visual Studio Code will both validate and format Task files when the redhat.vscode-yaml extension is installed. This extension use a language server for the YAML format, with support for JSON Schemas.
To validate Task files on the command-line, use check-jsonschema. The check-jsonschema tool automatically includes the schema for Task files. The yamllint command-line tool provides format and quality checks for all types of YAML file.
The check-jsonschema and yamllint projects also provide hooks for pre-commit, so that files are automatically checked before changes are committed to source control.
Validating Task files with pre-commit #
To validate Task files before you commit them to source control, add the hook for check-jsonschema and the hook for yamllint to the pre-commit configuration for your project.
Add these lines to the .pre-commit-config.yaml file in the root directory of your project:
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: "0.29.1"
hooks:
- id: check-taskfile
- repo: https://github.com/adrienverge/yamllint.git
rev: "v1.35.1"
hooks:
- id: yamllint
args: [--strict]
To ensure that yamllint handles Task files, add a .yamllint.yaml file with this content:
---
# Begin with yamllint default settings
extends: default
rules:
# Rules for curly braces: {}
braces:
forbid: false
min-spaces-inside: 1
max-spaces-inside: 1
min-spaces-inside-empty: 0
max-spaces-inside-empty: 0
# Rules for round brackets: ()
brackets:
forbid: false
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: 0
max-spaces-inside-empty: 0
# Do not require three dashes at the start of a YAML document
document-start: disable
# Rules for line length
line-length:
max: 88
level: error
The pre-commit checks automatically run when you commit code. You may also run the checks yourself at any time, with the pre-commit command-line tool. For example, this command validates all of the Task files in your project:
pre-commit run check-taskfile --all-files
Testing a Task #
To test a task, run it with the –dry option:
task --dry TASK-NAME
This compiles and prints tasks in the order that they would be run.
To debug a task, ensure that silent is not enabled in the appropriate Taskfile.yaml, so that the outputs of the commands are visible:
silent: false