169 lines
7.3 KiB
Bash
Executable File
169 lines
7.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# verify.sh — GuruRMM local pre-merge verification.
|
|
# Builds/checks a component the SAME way the server-side pipeline does, so you don't
|
|
# merge code that fails the post-merge build on .30. Does NOT trigger the production
|
|
# build (that's the webhook on push to main) — this is the local gate only.
|
|
#
|
|
# Usage:
|
|
# bash verify.sh server [--check] # SQLX_OFFLINE cargo build (or check) + .sqlx freshness warning
|
|
# bash verify.sh agent [--check] # cargo build (or check) + per-OS compile-gate warning
|
|
# bash verify.sh dashboard # npm install + npm run build
|
|
# bash verify.sh all [--check] # server + agent + dashboard
|
|
# bash verify.sh migrations # report highest migration number + any duplicate numbers
|
|
#
|
|
# See: projects/msp-tools/guru-rmm/docs/BUILD.md
|
|
# projects/msp-tools/guru-rmm/deploy/build-pipeline/README.md
|
|
|
|
set -uo pipefail
|
|
|
|
# Resolve repo root (4 levels up: .claude/skills/gururmm-build/scripts/ -> repo root).
|
|
CLAUDETOOLS_ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)}"
|
|
REPO_DIR="$CLAUDETOOLS_ROOT/projects/msp-tools/guru-rmm"
|
|
|
|
_logerr() { bash "$CLAUDETOOLS_ROOT/.claude/scripts/log-skill-error.sh" "gururmm-build" "$@" >/dev/null 2>&1 || true; }
|
|
|
|
# ASCII markers (no emojis — fleet rule).
|
|
OK="[OK]"; ERR="[ERROR]"; WARN="[WARNING]"; INFO="[INFO]"
|
|
|
|
die() { echo "$ERR $*" >&2; _logerr "$*"; exit 1; }
|
|
|
|
[ -d "$REPO_DIR" ] || die "guru-rmm checkout not found at $REPO_DIR (submodule not initialized?)"
|
|
|
|
# Host OS family.
|
|
case "$(uname -s 2>/dev/null)" in
|
|
Linux*) OS=linux ;;
|
|
Darwin*) OS=mac ;;
|
|
MINGW*|MSYS*|CYGWIN*) OS=windows ;;
|
|
*) OS=unknown ;;
|
|
esac
|
|
|
|
CMD="${1:-}"; shift || true
|
|
MODE="build"
|
|
for a in "$@"; do
|
|
case "$a" in
|
|
--check) MODE="check" ;;
|
|
*) die "unknown flag: $a" ;;
|
|
esac
|
|
done
|
|
[ -n "$CMD" ] || die "usage: verify.sh {server|agent|dashboard|all|migrations} [--check]"
|
|
|
|
have() { command -v "$1" >/dev/null 2>&1; }
|
|
|
|
# Names of files changed vs origin/main (committed) + uncommitted, restricted to a path prefix.
|
|
changed_under() {
|
|
local prefix="$1"
|
|
{
|
|
git -C "$REPO_DIR" diff --name-only origin/main...HEAD -- "$prefix" 2>/dev/null
|
|
git -C "$REPO_DIR" status --porcelain -- "$prefix" 2>/dev/null | awk '{print $2}'
|
|
} | sort -u
|
|
}
|
|
|
|
verify_server() {
|
|
echo "$INFO === server: $MODE (host=$OS) ==="
|
|
have cargo || die "cargo not on PATH — install the Rust toolchain to verify server"
|
|
|
|
# sqlx offline-cache freshness: the server build runs SQLX_OFFLINE=true against
|
|
# server/.sqlx. If server/ Rust changed but .sqlx did not, the build can fail on a
|
|
# cache mismatch — warn loudly (not fatal; queries may be unchanged).
|
|
local srv_rs srv_sqlx
|
|
srv_rs=$(changed_under "server" | grep -E '\.rs$' | wc -l | tr -d ' ')
|
|
srv_sqlx=$(changed_under "server/.sqlx" | wc -l | tr -d ' ')
|
|
if [ "$srv_rs" -gt 0 ] && [ "$srv_sqlx" -eq 0 ]; then
|
|
echo "$WARN server/*.rs changed but server/.sqlx was not regenerated."
|
|
echo "$WARN If you added/changed SQL queries or migrations, run (in server/, DB reachable):"
|
|
echo "$WARN cargo sqlx prepare && git add server/.sqlx && git commit"
|
|
echo "$WARN Otherwise the post-merge server build may fail on the offline cache."
|
|
fi
|
|
|
|
local sub="build --release"; [ "$MODE" = check ] && sub="check"
|
|
( cd "$REPO_DIR/server" && SQLX_OFFLINE=true cargo $sub )
|
|
local rc=$?
|
|
[ $rc -eq 0 ] || { _logerr "server cargo $sub failed (rc=$rc)" --context "os=$OS"; echo "$ERR server $MODE FAILED (rc=$rc)"; return 1; }
|
|
echo "$OK server $MODE passed"
|
|
}
|
|
|
|
verify_agent() {
|
|
echo "$INFO === agent: $MODE (host=$OS) ==="
|
|
have cargo || die "cargo not on PATH — install the Rust toolchain to verify agent"
|
|
|
|
# Compile-gate warning: platform-gated code is only verified on its own OS.
|
|
if [ "$OS" = windows ]; then
|
|
echo "$WARN On Windows, cargo cannot verify Linux-gated agent code (#[cfg(target_os=\"linux\")];"
|
|
echo "$WARN openssl-sys won't cross-build). The Linux agent build on .30 is the real gate —"
|
|
echo "$WARN build on Linux too, or watch /var/log/gururmm-build-linux.log after merge."
|
|
elif [ "$OS" = linux ]; then
|
|
echo "$INFO Linux host: this gates Linux + cross-platform agent code. Windows-only paths"
|
|
echo "$INFO (MSI/tray/legacy/x86) are gated only by the Beast/Pluto Windows build."
|
|
fi
|
|
|
|
local sub="build --release"; [ "$MODE" = check ] && sub="check"
|
|
( cd "$REPO_DIR/agent" && cargo $sub )
|
|
local rc=$?
|
|
[ $rc -eq 0 ] || { _logerr "agent cargo $sub failed (rc=$rc)" --context "os=$OS"; echo "$ERR agent $MODE FAILED (rc=$rc)"; return 1; }
|
|
echo "$OK agent $MODE passed (host-OS gate only — see compile-gate warning)"
|
|
}
|
|
|
|
verify_dashboard() {
|
|
echo "$INFO === dashboard: build (host=$OS) ==="
|
|
have npm || die "npm not on PATH — install Node to verify dashboard"
|
|
# 'npm install' (not ci): tolerates the package.json version-bump skew the pipeline makes.
|
|
( cd "$REPO_DIR/dashboard" && npm install --no-audit --no-fund && npm run build )
|
|
local rc=$?
|
|
[ $rc -eq 0 ] || { _logerr "dashboard npm build failed (rc=$rc)" --context "os=$OS"; echo "$ERR dashboard build FAILED (rc=$rc)"; return 1; }
|
|
[ -f "$REPO_DIR/dashboard/dist/index.html" ] || { _logerr "dashboard build produced no dist/index.html"; echo "$ERR dashboard build produced no dist/index.html"; return 1; }
|
|
echo "$OK dashboard build passed (dist/index.html present)"
|
|
}
|
|
|
|
check_migrations() {
|
|
echo "$INFO === migrations: numbering check ==="
|
|
local mdir=""
|
|
for cand in "server/migrations" "migrations"; do
|
|
[ -d "$REPO_DIR/$cand" ] && { mdir="$REPO_DIR/$cand"; break; }
|
|
done
|
|
[ -n "$mdir" ] || die "no migrations directory found (looked for server/migrations, migrations)"
|
|
echo "$INFO migrations dir: ${mdir#$REPO_DIR/}"
|
|
|
|
# Highest NNN prefix and any duplicate numbers.
|
|
local nums
|
|
nums=$(ls -1 "$mdir" 2>/dev/null | grep -E '^[0-9]+_' | sed -E 's/^([0-9]+)_.*/\1/' | sort)
|
|
[ -n "$nums" ] || { echo "$WARN no NNN_ migrations found in $mdir"; return 0; }
|
|
|
|
local highest next dupes
|
|
highest=$(printf '%s\n' "$nums" | tail -1)
|
|
next=$(printf '%03d' $((10#$highest + 1)))
|
|
echo "$OK highest migration on this checkout: $highest -> next free number: $next"
|
|
|
|
dupes=$(printf '%s\n' "$nums" | uniq -d)
|
|
if [ -n "$dupes" ]; then
|
|
echo "$ERR duplicate migration number(s) detected: $dupes"
|
|
printf '%s\n' "$dupes" | while read -r d; do
|
|
ls -1 "$mdir" | grep -E "^${d}_" | sed "s/^/$ERR /"
|
|
done
|
|
_logerr "duplicate migration number(s): $dupes"
|
|
return 1
|
|
fi
|
|
echo "$INFO Before naming a new migration, also check the highest number on origin/main"
|
|
echo "$INFO (another branch may have claimed $next): git fetch && ls $(printf '%s' "${mdir#$REPO_DIR/}")"
|
|
}
|
|
|
|
rc=0
|
|
case "$CMD" in
|
|
server) verify_server || rc=1 ;;
|
|
agent) verify_agent || rc=1 ;;
|
|
dashboard) verify_dashboard || rc=1 ;;
|
|
migrations) check_migrations || rc=1 ;;
|
|
all)
|
|
verify_server || rc=1
|
|
verify_agent || rc=1
|
|
verify_dashboard || rc=1
|
|
;;
|
|
*) die "unknown component: $CMD (use server|agent|dashboard|all|migrations)" ;;
|
|
esac
|
|
|
|
if [ $rc -eq 0 ]; then
|
|
echo "$OK verify.sh $CMD: PASS"
|
|
else
|
|
echo "$ERR verify.sh $CMD: FAIL"
|
|
fi
|
|
exit $rc
|