117 lines
3.7 KiB
Bash
Executable File
117 lines
3.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# check_coverage.sh — Check Go project coverage against thresholds
|
|
#
|
|
# Usage:
|
|
# bash scripts/test/check_coverage.sh [min-percentage]
|
|
#
|
|
# Default threshold: 85% (matches Hermes config agent.min_test_coverage)
|
|
#
|
|
# Reads thresholds from:
|
|
# 1. CLI argument (highest priority)
|
|
# 2. tests/quality/coverage_thresholds.tsv (per-package thresholds)
|
|
# 3. Default 85%
|
|
#
|
|
# Output:
|
|
# - Coverage report (stdout)
|
|
# - Exit code 1 if any package below threshold
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
DEFAULT_THRESHOLD="${1:-85}"
|
|
THRESHOLD_FILE="${PROJECT_DIR}/tests/quality/coverage_thresholds.tsv"
|
|
|
|
echo "==> coverage threshold: ${DEFAULT_THRESHOLD}%"
|
|
|
|
# Collect coverage
|
|
cd "$PROJECT_DIR"
|
|
COVERAGE_OUT=$(mktemp)
|
|
go test -count=1 -cover ./internal/... 2>&1 | tee "$COVERAGE_OUT"
|
|
|
|
# Check per-package thresholds from file if exists
|
|
HAS_FILE_THRESHOLDS=false
|
|
declare -A PACKAGE_THRESHOLDS
|
|
if [[ -f "$THRESHOLD_FILE" ]]; then
|
|
HAS_FILE_THRESHOLDS=true
|
|
while IFS=$'\t' read -r pkg threshold; do
|
|
[[ -z "$pkg" || "$pkg" == \#* ]] && continue
|
|
PACKAGE_THRESHOLDS["$pkg"]="$threshold"
|
|
done < "$THRESHOLD_FILE"
|
|
fi
|
|
|
|
# Parse and validate
|
|
EXIT_CODE=0
|
|
declare -a FAILURES=()
|
|
CURRENT_PKG=""
|
|
TOTAL_PKG=0
|
|
PASS_PKG=0
|
|
|
|
parse_coverage_line() {
|
|
local line="$1"
|
|
# Match: ok github.com/xxx/sub2api-cn-relay-manager/internal/provision 0.012s coverage: 82.8% of statements
|
|
# Match: ? github.com/xxx/sub2api-cn-relay-manager/internal/provision [no test files]
|
|
if [[ "$line" =~ ^ok[[:space:]]+.*/[^[:space:]]+[[:space:]]+[0-9.]+s[[:space:]]+coverage:[[:space:]]+([0-9.]+)% ]]; then
|
|
local pct="${BASH_REMATCH[1]}"
|
|
local pkg_name
|
|
pkg_name=$(echo "$line" | awk '{print $2}' | awk -F'/' '{print $NF}')
|
|
local threshold="$DEFAULT_THRESHOLD"
|
|
if $HAS_FILE_THRESHOLDS && [[ -n "${PACKAGE_THRESHOLDS[$pkg_name]:-}" ]]; then
|
|
threshold="${PACKAGE_THRESHOLDS[$pkg_name]}"
|
|
fi
|
|
TOTAL_PKG=$((TOTAL_PKG + 1))
|
|
if (( $(echo "$pct < $threshold" | bc -l 2>/dev/null || echo 1) )); then
|
|
FAILURES+=("${pkg_name}: ${pct}% < ${threshold}%")
|
|
EXIT_CODE=1
|
|
else
|
|
PASS_PKG=$((PASS_PKG + 1))
|
|
echo " ✅ ${pkg_name}: ${pct}% (threshold: ${threshold}%)"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
while IFS= read -r line; do
|
|
parse_coverage_line "$line"
|
|
done < "$COVERAGE_OUT"
|
|
|
|
echo ""
|
|
echo "==> summary: ${PASS_PKG}/${TOTAL_PKG} packages pass coverage threshold"
|
|
if [[ ${#FAILURES[@]} -gt 0 ]]; then
|
|
echo "FAILURES:"
|
|
for f in "${FAILURES[@]}"; do
|
|
echo " ❌ $f"
|
|
done
|
|
fi
|
|
|
|
# Optionally generate markdown report
|
|
REPORT_FILE="${COVERAGE_REPORT:-}"
|
|
if [[ -n "$REPORT_FILE" ]]; then
|
|
{
|
|
echo "# Coverage Report ($(date +%Y-%m-%d))"
|
|
echo ""
|
|
echo "| Package | Coverage | Threshold | Status |"
|
|
echo "|---------|----------|-----------|--------|"
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ ^ok[[:space:]]+.*/[^[:space:]]+[[:space:]]+[0-9.]+s[[:space:]]+coverage:[[:space:]]+([0-9.]+)% ]]; then
|
|
pkg=$(echo "$line" | awk '{print $2}' | awk -F'/' '{print $NF}')
|
|
pct="${BASH_REMATCH[1]}"
|
|
threshold="$DEFAULT_THRESHOLD"
|
|
if $HAS_FILE_THRESHOLDS && [[ -n "${PACKAGE_THRESHOLDS[$pkg]:-}" ]]; then
|
|
threshold="${PACKAGE_THRESHOLDS[$pkg]}"
|
|
fi
|
|
status="✅"
|
|
if (( $(echo "$pct < $threshold" | bc -l 2>/dev/null || echo 1) )); then
|
|
status="❌"
|
|
fi
|
|
echo "| ${pkg} | ${pct}% | ${threshold}% | ${status} |"
|
|
fi
|
|
done < "$COVERAGE_OUT"
|
|
echo ""
|
|
echo "**Overall: ${PASS_PKG}/${TOTAL_PKG} passing, exit $([ $EXIT_CODE -eq 0 ] && echo 0 || echo 1)**"
|
|
} > "$REPORT_FILE"
|
|
echo "Report: $REPORT_FILE"
|
|
fi
|
|
|
|
rm -f "$COVERAGE_OUT"
|
|
exit $EXIT_CODE
|