Simple YAML-based task runner written in Go.
- Not super slow
- Not super obscure
- No dependencies
- Variables
- Simple
Via binary releases.
Via go-get
:
$ go get github.com/tj/robo
Command-line usage.
Output tasks:
$ robo
aws – amazon web services cli
circle.open – open the repo in circle ci
events – send data to the "events" topic
push – push image from the current directory
Output task help:
$ robo help events
Usage:
events [project-id] [rate]
Description:
send data to the "events" topic
Examples:
Send 25 events a second to gy2d
$ robo events gy2d 25
Regardless of task type (shell, exec, script) any additional arguments given will be passed.
For example suppose you have the following task:
aws:
exec: ssh tools aws
You may then interact with the AWS cli as you would normally:
$ robo aws help
$ robo aws ec2 describe-instances
Task configuration.
The most basic task simply runs a shell command:
hello:
summary: some task
command: echo world
You may also define multi-line commands with YAML's |
:
hello:
summary: some task
command: |
echo hello
echo world
Commands are executed via sh -c
, thus you may use shell features and
positional variables, for example:
hello:
command: echo "Hello ${1:-there}"
Yields:
$ robo hello
Hello there
$ robo hello Tobi
Hello there Tobi
The exec alternative lets you replace the robo image without the fork & shell, however note that shell features are not available (pipes, redirection, etc).
hello:
summary: some task
exec: echo hello
Any arguments given are simply appended.
Shell scripts may be used instead of inline commands:
hello:
summary: some task
script: path/to/script.sh
If the script is executable, it is invoked directly, this allows you
to use #!
:
$ echo -e '#!/usr/bin/env ruby\nputs "yo"' > yo.rb
$ chmod +x yo.rb
$ cat > robo.yml
yo:
summary: yo from rb
script: yo.rb
^C
$ robo yo
yo
Script paths are relative to the config file, not the working directory.
Tasks may optionally specify usage parameters, which display upon help output:
events:
summary: send data to the "events" topic
exec: docker run -it events
usage: "[project-id] [rate]"
Tasks may optionally specify any number of example commands, which display upon help output:
events:
summary: send data to the "events" topic
exec: docker run -it events
usage: "[project-id] [rate]"
examples:
- description: Send 25 events a second to gy2d
command: robo events gy2d 25
Robo supports variables via the text/template package. All you have to do is define a map of variables
and use {{
}}
to refer to them.
Here's an example:
stage:
summary: Run commands against stage.
exec: ssh {{.hosts.stage}} -t robo
prod:
summary: Run commands against prod.
exec: ssh {{.hosts.prod}} -t robo
variables:
hosts:
prod: bastion-prod
stage: bastion-stage
Along with your own custom variables, robo defines the following variables:
$ robo variables
robo.file: /Users/amir/dev/src/github.com/tj/robo/robo.yml
robo.path: /Users/amir/dev/src/github.com/tj/robo
user.home: /Users/amir
user.name: Amir Abushareb
user.username: amir
Tasks may define env
key with an array of environment variables, this allows you
to re-use robo configuration files, for example:
// aws.yml
dev:
summary: AWS commands in dev environment
exec: aws
env: ["AWS_PROFILE=eng-dev"]
stage:
summary: AWS commands in stage environment
exec: aws
env: ["AWS_PROFILE=eng-stage"]
prod:
summary: AWS commands in prod environment
exec: aws
env: ["AWS_PROFILE=eng-prod"]
You can also override environment variables:
$ cat > robo.yml
home:
summary: overrides $HOME
exec: echo $HOME
env: ["HOME=/tmp"]
^C
$ robo home // => /tmp
Variables can also be used to set env vars.
$ cat > robo.yml
aws-stage:
summary: AWS stage
exec: aws
env: ["AWS_PROFILE={{.aws.profile}}"]
variables:
aws:
profile: eng-stage
^C
$ robo aws-stage ...
Note that you cannot use shell featurs in the environment key.
Task list
and help
output may be re-configured, for example if you
prefer to view usage information instead of the summary:
templates:
list: |
{{range .Tasks}} {{cyan .Name}} – {{.Usage}}
{{end}}
Or perhaps something more verbose:
templates:
list: |
{{range .Tasks}}
name: {{cyan .Name}}
summary: {{.Summary}}
usage: {{.Usage}}
{{end}}
By default ./robo.yml
is loaded, however if you want global tasks
you can simply alias to something like:
alias segment='robo --config ~/.robo.yml'
You can easily use Robo to chain Robo, which is useful for multi-environment setups. For example:
prod:
summary: production tasks
exec: robo --config production.yml
stage:
summary: stage tasks
exec: robo --config stage.yml
Or on remote boxes:
prod:
summary: production tasks
exec: ssh prod-tools -t robo --config production.yml
stage:
summary: stage tasks
exec: ssh stage-tools -t robo --config stage.yml
You can also use robo's builtin variables robo.path
, for example
if you put all robofiles in together:
├── dev.yml
├── prod.yml
├── root.yml
└── stage.yml
And you would like to call dev
, prod
and stage
from root
:
dev:
summary: Development commands
exec: robo --config {{ .robo.path }}/dev.yml
stage:
...
You can compose multiple commands into a single command
by utilizing robo's built-in robo.file
variable:
one:
summary: echo one
command: echo one
two:
summary: echo two
command: echo two
all:
summary: echo one two
command: |
robo -c {{ .robo.file }} one
robo -c {{ .robo.file }} two
$ robo all
one
two
We generally use Makefiles for project specific tasks, however the discoverability of global tasks within a large team is difficult unless there's good support for self-documentation, which Make is bad at.
I'm aware of the million other solutions (Sake, Thor, etc) but I just wanted something fast without dependencies.
MIT