Caution
This software is not verified, will have breaking changes and might have bugs.
Ror is a PFE task runner.
ror [flags] [task] [task args]-R: Repeat a task (see below).--export-taskfile: Exportror.kdltoTaskfile.yml(for compatibility with Task).-s,--silent: Silent mode (no output).-v: Verbose output.-vvv: Very verbose output.
ror -R foo- Success repeats immediately, including dependencies and dynamic
where/env commands. - Failure prints the usual error once, then waits for Ctrl+C to request a restart.
- The first Ctrl+C interrupts the current execution and starts a 400ms window immediately.
- A second Ctrl+C within that window exits with status 130, even during shutdown.
- Otherwise, execution restarts after both the window and the old execution have finished.
Shutdown sends SIGINT to the execution's process group, then SIGKILL after at most 2 seconds. A second Ctrl+C forces cleanup without waiting for that grace period. Background processes in the group are also cleaned up when a command finishes.
Configuration is loaded once. There is no file watching or configuration reload.
Put -R before the task name; task arguments and verbosity flags work as usual.
Without a selected/default task, ror still lists tasks rather than repeating the list.
Repeat mode requires Unix process groups and is intended for non-interactive tasks. Commands run outside the terminal's foreground group, so interactive terminal reads and job control are not supported. Processes that deliberately detach into another session or process group cannot be managed by ror.
Built-in commands are invoked with a leading +, so plain names stay free for tasks.
+init: Create a newror.kdltemplate.+validate <file>: Check that a file is validror.kdl.+version: Print version.+help: Print help message.
Ror uses KDL v2 for its configuration file ror.kdl. The file defines a set of tasks that can be executed.
Tasks are defined using the task node followed by the task name.
task my-task {
...
}You generally don't need quotes for task names unless they contain special characters (like spaces, brackets ()[]{} or symbols like =, ,, ;, \, /, <, >) or look like a number, boolean, or null.
Common safe characters include letters, numbers, -, and _.
Inside a task, you can define the following properties:
description: A string describing what the task does.cmd: The command to run.depends: A block listing dependencies usingon.env: Environment variables passed to the task command.vars: Task-level variables that override globalvarsby name.
Dependencies define other tasks that must run successfully before the current task. They are specified within a depends block using on.
task install {
depends {
on "build"
}
cmd "cp ./app /usr/local/bin/app"
}The cmd node specifies the shell command to execute. It supports variable substitution.
A plain env value is fixed, even if the same variable exists outside ror:
task serve {
env PORT="8080"
cmd "./server"
}Use expose to prefer a non-empty external value. If the variable is unset or empty, the configured value is used:
task serve {
env PORT="8080" {
expose
}
cmd "./server"
}Use execute to run the value as a shell command and use its stdout as the environment value (surrounding whitespace is trimmed). With both directives, a non-empty external value skips the command. Without expose, the command always runs. An empty command is invalid even if an external value exists. A failed command fails the task.
task build {
env REVISION="git rev-parse --short HEAD" {
expose
execute
}
cmd "echo $REVISION"
}KDL v2 requires child directives on separate lines (or separated with semicolons).
Env values may reference global and task vars with %%name%%. Expansion
happens before expose/execute handling, so it works for plain, exposed and
executed values alike:
vars { version "1.2.3" }
task build {
env APP_VERSION="%%version%%"
env REVISION="git rev-parse --short HEAD" {
expose
execute
}
cmd "./build.sh"
}A vars block defines named string values. It can be placed at the top level
(global) or inside a task (task-level). Values are substituted using the same
%%variable_name%% syntax as where variables.
vars {
hostname "hello"
domain "example.com"
}
task foo {
# Task-level vars override globals by name.
vars {
hostname "world"
}
cmd "ssh %%hostname%%.%%domain%%"
}Each entry is a name followed by a single string value. Duplicate names in the same block are an error.
Precedence, from lowest to highest:
- global
vars - task
vars whereinsidecmd
A task can freely use any global it does not override. A global that is
overridden is shadowed: there is no way to read the original value from within
that task. Vars are static strings; use where for dynamic ({ execute })
values.
Vars are expanded in cmd, description and env values using the same
%%variable_name%% syntax. No extra directive is needed. An unknown name is
left as-is so a command can still see it literally.
Variables are defined using where nodes attached to the cmd node or nested within other where nodes. They are substituted using %%variable_name%%.
Variable name can only contain symbols A-Z, a-z, 0-9, _ and -.
where my-var="value"Variables can be the result of a shell command execution by adding an { execute } block.
where current-date="date +%Y-%m-%d" { execute }We can go even deeper:
where current-date="date %%format%%" {
where format="+%Y-%m-%d"
execute
}A simple task to run a command.
task run {
description "Run the project"
cmd "go run ./main.go"
}A build task that injects git commit hash and compilation time into the binary.
task build {
description "Build the application"
cmd "go build -o out/app -ldflags='-X main.commit=%%commit%% -X main.date=%%date%%' ./cmd/app" {
where commit="git describe --tags --always --dirty" { execute }
where date="date +%Y-%m-%dT%H:%M:%SZ" { execute }
}
}A deploy task that ensures the application is tested and built first.
task deploy {
description "Deploy the application"
depends {
on "test"
on "build"
}
cmd "./scripts/deploy.sh"
}