From 298505d1e103b17b4ebe345ec8f8a6385e56477f Mon Sep 17 00:00:00 2001 From: Piotr Korkus Date: Wed, 18 Feb 2026 17:12:49 +0100 Subject: [PATCH 1/2] add rust line coverage calculation --- .bazelrc | 11 ++- .github/workflows/test_and_docs.yml | 1 + BUILD | 72 +++++++++++++++++++ .../score_modules_tooling.MODULE.bazel | 5 +- scripts/quality_runners.py | 67 ++++++++++++++--- 5 files changed, 142 insertions(+), 14 deletions(-) diff --git a/.bazelrc b/.bazelrc index 48b177fec6..ebc583f2d1 100644 --- a/.bazelrc +++ b/.bazelrc @@ -55,7 +55,16 @@ build:autosd-x86_64 --force_pic build:autosd-x86_64 --extra_toolchains=@autosd_10_gcc_repo//:gcc_toolchain_linux_x86_64 build:autosd-x86_64 --extra_toolchains=@rules_rpm//toolchains:linux_x86_64 - +# Ferrocene Rust coverage config +build:ferrocene-coverage --@rules_rust//rust/settings:extra_rustc_flag=-Cinstrument-coverage +build:ferrocene-coverage --@rules_rust//rust/settings:extra_rustc_flag=-Clink-dead-code +build:ferrocene-coverage --@rules_rust//rust/settings:extra_rustc_flag=-Ccodegen-units=1 +build:ferrocene-coverage --@rules_rust//rust/settings:extra_rustc_flag=-Cdebuginfo=2 +build:ferrocene-coverage --@rules_rust//rust/settings:extra_exec_rustc_flag=-Cinstrument-coverage +build:ferrocene-coverage --@rules_rust//rust/settings:extra_exec_rustc_flag=-Clink-dead-code +build:ferrocene-coverage --@rules_rust//rust/settings:extra_exec_rustc_flag=-Ccodegen-units=1 +build:ferrocene-coverage --@rules_rust//rust/settings:extra_exec_rustc_flag=-Cdebuginfo=2 +test:ferrocene-coverage --run_under=@score_tooling//coverage:llvm_profile_wrapper test:unit-tests --config=linux-x86_64 test:unit-tests --build_tests_only diff --git a/.github/workflows/test_and_docs.yml b/.github/workflows/test_and_docs.yml index 366339ce7e..fde8aceb6e 100644 --- a/.github/workflows/test_and_docs.yml +++ b/.github/workflows/test_and_docs.yml @@ -94,6 +94,7 @@ jobs: run: | mkdir -p artifacts find bazel-testlogs/external -name 'test.xml' -print0 | xargs -0 -I{} cp --parents {} artifacts/ + cp -r "$(bazel info bazel-bin)/coverage/rust-tests" artifacts/rust zip -r ${{ github.event.repository.name }}_test_reports.zip artifacts/ shell: bash diff --git a/BUILD b/BUILD index f8273c8126..f1c1e5c348 100644 --- a/BUILD +++ b/BUILD @@ -12,6 +12,7 @@ # ******************************************************************************* load("@score_docs_as_code//:docs.bzl", "docs") +load("@score_tooling//:defs.bzl", "rust_coverage_report") docs( data = [ @@ -25,3 +26,74 @@ docs( ], source_dir = "docs", ) + +# Rust coverage +rust_coverage_report( + name = "rust_coverage_score_baselibs_rust", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_baselibs_rust//src/...)', + visibility = ["//visibility:public"], +) + +rust_coverage_report( + name = "rust_coverage_score_communication", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_communication//score/...)', + visibility = ["//visibility:public"], +) + +rust_coverage_report( + name = "rust_coverage_score_persistency", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_persistency//src/...)', + visibility = ["//visibility:public"], +) + +rust_coverage_report( + name = "rust_coverage_score_orchestrator", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_orchestrator//src/...)', + visibility = ["//visibility:public"], +) + +rust_coverage_report( + name = "rust_coverage_score_kyron", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_kyron//src/...)', + visibility = ["//visibility:public"], +) + +rust_coverage_report( + name = "rust_coverage_score_lifecycle_health", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_lifecycle_health//src/...)', + visibility = ["//visibility:public"], +) + +rust_coverage_report( + name = "rust_coverage_score_logging", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_logging//score/...)', + visibility = ["//visibility:public"], +) diff --git a/bazel_common/score_modules_tooling.MODULE.bazel b/bazel_common/score_modules_tooling.MODULE.bazel index 380bc1836b..296c8af352 100644 --- a/bazel_common/score_modules_tooling.MODULE.bazel +++ b/bazel_common/score_modules_tooling.MODULE.bazel @@ -27,10 +27,9 @@ single_version_override( ) bazel_dep(name = "score_tooling") -git_override( +single_version_override( module_name = "score_tooling", - remote = "https://github.com/eclipse-score/tooling.git", - commit = "17671026150db4b4cc1b35e48af81b97e13685e5", + version = "1.1.2", ) bazel_dep(name = "score_platform") diff --git a/scripts/quality_runners.py b/scripts/quality_runners.py index 2dc7b516e3..f976e0abe6 100644 --- a/scripts/quality_runners.py +++ b/scripts/quality_runners.py @@ -32,6 +32,7 @@ def run_unit_test_with_coverage(module: Module) -> dict[str, str | int]: "--test_verbose_timeout_warnings", "--test_timeout=1200", "--config=unit-tests", + "--config=ferrocene-coverage", "--test_summary=testcase", "--test_output=errors", "--nocache_test_results", @@ -61,6 +62,15 @@ def run_cpp_coverage_extraction(module: Module, output_path: Path) -> int: return {**summary, "exit_code": result_cpp.exit_code} +def run_rust_coverage_extraction(module: Module, output_path: Path) -> int: + print_centered("QR: Running rust coverage analysis") + + result_rust = rust_coverage(module, output_path) + summary = extract_coverage_summary(result_rust.stdout) + + return {**summary, "exit_code": result_rust.exit_code} + + def cpp_coverage(module: Module, artifact_dir: Path) -> ProcessResult: # .dat files are already generated in UT step @@ -90,6 +100,24 @@ def cpp_coverage(module: Module, artifact_dir: Path) -> ProcessResult: return genhtml_result +def rust_coverage(module: Module, artifact_dir: Path) -> ProcessResult: + # .profraw files are already generated in UT step + + # Run bazel covverage target + # Create dedicated output directory for this module's coverage reports + output_dir = artifact_dir / "rust" / module.name + output_dir.mkdir(parents=True, exist_ok=True) + + bazel_call = [ + "bazel", + "run", + f"//:rust_coverage_{module.name}", + ] + bazel_result = run_command(bazel_call) + + return bazel_result + + def generate_markdown_report( data: dict[str, dict[str, int]], title: str, @@ -142,10 +170,10 @@ def extract_ut_summary(logs: str) -> dict[str, int]: def extract_coverage_summary(logs: str) -> dict[str, str]: """ - Extract coverage summary from genhtml output. + Extract coverage summary from coverage output (genhtml / rust_coverage_report). Args: - logs: Output from genhtml command + logs: Output from coverage command Returns: Dictionary with coverage percentages for lines, functions, and branches @@ -154,17 +182,21 @@ def extract_coverage_summary(logs: str) -> dict[str, str]: # Pattern to match coverage percentages in genhtml output # Example: " lines......: 93.0% (1234 of 1327 lines)" - pattern_lines = re.compile(r"lines\.+:\s+([\d.]+%)") - pattern_functions = re.compile(r"functions\.+:\s+([\d.]+%)") - pattern_branches = re.compile(r"branches\.+:\s+([\d.]+%)") - - if match := pattern_lines.search(logs): + pattern_cpp_lines = re.compile(r"lines\.+:\s+([\d.]+%)") + pattern_cpp_functions = re.compile(r"functions\.+:\s+([\d.]+%)") + pattern_cpp_branches = re.compile(r"branches\.+:\s+([\d.]+%)") + if match := pattern_cpp_lines.search(logs): summary["lines"] = match.group(1) - if match := pattern_functions.search(logs): + if match := pattern_cpp_functions.search(logs): summary["functions"] = match.group(1) - if match := pattern_branches.search(logs): + if match := pattern_cpp_branches.search(logs): summary["branches"] = match.group(1) + # Rust coverage currently returns only line coverage + pattern_rust_lines = re.compile(r"line coverage:\s+([\d.]+%)") + if match := pattern_rust_lines.search(logs): + summary["lines"] = match.group(1) + return summary @@ -267,7 +299,22 @@ def main() -> bool: unit_tests_summary[module.name] = run_unit_test_with_coverage(module=module) if "cpp" in module.metadata.langs: - coverage_summary[module.name] = run_cpp_coverage_extraction( + coverage_summary[f"{module.name}_cpp"] = run_cpp_coverage_extraction( + module=module, output_path=args.coverage_output_dir + ) + + if "rust" in module.metadata.langs: + DISABLED_RUST_COVERAGE = [ + "score_communication", + "score_orchestrator", + "score_baselibs_rust", + ] # Known issues with coverage extraction for these modules, mostly proc_macro + if module.name in DISABLED_RUST_COVERAGE: + print_centered( + f"QR: Skipping rust coverage extraction for module {module.name} due to known issues" + ) + continue + coverage_summary[f"{module.name}_rust"] = run_rust_coverage_extraction( module=module, output_path=args.coverage_output_dir ) From e8057b6d509fc08751218e875ade82d64f3e31f3 Mon Sep 17 00:00:00 2001 From: Piotr Korkus Date: Thu, 19 Feb 2026 09:26:51 +0100 Subject: [PATCH 2/2] automatic generation of rust_coverage BUILD file --- .github/workflows/known_good_correct.yml | 2 +- BUILD | 72 ------ known_good.json | 5 +- rust_coverage/BUILD | 96 ++++++++ .../update_module_from_known_good.py | 224 ++++++++++++------ scripts/quality_runners.py | 3 +- 6 files changed, 259 insertions(+), 143 deletions(-) create mode 100644 rust_coverage/BUILD diff --git a/.github/workflows/known_good_correct.yml b/.github/workflows/known_good_correct.yml index 83c7e88cf4..95ce610298 100644 --- a/.github/workflows/known_good_correct.yml +++ b/.github/workflows/known_good_correct.yml @@ -32,7 +32,7 @@ jobs: - name: Check run: | ls -la - scripts/known_good/update_module_from_known_good.py --known known_good.json --output-dir integration/bazel_common + scripts/known_good/update_module_from_known_good.py --known known_good.json --output-dir-modules bazel_common if git diff --quiet; then echo "No changes" else diff --git a/BUILD b/BUILD index f1c1e5c348..f8273c8126 100644 --- a/BUILD +++ b/BUILD @@ -12,7 +12,6 @@ # ******************************************************************************* load("@score_docs_as_code//:docs.bzl", "docs") -load("@score_tooling//:defs.bzl", "rust_coverage_report") docs( data = [ @@ -26,74 +25,3 @@ docs( ], source_dir = "docs", ) - -# Rust coverage -rust_coverage_report( - name = "rust_coverage_score_baselibs_rust", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_baselibs_rust//src/...)', - visibility = ["//visibility:public"], -) - -rust_coverage_report( - name = "rust_coverage_score_communication", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_communication//score/...)', - visibility = ["//visibility:public"], -) - -rust_coverage_report( - name = "rust_coverage_score_persistency", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_persistency//src/...)', - visibility = ["//visibility:public"], -) - -rust_coverage_report( - name = "rust_coverage_score_orchestrator", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_orchestrator//src/...)', - visibility = ["//visibility:public"], -) - -rust_coverage_report( - name = "rust_coverage_score_kyron", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_kyron//src/...)', - visibility = ["//visibility:public"], -) - -rust_coverage_report( - name = "rust_coverage_score_lifecycle_health", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_lifecycle_health//src/...)', - visibility = ["//visibility:public"], -) - -rust_coverage_report( - name = "rust_coverage_score_logging", - bazel_configs = [ - "linux-x86_64", - "ferrocene-coverage", - ], - query = 'kind("rust_test", @score_logging//score/...)', - visibility = ["//visibility:public"], -) diff --git a/known_good.json b/known_good.json index 5235f5eede..27a62fd948 100644 --- a/known_good.json +++ b/known_good.json @@ -28,6 +28,9 @@ "hash": "9f781acfb6d1a8fa06012ce772b0befb304acf31", "metadata": { "code_root_path": "//src/...", + "exclude_test_targets": [ + "//src/log/score_log_fmt_macro:tests" + ], "langs": [ "rust" ] @@ -119,7 +122,7 @@ }, "score_tooling": { "repo": "https://github.com/eclipse-score/tooling.git", - "hash": "17671026150db4b4cc1b35e48af81b97e13685e5" + "version": "1.1.2" }, "score_platform": { "repo": "https://github.com/eclipse-score/score.git", diff --git a/rust_coverage/BUILD b/rust_coverage/BUILD new file mode 100644 index 0000000000..3aa658edaa --- /dev/null +++ b/rust_coverage/BUILD @@ -0,0 +1,96 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# Generated from known_good.json at 2026-02-10T21:12:42+00:00Z +# Do not edit manually - use scripts/known_good/update_module_from_known_good.py + +load("@score_tooling//:defs.bzl", "rust_coverage_report") + + + +rust_coverage_report( + name = "rust_coverage_score_baselibs_rust", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_baselibs_rust//src/...) except @score_baselibs_rust//src/log/score_log_fmt_macro:tests', + visibility = ["//visibility:public"], +) + + +rust_coverage_report( + name = "rust_coverage_score_communication", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_communication//score/mw/com/impl/...) except @score_communication//score/mw/com/impl:unit_test_runtime_single_exec @score_communication//score/mw/com/impl/configuration:config_parser_test @score_communication//score/mw/com/impl/configuration:configuration_test @score_communication//score/mw/com/impl/tracing/configuration:tracing_filter_config_parser_test', + visibility = ["//visibility:public"], +) + + +rust_coverage_report( + name = "rust_coverage_score_persistency", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_persistency//src/...) except @score_persistency//src/cpp/tests:bm_kvs_cpp', + visibility = ["//visibility:public"], +) + + +rust_coverage_report( + name = "rust_coverage_score_orchestrator", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_orchestrator//src/...)', + visibility = ["//visibility:public"], +) + + +rust_coverage_report( + name = "rust_coverage_score_kyron", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_kyron//src/...)', + visibility = ["//visibility:public"], +) + + +rust_coverage_report( + name = "rust_coverage_score_lifecycle_health", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_lifecycle_health//src/...)', + visibility = ["//visibility:public"], +) + + +rust_coverage_report( + name = "rust_coverage_score_logging", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @score_logging//score/...) except @score_logging//score/datarouter/test/ut/ut_logging:dltprotocolUT @score_logging//score/datarouter/test/ut/ut_logging:persistentLogConfigUT @score_logging//score/datarouter/test/ut/ut_logging:socketserverConfigUT @score_logging//score/datarouter/test/ut/ut_logging:socketserverUT @score_logging//score/mw/log/legacy_non_verbose_api:unit_test', + visibility = ["//visibility:public"], +) + \ No newline at end of file diff --git a/scripts/known_good/update_module_from_known_good.py b/scripts/known_good/update_module_from_known_good.py index a7b9b25335..4932bca4aa 100755 --- a/scripts/known_good/update_module_from_known_good.py +++ b/scripts/known_good/update_module_from_known_good.py @@ -2,42 +2,47 @@ """ Read a known_good.json file and generate a score_modules.MODULE.bazel file with `bazel_dep` and `git_override` calls for each module in the JSON. +It generates also rust_coverage/BUILD file with `rust_coverage_report` for each module with rust impl. Usage: python3 scripts/known_good/update_module_from_known_good.py \ --known known_good.json \ - --output-dir bazel_common + --output-dir-modules bazel_common \ + --output-dir-coverage rust_coverage The generated score_modules_NAME_.MODULE.bazel file is included by MODULE.bazel. Note: To override repository commits before generating the MODULE.bazel file, use scripts/known_good/override_known_good_repo.py first to create an updated known_good.json. """ + import argparse +import logging import os import re -import logging -from typing import Dict, List, Optional from pathlib import Path +from typing import Dict, List, Optional from models import Module from models.known_good import load_known_good # Configure logging -logging.basicConfig(level=logging.WARNING, format='%(levelname)s: %(message)s') +logging.basicConfig(level=logging.WARNING, format="%(levelname)s: %(message)s") -def generate_git_override_blocks(modules: List[Module], repo_commit_dict: Dict[str, str]) -> List[str]: +def generate_git_override_blocks( + modules: List[Module], repo_commit_dict: Dict[str, str] +) -> List[str]: """Generate bazel_dep and git_override blocks for each module.""" blocks = [] - + for module in modules: commit = module.hash - + # Allow overriding specific repos via command line if module.repo in repo_commit_dict: commit = repo_commit_dict[module.repo] - + # Generate patches lines if bazel_patches exist patches_lines = "" if module.bazel_patches: @@ -45,61 +50,107 @@ def generate_git_override_blocks(modules: List[Module], repo_commit_dict: Dict[s for patch in module.bazel_patches: patches_lines += f' "{patch}",\n' patches_lines += " ],\n patch_strip = 1,\n" - + if module.version: # If version is provided, use bazel_dep with single_version_override block = ( f'bazel_dep(name = "{module.name}")\n' - 'single_version_override(\n' + "single_version_override(\n" f' module_name = "{module.name}",\n' f' version = "{module.version}",\n' - f'{patches_lines}' - ')\n' + f"{patches_lines}" + ")\n" ) else: if not module.repo or not commit: - logging.warning("Skipping module %s with missing repo or commit: repo=%s, commit=%s", - module.name, module.repo, commit) + logging.warning( + "Skipping module %s with missing repo or commit: repo=%s, commit=%s", + module.name, + module.repo, + commit, + ) continue # Validate commit hash format (7-40 hex characters) - if not re.match(r'^[a-fA-F0-9]{7,40}$', commit): - logging.warning("Skipping module %s with invalid commit hash: %s", module.name, commit) + if not re.match(r"^[a-fA-F0-9]{7,40}$", commit): + logging.warning( + "Skipping module %s with invalid commit hash: %s", + module.name, + commit, + ) continue - + # If no version, use bazel_dep with git_override block = ( f'bazel_dep(name = "{module.name}")\n' - 'git_override(\n' + "git_override(\n" f' module_name = "{module.name}",\n' f' remote = "{module.repo}",\n' f' commit = "{commit}",\n' - f'{patches_lines}' - ')\n' + f"{patches_lines}" + ")\n" ) - + blocks.append(block) - + return blocks + def generate_local_override_blocks(modules: List[Module]) -> List[str]: """Generate bazel_dep and local_path_override blocks for each module.""" blocks = [] - + for module in modules: block = ( f'bazel_dep(name = "{module.name}")\n' - 'local_path_override(\n' + "local_path_override(\n" f' module_name = "{module.name}",\n' f' path = "{module.name}",\n' - ')\n' + ")\n" ) - + blocks.append(block) - + return blocks -def generate_file_content(args: argparse.Namespace, modules: List[Module], repo_commit_dict: Dict[str, str], timestamp: Optional[str] = None) -> str: + +def generate_coverage_blocks(modules: List[Module]) -> List[str]: + """Generate rust_coverage_report blocks for each module with rust impl.""" + blocks = ["""load("@score_tooling//:defs.bzl", "rust_coverage_report")\n\n"""] + + for module in modules: + if "rust" not in module.metadata.langs: + continue + + if module.metadata.exclude_test_targets: + excluded_tests = f" except {' '.join([f'@{module.name}{target}' for target in module.metadata.exclude_test_targets])}" + else: + excluded_tests = "" + + block = f""" +rust_coverage_report( + name = "rust_coverage_{module.name}", + bazel_configs = [ + "linux-x86_64", + "ferrocene-coverage", + ], + query = 'kind("rust_test", @{module.name}{module.metadata.code_root_path}){excluded_tests}', + visibility = ["//visibility:public"], +) + """ + + blocks.append(block) + + return blocks + + +def generate_file_content( + args: argparse.Namespace, + modules: List[Module], + repo_commit_dict: Dict[str, str], + timestamp: Optional[str] = None, + file_type: str = "module", +) -> str: """Generate the complete content for score_modules.MODULE.bazel.""" # License header header = ( @@ -124,20 +175,23 @@ def generate_file_content(args: argparse.Namespace, modules: List[Module], repo_ "# Do not edit manually - use scripts/known_good/update_module_from_known_good.py\n" "\n" ) - - if args.override_type == "git": - blocks = generate_git_override_blocks(modules, repo_commit_dict) + if file_type == "module": + if args.override_type == "git": + blocks = generate_git_override_blocks(modules, repo_commit_dict) + else: + header += ( + "# Note: This file uses local_path overrides. Ensure that local paths are set up correctly.\n" + "\n" + ) + blocks = generate_local_override_blocks(modules) + elif file_type == "build": + blocks = generate_coverage_blocks(modules) else: - header += ( - "# Note: This file uses local_path overrides. Ensure that local paths are set up correctly.\n" - "\n" - ) - blocks = generate_local_override_blocks(modules) + raise ValueError(f"Invalid file_type: {file_type}") - if not blocks: raise SystemExit("No valid modules to generate git_override blocks") - + return header + "\n".join(blocks) @@ -156,7 +210,7 @@ def main() -> None: # Specify output directory for grouped modules python3 scripts/known_good/update_module_from_known_good.py \\ - --output-dir ./bazel_modules + --output-dir-modules ./bazel_modules # Preview without writing python3 scripts/known_good/update_module_from_known_good.py --dry-run @@ -164,38 +218,41 @@ def main() -> None: Note: - Generates score_modules_{group}.MODULE.bazel for each group - To override repository commits, use scripts/known_good/override_known_good_repo.py first. - """ + """, ) parser.add_argument( "--known", - default="known_good.json", - help="Path to known_good.json (default: known_good.json)" + default=Path(__file__).parents[2] / "known_good.json", + help="Path to known_good.json (default: known_good.json in repo root)", ) parser.add_argument( - "--output-dir", - default=".", - help="Output directory for grouped structure files (default: current directory)" + "--output-dir-modules", + default=Path(__file__).parents[2] / "bazel_common", + help="Output directory for grouped structure files (default: bazel_common in repo root)", + ) + parser.add_argument( + "--output-dir-coverage", + default=Path(__file__).parents[2] / "rust_coverage", + help="Output directory for BUILD coverage file (default: rust_coverage in repo root)", ) parser.add_argument( "--dry-run", action="store_true", - help="Print generated content instead of writing to file" + help="Print generated content instead of writing to file", ) parser.add_argument( - "-v", "--verbose", - action="store_true", - help="Enable verbose logging" + "-v", "--verbose", action="store_true", help="Enable verbose logging" ) parser.add_argument( "--repo-override", action="append", - help="Override commit for a specific repo (format: @)" + help="Override commit for a specific repo (format: @)", ) parser.add_argument( "--override-type", choices=["local_path", "git"], default="git", - help="Type of override to use (default: git)" + help="Type of override to use (default: git)", ) args = parser.parse_args() @@ -211,7 +268,9 @@ def main() -> None: # Parse repo overrides repo_commit_dict = {} if args.repo_override: - repo_pattern = re.compile(r'https://[a-zA-Z0-9.-]+/[a-zA-Z0-9._/-]+\.git@[a-fA-F0-9]{7,40}$') + repo_pattern = re.compile( + r"https://[a-zA-Z0-9.-]+/[a-zA-Z0-9._/-]+\.git@[a-fA-F0-9]{7,40}$" + ) for entry in args.repo_override: if not repo_pattern.match(entry): raise SystemExit( @@ -233,8 +292,8 @@ def main() -> None: raise SystemExit("No modules found in known_good.json") # Generate files based on structure (flat vs grouped) - output_dir = os.path.abspath(args.output_dir) - os.makedirs(output_dir, exist_ok=True) + output_dir_modules = os.path.abspath(args.output_dir_modules) + os.makedirs(output_dir_modules, exist_ok=True) generated_files = [] total_module_count = 0 @@ -249,26 +308,57 @@ def main() -> None: # Determine output filename: score_modules_{group}.MODULE.bazel output_filename = f"score_modules_{group_name}.MODULE.bazel" - output_path = os.path.join(output_dir, output_filename) + output_path_modules = os.path.join(output_dir_modules, output_filename) + output_path_coverage = args.output_dir_coverage / "BUILD" - # Generate file content - content = generate_file_content(args, modules, repo_commit_dict, known_good.timestamp) + # Generate file content of MODULE files + content_module = generate_file_content( + args, modules, repo_commit_dict, known_good.timestamp, file_type="module" + ) if args.dry_run: - print(f"\nDry run: would write to {output_path}\n") - print("---- BEGIN GENERATED CONTENT ----") - print(content) - print("---- END GENERATED CONTENT ----") - print(f"\nGenerated {len(modules)} {args.override_type}_override entries for group '{group_name}'") + print(f"\nDry run: would write to {output_path_modules}\n") + print("---- BEGIN GENERATED CONTENT FOR MODULE ----") + print(content_module) + print("---- END GENERATED CONTENT FOR MODULE ----") + print( + f"\nGenerated {len(modules)} {args.override_type}_override entries for group '{group_name}'" + ) else: - with open(output_path, "w", encoding="utf-8") as f: - f.write(content) - generated_files.append(output_path) + with open(output_path_modules, "w", encoding="utf-8") as f: + f.write(content_module) + generated_files.append(output_path_modules) total_module_count += len(modules) - print(f"Generated {output_path} with {len(modules)} {args.override_type}_override entries") + print( + f"Generated {output_path_modules} with {len(modules)} {args.override_type}_override entries" + ) + + # Generate file content of BUILD coverage files + if "target_sw" not in group_name: + continue # Only generate coverage for software modules + + content_build = generate_file_content( + args, modules, repo_commit_dict, known_good.timestamp, file_type="build" + ) + + if args.dry_run: + print(f"\nDry run: would write to {output_path_coverage}\n") + print("---- BEGIN GENERATED CONTENT FOR BUILD ----") + print(content_build) + print("---- END GENERATED CONTENT FOR BUILD ----") + print( + f"\nGenerated {len(modules)} {args.override_type}_override entries for group '{group_name}'" + ) + else: + with open(output_path_coverage, "w", encoding="utf-8") as f: + f.write(content_build) + generated_files.append(output_path_coverage) + print(f"Generated {output_path_coverage}") if not args.dry_run and generated_files: - print(f"\nSuccessfully generated {len(generated_files)} file(s) with {total_module_count} total modules") + print( + f"\nSuccessfully generated {len(generated_files)} file(s) with {total_module_count} total modules" + ) if __name__ == "__main__": diff --git a/scripts/quality_runners.py b/scripts/quality_runners.py index f976e0abe6..2f37818ce0 100644 --- a/scripts/quality_runners.py +++ b/scripts/quality_runners.py @@ -111,7 +111,7 @@ def rust_coverage(module: Module, artifact_dir: Path) -> ProcessResult: bazel_call = [ "bazel", "run", - f"//:rust_coverage_{module.name}", + f"//rust_coverage:rust_coverage_{module.name}", ] bazel_result = run_command(bazel_call) @@ -307,7 +307,6 @@ def main() -> bool: DISABLED_RUST_COVERAGE = [ "score_communication", "score_orchestrator", - "score_baselibs_rust", ] # Known issues with coverage extraction for these modules, mostly proc_macro if module.name in DISABLED_RUST_COVERAGE: print_centered(