#!/usr/bin/env bash # Local verification: runs the same fast checks as CI before pushing. # # scripts/check.sh fast (~1 min): fmt, clippy, i18n, scripts, workflows, semver # scripts/check.sh --full also runs workspace tests and cargo audit # # CI takes 5 to 30 minutes per run; almost everything that breaks CI is caught # here in seconds. set -uo pipefail cd "$(dirname "$0")/.." full=0 [ "${1:-}" = "--full" ] || [ "${1:-}" = "--completo" ] && full=1 failures=() step() { # step "name" command... local name="$1"; shift printf '\n\033[1m== %s\033[0m\n' "$name" if "$@"; then printf '\033[32mok\033[0m %s\n' "$name"; else printf '\033[31mFAILED\033[0m %s\n' "$name"; failures+=("$name"); fi } step "formatting (cargo fmt)" cargo fmt --all -- --check # Same flags as CI: warnings are treated as errors across all targets, including tests step "clippy (workspace, all targets)" env RUSTFLAGS="-D warnings" cargo clippy --workspace --all-targets step "UI translation coverage" node scripts/check-ui-i18n.mjs step "bash script syntax" bash -c 'for f in scripts/*.sh .githooks/*; do bash -n "$f" || exit 1; done' step "workflows and templates (valid YAML)" python3 -c " import glob, yaml for f in glob.glob('.gitea/**/*.yml', recursive=True): yaml.safe_load(open(f)) " step "consistent Semantic Versioning 2.0.0" python3 -c " import json, re, sys from pathlib import Path semver_re = re.compile( r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)' r'(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?' r'(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$' ) def cargo_version(path): m = re.search(r'^version\s*=\s*\"([^\"]+)\"', Path(path).read_text(), re.M) if not m: sys.exit(f'version not found in {path}') return m.group(1) versions = [ cargo_version('Cargo.toml'), cargo_version('apps/gui/src-tauri/Cargo.toml'), json.load(open('apps/gui/src-tauri/tauri.conf.json'))['version'], ] if len(set(versions)) != 1: sys.exit(f'version mismatch: Cargo.toml={versions[0]}, src-tauri={versions[1]}, tauri.conf={versions[2]}') if not semver_re.match(versions[0]): sys.exit(f'invalid SemVer 2.0.0 version: {versions[0]}') print(versions[0]) " if [ -f apps/gui/src-tauri/Cargo.toml ] && pkg-config --exists webkit2gtk-4.1 2>/dev/null; then step "desktop app (cargo check)" env RUSTFLAGS="" cargo check --manifest-path apps/gui/src-tauri/Cargo.toml else printf '\n(desktop app: skipped, WebKitGTK development libraries not installed; built in CI)\n' fi if [ "$full" = 1 ]; then step "tests (cargo test --workspace)" cargo test --workspace step "dependency audit (cargo audit)" cargo audit fi printf '\n' if [ ${#failures[@]} -eq 0 ]; then printf '\033[32mall checks passed\033[0m: ready to push.\n' else printf '\033[31mfailed:\033[0m %s\n' "${failures[*]}" exit 1 fi