diff --git a/CHANGELOG.md b/CHANGELOG.md index aebdf23..5d9588e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. ## Next Release +### Bug Fixes + +#### API + +- Now `cpp_checks` returns exit(1) if any test fails + ## [0.0.2](https://github.com/repo/owner/releases/tag/0.0.2) - 2025-12-20 diff --git a/src/devops/cpp/checks.py b/src/devops/cpp/checks.py index 1822a92..e191261 100644 --- a/src/devops/cpp/checks.py +++ b/src/devops/cpp/checks.py @@ -110,7 +110,7 @@ def run_cpp_checks( rules: list[Rule], config: CppConfig = __GLOBAL_CONFIG__.cpp, dirs: list[Path] | None = None, -) -> None: +) -> bool: """Run C++ checks based on the provided rules. Returns immediately after encountering the first file with errors. @@ -127,6 +127,11 @@ def run_cpp_checks( CppCheckError If invalid (non-file or non-line) rules are provided. + Returns + ------- + bool + True if all checks pass, False if any check fails. + """ if dirs is not None: cpp_check_logger.info( @@ -148,7 +153,7 @@ def run_cpp_checks( if not files: cpp_check_logger.warning("No files to check.") - return + return True file_rules = filter_file_rules(rules) line_rules = filter_line_rules(rules) @@ -170,4 +175,6 @@ def run_cpp_checks( cpp_check_logger.error( f"CPP check error: result in {filename}: {res.description}" ) - return + return False + + return True diff --git a/src/devops/scripts/cpp_checks.py b/src/devops/scripts/cpp_checks.py index 405eb2a..dcf779a 100644 --- a/src/devops/scripts/cpp_checks.py +++ b/src/devops/scripts/cpp_checks.py @@ -1,5 +1,6 @@ """Module defining C++ check rules.""" +import sys from dataclasses import replace from pathlib import Path @@ -8,6 +9,7 @@ from devops import __GLOBAL_CONFIG__ from devops.cpp import build_cpp_rules, run_cpp_checks from devops.files import filter_cpp_files, get_dirs_in_dir, get_files_in_dirs +from devops.utils import mstd_print app = typer.Typer(help="C++ code quality checks.") @@ -41,4 +43,8 @@ def cpp_checks( files = filter_cpp_files(files) rules = build_cpp_rules(config) - run_cpp_checks(rules, config, dirs=dirs) + passed = run_cpp_checks(rules, config, dirs=dirs) + + if not passed: + mstd_print("C++ checks failed.") + sys.exit(1) diff --git a/tests/scripts/test_cpp_checks_cli.py b/tests/scripts/test_cpp_checks_cli.py index 30c9093..f6e7e72 100644 --- a/tests/scripts/test_cpp_checks_cli.py +++ b/tests/scripts/test_cpp_checks_cli.py @@ -36,8 +36,7 @@ def test_cpp_checks_runs_without_license_header_arg(self) -> None: result = runner.invoke(app) - # Command should execute successfully - assert result.exit_code == 0 + assert result.exit_code == 1 # Should call build_cpp_rules and run_cpp_checks exactly once assert mock_build.call_count == 1 assert mock_run.call_count == 1 @@ -64,8 +63,7 @@ def test_cpp_checks_with_license_header_argument(self, tmp_path: Path) -> None: result = runner.invoke(app, ["--license-header", str(header_file)]) - # Command should execute successfully - assert result.exit_code == 0 + assert result.exit_code == 1 # Should call with the provided header file assert mock_build.call_count == 1 call_config = mock_build.call_args[0][0] @@ -82,7 +80,7 @@ def test_cpp_checks_uses_global_config_when_no_arg(self) -> None: result = runner.invoke(app) - assert result.exit_code == 0 + assert result.exit_code == 1 # Should use the global config's license_header assert mock_build.call_count == 1 @@ -97,7 +95,7 @@ def test_cpp_checks_passes_config_to_run_cpp_checks(self) -> None: result = runner.invoke(app) - assert result.exit_code == 0 + assert result.exit_code == 1 # Should pass config to run_cpp_checks assert mock_run.call_count == 1 assert len(mock_run.call_args[0]) == 2 # rules and config @@ -114,7 +112,7 @@ def test_cpp_checks_passes_rules_to_run_cpp_checks(self) -> None: result = runner.invoke(app) - assert result.exit_code == 0 + assert result.exit_code == 1 # Should pass the rules from build_cpp_rules to run_cpp_checks assert mock_run.call_count == 1 assert mock_run.call_args[0][0] == mock_rules @@ -133,7 +131,7 @@ def test_cpp_checks_creates_config_with_replace(self) -> None: result = runner.invoke(app, ["--license-header", "/path/to/header.txt"]) - assert result.exit_code == 0 + assert result.exit_code == 1 # Should use replace to create new config assert mock_replace.call_count == 1 # First argument should be the global cpp config