# Witryna development tasks version := `grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/'` # List available recipes default: @just --list # --- Formatting --- # Auto-format Rust code fmt: cargo fmt --all # --- Linting --- # Lint Rust (fmt check + clippy) lint-rust: cargo fmt --all -- --check cargo clippy --all-targets --all-features -- -D warnings # Lint YAML files (if any exist) lint-yaml: @if find . -name '*.yml' -o -name '*.yaml' | grep -q .; then yamllint $(find . -name '*.yml' -o -name '*.yaml'); else echo "No YAML files, skipping"; fi # Scan for leaked secrets lint-secrets: gitleaks protect --staged # Clippy pedantic + nursery (advisory, not enforced in CI) lint-pedantic: cargo clippy --all-targets --all-features -- -W clippy::pedantic -W clippy::nursery # Clippy picky: pedantic + nursery + restriction subset (strict, advisory) lint-picky: cargo clippy --all-targets --all-features -- -W clippy::pedantic -W clippy::nursery -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -W clippy::indexing_slicing -W clippy::clone_on_ref_ptr -W clippy::print_stdout -W clippy::print_stderr # Run all lints lint: lint-rust lint-yaml lint-secrets check-version # --- Version --- # Verify all files match Cargo.toml version check-version: #!/usr/bin/env bash set -euo pipefail v="{{version}}" # Arch pkgver: strip pre-release punctuation (0.2.0-rc.1 → 0.2.0rc1) pkgver=$(echo "$v" | sed 's/-\([a-z]*\)\./\1/') tag="v${v}" ok=true check() { grep -qF "$2" "$1" || { echo "MISMATCH: $1 missing '$2'"; ok=false; }; } check arch/PKGBUILD "pkgver=${pkgver}" check arch/PKGBUILD "_tag=${tag}" check man/witryna.1 "witryna ${v}\"" check man/witryna.1 "${tag}" check man/witryna.toml.5 "witryna ${v}\"" $ok && echo "All versions match Cargo.toml: ${v}" || { echo "Run 'just bump-version' to fix"; exit 1; } # Sync version in packaging/doc files to match Cargo.toml bump-version: #!/usr/bin/env bash set -euo pipefail v="{{version}}" pkgver=$(echo "$v" | sed 's/-\([a-z]*\)\./\1/') tag="v${v}" echo "Syncing to ${v} (pkgver=${pkgver}, tag=${tag})" sed -i "s/^pkgver=.*/pkgver=${pkgver}/" arch/PKGBUILD sed -i "s/^_tag=.*/_tag=${tag}/" arch/PKGBUILD sed -i "1s/\"witryna [^\"]*\"/\"witryna ${v}\"/" man/witryna.1 sed -i "1s/\"witryna [^\"]*\"/\"witryna ${v}\"/" man/witryna.toml.5 sed -i '/^\.SH VERSION$/,/^\.SH /{s/^v.*/'"${tag}"'/}' man/witryna.1 echo "Done. Remaining manual updates: CHANGELOG.md, README.md" # --- Testing --- # Run unit tests test: cargo test --all # Run integration tests (Tier 1 needs git, Tier 2 needs podman/docker) test-integration: cargo test --features integration # Run integration tests with single thread (required for SIGHUP tests) test-integration-serial: cargo test --features integration -- --test-threads=1 # Run all lints, unit tests, and integration tests test-all: lint test test-integration # --- Building --- # Build a release binary build-release: cargo build --release # --- Packaging --- # Build Debian package build-deb: cargo deb # Show contents of built Debian package inspect-deb: #!/usr/bin/env bash set -euo pipefail deb=$(find target/debian -name 'witryna_*.deb' 2>/dev/null | head -1) if [[ -z "$deb" ]]; then echo "No .deb found — run 'just build-deb' first" >&2; exit 1; fi echo "=== Info ===" && dpkg-deb --info "$deb" echo "" && echo "=== Contents ===" && dpkg-deb --contents "$deb" # Build RPM package (requires: cargo install cargo-generate-rpm) build-rpm: cargo build --release cargo generate-rpm # Show contents of built RPM package inspect-rpm: #!/usr/bin/env bash set -euo pipefail rpm=$(find target/generate-rpm -name 'witryna-*.rpm' 2>/dev/null | head -1) if [[ -z "$rpm" ]]; then echo "No .rpm found — run 'just build-rpm' first" >&2; exit 1; fi echo "=== Info ===" && rpm -qip "$rpm" echo "" && echo "=== Contents ===" && rpm -qlp "$rpm" echo "" && echo "=== Config files ===" && rpm -qcp "$rpm" echo "" && echo "=== Scripts ===" && rpm -q --scripts -p "$rpm" # Test PKGBUILD locally (requires makepkg) build-arch: cd arch && makepkg -sf # Build Nix package (requires nix with flakes) build-nix: nix build .#witryna # Show contents of built Arch package inspect-arch: #!/usr/bin/env bash set -euo pipefail pkg=$(find arch -name 'witryna-*.pkg.tar.zst' 2>/dev/null | head -1) if [[ -z "$pkg" ]]; then echo "No .pkg.tar.zst found — run 'just build-arch' first" >&2; exit 1; fi echo "=== Info ===" && pacman -Qip "$pkg" echo "" && echo "=== Contents ===" && pacman -Qlp "$pkg" echo "" && echo "=== Backup files ===" && pacman -Qip "$pkg" | grep -A99 "^Backup Files" # --- Release --- RELEASE_HOST := "git@sandcrawler" RELEASE_PATH := "/srv/git/release" # Build tarball with binary, config, service, man pages, examples build-tarball: build-release #!/usr/bin/env bash set -euo pipefail version=$(cargo metadata --format-version=1 --no-deps | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4) name="witryna-${version}-linux-amd64" staging="target/tarball/${name}" rm -rf "$staging" mkdir -p "$staging/examples/hooks" "$staging/examples/caddy" "$staging/examples/nginx" "$staging/examples/systemd" cp target/release/witryna "$staging/" cp examples/witryna.toml "$staging/" cp debian/witryna.service "$staging/" cp man/witryna.1 "$staging/" cp man/witryna.toml.5 "$staging/" cp README.md "$staging/" cp examples/hooks/caddy-deploy.sh "$staging/examples/hooks/" cp examples/caddy/Caddyfile "$staging/examples/caddy/" cp examples/nginx/witryna.conf "$staging/examples/nginx/" cp examples/witryna.yaml "$staging/examples/" cp examples/systemd/docker.conf "$staging/examples/systemd/" cp examples/systemd/podman.conf "$staging/examples/systemd/" tar -czf "target/tarball/${name}.tar.gz" -C target/tarball "$name" echo "target/tarball/${name}.tar.gz" # Upload deb to release server release-deb: build-deb #!/usr/bin/env bash set -euo pipefail f=$(find target/debian -name 'witryna_*.deb' | sort -V | tail -1) if [[ -z "$f" ]]; then echo "No .deb found" >&2; exit 1; fi sha256sum "$f" > "${f}.sha256" scp "$f" "${f}.sha256" "{{RELEASE_HOST}}:{{RELEASE_PATH}}/" echo "Done — https://release.craftknight.com/" # Upload rpm to release server release-rpm: build-rpm #!/usr/bin/env bash set -euo pipefail f=$(find target/generate-rpm -name 'witryna-*.rpm' | sort -V | tail -1) if [[ -z "$f" ]]; then echo "No .rpm found" >&2; exit 1; fi sha256sum "$f" > "${f}.sha256" scp "$f" "${f}.sha256" "{{RELEASE_HOST}}:{{RELEASE_PATH}}/" echo "Done — https://release.craftknight.com/" # Upload tarball to release server release-tarball: build-tarball #!/usr/bin/env bash set -euo pipefail f=$(find target/tarball -name 'witryna-*.tar.gz' | sort -V | tail -1) if [[ -z "$f" ]]; then echo "No tarball found" >&2; exit 1; fi sha256sum "$f" > "${f}.sha256" scp "$f" "${f}.sha256" "{{RELEASE_HOST}}:{{RELEASE_PATH}}/" echo "Done — https://release.craftknight.com/" # Build and upload all packages (deb + rpm + tarball) release: release-deb release-rpm release-tarball # --- Pre-commit --- # Run all pre-commit checks (mirrors lefthook) pre-commit: lint test