Skip to content

Commit 8a84948

Browse files
committed
ci: merge coverage into one report; fix Api assembly exclusion
1 parent 8419186 commit 8a84948

2 files changed

Lines changed: 31 additions & 54 deletions

File tree

DocAnalytics.Api/Program.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Diagnostics.CodeAnalysis;
21
using System.Text.Json;
32
using System.Threading.RateLimiting;
43
using DocAnalytics.Api.Auth; // JwtSettings
@@ -19,7 +18,6 @@
1918
using DocAnalytics.Service.Realtime;
2019
using Microsoft.Extensions.Options;
2120

22-
[assembly: ExcludeFromCodeCoverage]
2321

2422

2523
var builder = WebApplication.CreateBuilder(args);

scripts/coverage-gate.sh

Lines changed: 31 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ FLOOR_API=22
88

99
ROOT="$(pwd)"
1010
OUT="$ROOT/coverage-out"
11-
mkdir -p "$OUT"
11+
rm -rf "$OUT"; mkdir -p "$OUT"
1212

1313
echo "== Restore local tools (ReportGenerator) =="
1414
dotnet tool restore
@@ -21,69 +21,48 @@ run_test () {
2121
--configuration Release \
2222
--collect:"XPlat Code Coverage" \
2323
--settings coverage.runsettings \
24-
--results-directory "$dir" \
25-
--logger "trx;LogFileName=$name.trx"
24+
--results-directory "$dir"
2625
}
2726

2827
run_test "DocAnalytics.Domain.Tests/DocAnalytics.Domain.Tests.csproj" "domain"
2928
run_test "DocAnalytics.Data.Tests/DocAnalytics.Data.Tests.csproj" "data"
3029
run_test "DocAnalytics.Service.Tests/DocAnalytics.Service.Tests.csproj" "service"
3130
run_test "DocAnalytics.Api.Tests/DocAnalytics.Api.Tests.csproj" "api"
3231

33-
find_cobertura () { find "$OUT/$1" -type f -name "coverage.cobertura.xml" | head -n 1; }
32+
mapfile -t COBS < <(find "$OUT" -type f -name "coverage.cobertura.xml")
33+
if [[ ${#COBS[@]} -eq 0 ]]; then
34+
echo "ERROR: no cobertura files found"; exit 2
35+
fi
36+
REPORTS=$(IFS=';'; echo "${COBS[*]}")
37+
echo "== Merging ${#COBS[@]} coverage files into one report =="
3438

35-
gen_summary () {
36-
local name="$1"; local cobertura="$2"; local target="$OUT/summary-$name"
37-
mkdir -p "$target"
38-
dotnet reportgenerator \
39-
"-reports:$cobertura" \
40-
"-targetdir:$target" \
41-
"-reporttypes:JsonSummary" \
42-
"-verbosity:Error" >/dev/null
43-
}
44-
45-
for layer in domain data service api; do
46-
cov="$(find_cobertura "$layer")"
47-
if [[ -z "${cov:-}" ]]; then
48-
echo "ERROR: no coverage.cobertura.xml for $layer"; exit 2
49-
fi
50-
gen_summary "$layer" "$cov"
51-
done
39+
dotnet reportgenerator \
40+
"-reports:$REPORTS" \
41+
"-targetdir:$OUT/summary" \
42+
"-reporttypes:JsonSummary" \
43+
"-verbosity:Error" >/dev/null
5244

5345
echo "== Coverage gate (per-assembly line %) =="
54-
python3 - "$OUT" "$FLOOR_SERVICE" "$FLOOR_DOMAIN" "$FLOOR_DATA" "$FLOOR_API" <<'PY'
55-
import json, os, sys
56-
out = sys.argv[1]
57-
targets = {
58-
"service": ("DocAnalytics.Service", float(sys.argv[2])),
59-
"domain": ("DocAnalytics.Domain", float(sys.argv[3])),
60-
"data": ("DocAnalytics.Data", float(sys.argv[4])),
61-
"api": ("DocAnalytics.Api", float(sys.argv[5])),
46+
python3 - "$OUT/summary/Summary.json" "$FLOOR_SERVICE" "$FLOOR_DOMAIN" "$FLOOR_DATA" "$FLOOR_API" <<'PY'
47+
import json, sys
48+
with open(sys.argv[1]) as f:
49+
doc = json.load(f)
50+
floors = {
51+
"DocAnalytics.Service": float(sys.argv[2]),
52+
"DocAnalytics.Domain": float(sys.argv[3]),
53+
"DocAnalytics.Data": float(sys.argv[4]),
54+
"DocAnalytics.Api": float(sys.argv[5]),
6255
}
63-
64-
def asm_cov(report_name, asm_name):
65-
p = os.path.join(out, f"summary-{report_name}", "Summary.json")
66-
with open(p) as f:
67-
doc = json.load(f)
68-
for a in doc.get("coverage", {}).get("assemblies", []):
69-
if a.get("name") == asm_name:
70-
if a.get("coverage") is not None:
71-
return float(a["coverage"])
72-
cl = a.get("coveredlines", 0); cov = a.get("coverablelines", 0)
73-
return (100.0 * cl / cov) if cov else 0.0
74-
return None
75-
56+
asms = { a["name"]: a for a in doc.get("coverage", {}).get("assemblies", []) }
7657
fail = False
77-
for rep, (asm, floor) in targets.items():
78-
lc = asm_cov(rep, asm)
79-
if lc is None:
80-
print(f"{rep:8} assembly {asm} NOT FOUND -> FAIL")
81-
fail = True
82-
continue
58+
for name, floor in floors.items():
59+
a = asms.get(name)
60+
if a is None:
61+
print(f"{name:22} NOT FOUND -> FAIL"); fail = True; continue
62+
lc = float(a["coverage"]) if a.get("coverage") is not None else \
63+
(100.0 * a.get("coveredlines", 0) / a["coverablelines"] if a.get("coverablelines") else 0.0)
8364
ok = lc + 1e-9 >= floor
84-
if not ok:
85-
fail = True
86-
print(f"{rep:8} {asm:22} line={lc:6.2f} floor={floor:5.1f} -> {'OK' if ok else 'FAIL'}")
65+
if not ok: fail = True
66+
print(f"{name:22} line={lc:6.2f} floor={floor:5.1f} -> {'OK' if ok else 'FAIL'}")
8767
sys.exit(1 if fail else 0)
8868
PY
89-

0 commit comments

Comments
 (0)