Day-to-day workflow#
The commands you use every day, and the flags that matter.
Testing#
rig test runs the :test alias of the target module. The exec-fn
recorded in the lockfile gives the command. Without -p, Rig runs every
module that declares a test exec-fn, in dependency order.
rig test # all testable modules
rig test -p modules/orchestrator # one modulePass extra arguments as EDN literals. Rig forwards them to the test runner as key/value opts:
rig test :kaocha.filter/focus '[:unit]'Rig supports keywords, strings, numbers, booleans, vectors, and maps. Any
option your runner accepts works, exactly as it works with clj -X:test.
The exit code of the child process becomes Rig's exit code: a failing test
suite fails your shell.
A module's :test alias can carry reporters as :extra-deps without
activating them. A scaffolded module ships the kaocha JUnit XML and
coverage reporters this way — dormant until a run loads them with
:plugins:
# JUnit XML for CI: the plugin writes to :junit-xml-file
rig test :plugins '[:kaocha.plugin/junit-xml]' \
:kaocha/cli-options '{:junit-xml-file "target/junit.xml"}'
# coverage: prints a table and writes target/coverage/
rig test :plugins '[:kaocha.plugin/cloverage]'The paths are relative to the module directory (the runner's working directory).
A module participates when its :test alias declares an :exec-fn. Rig
skips modules without one.
Running code#
rig run -p modules/orchestrator -- --env devrig run launches the :rig/main of the module on its locked classpath.
Program arguments are plain strings. To keep program flags from acting as
Rig flags, separate them with --:
rig run -p modules/orchestrator # no program args
rig run -p modules/orchestrator -- --env dev # flags for the program--alias <name>runs on the classpath of a different alias, for example a:devalias with reloaded REPL tooling.- Rig applies the JVM options of the module and the alias.
- The working directory is the module directory.
rig nrepl # nREPL server on the module classpath
rig nrepl --alias dev -p modules/orchestratorThe development REPL: the dev module#
Scaffolded projects carry a workspace-level dev module: one development
module for the whole workspace, not one per module. Its deps.edn loads
the app module by :local/root and pins reloaded.repl
(the reloaded workflow);
dev/user.clj is the scratch namespace the REPL opens in.
rig nrepl -p devThe server runs in that terminal; quitting the console stops it.
With the app open, work in user.clj. After a save, reload the changed
namespaces — CIDER's cider-ns-refresh needs the cider-nrepl middleware
(see Connecting the editor below); without it, re-evaluate user — and
(reloaded/go) restarts the system on the new code. When the app grows
a component system, wire the reloaded workflow to it — user.clj's
docstring carries the incantation:
(require '[reloaded.repl :as reloaded])
(reloaded/set-init! #'start-system)
(reloaded/go) ;; start, or reload changed namespaces and restart
(reloaded/stop)
(reloaded/reset) ;; stop, unload every namespace, start againA new module does not enter dev on its own: rig new-module leaves it
out, so the development classpath stays what you asked for. Add a module
to dev/deps.edn when you want it in the REPL —
example/other {:local/root "../modules/other"} — then rig lock.
The dev module is not built, published, or tested: it declares no
:rig/lib, no test exec-fn, no build. It exists for the REPL.
Connecting the editor#
nREPL writes the port of a running server to .nrepl-port in the module
directory and removes the file when the JVM exits. A hard kill leaves the
file behind, so add .nrepl-port to your .gitignore.
Recent CIDER suggests the running server at the connect prompt.
cider-connect (C-c C-x c s) offers the port from the file when your
buffer is inside the module. A machine-wide process scan finds a running
nrepl.cmdline from any buffer. The port file works on any platform; the
scan needs Linux or macOS. Without the scan, type the port from the
startup banner.
Rig starts the server without nREPL middleware, so CIDER's completion,
debugger, and refresh stay off. To turn them on, put cider/cider-nrepl
on the classpath and list the middleware in a dev/.nrepl.edn;
nrepl.cmdline reads that file from the module directory:
{:middleware [^:optional cider.nrepl/cider-middleware]}Declare cider/cider-nrepl as an :extra-dep of a :dev alias in
dev/deps.edn and start the server with rig nrepl -p dev --alias dev.
The ^:optional marker skips the middleware when it is missing from the
classpath.
The escape hatch: rig exec#
When Rig has no verb for your task — a script, a linter, a database
client — rig exec runs any command with the locked classpath of the
project exported:
rig exec my-tool --some-arg
rig exec -p modules/orchestrator --alias test python manage.py shellThe command inherits:
CLASSPATH— the locked classpath of the module (alias included);JAVA_OPTS— the JVM options of the module and the alias, if any;- the module directory as working directory.
The exit code of your command becomes Rig's exit code.
Code hygiene#
rig fmt # cljfmt (the version pinned in the kernel)
rig fmt --check # CI: report without fixing
rig clean # remove target dirs of all target modules
rig clean -p modules/appfmt uses the cljfmt pinned inside the kernel jar of Rig, so everyone
formats with the same version. It works without a lockfile.
What every hot command does first#
test, run, nrepl, exec, and build apply the same lockfile
discipline before they launch anything:
- no lockfile →
no lock at /home/dev/app/deps.lock (run 'rig lock'), exit 3; - manifest changed →
lock is stale (manifest changed in: <modules>); run 'rig lock' to refresh, exit 3. The hot commands never write the lockfile; runrig lock(orrig add/rig remove/rig update) and re-run; - Rig hash-checks every classpath artifact against the lockfile, securing
it from the cache or a checksum-checked
~/.m2. Rig downloads missing artifacts unless--offline.
So rig test from a dirty checkout runs the locked classpath, or fails
with the hint. You never get a quiet re-resolution.
Module targeting#
-p, --path <module> targets one module by its directory
(-p modules/orchestrator) or by a path to it. If you omit it (or pass
-p .), the command targets the root module; for multi-module commands,
it targets all modules in dependency order. Every command that takes a
module accepts -p.