Skip to content

Feat/add new metric checker tool#4334

Open
ChristianHuehn wants to merge 32 commits intomainfrom
feat/add-new-metric-checker-tool
Open

Feat/add new metric checker tool#4334
ChristianHuehn wants to merge 32 commits intomainfrom
feat/add-new-metric-checker-tool

Conversation

@ChristianHuehn
Copy link
Collaborator

Closes: #4333

Description

Definition of Done

A PR is only ready for merge once all the following acceptance criteria are fulfilled:

  • Changes have been manually tested
  • All TODOs related to this PR have been closed
  • There are automated tests for newly written code and bug fixes
  • All bugs discovered while working on this PR have been submitted as issues (if not already an open issue)
  • Documentation (GH-pages, analysis/visualization READMEs, parser READMEs, --help, etc.) has been updated (almost always necessary except for bug fixes)
  • CHANGELOG.md has been updated

Screenshots or gifs

ChristianHuehn and others added 15 commits November 3, 2025 21:41
Add a new CLI tool that validates code metrics against configurable thresholds for use in CI/CD pipelines. The tool uses UnifiedParser internally to analyze code and reports violations when metrics exceed specified limits.

Features:
- Validates file-level metrics from UnifiedParser (rloc, complexity, etc.)
- Supports YAML and JSON configuration files via Jackson
- Reports violations sorted by severity (worst offenders first)
- Color-coded console output with formatted tables
- Exit codes: 0 (pass), 1 (violations), 2 (errors)
- Interactive mode support via Dialog
- Comprehensive documentation with usage examples

Implementation:
- New module: analysers/tools/MetricThresholdChecker
- Dependencies: Jackson 2.18.2 (databind, dataformat-yaml, module-kotlin)
- Registered in Ccsh and settings.gradle.kts
- Added YAML/YML file extensions to FileExtension enum

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Document the new MetricThresholdChecker tool in the unreleased section of the CHANGELOG.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive documentation for the new MetricThresholdChecker tool to the GitHub Pages site. Includes:
- Tool overview and features
- Configuration format (YAML/JSON)
- Available metrics from UnifiedParser
- Usage examples and parameters
- CI/CD integration examples for GitHub Actions, GitLab CI, and Jenkins
- Tips for prioritizing fixes and iterative improvement
- Common use cases

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add 22 test cases covering MetricThreshold validation logic
- Test min/max threshold violations and boundary conditions
- Test violation type detection (BELOW_MIN, ABOVE_MAX)
- Test edge cases: decimals, negatives, zero, large numbers
- Test threshold value retrieval by violation type
- All tests follow Arrange-Act-Assert pattern
- Achieves comprehensive coverage of threshold validation logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add 14 test cases for config file loading and parsing
- Test JSON and YAML format parsing (yml, yaml extensions)
- Test edge cases: empty metrics, missing keys, decimals
- Test error scenarios: invalid syntax, non-existent files
- Test validation: unsupported extensions, non-numeric values
- Test case-insensitive extension handling
- Add 11 test resource files for various scenarios
- All tests follow Arrange-Act-Assert pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add 16 test cases for threshold validation logic
- Test min/max violation detection for file metrics
- Test nested folder structure traversal
- Test multiple files and multiple metric violations
- Test edge cases: empty projects, only folders, no metrics
- Test node type filtering (skip Class, Method, Package nodes)
- Test boundary conditions and decimal values
- Test non-numeric attribute value handling
- Test path construction for violations
- All tests follow Arrange-Act-Assert pattern with helper functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add 18 test cases for violation output formatting
- Test success and failure message formatting
- Test violation grouping by metric name
- Test table formatting with headers and data
- Test excess amount calculation and display (+/- signs)
- Test threshold value display (min/max)
- Test number formatting (integers vs decimals)
- Test violation sorting by excess amount
- Test multiple metrics with different violation counts
- Test long path truncation
- Handle locale-dependent decimal separators
- All tests follow Arrange-Act-Assert pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add 16 integration test cases for main CLI tool
- Test successful execution with passing thresholds
- Test CLI parameter handling (verbose, exclude, file-extensions)
- Test input validation (null paths, non-existent files)
- Test bypass-gitignore flag functionality
- Test single file and directory analysis
- Test multiple exclude patterns and file extensions
- Test interface methods (isApplicable, getDialog)
- Test constants (NAME, DESCRIPTION)
- Add sample code files and test configurations
- Handle exitProcess(1) limitations in testing
- All tests follow Arrange-Act-Assert pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Move inline comments to separate lines per ktlint rules
- Fix argument formatting in test cases
- All tests still pass with 82% branch coverage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Reorganized test resource files into logical subdirectories:
- config/: Valid configuration files for positive test cases
- config-invalid/: Invalid configurations for error handling tests
- sample-code/: Test source code files (already existed)

Updated test file paths in MetricThresholdCheckerTest and ThresholdConfigurationLoaderTest to reflect new structure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ation

Reorganize MetricThresholdChecker from flat 17-file structure into logical
subdirectories following patterns used in other analysers:

- model/ - Data model classes (ThresholdConfiguration, etc.)
- config/ - Configuration loading (ThresholdConfigurationLoader)
- validation/ - Validation logic (ThresholdValidator)
- output/ - Output formatting with subdirectories:
  - renderers/ - High-level rendering (SummaryRenderer, ViolationTableRenderer, ViolationGroupRenderer)
  - formatters/ - Low-level formatting utilities (NumberFormatter, PathFormatter, etc.)

