Introduce a DSL to replace the plain bash scripts

It's really important for `git-check-assertions` blocks to be 'obviously
correct', so that we don't need to... test the tests that test the tests.

Let's introduce a little DSL that is less error-prone than a plain bash
script.
This commit is contained in:
Sven van Heugten 2026-04-16 06:25:28 +02:00
parent ad10b2cc4c
commit 4704cc088d
No known key found for this signature in database
GPG key ID: D612F88666F4F660
3 changed files with 130 additions and 127 deletions

View file

@ -24,48 +24,6 @@
set -euo pipefail
# helper functions inspired by bats/bats-assert
run() {
set +e
tmp_output="$(mktemp)"
"$@" 2>&1 | tee "$tmp_output"
status=${PIPESTATUS[0]}
set -e
output="$(cat "$tmp_output")"
rm -f "$tmp_output"
printf '%s\n' "$output"
return 0
}
assert_success() {
if [ "$status" -ne 0 ]; then
echo "Expected command to succeed, but it failed."
exit 1
fi
}
assert_failure() {
if [ "$status" -eq 0 ]; then
echo "Expected command to fail, but it succeeded."
exit 1
fi
}
assert_output() {
if [ "${1:-}" = "--partial" ]; then
local expected="$2"
if [[ "$output" != *"$expected"* ]]; then
echo "Expected output to contain: $expected"
echo "Actual output: $output"
exit 1
fi
return 0
fi
if [ "$output" != "$1" ]; then
echo "Expected output to equal: $1"
echo "Actual output: $output"
exit 1
fi
}
export -f run assert_success assert_failure assert_output
# main flow
if [ ! -z "$(git status --porcelain)" ]; then
echo "Uncommitted changes. Refusing to run." >&2
@ -121,8 +79,64 @@ for commit_hash in "${commits[@]}"; do
check_assertions() {
python3 - "$block" <<-EOF
import sys
import re
import subprocess
subprocess.run(sys.argv[1], shell=True, check=True)
block = sys.argv[1]
steps = []
current_step = None
for line_number, raw_line in enumerate(block.splitlines(), start=1):
line = raw_line.rstrip("\\r")
if not line.strip():
continue
match = re.match(r"^\\[(success|failure)\\]\\s+(.+)$", line)
if match:
current_step = {
"expects_success": match.group(1) == "success",
"command": match.group(2),
"assertions": [],
}
steps.append(current_step)
continue
if current_step is None:
print(
f"DSL parse error on line {line_number}: "
"assertion text must follow [success] or [failure]."
)
sys.exit(1)
current_step["assertions"].append(line)
for step in steps:
completed = subprocess.run(
["sh", "-lc", step["command"]],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
output = completed.stdout or ""
if output:
sys.stdout.write(output)
if not output.endswith("\\n"):
sys.stdout.write("\\n")
if step["expects_success"]:
if completed.returncode != 0:
print("Expected command to succeed, but it failed.")
sys.exit(1)
elif completed.returncode == 0:
print("Expected command to fail, but it succeeded.")
sys.exit(1)
for expected in step["assertions"]:
if expected not in output:
print(f"Expected output to contain: {expected}")
print(f"Actual output: {output}")
sys.exit(1)
EOF
}
if ! check_assertions; then