Ok, Make/Makefiles are great. I spoke about then in the last post.
But what if:
- I want to break them in different files
- Use a better syntax (maybe yaml?)
- Cache the tasks, even the ones that don't generate artifacts (e.g. lint)
- put tasks and aliases close
- validate the task execution
- have global tasks to run in any folder (e.g. backup)
- dry run
- watch task
Taskfile to rescue
Just need to install Task (or go-task on github).
The documentation is pretty simple IMHO, but I want to highlight some things that I do use in daily bases that I think it does a great difference.
Show me the code
For this I will use the sample from previous post (makefile here)
# yaml-language-server: $schema=https://json.schemastore.org/taskfile.json
---
version: '3'
env:
DATABASE_URL: postgres://postgres:sample@localhost:5432/sample
includes:
docker-compose:
aliases: [dc]
taskfile: ./Taskfile-docker-compose.yaml
prisma:
aliases: [p]
taskfile: ./Taskfile-prisma.yaml
tasks:
default:
desc: Show help
aliases: [h]
silent: true
cmds:
- task -l --sort alphanumeric
clean:
desc: Remove node modules
aliases: [c]
cmds:
- rm -rf node-modules
install:
desc: Install dependencies
aliases: [i]
run: once
cmds:
- npm install
preconditions:
- test -f package.json
- test -f package-lock.json
sources:
- package.json
- package-lock.json
status:
- test -d node_modules
run-only:
aliases: [ro]
interactive: true
ignore_error: true
dotenv: ['.env']
cmds:
- task: install
- task: prisma:generate
- npx --yes esno src/index.ts
run:
desc: Run the project
aliases: [r]
cmds:
- task: docker-compose:up
- task: prisma:push
- task: run-only
There are a lot of things going on here, so trying to explain some things:
- The first line is just for auto complete on IDEs (like vscode, zed)
- We can define global env vars in the script itself (e.g.
DATABASE_URL
) - We can import part of the scripts. You just need to have your global ones (e.g. terraform, docker-compose, prisma, git, etc). It does work with remote files.
- You can expose/hide tasks with internal flag
Now the best part - cache
Pay a close look on the install task.
- it only runs if
package.json
andpackage-lock.json
are present (programatic checks) - Prevent unnecessary work: it caches the execution using the
source
attribute. - at the end it checks if the
node_modules
folder was created. - Even caching based on the
source
, if you remove thenode_modules
folder (check) it will run again.
So, you just need to run your daily tasks (e.g. tests, lints, run local) and the script itself will detect what is pending and run it if needed.
No more crazy issues that you forgot to update a dependency or database change.
Ok, show me a normal day of work
At the first time, you just need to run task r
to run the app. It will install dependencies, start database, apply db changes and run the app.
But what happen if someone changes a dependency? No problem. Taskfile will detect and will run npm install
again.
But if someone just changes the db schema? No problem. It will generate the classes again.
If nothing changes, it will just run the app (ok, the docker part is not optimized, but you got the idea).
If need to stop the app and run again you can go direct to task ro
(ro = run only).
Full Project
As always, the full sample is available on github.
Closing thoughts
Now go to the documentation.
Remove commands from README.md
files and confluence/sharepoint. Also remove it from anemic package.json
😛
My global taskfiles are shared here for reference.
My backup scripts using rsync are also on taskfiles, but this is a subject for another post.