All files moved with git mv to preserve history. All package declarations
and imports updated. Build, tests (131 passing), and ktlint checks verified.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed multiple alignment issues in violation table rendering:

1. ANSI color code handling - Replaced broken substring() approach with
   manual padding that accounts for invisible ANSI color codes

2. Table width overflow - Added MAX_PATH_WIDTH=50 cap to prevent table
   from becoming too wide for terminal

3. Path truncation - Changed from middle truncation to start truncation
   (e.g., "...ectories/File.kt") to keep filename visible

4. Path alignment - Right-aligned path column so filenames line up
   vertically for easier scanning

Updated PathFormatterTest to match new truncation behavior with exact
expected output assertions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
MetricThresholdChecker was duplicating UnifiedParser's scanning logic,
requiring manual AttributeDescriptor registration which was bug-prone.

Changes:
- Add UnifiedParser.parse() as public API for library usage
- Refactor MetricThresholdChecker to use UnifiedParser.parse()
- Remove duplicated ProjectScanner setup code
- AttributeDescriptors now included automatically

This eliminates code duplication and ensures MetricThresholdChecker
benefits from any UnifiedParser improvements.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
christian-huehn-mw and others added 2 commits November 7, 2025 07:55
Refactored MetricThresholdChecker code based on PR #4334 review feedback:

- TextWrapper.wrap(): Simplified complex logic inline, reduced conditional
  complexity, and made flow more linear
- ViolationGroupRenderer.render(): Extracted into smaller focused methods
  (addViolationsHeader, renderMetricGroup, addMetricDescription,
  sortViolationsByExcess) for better readability
- ViolationTableRenderer: Replaced string concatenation with Kotlin template
  strings and added intermediate variables to fix ktlint line length violations
- ThresholdValidator.validateNode(): Used else branch instead of comma-separated
  node types for cleaner when statement
- ThresholdValidator.validateFileMetrics(): Reduced nesting depth from 3 to 1
  level using guard clauses with continue statements

All 131 tests passing. Code style checks passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@ChristianHuehn ChristianHuehn marked this pull request as ready for review November 7, 2025 06:56
Comment on lines +51 to +79
fun parse(
inputFile: File,
excludePatterns: List<String> = emptyList(),
fileExtensions: List<String> = emptyList(),
bypassGitignore: Boolean = false,
verbose: Boolean = false
): Project {
val projectBuilder = ProjectBuilder()
val useGitignore = !bypassGitignore

val projectScanner = ProjectScanner(
inputFile,
projectBuilder,
excludePatterns,
fileExtensions,
emptyMap(),
useGitignore
)

projectScanner.traverseInputProject(verbose)

if (!projectScanner.foundParsableFiles()) {
Logger.warn { "No parsable files found in the given input path" }
}

projectBuilder.addAttributeDescriptions(getAttributeDescriptors())

return projectBuilder.build()
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function mirrors a lot of the functionality of the private "scanInputProject" function without:

  • handling of piped input
  • logic to adjust exclusion patterns based on gitignore files
  • reporting result of the unifiedparser
    This should be refactored to avoid duplicated code

christian-huehn-mw and others added 7 commits November 11, 2025 11:47
…entry (#4334)

Added missing issue reference to MetricThresholdChecker tool entry in CHANGELOG.md as requested in PR review.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Removed javax-activation dependency from libs.versions.toml as it is no longer used in the codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Added proper Arrange/Act/Assert comments to all tests
- Moved class-level comment about exitProcess limitations to top
- Removed redundant inline comments
- Renamed unclear test methods to better reflect what they test
- All tests still passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…idatorTest (#4334)

Replaced all [0] array access with .first() for better Kotlin idioms and null safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
)

Changed ambiguous regex that accepted both 75.56 and 75.57 to explicit expectation of 75.57 for round-half-up behavior. Test name updated to reflect rounding mode.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added validation to throw IllegalArgumentException when max is less than min in MetricThreshold. Includes test coverage for this edge case.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Refactored ThresholdValidator to use functional approach without side effects:
- Changed validateNode() to return List<ThresholdViolation> instead of mutating parameter
- Use flatMap for collecting child violations
- Use mapNotNull for collecting file metric violations
- All functions now return new lists instead of modifying mutable state

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
christian-huehn-mw and others added 6 commits November 11, 2025 11:55
Refactored TextWrapper to be more self-explanatory:
- Extracted helper methods with descriptive names (shouldStartNewLine, hasContent, etc.)
- Replaced cryptic variable names with clear ones (hasContentAlready instead of needsSpace)
- Simplified main wrap() method to read like plain English
- Renamed WORD_SEPARATOR_LENGTH to SPACE_LENGTH for clarity

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…4334)

Changed NumberFormatter to explicitly use BigDecimal with RoundingMode.HALF_UP instead of relying on String.format's default banker's rounding. This ensures consistent and predictable rounding behavior for all decimal values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…gurationLoader (#4334)

Refactored to use type-safe Jackson deserialization:
- Removed all @Suppress annotations for unchecked casts
- Removed unsafe type casts
- Introduced DTOs (ConfigurationDTO, MetricThresholdDTO) for type-safe deserialization
- Added proper Jackson configuration to ignore unknown properties
- Cleaner separation between JSON/YAML parsing and domain models

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add MetricThresholdChecker tool for CI/CD pipelines

3 participants