An introduction to the XC README task runner [0], why I built it and how to use it.
The problem #
The concept for xc [1] came out of a conversation I had with Adrian Hesketh [2] whilst programming.
We are currently working on a system split into multiple microservices, growing in numbers. So, documentation is key to keeping everyone on the same page.
One example of this is having some useful commands one may use frequently whilst working on a service.
These commands include very frequently used commands like go run main.go
or go test ./...
and some maybe less frequently used commands that are still useful to know.
Our solution for this was make
[3], and using this as a task runner is not really what it was built for. And it can quickly become hard to understand what a task is doing if someone who knows make
well is writing it.
This looked something like the following:
get:
go get ./...
setup-private:
go env -w GOPRIVATE=github.com/joerdav
build: setup-private
cd api && go build ./...
cd cdk && go build
run-dynamodb-local:
./run-dynamodb-local.sh
test: setup-private
cd api && go test ./...
cover: setup-private
cd api && go test ./... --cover
deploy: setup-private
cd cdk && cdk deploy
Looking at alternatives there's npm run
which is meant primarily for Node applications;
There's go-task
[4] which seems to be a great, well supported task runner, it just involved writing YAML and isn't too accessible or usable when someone doesn't have go-task
installed on their machine.
The first solution that came to mind was to create shell files for each task in the project root, most OSs have a way to run a shell script, so anyone can run it.
But my main concern around that idea was sign-posting. Yes, you could link the scripts in the README but this could easily become out of date, and also if someone want's to view these useful commands then it involves a certain degree of digging.
The shell solution also promotes the temptation to make overly complicated tasks, just like with make
.
The solution #
I had the bright idea to put useful commands in the README, this means they are easily findable by anyone, even if they don't have the means to run the tasks.
And to define a syntax of writing these commands so they were easily ran by a command for convenience.
So I began building and the following is what I came up with: XC [5].
To get started simply create a Tasks
heading in your README.md and add some titles of commands with code blocks defining the command:
## Tasks
### run
```
go run main.go
```
### test
```
go test ./...
```
### say-something
```
echo hello
```
And of course this will be extremely readable once rendered:
Tasks
run
go run main.go
test
go test ./...
say-something
echo hello
Install XC (requires Go, and requires $GOBIN to be in your $PATH).
go install github.com/joerdav/xc/cmd/xc@v0.0.20
Now you can list and run the tasks with XC.
$ xc
tasks:
run
test
say-something
$ xc say-something
.: echo hello
hello
Some other features currently implemented are:
Descriptions
README:
## Tasks
### other-task
Could run the tests?
```
echo hello
```
### say-something
Just an example.
```
echo hello
```
Output:
xc
tasks:
other-task Could run the tests?
say-something Just an example.
Dependencies
README:
## Tasks
### other-task
```
echo other
```
### say-something
Requires: other-task
```
echo hello
```
Output:
$ xc
tasks:
other-task
say-something Requires: other-task
$ xc say-something
.: echo other
other
.: echo hello
hello
Environment Variables
README:
## Tasks
### say-something
Env: MESSAGE=hello
```
printenv MESSAGE
```
Output:
$ xc say-something
.: printenv MESSAGE
hello
Execution Directories
README:
## Tasks
### printdir
Directory: ./otherdir
```
pwd
```
Output:
$ xc printdir
./otherdir: pwd
/Users/joe.davidson/src/repo/otherdir
Compound Commands
README:
## Tasks
### task1
```
echo task1
```
### task2
```
echo task2
```
### both
Requires: task1, task2
Output:
$ xc both
.: echo task1
task1
.: echo task2
task2
Summary #
In summary, I've built a README task runner called XC. Please do make your way onto the GitHub page [6] and make suggestions/contributions.