Skip to content

๐Ÿ“Ÿ Command line

rundot RUNBOOK [--dry] [--step | --no-step] [--show-code]      # run a runbook
rundot run RUNBOOK [--dry] [--step | --no-step] [--show-code]  # the same, in full
rundot check RUNBOOK                                           # find problems without running anything
rundot inputs RUNBOOK                                          # list the inputs a runbook needs
rundot library                                                 # list the books in your runbook library
rundot backends                                                # list the languages rundot can run
rundot --version

rundot on its own shows this list.

Naming a runbook

RUNBOOK is a file, or the name of a book in your runbook library:

rundot RELEASING.md        # the file RELEASING.md, here
rundot rebuild-frontend    # the book rebuild-frontend.md, in your library
  1. If RUNBOOK is a file that exists, that's the runbook, so a file is never hidden by a book with the same name.
  2. Otherwise, if it has no /, it's the book <name>.md in your library. The .md is optional.
  3. Otherwise it's a usage error, which names both places rundot looked:
Error: Invalid value for 'RUNBOOK': no runbook 'rebuild-frontend': no such file here, and no rebuild-frontend.md in the library at /home/you/runbooks

rundot run

Runs a runbook, step by step.

rundot RELEASING.md

You don't need to type run: anything after rundot that isn't a command is a runbook. Options go before or after it, so rundot RELEASING.md --dry is the same as rundot --dry RELEASING.md. Use rundot run check to run a book called check.md, since rundot check is the command.

  1. Checks the runbook, as rundot check does. Errors stop it here.
  2. Collects the inputs. See Inputs.
  3. Shows the plan and asks Start? [y/N].
  4. Runs each step in order, streaming each block's output as it's printed. Each block shows its language and when it started, then what it printed, then its exit code and how long it took. A line it wrote to stderr has a red โ”‚.
VERSION (The version to release, e.g. 1.2.0): 1.2.0
โ•ญโ”€ Release my-package โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ directory  /home/you/Projects/my-package โ”‚
โ”‚ inputs     VERSION=1.2.0                 โ”‚
โ”‚ steps      1. Run the tests              โ”‚
โ”‚            2. Tag the release            โ”‚
โ”‚            3. Publish on GitHub          โ”‚
โ”‚ blocks     2 run blocks                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
Start? [y/N] y

1/3  Run the tests โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh ยท 10:02:13.482
  โ”‚ ...
  โ”” โœ“ exit 0 ยท 4.2s

2/3  Tag the release โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh ยท 10:02:17.705
  โ”” โœ“ exit 0 ยท 0.1s

3/3  Publish on GitHub โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
โ•ญโ”€ confirm โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Create a GitHub release from tag 1.2.0. โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
Continue? [y/N] y

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ โœ“ finished ok ยท 12.8s โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
transcript: logs/release-1.2.0.md

directory is where blocks will run. See Where blocks run.

The run stops at the first block that fails:

1/1  Build โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh ยท 10:02:13.482
  โ”‚ Building
  โ”‚ make: *** [build] Error 2
  โ”” โœ— exit 2 ยท 0.0s

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ โœ— failed at "Build" (exit 2) ยท 0.0s โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Only y answers Start? and Continue? with yes. Anything else, including enter, ends the run as aborted.

--show-code

Shows each block's code above what it printed:

  โ”Œ sh ยท 10:02:13.482
  โ”‚ echo "Building"
  โ”œ output
  โ”‚ Building
  โ”” โœ“ exit 0 ยท 0.0s

--dry always shows the code.

Picking a book

With no runbook, rundot run asks which book from your library to run:

$ rundot run
  1. rebuild-frontend     Rebuild the frontend
  2. update-project-deps  Update a project's dependencies
Run which? (q to quit) 1

Answer with a number. --dry and --step work too. Answer q, or press enter, to stop without running anything.

--dry

Shows what the runbook would do, without running anything.

rundot --dry RELEASING.md
  • Every block is shown with its inputs filled in.
  • There's no Start?, confirm blocks don't wait, and no transcript is written.
  • Secrets and input blocks aren't asked for.
