mongo/evergreen/generate_symbol_check_report.py
Daniel Moody f7c6ecd634 SERVER-117835 fix symbol check suggested command (#47067)
GitOrigin-RevId: 68c94d6912ada19f0b87499ac8030674b9b75be0
2026-01-27 22:38:04 +00:00

115 lines
3.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import os
import sys
from buildscripts.simple_report import make_report, put_report, try_combine_reports
from buildscripts.util.read_config import read_config_file
def _read_optional_text_file(path: str) -> str | None:
try:
with open(path) as f:
content = f.read().strip()
except OSError:
return None
return content or None
def _with_debug_target(target: str) -> str:
"""Symbol-check aspect emits cc_library-like targets as *_with_debug."""
if target.endswith("_with_debug"):
return target
return f"{target}_with_debug"
# 1. detect if we should run symbol-check reporting
expansions = read_config_file("../expansions.yml")
symbol_check = expansions.get("run_for_symbol_check", None)
if not symbol_check:
sys.exit(0)
failures = []
# Prefer the exact Bazel flags/invocation emitted by the Evergreen Bazel compile script.
# This script is run from the "src" directory (see evergreen/run_python_script.sh).
bazel_build_flags = _read_optional_text_file(".bazel_build_flags")
bazel_build_invocation = _read_optional_text_file(".bazel_build_invocation")
# 2. walk bazel-bin for *_checked files emitted by the aspect
for root, _, files in os.walk("bazel-bin"):
for name in files:
if not name.endswith("_checked"):
continue
checked_path = os.path.join(root, name)
# default values in case we fall back to text mode
target = None
sym_file = None
missing = None
status = None
with open(checked_path) as f:
data = json.load(f)
status = data.get("status")
target = data.get("target")
sym_file = data.get("sym_file")
missing = data.get("missing", [])
if status == "failed":
# build content for the report
lines = []
lines.append(f"Symbol check failed for: {target}")
lines.append("Missing symbols:")
for m in missing:
lines.append(f" - {m}")
lines.append(
f"Please check to see if {target} is missing any deps that would include the symbols above"
)
# reproduction hint adjust this to your CI config name
# if you have a real config, e.g. --config=symbol-check, use that
repro_target = target or sym_file or checked_path
lines.append("")
lines.append("To reproduce:")
repro_target = _with_debug_target(str(repro_target))
if bazel_build_flags:
lines.append(f" bazel build {bazel_build_flags} {repro_target}")
else:
lines.append(f" bazel build --config=symbol-checker {repro_target}")
content = "\n".join(lines)
# for symbol check we don't have a real src path like clang-tidy,
# so use a synthetic "file" name that encodes the bazel target
synthetic_file = f"symbol_check:{target or checked_path}"
failures.append((synthetic_file, content))
# 3. write a helper invocation file
with open("bazel-invocation.txt", "w") as f:
if bazel_build_invocation:
# Keep the exact command that CI ran (targets included).
f.write(bazel_build_invocation)
elif bazel_build_flags:
# Fall back to the exact flags from CI (best effort on targets).
f.write(f"bazel build {bazel_build_flags} //src/...")
else:
# Last-resort fallback.
f.write("bazel build --config=symbol-checker //src/...")
# 4. emit reports
if failures:
for filename, content in failures:
report = make_report(filename, content, 1)
try_combine_reports(report)
put_report(report)
sys.exit(1)
else:
report = make_report("symbol-check", "all symbol checks passed", 0)
try_combine_reports(report)
put_report(report)
sys.exit(0)