justfile for repetitive workflows, release cut included
Gates / frontend (push) Successful in 1m10s
CI / gates (push) Canceled after 1m37s
Gates / test (push) Canceled after 0s
Gates / test-aarch64 (push) Canceled after 0s
Gates / package (push) Canceled after 0s
Gates / container (push) Canceled after 0s

This commit is contained in:
2026-08-20 22:40:08 +02:00
parent 324704b53f
commit 386c289140
+86
View File
@@ -0,0 +1,86 @@
# Repetitive workflows. Anything a release or a review runs twice belongs here,
# so a step cannot be forgotten by hand (v0.0.7 first failed on an unbumped
# build.zig.zon that only verify-dist caught, one CI round too late).
repo := "mokhtar/nxdns"
forge := "https://git.mial.net"
# every recipe, described
default:
@just --list
# unit suite
test:
zig build test
# unit + integration suite
itest:
zig build test -Dintegration
# admin: typecheck, tests, lint, formatting
admin-check:
cd admin && npx tsc -b && npx vitest run && npx oxlint && npx prettier --check .
# regenerate the contract goldens from live responses
goldens:
zig build test -Dintegration -Dcontract-samples-out="{{justfile_directory()}}/admin/src/lib/contractSamples.gen.ts"
# the binary with the real admin UI embedded (the default build embeds a placeholder)
build:
cd admin && npm run build
zig build -Dadmin-dist=admin/dist
# everything CI gates on, locally
verify: test itest admin-check
zig fmt --check src/ tools/
# cut a release: preflight, bump, push, wait for CI, signed tag, watch the run.
# Requires: clean tree, master, CHANGELOG section for the version already written.
release version:
#!/usr/bin/env sh
set -eu
v="{{version}}"
[ -z "$(git status --porcelain)" ] || { echo "release: tree is dirty"; exit 1; }
[ "$(git branch --show-current)" = "master" ] || { echo "release: not on master"; exit 1; }
grep -q "^## \[$v\]" CHANGELOG.md || { echo "release: CHANGELOG.md has no ## [$v] section"; exit 1; }
git ls-remote --exit-code --tags origin "v$v" >/dev/null 2>&1 && { echo "release: tag v$v already on origin"; exit 1; }
if ! grep -q "\.version = \"$v\"" build.zig.zon; then
sed -i "s/\.version = \"[^\"]*\"/.version = \"$v\"/" build.zig.zon
grep -q "\.version = \"$v\"" build.zig.zon || { echo "release: version bump failed"; exit 1; }
git add build.zig.zon
git commit -S -m "build: bump version to $v"
fi
git push origin master
sha=$(git rev-parse HEAD)
echo "release: waiting for CI on $sha"
while :; do
state=$(curl -sf "{{forge}}/api/v1/repos/{{repo}}/commits/$sha/status" | python3 -c "import json,sys; print(json.load(sys.stdin).get('state') or 'pending')") || state=pending
case "$state" in
success) break ;;
pending) sleep 30 ;;
*) echo "release: CI is $state on $sha — not tagging"; exit 1 ;;
esac
done
git tag -s "v$v" -m "v$v" "$sha"
git push origin "v$v"
echo "release: tag v$v pushed, watching the release run"
while :; do
line=$(curl -sf "{{forge}}/api/v1/repos/{{repo}}/actions/runs?limit=10" | python3 -c "
import json,sys
for r in json.load(sys.stdin).get('workflow_runs', []):
if r.get('path','').startswith('release.yml') and r.get('head_sha') == '$sha':
print(r.get('status',''), r.get('conclusion','') or ''); break
") || line=""
set -- $line ""
if [ "${1:-}" = "completed" ]; then
[ "$2" = "success" ] || { echo "release: workflow concluded $2 — read the publish job log"; exit 1; }
break
fi
sleep 60
done
curl -sf "{{forge}}/api/v1/repos/{{repo}}/releases/tags/v$v" | python3 -c "
import json,sys
d = json.load(sys.stdin)
print('release: published', d['tag_name'], 'with', len(d.get('assets', [])), 'assets')
for a in d.get('assets', []): print(' ', a['name'])
"