I've been working on my own task runner, tsk. I don't know how to pronounce it. I'm criminally terrible at naming things, so the best I could up come up with was just dropping the vowel from "task". Maybe it's an acronym? Who knows.
Anyway, it's a single binary without dependencies and uses TOML to describe tasks.
Here's the requisite "Hello, world!" example,
1[tasks.hello_world]
2env = {msg = "Hello, world!"}
3cmds = [
4 "echo $msg",
5]
It's pretty simple and bare-bones but has a couple features that I think are neat.
Opinionated support for scripts #
I've shared my rambling thoughts on task runners recently and one of my points was including too much shell in a YAML/TOML/whatever task config was an anti-pattern.
tsk
is opinionated about making it simple to connect a task and a script. When the cmd
field is omitted, tsk
will look for a script with the same name of the task in the scripts
directory. So given the task definition,
1[tasks.hello_world]
2env = {msg = "Hello, world!"}
tsk
will execute scripts/hello_world.sh
.
Dependency groups #
Dependencies or prereqrusites are common features in task runners. What I haven't seen, but wanted, was the ability to express more complicated dependency ordering. In tsk
, dependencies are other tasks expressed as nested lists. Tasks within a group run in parallel, while the groups run sequentially.
Example time! This task definition,
1[tasks.dep_groups]
2deps = [
3 ["setup1", "setup2"], # setup1 and setup2 run in parallel
4 ["setup3"], # setup3 runs after the tasks in the previous group complete
5]
6cmds = ["echo 'running cmd...'"]
7
8[tasks.setup1]
9cmds = ["sleep 1", "echo 'doing setup1...'"]
10
11[tasks.setup2]
12cmds = ["echo 'doing setup2...'"]
13
14[tasks.setup3]
15cmds = ["echo 'doing setup3...'"]
produces the output,
1➜ tsk dep_groups
2doing setup2...
3doing setup1...
4doing setup3...
5running cmd...
tsk
has been working well for me on small projects—I even use it to build and release tsk
itself!