VERSION (The version to release, e.g. 1.2.0): 1.2.0
โ•ญโ”€ Release my-package โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ directory  /home/you/Projects/my-package โ”‚
โ”‚ inputs     VERSION=1.2.0                 โ”‚
โ”‚ steps      1. Run the tests              โ”‚
โ”‚            2. Tag the release            โ”‚
โ”‚            3. Publish on GitHub          โ”‚
โ”‚ blocks     2 run blocks                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
dry run: nothing will be run

1/3  Run the tests โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh
  โ”‚ make test
  โ”” not run

2/3  Tag the release โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh
  โ”‚ git tag 1.2.0
  โ”” not run

3/3  Publish on GitHub โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
โ•ญโ”€ confirm โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Create a GitHub release from tag 1.2.0. โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ dry run, nothing was run โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

--step

Asks before running each run block.

rundot --step RELEASING.md
1/2  Build โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh ยท 10:02:13.482
  โ”œ Run this block? [y]es / [s]kip / [q]uit y
  โ”‚ Building
  โ”” โœ“ exit 0 ยท 0.0s

2/2  Publish โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

  โ”Œ sh ยท 10:02:13.486
  โ”œ Run this block? [y]es / [s]kip / [q]uit s
  โ”” โ†ท skipped

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ โœ“ finished ok ยท 0.0s โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

y runs the block, s skips it, and q ends the run as aborted. The code isn't shown unless you add --show-code. With --dry, --step does nothing, since nothing runs.

A runbook that should always be run this way can set step: true in its frontmatter, so you don't need to remember --step. To run one of those straight through, pass --no-step.

Pressing Ctrl-C

  • A running block gets the Ctrl-C too, and rundot waits for it to stop.
  • If a block ignores it, press Ctrl-C again to stop the block and everything it started.
  • The run ends as โœ— interrupted at "<step>".

rundot check

Finds problems in a runbook without running anything.

rundot check RELEASING.md
RELEASING.md: ok

Each problem is shown with its line, so your editor can jump to it:

broken.md:6: error: input VERSION is declared twice (first on line 4)
broken.md:8: warning: input BRANCH is never used
broken.md:12: error: run blocks must be inside a step (a ## heading)
broken.md:19: error: <TAG> isn't a declared input
broken.md:21: error: syntax error near unexpected token `fi'

4 errors, 1 warning

Errors stop the runbook running:

  • a missing title, or a frontmatter value of the wrong type
  • an input without a name or description, a name that isn't UPPER_SNAKE_CASE or is declared twice, or a pattern that isn't a valid regular expression
  • a default or choices that can't work. See Defaults and Choices.
  • a placeholder that isn't a declared input, or a secret used as a placeholder
  • an input block that isn't valid YAML, or is used before it's asked for
  • a block before the first ## heading
  • a run block in a language no backend runs, or a python command that isn't installed
  • a syntax error in a shell or Python block

Warnings don't:

  • a frontmatter or input key rundot doesn't know, often a typo
  • an input nothing uses
  • a Python SyntaxWarning, and shellcheck findings if it's installed

rundot inputs

Lists the inputs a runbook needs, so you know what to have ready.

rundot inputs PUBLISHING.md
VERSION  The version being released, e.g. 1.2.0
         pattern: ^\d+\.\d+\.\d+$
BRANCH   The branch to release from
         default: main
PR       The number GitHub gave the pull request
         pattern: ^\d+$
         asked in "Open the pull request"
OTP      The code from your authenticator app
         pattern: ^\d{6}$
         secret
         asked in "Publish"

Inputs from input blocks come last, with the step that asks for them. Frontmatter inputs are listed even if the rest of the runbook is broken.

rundot library

Lists the books in your runbook library, with each one's title and description.

$ rundot library
library: /home/you/runbooks
rebuild-frontend     Rebuild the frontend
                     Clean install the frontend's dependencies, then rebuild it.
update-project-deps  Update a project's dependencies

A book whose frontmatter can't be read is still listed, with why.

rundot backends

Lists the languages rundot can run, and the package each comes from.

$ rundot backends
python  python, py       rundot.backends.python:PythonBackend (rundot 0.2.0)
shell   sh, bash, shell  rundot.backends.shell:ShellBackend (rundot 0.2.0)

Exit codes

Code Meaning
0 The run finished, or check found no errors.
1 A block failed, the run was aborted or interrupted, check found errors, or the runbook couldn't be read.
2 The command was used wrongly, e.g. a runbook that doesn't exist.