mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-10-26 06:43:15 +08:00
The full Windows leg on the VM stopped at the coverage-map contract and was reported green. Two defects, one hiding the other: - The VM verdict counted the completion marker anywhere in the log. The isolated-venue contract's stubbed entry prints that marker, and a capacity case prints "expected=0 passed=True", so a leg that stopped at a later contract, with no suite run, read as complete. The marker now counts only as the log's last step header, which is where scripts/test.sh prints it; the verdict contract pins the observed shape (14 cases). - Under the native python3 the Windows legs install, the test-impact contracts failed: the coverage-map builder cannot start the leg's bash fakes, the scripts wrote CRLF, and cmp (diffutils) is not installed there. selection.py, coverage-merge.py and coverage-map.py now write LF on every host, so their outputs are byte-identical across platforms; the two cmp checks compare bytes in the shell; the builder's functional leg is skipped under a native Windows python with the reason and what was tried (the map is built only by the ubuntu publish job), while both pure-python parser tests still run there. Production was not affected by the CRLF: run-tests-parallel.sh strips CR from the selection and the runner trims its tokens. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
137 lines
5.8 KiB
Python
137 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""coverage-merge.py — the incremental coverage map of a main-branch push.
|
|
|
|
Merges FRESH (coverage-map.py output for the suites the push re-ran, made with
|
|
the new commit's instrumented runner, so its functions.tsv is the new image's
|
|
complete function table) into PREVIOUS (the previous published map):
|
|
|
|
* a suite FRESH ran keeps FRESH's rows exactly;
|
|
* every other suite the new runner still lists is carried from PREVIOUS,
|
|
each row's function ids remapped by (source file, name) onto FRESH's
|
|
table; a function the new image no longer has drops out of the row, and a
|
|
row's status (an incomplete row stays incomplete) is never improved;
|
|
* a PREVIOUS suite the new runner no longer lists is dropped.
|
|
|
|
The merged meta.json names --commit and recounts every suite, so the C reader
|
|
(cbm_coverage_map_metadata_matches) checks it like a full map. When the map was
|
|
observed is not decided here: the producer carries the oldest observation of
|
|
the previous bundle forward, so an incremental map ages out unless a full
|
|
refresh runs (the receipt's 7-day bound).
|
|
|
|
Usage: coverage-merge.py --previous DIR --fresh DIR --suites FILE --commit SHA --out DIR
|
|
Exit: 0 merged · 1 inconsistent inputs · 2 usage.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
SETUP = "*"
|
|
|
|
|
|
def fail(message: str) -> None:
|
|
print(f"coverage-merge: {message}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def read_functions(path: str) -> tuple[dict[int, tuple[str, str]], list[str]]:
|
|
by_id: dict[int, tuple[str, str]] = {}
|
|
lines = []
|
|
with open(path, encoding="utf-8") as handle:
|
|
for line in handle:
|
|
line = line.rstrip("\n")
|
|
if not line:
|
|
continue
|
|
fields = line.split("\t")
|
|
if len(fields) != 3 or not fields[0].isdigit():
|
|
fail(f"malformed function row in {path}: {line!r}")
|
|
by_id[int(fields[0])] = (fields[1], fields[2])
|
|
lines.append(line)
|
|
return by_id, lines
|
|
|
|
|
|
def read_tests(path: str) -> list[tuple[str, str, str, str, list[int]]]:
|
|
rows = []
|
|
with open(path, encoding="utf-8") as handle:
|
|
for line in handle:
|
|
line = line.rstrip("\n")
|
|
if not line:
|
|
continue
|
|
fields = line.split("\t")
|
|
if len(fields) != 4 or ":" not in fields[0]:
|
|
fail(f"malformed test row in {path}: {line!r}")
|
|
suite, test = fields[0].split(":", 1)
|
|
ids = [int(token) for token in fields[3].split()] if fields[3] else []
|
|
rows.append((suite, test, fields[1], fields[2], ids))
|
|
return rows
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
|
|
for flag in ("previous", "fresh", "suites", "commit", "out"):
|
|
parser.add_argument("--" + flag, required=True)
|
|
args = parser.parse_args()
|
|
|
|
_, fresh_lines = read_functions(os.path.join(args.fresh, "functions.tsv"))
|
|
fresh_by_id, _ = read_functions(os.path.join(args.fresh, "functions.tsv"))
|
|
previous_by_id, _ = read_functions(os.path.join(args.previous, "functions.tsv"))
|
|
fresh_ids = {key: ident for ident, key in fresh_by_id.items()}
|
|
with open(os.path.join(args.fresh, "meta.json"), encoding="utf-8") as handle:
|
|
fresh_meta = json.load(handle)
|
|
with open(os.path.join(args.previous, "meta.json"), encoding="utf-8") as handle:
|
|
previous_meta = json.load(handle)
|
|
with open(args.suites, encoding="utf-8") as handle:
|
|
listed = [line.strip() for line in handle if line.strip()]
|
|
|
|
fresh_rows = read_tests(os.path.join(args.fresh, "tests.tsv"))
|
|
previous_rows = read_tests(os.path.join(args.previous, "tests.tsv"))
|
|
rerun = {row[0] for row in fresh_rows}
|
|
if not rerun <= set(listed):
|
|
fail("a re-run suite is not listed by the new runner")
|
|
|
|
merged = [row for row in fresh_rows]
|
|
for suite, test, status, reason, ids in previous_rows:
|
|
if suite in rerun or suite not in listed:
|
|
continue
|
|
mapped = sorted({fresh_ids[previous_by_id[i]] for i in ids
|
|
if i in previous_by_id and previous_by_id[i] in fresh_ids})
|
|
merged.append((suite, test, status, reason, mapped))
|
|
merged.sort(key=lambda row: (row[0], row[1]))
|
|
|
|
suite_meta = {entry["suite"]: entry for entry in previous_meta.get("suites", [])}
|
|
for entry in fresh_meta.get("suites", []):
|
|
suite_meta[entry["suite"]] = entry
|
|
counts: dict[str, list[int]] = {}
|
|
for suite, test, status, _, _ in merged:
|
|
tally = counts.setdefault(suite, [0, 0])
|
|
if test != SETUP:
|
|
tally[0] += 1
|
|
tally[1] += status != "complete"
|
|
suites = []
|
|
for suite in sorted(counts):
|
|
entry = dict(suite_meta.get(suite, {"suite": suite, "exit": 0}))
|
|
entry["tests"], entry["incomplete"] = counts[suite]
|
|
suites.append(entry)
|
|
|
|
os.makedirs(args.out, exist_ok=True)
|
|
with open(os.path.join(args.out, "functions.tsv"), "w", encoding="utf-8", newline="\n") as handle:
|
|
handle.write("".join(line + "\n" for line in fresh_lines))
|
|
with open(os.path.join(args.out, "tests.tsv"), "w", encoding="utf-8", newline="\n") as handle:
|
|
for suite, test, status, reason, ids in merged:
|
|
handle.write(f"{suite}:{test}\t{status}\t{reason}\t{' '.join(map(str, ids))}\n")
|
|
meta = dict(fresh_meta)
|
|
meta.update({"commit": args.commit, "tests": sum(c[0] for c in counts.values()),
|
|
"incomplete": sum(c[1] for c in counts.values()), "suites": suites})
|
|
with open(os.path.join(args.out, "meta.json"), "w", encoding="utf-8", newline="\n") as handle:
|
|
json.dump(meta, handle, indent=1)
|
|
handle.write("\n")
|
|
print(f"merged: {len(rerun)} suite(s) re-run, "
|
|
f"{len(counts) - len(rerun & set(counts))} carried, {len(merged)} rows")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|