5c50742a61
`scripts/ci.sh` is the source of truth for what must pass before a PR is mergeable. CLAUDE.md section 10.4 requires the Gitea workflow to run the same checks; the workflow calls this script rather than reimplementing the steps, so the two cannot drift apart. Runs: cargo fmt --check, clippy -D warnings, cargo test, the section 5 size gate, Android lint/assembleRelease, and a gitleaks scan. Verified behaviour, rather than assumed: - **Failures really fail.** Injected a syntax error into `core/src/lib.rs` and confirmed `ci.sh --keep-going` exits 1 and names all four dependent checks; then restored the file and confirmed a clean exit 0. `--keep-going` captures failures per step in a subshell instead of letting `set -e` abort the run, so the summary records what already passed. - **Skips are never passes.** Android and gitleaks both skip on this machine (no SDK, no gitleaks), and each SKIP names what was skipped and why, with the summary listing them separately from the passes. A skip that reads as a green tick is how CI quietly stops testing anything. - **Runs from any CWD.** `cargo` resolves a workspace from the CWD, not from the script's location, so `ci.sh` cds to the repo root. Verified by running it from `/tmp`. - **`cargo` is on PATH.** rustup adds `~/.cargo/bin` via `~/.bashrc`, which a non-interactive shell does not read — so a script invoked from CI or by absolute path failed with "command not found" until `lib.sh` prepends it. - **Size gate resolves absolute paths.** `CARGO_TARGET_DIR` is absolute by default, so joining it onto the repo root produced a doubled path; the default is now only joined when relative. Build artifacts go to `$HOME/.blocker-target`, outside the repo, so `target/` never appears in `git status` and can be deleted in one command. Co-Authored-By: Claude Code <noreply@anthropic.com>
44 lines
1.8 KiB
Bash
Executable File
44 lines
1.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Size gate: fail if the stripped release daemon exceeds the section 5 budget.
|
|
#
|
|
# Usage: size-check.sh [binary-path] [max-bytes]
|
|
#
|
|
# Kept separate from ci.sh so the Gitea workflow can run it as its own step
|
|
# against an artifact it has already built, rather than rebuilding.
|
|
|
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/lib.sh"
|
|
|
|
# Default binary path. CARGO_TARGET_DIR may be absolute (the usual case — it
|
|
# points outside the repo) or relative, so it must not be blindly joined onto
|
|
# REPO_ROOT: doing that turns "/home/sp/.blocker-target/..." into
|
|
# "/home/sp/blocker//home/sp/.blocker-target/...".
|
|
DEFAULT_TARGET="${CARGO_TARGET_DIR:-${HOME}/.blocker-target}"
|
|
if [[ "${DEFAULT_TARGET}" = /* ]]; then
|
|
DEFAULT_BINARY="${DEFAULT_TARGET}/release/blocker-daemon"
|
|
else
|
|
DEFAULT_BINARY="${REPO_ROOT}/${DEFAULT_TARGET}/release/blocker-daemon"
|
|
fi
|
|
|
|
BINARY="${1:-${DEFAULT_BINARY}}"
|
|
MAX_BYTES="${2:-${MAX_DAEMON_BYTES}}"
|
|
|
|
# Normalise so the message shows the real path rather than a doubled prefix.
|
|
BINARY="$(cd -- "$(dirname -- "${BINARY}")" 2>/dev/null && pwd)/$(basename -- "${BINARY}")" \
|
|
|| die "binary not found: ${BINARY}"
|
|
|
|
SIZE="$(stat -c %s "${BINARY}" 2>/dev/null || stat -f %z "${BINARY}")"
|
|
|
|
# Human-readable, using 1024-based units to match how the budget is written.
|
|
printf 'binary : %s\n' "${BINARY}"
|
|
printf 'size : %s bytes (%d.%03d MB)\n' \
|
|
"${SIZE}" "$((SIZE / 1048576))" "$(((SIZE % 1048576) * 1000 / 1048576))"
|
|
printf 'budget : %s bytes (%d MB)\n' "${MAX_BYTES}" "$((MAX_BYTES / 1048576))"
|
|
|
|
if (( SIZE > MAX_BYTES )); then
|
|
printf '%sOVER BUDGET by %s bytes%s\n' "${C_RED}" "$((SIZE - MAX_BYTES))" "${C_RESET}"
|
|
exit 1
|
|
fi
|
|
|
|
printf '%swithin budget, %s bytes headroom%s\n' \
|
|
"${C_GREEN}" "$((MAX_BYTES - SIZE))" "${C_RESET}" |