clawdie-ai/scripts/write-test-build-status.sh
Operator & Codex 17746bb98b Fix test status stamping
---
Build: pass | Tests: pass — 2380 passed (175 files)
2026-05-11 08:38:02 +02:00

146 lines
4.2 KiB
Bash
Executable file

#!/bin/sh
# write-test-build-status: run the project's build and test commands and
# persist their outcome as JSON for the structured /testreport.
#
# Usage:
# scripts/write-test-build-status.sh # run both
# scripts/write-test-build-status.sh build # run build only
# scripts/write-test-build-status.sh tests # run tests only
#
# Status dir resolves to $AGENT_STATUS_DIR, then the legacy $CLAWDIE_VAR_DIR,
# and otherwise defaults to the repo-local tmp/status directory, matching
# getDefaultStatusDir() in src/reports/test-report.ts.
set -u
REPO_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$REPO_ROOT"
STATUS_DIR=${AGENT_STATUS_DIR:-${CLAWDIE_VAR_DIR:-"$REPO_ROOT/tmp/status"}}
mkdir -p "$STATUS_DIR"
TMP_DIR="$REPO_ROOT/tmp/test-build-status"
mkdir -p "$TMP_DIR"
BUILD_PATH="$STATUS_DIR/build-status.json"
TEST_PATH="$STATUS_DIR/test-status.json"
iso_now() {
# GNU date supports -Iseconds; BSD date does not. Fall back to printf.
date -u +"%Y-%m-%dT%H:%M:%SZ"
}
write_status() {
out_path=$1
status=$2
command=$3
exit_code=$4
duration_ms=$5
extra=$6
completed_at=$(iso_now)
# Use node to encode JSON safely.
node -e '
const fs = require("fs");
const [outPath, status, command, exitCode, durationMs, completedAt, extraJson] =
process.argv.slice(1);
let payload = {
status,
command,
exitCode: Number(exitCode),
completedAt,
durationMs: Number(durationMs),
};
if (extraJson) {
try { payload = { ...payload, ...JSON.parse(extraJson) }; } catch {}
}
fs.writeFileSync(outPath, JSON.stringify(payload, null, 2) + "\n");
' "$out_path" "$status" "$command" "$exit_code" "$duration_ms" "$completed_at" "$extra"
}
run_build() {
cmd="npm run build --silent"
start=$(date +%s)
log_file="$TMP_DIR/build-$$.log"
rm -f "$log_file"
# shellcheck disable=SC2086
$cmd >"$log_file" 2>&1
exit_code=$?
end=$(date +%s)
duration_ms=$(( (end - start) * 1000 ))
status="ok"
[ "$exit_code" -ne 0 ] && status="fail"
summary=$(tail -n 1 "$log_file" | tr -d '\r')
extra=$(node -e '
const summary = process.argv[1] || "";
process.stdout.write(JSON.stringify({ summary }));
' "$summary")
write_status "$BUILD_PATH" "$status" "$cmd" "$exit_code" "$duration_ms" "$extra"
rm -f "$log_file"
echo "build: $status (exit $exit_code, ${duration_ms}ms) -> $BUILD_PATH"
return "$exit_code"
}
run_tests() {
json_file="$TMP_DIR/tests-$$.json"
rm -f "$json_file"
cmd="npx vitest run"
start=$(date +%s)
npx vitest run --reporter=json --outputFile="$json_file" >/dev/null 2>&1
exit_code=$?
end=$(date +%s)
duration_ms=$(( (end - start) * 1000 ))
status="ok"
[ "$exit_code" -ne 0 ] && status="fail"
extra=$(node -e '
const fs = require("fs");
const path = process.argv[1];
let raw;
try { raw = fs.readFileSync(path, "utf8"); } catch { process.stdout.write("{}"); process.exit(0); }
let parsed;
try { parsed = JSON.parse(raw); } catch { process.stdout.write("{}"); process.exit(0); }
const total = parsed.numTotalTests ?? 0;
const totalFiles = parsed.testResults?.length ?? parsed.numTotalTestSuites ?? 0;
const failing = parsed.numFailedTests ?? 0;
const skipped = parsed.numPendingTests ?? 0;
const failingNames = [];
for (const file of parsed.testResults || []) {
for (const t of file.assertionResults || []) {
if (t.status === "failed") {
const ancestors = (t.ancestorTitles || []).join(" > ");
failingNames.push(ancestors ? `${ancestors} > ${t.title}` : t.title);
}
}
}
process.stdout.write(JSON.stringify({
totalTests: total,
totalFiles,
failingTests: failing,
skippedTests: skipped,
failingTestNames: failingNames,
}));
' "$json_file")
write_status "$TEST_PATH" "$status" "$cmd" "$exit_code" "$duration_ms" "$extra"
rm -f "$json_file"
echo "tests: $status (exit $exit_code, ${duration_ms}ms) -> $TEST_PATH"
return "$exit_code"
}
target=${1:-both}
rc=0
case "$target" in
build)
run_build || rc=$?
;;
tests|test)
run_tests || rc=$?
;;
both|"")
run_build || rc=$?
run_tests || rc=$?
;;
*)
echo "usage: $0 [build|tests|both]" >&2
exit 2
;;
esac
exit "$rc"