Being reluctant to use Makefiles, I recently fell in love with Taskfile, which allows to do pretty much the same thing, but with a simpler syntax.
What is Taskfile?
Taskfile is a task launcher written in Go, which implies that it is in fact an executable that can be installed simply by putting it in a folder located in the system's PATH for example.
The syntax of Taskfile is quite easy to learn. It's YAML, to be written to a Taskfile.yml file. As a bonus, native support for Windows!
A lot of things are possible with Taskfile, just like with Makefile:
- dependency between tasks
- possibility of performing several tasks in parallel
- avoid executing a command if nothing has changed (in composer.lock or yarn.lock files for example)
- better readability
- description of the tasks available by entering a simple key
Let's take an example: I want to run Docker containers, Symfony server and fixtures. I'll run the following command: task start fixtures, so the start task (for Docker and the Symfony binary) and fixtures task will be run one after the other. By adding the --parallel option, both tasks will be started at the same time.
My Taskfile for Symfony
Here is my Taskfile.yml file (each task is described so that we know what it is doing):
version: '3'
tasks:
fixtures:
desc: Generate fixtures for dev environment
cmds:
- symfony console d:d:d --force --if-exists --quiet
- symfony console d:d:c --quiet
- symfony console d:s:u --force --quiet
- symfony console d:m:sync-metadata-storage --quiet
- symfony console d:m:v --add --all --quiet
- symfony console h:f:l --no-interaction --quiet
composer:
desc: Install PHP vendors
cmds:
- composer install
sources:
- composer.lock
generates:
- vendor/**/*
start:
desc: Start Docker containers & Symfony server
cmds:
- docker-compose up -d
- symfony serve -d
stop:
desc: Stop Docker containers & Symfony server
cmds:
- docker-compose stop
- symfony server:stop
test:
desc: Run tests
cmds:
- task: setup_tests
- symfony run bin/phpunit
coverage:
desc: Run tests with coverage
cmds:
- task: setup_tests
- symfony php -dpcov.enabled=1 bin/phpunit --coverage-html=public/coverage
setup_tests:
cmds:
- symfony console d:d:d --force --if-exists --quiet --env=test
- symfony console d:d:c --quiet --env=test
- symfony console d:s:u --force --quiet --env=test
- symfony console h:f:l --no-interaction --quiet --env=test
ci:
desc: Check code style, static analysis...
cmds:
- symfony composer ci
cs-fix:
desc: Fix code style
cmds:
- symfony composer cs:fix
node_modules:
desc: Update frontend vendors
cmds:
- yarn install
sources:
- yarn.lock
generates:
- node_modules/**/*
assets:
desc: Build frontend assets
cmds:
- task: node_modules
- yarn run dev
sources:
- assets/**/*
generates:
- public/build/**/*
Some explanations
Each task can be documented using the desc key, so that by running the task -l command, we get a list of each documented task looking like this:
- assets: Build frontend assets
- ci: Check code style, static analysis...
- composer: Install PHP vendors
- coverage: Run tests with coverage
- cs-fix: Fix code style
- fixtures: Generate fixtures for dev environment
- node_modules: Update frontend vendors
- start: Start Docker containers & Symfony server
- stop: Stop Docker containers & Symfony server
- test: Run tests
Note that the setup_tests task does not appear in this list, as it is not documented. So much the better, I did not intend to use it without launching the tests after.
As for a Makefile, you can define dependencies between tasks. For example, the assets task first requires the node_modules task to be performed.
Note that a system makes it possible not to execute the task in question if nothing has changed since the last launch. For example for the composer task, it does not need to be executed if the composer.lock file has not been modified since the last execution.
Speaking of which, don't forget to add the exclusion of the /.task folder in eg. your .gitignore file. This folder notably contains the checksum of the files entered by the sources parameter, which prevents the unnecessary execution of a task.
Et voilà! :) If you have any questions, comments, suggestions... Feel free to post a comment below :)
Comments
Posted by Nicolas on 27/11/2020 at 11:06.
Bonjour,Ne connaissant pas Taskfile, j'ai trouvé ton article très instructif.
Au tout début de ton article tu mets que tu es très réticent à l'utilisation d'un Makefile et je suis curieux de savoir pourquoi ?
Merci d'avance.
Nicolas
Posted by jmsche on 30/11/2020 at 14:08.
Bonjour Nicolas,Je trouve simplement que la syntaxe du Makefile n'est pas des plus claires et lisibles.
Évidemment les réfractaires au YAML peuvent dire la même chose du Taskfile :)
Un gros avantage est également la prise en charge native de Windows, ce qui n'est pas le cas avec Makefile, même s'il existe plusieurs variantes pour Windows qui fonctionnent plus ou moins.
jmsche
Posted by Brian on 02/12/2020 at 21:12.
I think there is a typo in the fixtures task.symfony console h:f:l --no-interaction --quiet
should be
symfony console d:f:l --no-interaction --quiet
Thank you for making this, I'm already using it on a new Symfony project.
Posted by jmsche on 02/12/2020 at 21:17.
Hi Brian,Thanks for your comment :)
It's not a typo :) I use hautelook/alice-bundle for fixtures, not doctrine/doctrine-fixtures-bundle, hence the difference :)
Posted by Jonathan on 17/03/2021 at 14:35.
Super pratique j'avais déjà vu ça dans un projet mais j'avais pas capté l'utilité .Posted by jb dev labs on 13/06/2022 at 08:54.
Effectivement, le YAML est plus clair et plus strict que la syntaxe du Makefile et ça le rends plus interopérable. C'est un outils plus destiné aux projets dont les postes de dev sont hétérogène.