|
4 | 4 | # Runs unit tests (with -short to skip integration tests) for each Go service |
5 | 5 | # and fails if any service falls below the minimum coverage threshold. |
6 | 6 | # |
| 7 | +# Exclusions are read from codecov.yml (single source of truth). |
| 8 | +# This script converts codecov glob patterns to grep filters applied to |
| 9 | +# Go coverprofiles, so both Codecov and this script enforce the same rules. |
| 10 | +# |
7 | 11 | # Usage: |
8 | 12 | # ./scripts/check-service-coverage.sh |
9 | 13 | # |
10 | 14 | # Environment variables: |
11 | | -# COVERAGE_THRESHOLD Minimum coverage % required per service (default: 70) |
| 15 | +# COVERAGE_THRESHOLD Minimum coverage % required per service (default: 80) |
12 | 16 |
|
13 | 17 | set -euo pipefail |
14 | 18 |
|
15 | 19 | REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
16 | | -THRESHOLD="${COVERAGE_THRESHOLD:-70}" |
| 20 | +THRESHOLD="${COVERAGE_THRESHOLD:-80}" |
17 | 21 | TMPDIR="${TMPDIR:-/tmp}" |
18 | 22 |
|
19 | | -# Validate THRESHOLD is a non-negative integer in range 0–100 |
| 23 | +# Validate THRESHOLD is a non-negative integer in range 0-100 |
20 | 24 | if ! [[ "${THRESHOLD}" =~ ^[0-9]+$ ]] || [ "${THRESHOLD}" -gt 100 ]; then |
21 | 25 | echo "ERROR: COVERAGE_THRESHOLD must be an integer between 0 and 100 (got: '${THRESHOLD}')" >&2 |
22 | 26 | exit 1 |
23 | 27 | fi |
24 | 28 |
|
| 29 | +# Build exclude pattern from codecov.yml (single source of truth for exclusions). |
| 30 | +# See scripts/codecov-exclude-pattern.sh for the glob-to-grep conversion logic. |
| 31 | +EXCLUDE_PATTERN="" |
| 32 | +exclude_script="${REPO_ROOT}/scripts/codecov-exclude-pattern.sh" |
| 33 | +if [ -x "${exclude_script}" ]; then |
| 34 | + if exclude=$("${exclude_script}"); then |
| 35 | + EXCLUDE_PATTERN="${exclude}" |
| 36 | + echo "Exclude pattern (from codecov.yml): ${EXCLUDE_PATTERN}" |
| 37 | + else |
| 38 | + echo "WARNING: Failed to read exclusions from codecov.yml" |
| 39 | + fi |
| 40 | +else |
| 41 | + echo "WARNING: ${exclude_script} not found, running without exclusions" |
| 42 | +fi |
| 43 | + |
25 | 44 | FAILED=0 |
26 | 45 | PASSED=0 |
27 | 46 | SKIPPED=0 |
28 | 47 |
|
| 48 | +echo "" |
29 | 49 | echo "Per-service Go coverage check (threshold: ${THRESHOLD}%)" |
30 | 50 | echo "Using -short flag to skip integration tests" |
31 | 51 | echo "" |
@@ -70,13 +90,25 @@ for service_dir in "${REPO_ROOT}"/services/*/; do |
70 | 90 | continue |
71 | 91 | fi |
72 | 92 |
|
73 | | - if ! coverage="$(go tool cover -func="${coverage_file}" | awk '/^total:/ { gsub(/%/, "", $3); print $3 }')"; then |
| 93 | + # Filter coverprofile using exclusions derived from codecov.yml |
| 94 | + target_file="${coverage_file}" |
| 95 | + if [ -n "${EXCLUDE_PATTERN}" ]; then |
| 96 | + filtered_file="${TMPDIR}/meridian_coverage_${service}_filtered.out" |
| 97 | + head -1 "${coverage_file}" > "${filtered_file}" |
| 98 | + tail -n +2 "${coverage_file}" \ |
| 99 | + | grep -v -E "${EXCLUDE_PATTERN}" \ |
| 100 | + >> "${filtered_file}" || true |
| 101 | + rm -f "${coverage_file}" |
| 102 | + target_file="${filtered_file}" |
| 103 | + fi |
| 104 | + |
| 105 | + if ! coverage="$(go tool cover -func="${target_file}" | awk '/^total:/ { gsub(/%/, "", $3); print $3 }')"; then |
74 | 106 | echo " SKIP ${service} (cover command failed)" |
75 | 107 | SKIPPED=$((SKIPPED + 1)) |
76 | | - rm -f "${coverage_file}" |
| 108 | + rm -f "${target_file}" |
77 | 109 | continue |
78 | 110 | fi |
79 | | - rm -f "${coverage_file}" |
| 111 | + rm -f "${target_file}" |
80 | 112 |
|
81 | 113 | if [ -z "${coverage}" ]; then |
82 | 114 | echo " SKIP ${service} (could not parse coverage)" |
|
0 commit comments