Releases: esliph/spur
Release list
spur 0.3.1
0.3.1 - 2026-09-30
Fixed
- The recursion guard tells tasks apart by their Spurfile as well as their name:
installcallingspur -C sub installno longer exits 68, while a real recursion is still caught across Spurfiles and through a symlinked directory.SPUR_STACKnow holds one frame per line, the task name and the physical path of its Spurfile.
Install
curl -fsSL https://raw.githubusercontent.com/esliph/spur/v0.3.1/spur \
-o ~/.local/bin/spur && chmod +x ~/.local/bin/spurOr download spur from the assets below and chmod +x it, or vendor it by copying the file into your repository.
spur 0.3.0
0.3.0 - 2026-09-30
Changed
- The runner no longer uses
dirnameorbasename: it depends onsh,awkandcat, nothing else, andexec-minimal-pathruns it with only those three onPATH. Paths are split with parameter expansion, which removes about ten processes from every run. - A run parses the Spurfile once instead of twice, and
--checkonce instead of once per task plus two. Under dash on Windows, a trivial run went from 205 to 99 ms and--checkof 50 tasks from 4.5 to 1.9 s.
Added
CHANGELOG.md, the source of the release notes, and a release process:spur release X.Y.Zprepares the release pull request, and merging it intomastertags and publishes the version once CI is green.
Install
curl -fsSL https://raw.githubusercontent.com/esliph/spur/v0.3.0/spur \
-o ~/.local/bin/spur && chmod +x ~/.local/bin/spurOr download spur from the assets below and chmod +x it, or vendor it by copying the file into your repository.
spur 0.2.0
0.2.0 - 2026-09-28
New ways to read a Spurfile without running it, sections in spur list, and a round of fixes from the branch review. The runner is still one file that depends on sh, awk, dirname, basename and cat, and nothing else — now pinned by a test. Everything here landed in #2.
Added
##@ Titlelines group the tasks that follow into sections inspur list.--checksyntax-checks every task, or just one (spur --check deploy), without running anything, and reports what is malformed, including a heredoc that is never terminated.--namesprints the bare task names, one per line, for scripts and shell completion.spur --describe <task>prints a task's long help (its##block).- An unknown task suggests the closest task names, and suggests no unrelated name for a short one.
Fixed
SPUR_BINresolves to./spurwhen the runner is started assh spur.-fand-Care kept in the hints printed after an error, so the suggested command works as printed.###lines stay out of a task's long help.- The caller's environment is no longer overwritten by the runner's own variables: every runner variable is now prefixed
spur_orSPUR_, andexec-caller-environment-keptscans the runner to keep it that way. --checkparses the preamble once and assembles without subshells.
Tests, benchmarks and CI
tests/run.shruns the cases in parallel workers (SPUR_TEST_JOBS, default the number of CPUs) and reports in alphabetical order.SPUR_TEST_TIMES=1times each case and lists the five slowest,SPUR_TEST_AWKchooses the awk the runner runs with, and Ctrl-C or TERM stops the workers cleanly, a second signal included under bash 3.2.- A benchmark harness,
tests/bench/run.sh, with six scenarios. It prints min, mean and max per scenario, with no baseline and no threshold. - The suite grew from 48 to 114 cases, adding tab dedent, CRLF,
-Cwith-f, empty bodies, nearest-Spurfile discovery, multi-line preambles, digits and underscore in task names, andexec-minimal-path. - CI pins shellcheck to 0.11.0, adds macOS (bash 3.2, BSD awk), runs the suite under dash once per awk (
gawk --posix,mawk,original-awk) and runs every benchmark once.
Install
curl -fsSL https://raw.githubusercontent.com/esliph/spur/v0.2.0/spur \
-o ~/.local/bin/spur && chmod +x ~/.local/bin/spurUpgrading from 0.1.0 is the same command. Or download spur from the assets below and chmod +x it, or vendor it by copying the file into your repository.
spur 0.1.0
0.1.0 - 2026-09-22
First release. spur reads a Spurfile, lists the tasks and runs one per invocation in a single shell. The whole program is one file that depends on sh and awk: no build step and no runtime to install.
The scope is deliberate: spur runs tasks, it does not build software — no dependency graph, no timestamp rebuilds, no pattern rules. It needs a POSIX shell, so on Windows it runs under Git Bash, MSYS2, WSL or Cygwin. The trade-offs that follow are listed in the README under What it costs.
Added
- The
Spurfilelanguage: a line matching^[A-Za-z0-9_.-]+:opens a task,## textin the header documents it for--list, and the indented body is
dedented before it runs, soif,forand heredocs keep their relative shape. Everything before the first task is the preamble, injected at the top of every task that runs. - One shell for the whole body, with
set -eon:cdpersists, variables persist, and stdin stays free, so interactive tasks work. - A body that reaches the shell byte for byte. The runner expands nothing, so
$IMAGE,$(date),${x:-y}and$$arrive intact and there is no template layer to escape. - Positional passthrough:
spur test -k login -vvhands-k login -vvto the body as"$@". The first word that does not start with-is the task name; everything after it belongs to the task. - Spurfile discovery:
Spurfile, thenspurfile, in the current directory and then upwards to/. Every task runs in the directory that holds the file in use. - Chained calls: the assembled script injects a
spurfunction pointing at the runner itself. A recursion guard overSPUR_STACKexits 68, while repeated non-recursive calls are allowed. - Runner flags:
-f FILE,-C DIR,-l/--list,-n(print the assembled script instead of running it),-x(trace withPS4='$ ', after the preamble),-h/--helpand-v/--version. Short flags cannot be grouped. - Exit codes in the
sysexitsrange, so they never collide with a task's own, which is propagated unchanged: 64 usage, 65 malformed Spurfile, 66 Spurfile not found, 67 unknown task, 68 recursion. - Exported environment:
SPUR_BIN,SPUR_ROOT,SPUR_INVOCATION_DIR,SPUR_TASKandSPUR_STACK. - Shell diagnostics labelled
spur <task>: line N: ..., from$0on the singlesh -cthat runs the task. - Documentation:
README.mdas the user-facing contract (the language, the CLI, the exit codes, the make → spur mapping and the known limitations),CONTRIBUTING.mdfor the testing rules, and an MITLICENSE. - A behavior suite of 48 cases under
tests/, run by a dependency-free harness, plus CI runningshellcheck -s shand the suite undersh,dash,bashand busyboxash. Green on this tag.
Install
curl -fsSL https://raw.githubusercontent.com/esliph/spur/v0.1.0/spur \
-o ~/.local/bin/spur && chmod +x ~/.local/bin/spurOr download spur from the assets below and chmod +x it. Or vendor it: copy the file into your repository and commit it, and anyone who clones runs ./spur test with nothing installed.