Rune
Scripts for builds and deployments that check before they run.
Rune is a script language for builds, tests and deployments. It replaces the bash and ksh scripts that such work tends to collect, with one way to do each thing and no shell in between. The whole script is checked before its first line runs, so a deployment does not stop halfway through because of an unknown name near its end.
Every script sees the others
Every Rune script on the computer is a job on one shared bus, and each job sees the others. The bus reports when a job starts, waits, fails or finishes, and when one vanishes. A script sends its own events with
emit("build.done", {target: "app"}).Wait for what really happened
wait for "deploy.done" where e.data.target == "live" within 10waits for the next event that fits, and never misses one that came before the wait began or gives the same one twice.on "build.step" as s { ... }runs a block for each event while the script waits, so tests finish as soon as the thing is done.Commands without a shell
A command is a list of arguments, so
$ cp {src} {dst}passes each value as one argument, whatever it holds. Nothing is split, globbed or quoted a second time.A failure stops the script
A failed command stops the script and shows its exit code and the end of its error output. When a step may fail on purpose,
try $gives a result you can check.Secrets that stay secret
A secret prints as *** everywhere, error messages included. It can't go into a command's arguments or a text, and it reaches a program through its standard input or its environment.
Rebuilds only what changed
makeruns a step only when its inputs, or its key such as a compiler flag, have changed since its outputs were last made.parspreads independent work over every core.Checked before it runs
rune checkfinds every mistake in a script without running it, andrune check --jsongives the same report to a tool.rune fmtlays the file out the one way and never changes what it does.Network and data built in
HTTP, TLS, JSON and regular expressions are part of the language, so a deployment can check a health address or read a release file without another tool. Shared code goes in a file of its own, brought in with
use.
This short script builds a Go tool only when its sources have changed, runs its tests and copies the result into dist/.
# Build the tool when its sources changed, test it, then copy it to dist/.
let version = "1.2.0"
let tool = join_path("build", "tool")
let shipped = join_path("dist", "tool-" + version)
if is_dir("build") == false { mkdir("build") }
make([tool], glob("src/**/*.go"), "release " + version, () => {
$ go build -o {tool} ./src
})
$ go test ./src/... with timeout: 10m
if is_dir("dist") == false { mkdir("dist") }
copy_file(tool, shipped)
print("ready:", shipped)
Where to get it
On Windows, get Rune from the Microsoft Store, which adds the rune command to every terminal. On macOS, download the signed and notarised installer for Apple silicon from antisoftworks.com/rune. On Linux, install the .deb or Arch package, or unpack the tarball on a server, from antisoftworks.com/rune.
Rune is free to use, including commercially, and its source code is not published.
rune --llm prints the whole language as one short read, written for a language model to learn from, and rune --llm --json gives it as data. Every example in it runs as a test, so it stays right.
Rune also reports its own crashes, and rune report bug "what happened" sends a bug report in one command.